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