/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include /* defines F_LOCK for lockf */ #include /* for getopt(3) */ #include #include #include #include #include #include #include #include #include #include #include extern int optind; extern char *optarg; #define NAME_MAX 64 #define GLOBAL 0 #define NOGLOBAL 1 #ifndef MNTOPT_NOGLOBAL #define MNTOPT_NOGLOBAL "noglobal" #endif /* MNTOPT_NOGLOBAL */ static int gflg = 0; /* mount into global name space: flag form */ static int global = 0; /* mount into global name space: option form */ static int havegblopt = 0; /* global value supercedes gflg value */ static int qflg = 0; /* quiet option - don't flag bad options */ static char fstype[] = MNTTYPE_HSFS; static char typename[NAME_MAX], *myname; /* * Mount options that require special handling */ static char *myopts[] = { MNTOPT_GLOBAL, MNTOPT_NOGLOBAL, NULL }; static void rpterr(char *, char *); static void usage(void); int main(int argc, char **argv) { char *options, *value; char *special, *mountp; char *gopt; struct mnttab mm; int c; char obuff[MAX_MNTOPT_STR]; char saved_input_options[MAX_MNTOPT_STR]; int hsfs_flags; int flags; int Oflg = 0; /* Overlay mounts */ (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); myname = strrchr(argv[0], '/'); if (myname) myname++; else myname = argv[0]; snprintf(typename, sizeof (typename), "%s %s", fstype, myname); argv[0] = typename; /* * Check for arguments requiring special handling. Ignore * unrecognized options. */ strcpy(obuff, "ro"); /* default */ while ((c = getopt(argc, argv, "o:rmOgq")) != EOF) { switch (c) { case 'o': if (strlen(optarg) > MAX_MNTOPT_STR) { (void) fprintf(stderr, gettext( "%s: option set too long\n"), myname); exit(1); } if (strlen(optarg) == 0) { (void) fprintf(stderr, gettext( "%s: missing suboptions\n"), myname); exit(1); } strcpy(obuff, optarg); options = optarg; while (*options != '\0') { switch (getsubopt(&options, myopts, &value)) { case GLOBAL: havegblopt = 1; global = 1; break; case NOGLOBAL: havegblopt = 1; global = 0; break; } } break; case 'O': Oflg++; break; case 'r': /* accept for backwards compatibility */ break; case 'm': break; case 'g': gflg++; break; case 'q': qflg++; break; } } if ((argc - optind) != 2) usage(); special = argv[optind++]; mountp = argv[optind++]; /* * Force readonly. obuff is guaranteed to have something in * it. We might end up with "ro,ro", but that's acceptable. */ flags = MS_RDONLY; if ((strlen(obuff) + strlen(MNTOPT_RO) + 2) > MAX_MNTOPT_STR) { (void) fprintf(stderr, gettext("%s: option set too long\n"), myname); exit(1); } strcat(obuff, ","); strcat(obuff, MNTOPT_RO); flags |= Oflg ? MS_OVERLAY : 0; /* * xxx it's not clear if should just put MS_GLOBAL in flags, * or provide it as a string. Be safe, do both. The subopt * version has precedence over the switch version. */ gopt = NULL; if ((havegblopt && global) || gflg) { gopt = MNTOPT_GLOBAL; flags |= MS_GLOBAL; } else if (havegblopt) { gopt = MNTOPT_NOGLOBAL; } if (gopt != NULL) { if ((strlen(obuff) + strlen(gopt) + 2) > MAX_MNTOPT_STR) { (void) fprintf(stderr, gettext("%s: option set too long\n"), myname); exit(1); } strcat(obuff, ","); strcat(obuff, gopt); } signal(SIGHUP, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGINT, SIG_IGN); /* * Save a copy of the options to compare with the options that * were actually recognized and supported by the kernel. */ (void) strcpy(saved_input_options, obuff); /* * Perform the mount. */ if (mount(special, mountp, flags | MS_OPTIONSTR, fstype, NULL, 0, obuff, sizeof (obuff)) == -1) { rpterr(special, mountp); exit(31+2); } if (!qflg) { cmp_requested_to_actual_options(saved_input_options, obuff, special, mountp); } exit(0); /* NOTREACHED */ } static void rpterr(char *bs, char *mp) { switch (errno) { case EPERM: (void) fprintf(stderr, gettext("%s: insufficient privileges\n"), myname); break; case ENXIO: (void) fprintf(stderr, gettext("%s: %s no such device\n"), myname, bs); break; case ENOTDIR: (void) fprintf(stderr, gettext("%s: %s not a directory\n\tor a " "component of %s is not a directory\n"), myname, mp, bs); break; case ENOENT: (void) fprintf(stderr, gettext("%s: %s or %s, no such file or directory\n"), myname, bs, mp); break; case EINVAL: (void) fprintf(stderr, gettext("%s: %s is not an hsfs file " "system.\n"), typename, bs); break; case EBUSY: (void) fprintf(stderr, gettext("%s: %s is already mounted or %s is busy\n"), myname, bs, mp); break; case ENOTBLK: (void) fprintf(stderr, gettext("%s: %s not a block device\n"), myname, bs); break; case EROFS: (void) fprintf(stderr, gettext("%s: %s write-protected\n"), myname, bs); break; case ENOSPC: (void) fprintf(stderr, gettext("%s: %s is corrupted. needs checking\n"), myname, bs); break; default: perror(myname); (void) fprintf(stderr, gettext("%s: cannot mount %s\n"), myname, bs); } } static void usage() { char *opts; opts = "{-r | -o ro | -o nrr | -o nosuid | -o notraildot | -o nomaplcase}"; (void) fprintf(stdout, gettext("hsfs usage: mount [-F hsfs] %s {special | mount_point}\n"), opts); (void) fprintf(stdout, gettext("hsfs usage: mount [-F hsfs] %s special mount_point\n"), opts); exit(32); }