1 /*        $NetBSD: mount_linux.c,v 1.1.1.3 2015/01/17 16:34:16 christos Exp $   */
2 
3 /*
4  * Copyright (c) 1997-2014 Erez Zadok
5  * Copyright (c) 1990 Jan-Simon Pendry
6  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7  * Copyright (c) 1990 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Jan-Simon Pendry at Imperial College, London.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *
38  * File: am-utils/conf/mount/mount_linux.c
39  */
40 
41 /*
42  * Linux mount helper.
43  */
44 
45 #ifdef HAVE_CONFIG_H
46 # include <config.h>
47 #endif /* HAVE_CONFIG_H */
48 #include <am_defs.h>
49 #include <amu.h>
50 #include <nfs_common.h>
51 
52 #ifdef HAVE_RPC_AUTH_H
53 # include <rpc/auth.h>
54 #endif
55 
56 #ifndef MOUNT_TYPE_UFS
57 /*
58  * Autoconf didn't find any disk-based f/s on this system,
59  * So provide some default definition for this file to compile.
60  */
61 # define MOUNT_TYPE_UFS                 "no_disk_fs"
62 #endif /* not MOUNT_TYPE_UFS */
63 
64 struct opt_map {
65   const char *opt;            /* option name */
66   int inv;                              /* true if flag value should be inverted */
67   int mask;                             /* flag mask value */
68 };
69 
70 const struct opt_map opt_map[] =
71 {
72   {"defaults",                0,        0},
73   {MNTTAB_OPT_RO,   0,        MNT2_GEN_OPT_RDONLY},
74   {MNTTAB_OPT_RW,   1,        MNT2_GEN_OPT_RDONLY},
75   {MNTTAB_OPT_EXEC, 1,        MNT2_GEN_OPT_NOEXEC},
76   {MNTTAB_OPT_NOEXEC,         0,        MNT2_GEN_OPT_NOEXEC},
77   {MNTTAB_OPT_SUID, 1,        MNT2_GEN_OPT_NOSUID},
78   {MNTTAB_OPT_NOSUID,         0,        MNT2_GEN_OPT_NOSUID},
79 #ifdef MNT2_GEN_OPT_NODEV
80   {MNTTAB_OPT_NODEV,          0,        MNT2_GEN_OPT_NODEV},
81 #endif /* MNT2_GEN_OPT_NODEV */
82 #ifdef MNT2_GEN_OPT_SYNC
83   {MNTTAB_OPT_SYNC, 0,        MNT2_GEN_OPT_SYNC},
84   {MNTTAB_OPT_ASYNC,          1,        MNT2_GEN_OPT_SYNC},
85 #endif /* MNT2_GEN_OPT_SYNC */
86 #ifdef MNT2_GEN_OPT_NOSUB
87   {MNTTAB_OPT_SUB,  1,        MNT2_GEN_OPT_NOSUB},
88   {MNTTAB_OPT_NOSUB,          0,        MNT2_GEN_OPT_NOSUB},
89 #endif /* MNT2_GEN_OPT_NOSUB */
90 #ifdef MNT2_GEN_OPT_SYNCHRONOUS
91   {"synchronous",   0,        MNT2_GEN_OPT_SYNCHRONOUS},
92 #endif /* MNT2_GEN_OPT_SYNCHRONOUS */
93 #ifdef MNT2_GEN_OPT_MANDLOCK
94   {"mandlock",                0,        MNT2_GEN_OPT_MANDLOCK},
95 #endif /* MNT2_GEN_OPT_MANDLOCK */
96 #ifdef MNT2_GEN_OPT_NOATIME
97   {"noatime",                 0,        MNT2_GEN_OPT_NOATIME},
98 #endif /* MNT2_GEN_OPT_NOATIME */
99 #ifdef MNT2_GEN_OPT_NODIRATIME
100   {"nodiratime",    0,        MNT2_GEN_OPT_NODIRATIME},
101 #endif /* MNT2_GEN_OPT_NODIRATIME */
102   {NULL,            0,        0}
103 };
104 
105 struct fs_opts {
106   const char *opt;
107   int type;                             /* XXX: Ion, what is this for? */
108 };
109 
110 const struct fs_opts iso_opts[] = {
111   { "map",          0 },
112   { "norock",       0 },
113   { "cruft",        0 },
114   { "unhide",       0 },
115   { "conv",         1 },
116   { "block",        1 },
117   { "mode",         1 },
118   { "gid",          1 },
119   { "uid",          1 },
120   { NULL, 0 }
121 };
122 
123 const struct fs_opts dos_opts[] = {
124   { "check",        1 },
125   { "conv",         1 },
126   { "uid",          1 },
127   { "gid",          1 },
128   { "umask",        1 },
129   { "debug",        0 },
130   { "fat",          1 },
131   { "quiet",        0 },
132   { "blocksize",1 },
133   { NULL, 0 }
134 };
135 
136 const struct fs_opts autofs_opts[] = {
137   { "fd", 1 },
138   { "pgrp",         1 },
139   { "minproto",     1 },
140   { "maxproto",     1 },
141   { NULL, 0 }
142 };
143 
144 const struct fs_opts lustre_opts[] = {
145   { "flock",                  0 },
146   { "localflock",   0 },
147   { NULL,           0 }
148 };
149 
150 const struct fs_opts null_opts[] = {
151   { NULL, 0 }
152 };
153 
154 const struct fs_opts ext2_opts[] = {
155   { "check",                            1 },
156   { "nocheck",                          0 },
157   { "debug",                            0 },
158   { "errors",                           1 },
159   { "grpid",                            0 },
160   { "nogrpid",                          0 },
161   { "bsdgroups",              0 },
162   { "sysvgroups",             0 },
163   { "grpquota",                         0 },
164   { "usrquota",                         0 },
165   { "noquota",                          0 },
166   { "quota",                            0 },
167   { "nouid32",                          0 },
168   { "oldalloc",                         0 },
169   { "orlov",                            0 },
170   { "resgid",                           1 },
171   { "resuid",                           1 },
172   { "sb",                     1 },
173   { "user_xattr",             1 },
174   { "nouser_xattr",           1 },
175   { "journal_dev",            0 },
176   { "norecovery",             0 },
177   { "noload",                           0 },
178   { "data",                             1 },
179   { "barrier",                          1 },
180   { "commit",                           1 },
181   { "user_xattr",             0 },
182   { "nouser_xattr",           0 },
183   { "acl",                              0 },
184   { "noacl",                            0 },
185   { "bsddf",                            0 },
186   { "minixdf",                          0 },
187   { "usrjquota",              1 },
188   { "grpjquota",              1 },
189   { "jqfmt",                            1 },
190   { NULL, 0 }
191 };
192 
193 const struct fs_opts ext3_opts[] = {
194   { "check",                            1 },
195   { "nocheck",                          0 },
196   { "debug",                            0 },
197   { "errors",                           1 },
198   { "grpid",                            0 },
199   { "nogrpid",                          0 },
200   { "bsdgroups",              0 },
201   { "sysvgroups",             0 },
202   { "grpquota",                         0 },
203   { "usrquota",                         0 },
204   { "noquota",                          0 },
205   { "quota",                            0 },
206   { "nouid32",                          0 },
207   { "oldalloc",                         0 },
208   { "orlov",                            0 },
209   { "resgid",                           1 },
210   { "resuid",                           1 },
211   { "sb",                     1 },
212   { "user_xattr",             1 },
213   { "nouser_xattr",           1 },
214   { "journal",                          1 },
215   { "journal_dev",            1 },
216   { "norecovery",             0 },
217   { "noload",                           0 },
218   { "data",                             1 },
219   { "barrier",                          1 },
220   { "commit",                           1 },
221   { "user_xattr",             0 },
222   { "nouser_xattr",           0 },
223   { "acl",                              0 },
224   { "noacl",                            0 },
225   { "bsddf",                            0 },
226   { "minixdf",                          0 },
227   { "usrjquota",              1 },
228   { "grpjquota",              1 },
229   { "jqfmt",                            1 },
230   { NULL, 0 }
231 };
232 
233 const struct fs_opts ext4_opts[] = {
234   { "debug",                            0 },
235   { "errors",                           1 },
236   { "grpid",                            0 },
237   { "nogrpid",                          0 },
238   { "bsdgroups",              0 },
239   { "sysvgroups",             0 },
240   { "grpquota",                         0 },
241   { "usrquota",                         0 },
242   { "noquota",                          0 },
243   { "quota",                            0 },
244   { "oldalloc",                         0 },
245   { "orlov",                            0 },
246   { "resgid",                           1 },
247   { "resuid",                           1 },
248   { "sb",                     1 },
249   { "user_xattr",             1 },
250   { "nouser_xattr",           1 },
251   { "journal",                          1 },
252   { "journal_dev",            1 },
253   { "noload",                           0 },
254   { "data",                             1 },
255   { "commit",                           1 },
256   { "user_xattr",             0 },
257   { "nouser_xattr",           0 },
258   { "acl",                              0 },
259   { "noacl",                            0 },
260   { "bsddf",                            0 },
261   { "minixdf",                          0 },
262   { "usrjquota",              1 },
263   { "grpjquota",              1 },
264   { "jqfmt",                            1 },
265   { "journal_checksum",                 0 },
266   { "journal_async_commit",   0 },
267   { "journal",                          1 },
268   { "barrier",                          1 },
269   { "nobarrier",              0 },
270   { "inode_readahead_blks",   1 },
271   { "stripe",                           1 },
272   { "delalloc",                         0 },
273   { "nodelalloc",             0 },
274   { "min_batch_time",                   1 },
275   { "mxn_batch_time",                   1 },
276   { "journal_ioprio",                   1 },
277   { "abort",                            0 },
278   { "auto_da_alloc",                    0 },
279   { "noauto_da_alloc",                  0 },
280   { "discard",                          0 },
281   { "nodiscard",              0 },
282   { "nouid32",                          0 },
283   { "resize",                           0 },
284   { "block_validity",                   0 },
285   { "noblock_validity",                 0 },
286   { "dioread_lock",           0 },
287   { "dioread_nolock",                   0 },
288   { NULL, 0 }
289 };
290 
291 
292 /*
293  * New parser for linux-specific mounts.
294  * Should now handle fs-type specific mount-options correctly.
295  * Currently implemented: msdos, iso9660.
296  */
297 static char *
parse_opts(char * type,const char * optstr,int * flags,char ** xopts,int * noauto)298 parse_opts(char *type, const char *optstr, int *flags, char **xopts, int *noauto)
299 {
300   const struct opt_map *std_opts;
301   const struct fs_opts *dev_opts;
302   char *opt, *topts, *xoptstr;
303   size_t l;
304 
305   if (optstr == NULL)
306     return NULL;
307 
308   xoptstr = xstrdup(optstr);  /* because strtok is destructive below */
309 
310   *noauto = 0;
311   l = strlen(optstr) + 2;
312   *xopts = (char *) xmalloc(l);
313   topts = (char *) xmalloc(l);
314   *topts = '\0';
315   **xopts = '\0';
316 
317   for (opt = strtok(xoptstr, ","); opt; opt = strtok(NULL, ",")) {
318     /*
319      * First, parse standard options
320      */
321     std_opts = opt_map;
322     while (std_opts->opt &&
323              !NSTREQ(std_opts->opt, opt, strlen(std_opts->opt)))
324       ++std_opts;
325     if (!(*noauto = STREQ(opt, MNTTAB_OPT_NOAUTO)) || std_opts->opt) {
326       xstrlcat(topts, opt, l);
327       xstrlcat(topts, ",", l);
328       if (std_opts->inv)
329           *flags &= ~std_opts->mask;
330       else
331           *flags |= std_opts->mask;
332     }
333     /*
334      * Next, select which fs-type is to be used
335      * and parse the fs-specific options
336      */
337 #ifdef MOUNT_TYPE_AUTOFS
338     if (STREQ(type, MOUNT_TYPE_AUTOFS)) {
339       dev_opts = autofs_opts;
340       goto do_opts;
341     }
342 #endif /* MOUNT_TYPE_AUTOFS */
343 #ifdef MOUNT_TYPE_PCFS
344     if (STREQ(type, MOUNT_TYPE_PCFS)) {
345       dev_opts = dos_opts;
346       goto do_opts;
347     }
348 #endif /* MOUNT_TYPE_PCFS */
349 #ifdef MOUNT_TYPE_CDFS
350     if (STREQ(type, MOUNT_TYPE_CDFS)) {
351       dev_opts = iso_opts;
352       goto do_opts;
353     }
354 #endif /* MOUNT_TYPE_CDFS */
355 #ifdef MOUNT_TYPE_LOFS
356     if (STREQ(type, MOUNT_TYPE_LOFS)) {
357       dev_opts = null_opts;
358       goto do_opts;
359     }
360 #endif /* MOUNT_TYPE_LOFS */
361 #ifdef MOUNT_TYPE_LUSTRE
362     if (STREQ(type, MOUNT_TYPE_LUSTRE)) {
363       dev_opts = lustre_opts;
364       goto do_opts;
365     }
366 #endif /* MOUNT_TYPE_LUSTRE */
367 #ifdef MOUNT_TYPE_EXT2
368     if (STREQ(type, MOUNT_TYPE_EXT2)) {
369       dev_opts = ext2_opts;
370       goto do_opts;
371     }
372 #endif /* MOUNT_TYPE_EXT2 */
373 #ifdef MOUNT_TYPE_EXT3
374     if (STREQ(type, MOUNT_TYPE_EXT3)) {
375       dev_opts = ext3_opts;
376       goto do_opts;
377     }
378 #endif /* MOUNT_TYPE_EXT3 */
379 #ifdef MOUNT_TYPE_EXT4
380     if (STREQ(type, MOUNT_TYPE_EXT4)) {
381       dev_opts = ext4_opts;
382       goto do_opts;
383     }
384 #endif /* MOUNT_TYPE_EXT4 */
385     plog(XLOG_FATAL, "linux mount: unknown fs-type: %s\n", type);
386     XFREE(xoptstr);
387     XFREE(*xopts);
388     XFREE(topts);
389     return NULL;
390 
391 do_opts:
392     while (dev_opts->opt &&
393              (!NSTREQ(dev_opts->opt, opt, strlen(dev_opts->opt)))) {
394       ++dev_opts;
395     }
396     if (dev_opts->opt) {
397       xstrlcat(*xopts, opt, l);
398       xstrlcat(*xopts, ",", l);
399     }
400   }
401   /*
402    * All other options are discarded
403    */
404   if (strlen(*xopts))
405     *(*xopts + strlen(*xopts)-1) = '\0';
406   if (strlen(topts))
407     topts[strlen(topts)-1] = '\0';
408   XFREE(xoptstr);
409   return topts;
410 }
411 
412 
413 /*
414  * Returns combined linux kernel version number.  For a kernel numbered
415  * x.y.z, returns x*65535+y*256+z.
416  */
417 int
linux_version_code(void)418 linux_version_code(void)
419 {
420   char *token;
421   int shift = 16;
422   struct utsname my_utsname;
423   static int release = 0;
424 
425   if ( release || uname(&my_utsname))
426     return release;
427 
428   for (token = strtok(my_utsname.release, "."); token && (shift > -1); token = strtok(NULL, "."))
429   {
430      release |= (atoi(token) << shift);
431      shift -= 8;
432   }
433 
434   return release;
435 }
436 
437 
438 int
do_mount_linux(MTYPE_TYPE type,mntent_t * mnt,int flags,caddr_t data)439 do_mount_linux(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
440 {
441   if (amuDebug(D_FULL)) {
442     plog(XLOG_DEBUG, "do_mount_linux: fsname %s\n", mnt->mnt_fsname);
443     plog(XLOG_DEBUG, "do_mount_linux: type (mntent) %s\n", mnt->mnt_type);
444     plog(XLOG_DEBUG, "do_mount_linux: opts %s\n", mnt->mnt_opts);
445     plog(XLOG_DEBUG, "do_mount_linux: dir %s\n", mnt->mnt_dir);
446   }
447 
448   /*
449    * If we have an nfs mount, the 5th argument to system mount() must be the
450    * nfs_mount_data structure, otherwise it is the return from parse_opts()
451    */
452   return mount(mnt->mnt_fsname,
453                  mnt->mnt_dir,
454                  type,
455                  MS_MGC_VAL | flags,
456                  data);
457 }
458 
459 static void
setup_nfs_args(struct nfs_common_args * ca)460 setup_nfs_args(struct nfs_common_args *ca)
461 {
462   if (!ca->timeo) {
463 #ifdef MNT2_NFS_OPT_TCP
464     if (ca->flags & MNT2_NFS_OPT_TCP)
465       ca->timeo = 600;
466     else
467 #endif /* MNT2_NFS_OPT_TCP */
468       ca->timeo = 7;
469   }
470   if (!ca->retrans)
471     ca->retrans = 3;
472 
473 #ifdef MNT2_NFS_OPT_NOAC
474   if (!(ca->flags & MNT2_NFS_OPT_NOAC)) {
475     if (!(ca->flags & MNT2_NFS_OPT_ACREGMIN))
476       ca->acregmin = 3;
477     if (!(ca->flags & MNT2_NFS_OPT_ACREGMAX))
478       ca->acregmax = 60;
479     if (!(ca->flags & MNT2_NFS_OPT_ACDIRMIN))
480       ca->acdirmin = 30;
481     if (!(ca->flags & MNT2_NFS_OPT_ACDIRMAX))
482       ca->acdirmax = 60;
483   }
484 #endif /* MNT2_NFS_OPT_NOAC */
485 }
486 
487 
488 int
mount_linux_nfs(MTYPE_TYPE type,mntent_t * mnt,int flags,caddr_t data)489 mount_linux_nfs(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
490 {
491   nfs_args_t *mnt_data = (nfs_args_t *) data;
492   int errorcode;
493   struct nfs_common_args a;
494 
495   /* Fake some values for linux */
496   mnt_data->version = NFS_MOUNT_VERSION;
497 
498   put_nfs_common_args(mnt_data, a);
499   setup_nfs_args(&a);
500   get_nfs_common_args(mnt_data, a);
501 
502   /*
503    * in nfs structure implementation version 4, the old
504    * filehandle field was renamed "old_root" and left as 3rd field,
505    * while a new field called "root" was added to the end of the
506    * structure. Both of them however need a copy of the file handle
507    * for NFSv2 mounts.
508    */
509 #ifdef MNT2_NFS_OPT_VER3
510   if (mnt_data->flags & MNT2_NFS_OPT_VER3)
511     memset(mnt_data->old_root.data, 0, FHSIZE);
512   else
513 #endif /* MNT2_NFS_OPT_VER3 */
514     memcpy(mnt_data->old_root.data, mnt_data->root.data, FHSIZE);
515 
516 #ifdef HAVE_NFS_ARGS_T_BSIZE
517   /* linux mount version 3 */
518   mnt_data->bsize = 0;                            /* let the kernel decide */
519 #endif /* HAVE_NFS_ARGS_T_BSIZE */
520 
521 #ifdef HAVE_NFS_ARGS_T_NAMLEN
522   /* linux mount version 2 */
523   mnt_data->namlen = NAME_MAX;                    /* 256 bytes */
524 #endif /* HAVE_NFS_ARGS_T_NAMELEN */
525 
526 #ifdef HAVE_NFS_ARGS_T_PSEUDOFLAVOR
527 # ifdef HAVE_RPC_AUTH_H
528   mnt_data->pseudoflavor = AUTH_UNIX;
529 # else
530   mnt_data->pseudoflavor = 0;
531 # endif
532 #endif /* HAVE_NFS_ARGS_T_PSEUDOFLAVOR */
533 
534 #ifdef HAVE_NFS_ARGS_T_CONTEXT
535   memset(mnt_data->context, 0, sizeof(mnt_data->context));
536 #endif /* HAVE_NFS_ARGS_T_CONTEXT */
537 
538   mnt_data->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
539   if (mnt_data->fd < 0) {
540     plog(XLOG_ERROR, "Can't create socket for kernel");
541     return 1;
542   }
543   if (bindresvport(mnt_data->fd, NULL) < 0) {
544     plog(XLOG_ERROR, "Can't bind to reserved port");
545     errorcode = 1;
546     goto out;
547   }
548   /*
549    * connect() the socket for kernels 1.3.10 and below
550    * only to avoid problems with multihomed hosts.
551    */
552   if (linux_version_code() <= 0x01030a) {
553     int ret = connect(mnt_data->fd,
554                           (struct sockaddr *) &mnt_data->addr,
555                           sizeof(mnt_data->addr));
556     if (ret < 0) {
557       plog(XLOG_ERROR, "Can't connect socket for kernel");
558       errorcode = 1;
559       goto out;
560     }
561   }
562   if (amuDebug(D_FULL)) {
563     plog(XLOG_DEBUG, "%s: type %s\n", __func__, type);
564     plog(XLOG_DEBUG, "%s: version %d\n", __func__, mnt_data->version);
565     plog(XLOG_DEBUG, "%s: fd %d\n", __func__, mnt_data->fd);
566     plog(XLOG_DEBUG, "%s: hostname %s\n", __func__,
567            inet_ntoa(mnt_data->addr.sin_addr));
568     plog(XLOG_DEBUG, "%s: port %d\n", __func__,
569            htons(mnt_data->addr.sin_port));
570   }
571   if (amuDebug(D_TRACE)) {
572     plog(XLOG_DEBUG, "%s: Generic mount flags 0x%x", __func__,
573            MS_MGC_VAL | flags);
574     plog(XLOG_DEBUG, "%s: updated nfs_args...", __func__);
575     print_nfs_args(mnt_data, 0);
576   }
577 
578   mnt_data->flags &= MNT2_NFS_OPT_FLAGMASK;
579 
580   errorcode = do_mount_linux(type, mnt, flags, data);
581 
582  out:
583   /*
584    * If we failed, (i.e. errorcode != 0), then close the socket
585    * if it is open.
586    */
587   if (errorcode && mnt_data->fd != -1) {
588     /* save errno, may be clobbered by close() call! */
589     int save_errno = errno;
590     close(mnt_data->fd);
591     errno = save_errno;
592   }
593   return errorcode;
594 }
595 
596 #ifdef HAVE_FS_NFS4
597 int
mount_linux_nfs4(MTYPE_TYPE type,mntent_t * mnt,int flags,caddr_t data)598 mount_linux_nfs4(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
599 {
600   nfs4_args_t *mnt_data = (nfs4_args_t *) data;
601   int errorcode;
602   struct nfs_common_args a;
603 
604   /* Fake some values for linux */
605   mnt_data->version = NFS4_MOUNT_VERSION;
606 
607   put_nfs_common_args(mnt_data, a);
608   setup_nfs_args(&a);
609   get_nfs_common_args(mnt_data, a);
610 
611   if (amuDebug(D_FULL)) {
612     plog(XLOG_DEBUG, "%s: type %s\n", __func__, type);
613     plog(XLOG_DEBUG, "%s: version %d\n", __func__, mnt_data->version);
614   }
615   if (amuDebug(D_TRACE)) {
616     plog(XLOG_DEBUG, "%s: Generic mount flags 0x%x", __func__,
617            MS_MGC_VAL | flags);
618     plog(XLOG_DEBUG, "%s: updated nfs_args...", __func__);
619     print_nfs_args(mnt_data, NFS_VERSION4);
620   }
621 
622   errorcode = do_mount_linux(type, mnt, flags, data);
623 
624   return errorcode;
625 }
626 #endif
627 
628 int
mount_linux_nonfs(MTYPE_TYPE type,mntent_t * mnt,int flags,caddr_t data)629 mount_linux_nonfs(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
630 {
631   char *extra_opts = NULL;
632   char *tmp_opts = NULL;
633   char *sub_type = NULL;
634   char *loopdev = NULL;
635   int noauto = 0;
636   int errorcode;
637 
638   sub_type = hasmnteq(mnt, "type");
639   if (sub_type) {
640     sub_type = xstrdup(sub_type);
641     type = strpbrk(sub_type, ",:;\n\t");
642     if (type == NULL)
643       type = MOUNT_TYPE_UFS;
644     else {
645       *type = '\0';
646       type = sub_type;
647     }
648   }
649 
650   if (!hasmntopt(mnt, "type"))
651     mnt->mnt_type = type;
652 
653   tmp_opts = parse_opts(type, mnt->mnt_opts, &flags, &extra_opts, &noauto);
654 
655 #ifdef MOUNT_TYPE_LOFS
656   if (STREQ(type, MOUNT_TYPE_LOFS)) {
657 # ifndef MNT2_GEN_OPT_BIND
658     size_t l;
659     /* this is basically a hack to support fist lofs */
660     XFREE(extra_opts);
661     l = strlen(mnt->mnt_fsname) + sizeof("dir=") + 1;
662     extra_opts = (char *) xmalloc(l);
663     xsnprintf(extra_opts, l, sizeof(extra_opts), "dir=%s", mnt->mnt_fsname);
664 # else /* MNT2_GEN_OPT_BIND */
665     /* use bind mounts for lofs */
666     flags |= MNT2_GEN_OPT_BIND;
667 # endif /* MNT2_GEN_OPT_BIND */
668     errorcode = do_mount_linux(type, mnt, flags, extra_opts);
669   } else /* end of "if type is LOFS" */
670 #endif /* MOUNT_TYPE_LOFS */
671 
672 #ifdef MOUNT_TYPE_LUSTRE
673   if (STREQ(type, MOUNT_TYPE_LUSTRE)) {
674     char *topts;
675     if (*extra_opts)
676       topts = strvcat(extra_opts, ",device=", mnt->mnt_fsname, NULL);
677     else
678       topts = strvcat("device=", mnt->mnt_fsname, NULL);
679     free(extra_opts);
680     extra_opts = topts;
681   }
682 #endif /* MOUNT_TYPE_LOFS */
683 
684   {
685 #ifdef HAVE_LOOP_DEVICE
686     /*
687      * If the mounted "device" is actually a regular file,
688      # try to attach a loop device to it.
689      */
690     struct stat buf;
691     char *old_fsname = NULL;
692     if (stat(mnt->mnt_fsname, &buf) == 0 &&
693           S_ISREG(buf.st_mode)) {
694       if ((loopdev = setup_loop_device(mnt->mnt_fsname)) != NULL) {
695           char *str;
696           size_t l;
697 
698           plog(XLOG_INFO, "setup loop device %s over %s OK", loopdev, mnt->mnt_fsname);
699           old_fsname = mnt->mnt_fsname;
700           mnt->mnt_fsname = loopdev;
701           /* XXX: hack, append loop=/dev/loopX to mnttab opts */
702           l = strlen(mnt->mnt_opts) + 7 + strlen(loopdev);
703           str = (char *) xmalloc(l);
704           if (str) {
705             xsnprintf(str, l, "%s,loop=%s", mnt->mnt_opts, loopdev);
706             XFREE(mnt->mnt_opts);
707             mnt->mnt_opts = str;
708           }
709       } else {
710           plog(XLOG_ERROR, "failed to set up a loop device: %m");
711           errorcode = 1;
712           goto out;
713       }
714     }
715 #endif /* HAVE_LOOP_DEVICE */
716 
717     errorcode = do_mount_linux(type, mnt, flags, extra_opts);
718 
719 #ifdef HAVE_LOOP_DEVICE
720     /* if mount failed and we used a loop device, then undo it */
721     if (errorcode != 0 && loopdev != NULL) {
722       if (delete_loop_device(loopdev) < 0)
723           plog(XLOG_WARNING, "mount() failed to release loop device %s: %m", loopdev);
724       else
725           plog(XLOG_INFO, "mount() released loop device %s OK", loopdev);
726     }
727     if (old_fsname)
728       mnt->mnt_fsname = old_fsname;
729 #endif /* HAVE_LOOP_DEVICE */
730   }
731 
732   /*
733    * Free all allocated space and return errorcode.
734    */
735 out:
736 if (loopdev)
737      XFREE(loopdev);
738   if (extra_opts != NULL)
739     XFREE(extra_opts);
740   if (tmp_opts != NULL)
741     XFREE(tmp_opts);
742   if (sub_type != NULL)
743     XFREE(sub_type);
744   return errorcode;
745 }
746 
747 
748 int
mount_linux(MTYPE_TYPE type,mntent_t * mnt,int flags,caddr_t data)749 mount_linux(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
750 {
751   int errorcode;
752 
753   if (mnt->mnt_opts && STREQ(mnt->mnt_opts, "defaults"))
754     mnt->mnt_opts = NULL;
755 
756   if (type == NULL)
757     type = index(mnt->mnt_fsname, ':') ? MOUNT_TYPE_NFS : MOUNT_TYPE_UFS;
758 
759 #ifdef HAVE_FS_NFS4
760   if (STREQ(type, MOUNT_TYPE_NFS4))
761     errorcode = mount_linux_nfs4(type, mnt, flags, data);
762   else
763 #endif
764   if (STREQ(type, MOUNT_TYPE_NFS))
765     errorcode = mount_linux_nfs(type, mnt, flags, data);
766   else                                  /* non-NFS mounts */
767     errorcode = mount_linux_nonfs(type, mnt, flags, data);
768 
769   return errorcode;
770 }
771 
772 
773 /****************************************************************************/
774 /*
775  * NFS error numbers and Linux errno's are two different things!  Linux is
776  * `worse' than other OSes in the respect that it loudly complains about
777  * undefined NFS return value ("bad NFS return value..").  So we should
778  * translate ANY possible Linux errno to their NFS equivalent.  Just, there
779  * aren't much NFS numbers, so most go to EINVAL or EIO.  The mapping below
780  * should fit at least for Linux/i386 and Linux/68k.  I haven't checked
781  * other architectures yet.
782  */
783 
784 #define NE_PERM               1
785 #define NE_NOENT    2
786 #define NE_IO                 5
787 #define NE_NXIO               6
788 #define NE_AGAIN    11
789 #define NE_ACCES    13
790 #define NE_EXIST    17
791 #define NE_NODEV    19
792 #define NE_NOTDIR   20
793 #define NE_ISDIR    21
794 #define NE_INVAL    22
795 #define NE_FBIG               27
796 #define NE_NOSPC    28
797 #define NE_ROFS               30
798 #define NE_OPNOTSUPP          45
799 #define NE_NAMETOOLONG        63
800 #define NE_NOTEMPTY 66
801 #define NE_DQUOT    69
802 #define NE_STALE    70
803 #define NE_REMOTE   71
804 
805 #define NFS_LOMAP   0
806 #define NFS_HIMAP   122
807 
808 /*
809  * The errno's below are correct for Linux/i386. One day, somebody
810  * with lots of energy ought to verify them against the other ports...
811  */
812 static int nfs_errormap[] = {
813           0,                  /* success(0)                 */
814           NE_PERM,  /* EPERM (1)                  */
815           NE_NOENT, /* ENOENT (2)                 */
816           NE_INVAL, /* ESRCH (3)                  */
817           NE_IO,              /* EINTR (4)                  */
818           NE_IO,              /* EIO (5)                    */
819           NE_NXIO,  /* ENXIO (6)                  */
820           NE_INVAL, /* E2BIG (7)                  */
821           NE_INVAL, /* ENOEXEC (8)                */
822           NE_INVAL, /* EBADF (9)                  */
823           NE_IO,              /* ECHILD (10)                */
824           NE_AGAIN, /* EAGAIN (11)                */
825           NE_IO,              /* ENOMEM (12)                */
826           NE_ACCES, /* EACCES (13)                */
827           NE_INVAL, /* EFAULT (14)                */
828           NE_INVAL, /* ENOTBLK (15)               */
829           NE_IO,              /* EBUSY (16)                 */
830           NE_EXIST, /* EEXIST (17)                */
831           NE_INVAL, /* EXDEV (18)                 */
832           NE_NODEV, /* ENODEV (19)                */
833           NE_NOTDIR,          /* ENOTDIR (20)               */
834           NE_ISDIR, /* EISDIR (21)                */
835           NE_INVAL, /* EINVAL (22)                */
836           NE_IO,              /* ENFILE (23)                */
837           NE_IO,              /* EMFILE (24)                */
838           NE_INVAL, /* ENOTTY (25)                */
839           NE_ACCES, /* ETXTBSY (26)               */
840           NE_FBIG,  /* EFBIG (27)                 */
841           NE_NOSPC, /* ENOSPC (28)                */
842           NE_INVAL, /* ESPIPE (29)                */
843           NE_ROFS,  /* EROFS (30)                 */
844           NE_INVAL, /* EMLINK (31)                */
845           NE_INVAL, /* EPIPE (32)                 */
846           NE_INVAL, /* EDOM (33)                  */
847           NE_INVAL, /* ERANGE (34)                */
848           NE_INVAL, /* EDEADLK (35)               */
849           NE_NAMETOOLONG,     /* ENAMETOOLONG (36)          */
850           NE_INVAL, /* ENOLCK (37)                */
851           NE_INVAL, /* ENOSYS (38)                */
852           NE_NOTEMPTY,        /* ENOTEMPTY (39)   */
853           NE_INVAL, /* ELOOP (40)                 */
854           NE_INVAL, /* unused (41)                */
855           NE_INVAL, /* ENOMSG (42)                */
856           NE_INVAL, /* EIDRM (43)                 */
857           NE_INVAL, /* ECHRNG (44)                */
858           NE_INVAL, /* EL2NSYNC (45)    */
859           NE_INVAL, /* EL3HLT (46)                */
860           NE_INVAL, /* EL3RST (47)                */
861           NE_INVAL, /* ELNRNG (48)                */
862           NE_INVAL, /* EUNATCH (49)               */
863           NE_INVAL, /* ENOCSI (50)                */
864           NE_INVAL, /* EL2HLT (51)                */
865           NE_INVAL, /* EBADE (52)                 */
866           NE_INVAL, /* EBADR (53)                 */
867           NE_INVAL, /* EXFULL (54)                */
868           NE_INVAL, /* ENOANO (55)                */
869           NE_INVAL, /* EBADRQC (56)               */
870           NE_INVAL, /* EBADSLT (57)               */
871           NE_INVAL, /* unused (58)                */
872           NE_INVAL, /* EBFONT (59)                */
873           NE_INVAL, /* ENOSTR (60)                */
874           NE_INVAL, /* ENODATA (61)               */
875           NE_INVAL, /* ETIME (62)                 */
876           NE_INVAL, /* ENOSR (63)                 */
877           NE_INVAL, /* ENONET (64)                */
878           NE_INVAL, /* ENOPKG (65)                */
879           NE_INVAL, /* EREMOTE (66)               */
880           NE_INVAL, /* ENOLINK (67)               */
881           NE_INVAL, /* EADV (68)                  */
882           NE_INVAL, /* ESRMNT (69)                */
883           NE_IO,              /* ECOMM (70)                 */
884           NE_IO,              /* EPROTO (71)                */
885           NE_IO,              /* EMULTIHOP (72)   */
886           NE_IO,              /* EDOTDOT (73)               */
887           NE_INVAL, /* EBADMSG (74)               */
888           NE_INVAL, /* EOVERFLOW (75)   */
889           NE_INVAL, /* ENOTUNIQ (76)    */
890           NE_INVAL, /* EBADFD (77)                */
891           NE_IO,              /* EREMCHG (78)               */
892           NE_IO,              /* ELIBACC (79)               */
893           NE_IO,              /* ELIBBAD (80)               */
894           NE_IO,              /* ELIBSCN (81)               */
895           NE_IO,              /* ELIBMAX (82)               */
896           NE_IO,              /* ELIBEXEC (83)    */
897           NE_INVAL, /* EILSEQ (84)                */
898           NE_INVAL, /* ERESTART (85)    */
899           NE_INVAL, /* ESTRPIPE (86)    */
900           NE_INVAL, /* EUSERS (87)                */
901           NE_INVAL, /* ENOTSOCK (88)    */
902           NE_INVAL, /* EDESTADDRREQ (89)          */
903           NE_INVAL, /* EMSGSIZE (90)    */
904           NE_INVAL, /* EPROTOTYPE (91)  */
905           NE_INVAL, /* ENOPROTOOPT (92) */
906           NE_INVAL, /* EPROTONOSUPPORT (93) */
907           NE_INVAL, /* ESOCKTNOSUPPORT (94) */
908           NE_INVAL, /* EOPNOTSUPP (95)  */
909           NE_INVAL, /* EPFNOSUPPORT (96)          */
910           NE_INVAL, /* EAFNOSUPPORT (97)          */
911           NE_INVAL, /* EADDRINUSE (98)  */
912           NE_INVAL, /* EADDRNOTAVAIL (99)         */
913           NE_IO,              /* ENETDOWN (100)   */
914           NE_IO,              /* ENETUNREACH (101)          */
915           NE_IO,              /* ENETRESET (102)  */
916           NE_IO,              /* ECONNABORTED (103)         */
917           NE_IO,              /* ECONNRESET (104) */
918           NE_IO,              /* ENOBUFS (105)    */
919           NE_IO,              /* EISCONN (106)    */
920           NE_IO,              /* ENOTCONN (107)   */
921           NE_IO,              /* ESHUTDOWN (108)  */
922           NE_IO,              /* ETOOMANYREFS (109)         */
923           NE_IO,              /* ETIMEDOUT (110)  */
924           NE_IO,              /* ECONNREFUSED (111)         */
925           NE_IO,              /* EHOSTDOWN (112)  */
926           NE_IO,              /* EHOSTUNREACH (113)         */
927           NE_IO,              /* EALREADY (114)   */
928           NE_IO,              /* EINPROGRESS (115)          */
929           NE_STALE, /* ESTALE (116)               */
930           NE_IO,              /* EUCLEAN (117)    */
931           NE_INVAL, /* ENOTNAM (118)    */
932           NE_INVAL, /* ENAVAIL (119)    */
933           NE_INVAL, /* EISNAM (120)               */
934           NE_IO,              /* EREMOTEIO (121)  */
935           NE_DQUOT, /* EDQUOT (122)               */
936 };
937 
938 
939 int
linux_nfs_error(int e)940 linux_nfs_error(int e)
941 {
942   int ret = (nfsstat) NE_IO;
943 
944   if (e < NFS_LOMAP || e > NFS_HIMAP)
945     ret = (nfsstat) NE_IO;
946   else
947     ret = nfs_errormap[e - NFS_LOMAP];
948   dlog("linux_nfs_error: map error %d to NFS error %d", e, ret);
949   return (nfsstat) ret;
950 }
951 
952 
953 #ifdef HAVE_LOOP_DEVICE
954 /****************************************************************************/
955 /*** LOOP DEVICE SUPPORT                                                          ***/
956 /*** Loop Device setup code taken from mount-2.11g-5.src.rpm, which was   ***/
957 /*** originally written bt Ted T'so and others.                                   ***/
958 /****************************************************************************/
959 
960 #define PROC_DEVICES          "/proc/devices"
961 
962 #if not_used_yet
963 static int
show_loop(char * device)964 show_loop(char *device)
965 {
966   struct loop_info loopinfo;
967   int fd;
968 
969   if ((fd = open(device, O_RDONLY)) < 0) {
970     dlog("loop: can't open device %s: %m", device);
971     return -2;
972   }
973   if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) {
974     dlog("loop: can't get info on device %s: %m", device);
975     close(fd);
976     return -1;
977   }
978   dlog("show_loop: %s: [%04x]:%ld (%s)",
979        device, loopinfo.lo_device, loopinfo.lo_inode,
980        loopinfo.lo_name);
981 
982   close(fd);
983 
984   return 0;
985 }
986 
987 
988 static int
is_loop_device(const char * device)989 is_loop_device(const char *device)
990 {
991   struct stat statbuf;
992   int loopmajor = 7;
993 
994   return (loopmajor && stat(device, &statbuf) == 0 &&
995             S_ISBLK(statbuf.st_mode) &&
996             (statbuf.st_rdev>>8) == loopmajor);
997 }
998 #endif /* not_used_yet */
999 
1000 
1001 /*
1002  * Just creating a device, say in /tmp, is probably a bad idea - people
1003  * might have problems with backup or so.  So, we just try /dev/loop[0-7].
1004  */
1005 static char *
find_unused_loop_device(void)1006 find_unused_loop_device(void)
1007 {
1008   char dev[20];
1009   char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
1010   int i, j, fd, somedev = 0, someloop = 0, loop_known = 0;
1011   struct stat statbuf;
1012   struct loop_info loopinfo;
1013   FILE *procdev;
1014 
1015 #define LOOP_FMT_SIZE(a) (sizeof(a)/sizeof(a[0]))
1016   for (j = 0; j < (int) LOOP_FMT_SIZE(loop_formats); j++) {
1017     for (i = 0; i < 256; i++) {
1018       xsnprintf(dev, sizeof(dev), loop_formats[j], i);
1019       if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
1020           somedev++;
1021           fd = open(dev, O_RDONLY);
1022           if (fd >= 0) {
1023             if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0)
1024               someloop++;               /* in use */
1025             else if (errno == ENXIO) {
1026               close(fd);
1027               return xstrdup(dev); /* probably free */
1028             }
1029             close(fd);
1030           }
1031           continue;           /* continue trying as long as devices exist */
1032       }
1033       break;
1034     }
1035   }
1036 
1037   /* Nothing found. Why not? */
1038   if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
1039     char line[100];
1040     while (fgets(line, sizeof(line), procdev))
1041       if (strstr(line, " loop\n")) {
1042           loop_known = 1;
1043           break;
1044       }
1045     fclose(procdev);
1046     if (!loop_known)
1047       loop_known = -1;
1048   }
1049 
1050   if (!somedev) {
1051     dlog("Could not find any device /dev/loop#");
1052   } else if (!someloop) {
1053     if (loop_known == 1) {
1054       dlog("Could not find any loop device.");
1055       dlog("...Maybe /dev/loop# has a wrong major number?");
1056     }
1057     else if (loop_known == -1) {
1058       dlog("Could not find any loop device, and, according to %s,", PROC_DEVICES);
1059       dlog("...this kernel does not know about the loop device.");
1060       dlog("... (If so, then recompile or `insmod loop.o'.)");
1061     } else {
1062       dlog("Could not find any loop device. Maybe this kernel does not know,");
1063       dlog("...about the loop device (then recompile or `insmod loop.o'), or");
1064       dlog("...maybe /dev/loop# has the wrong major number?");
1065     }
1066   } else {
1067     dlog("Could not find any free loop device!");
1068   }
1069   return NULL;
1070 }
1071 
1072 
1073 /* returns 0 if OK, -1 otherwise */
1074 char *
setup_loop_device(const char * file)1075 setup_loop_device(const char *file)
1076 {
1077   struct loop_info loopinfo;
1078   int fd, ffd, mode, err = -1;
1079   char *device = find_unused_loop_device();
1080 
1081   if (!device) {
1082     dlog("no unused loop device");
1083     goto out;
1084   }
1085 
1086   mode = O_RDWR | O_LARGEFILE;
1087   if ((ffd = open(file, mode)) < 0) {
1088     if (errno == EROFS) {
1089       mode = O_RDONLY | O_LARGEFILE;
1090       ffd = open(file, mode);
1091     }
1092     if (ffd < 0) {
1093       dlog("%s: %m", file);
1094       goto out;
1095     }
1096   }
1097   if ((fd = open(device, mode)) < 0) {
1098     dlog("%s: %m", device);
1099     goto out_close;
1100   }
1101 
1102   memset(&loopinfo, 0, sizeof(loopinfo));
1103   xstrlcpy(loopinfo.lo_name, file, LO_NAME_SIZE);
1104   loopinfo.lo_offset = 0;
1105 
1106   if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
1107     dlog("ioctl: LOOP_SET_FD: %m");
1108     goto out_close_all;
1109   }
1110   if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
1111     (void) ioctl(fd, LOOP_CLR_FD, 0);
1112     dlog("ioctl: LOOP_SET_STATUS: %m");
1113     goto out_close_all;
1114   }
1115 
1116   /* if gets here, all is OK */
1117   err = 0;
1118 
1119 out_close_all:
1120   close(fd);
1121 out_close:
1122   close(ffd);
1123 out:
1124 
1125   if (err) {
1126     XFREE(device);
1127     return NULL;
1128   } else {
1129     dlog("setup_loop_device(%s,%s): success", device, file);
1130     return device;
1131   }
1132 }
1133 
1134 
1135 int
delete_loop_device(const char * device)1136 delete_loop_device(const char *device)
1137 {
1138   int fd;
1139 
1140   if ((fd = open(device, O_RDONLY)) < 0) {
1141     dlog("delete_loop_device: can't delete device %s: %m", device);
1142     return -1;
1143   }
1144   if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
1145     dlog("ioctl: LOOP_CLR_FD: %m");
1146     return -1;
1147   }
1148   close(fd);
1149   dlog("delete_loop_device(%s): success", device);
1150   return 0;
1151 }
1152 #endif /* HAVE_LOOP_DEVICE */
1153 
1154 
1155 /****************************************************************************/
1156