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