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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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