12621Sllai1 /*
22621Sllai1 * CDDL HEADER START
32621Sllai1 *
42621Sllai1 * The contents of this file are subject to the terms of the
52621Sllai1 * Common Development and Distribution License (the "License").
62621Sllai1 * You may not use this file except in compliance with the License.
72621Sllai1 *
82621Sllai1 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92621Sllai1 * or http://www.opensolaris.org/os/licensing.
102621Sllai1 * See the License for the specific language governing permissions
112621Sllai1 * and limitations under the License.
122621Sllai1 *
132621Sllai1 * When distributing Covered Code, include this CDDL HEADER in each
142621Sllai1 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152621Sllai1 * If applicable, add the following below this CDDL HEADER, with the
162621Sllai1 * fields enclosed by brackets "[]" replaced with your own identifying
172621Sllai1 * information: Portions Copyright [yyyy] [name of copyright owner]
182621Sllai1 *
192621Sllai1 * CDDL HEADER END
202621Sllai1 */
212621Sllai1
222621Sllai1 /*
23*10116SEric.Taylor@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
242621Sllai1 * Use is subject to license terms.
252621Sllai1 */
262621Sllai1
272621Sllai1 #include <sys/types.h>
282621Sllai1 #include <limits.h>
292621Sllai1 #include <stdio.h>
302621Sllai1 #include <stdlib.h>
312621Sllai1 #include <unistd.h>
322621Sllai1 #include <signal.h>
332621Sllai1 #include <errno.h>
342621Sllai1 #include <string.h>
352621Sllai1 #include <locale.h>
362621Sllai1 #include <sys/stat.h>
372621Sllai1 #include <sys/mount.h>
382621Sllai1 #include <sys/mntent.h>
39*10116SEric.Taylor@Sun.COM #include <sys/fs/sdev_impl.h>
402621Sllai1
412621Sllai1
422621Sllai1 #define READFLAG_RO 1
432621Sllai1 #define READFLAG_RW 2
442621Sllai1
452621Sllai1
462621Sllai1 extern int optind;
472621Sllai1 extern char *optarg;
482621Sllai1
492621Sllai1 static char typename[64], *myname;
502621Sllai1 static char fstype[] = MNTTYPE_DEV;
512621Sllai1
522621Sllai1 static int readflag;
532621Sllai1 static int overlay;
542621Sllai1 static int remount;
552621Sllai1
562621Sllai1 static char *special;
572621Sllai1 static char *mountpt;
582621Sllai1 static struct sdev_mountargs mountargs;
592621Sllai1
602621Sllai1 static char *myopts[] = {
612621Sllai1 #define SUBOPT_READONLY 0
622621Sllai1 "ro",
632621Sllai1 #define SUBOPT_READWRITE 1
642621Sllai1 "rw",
652621Sllai1 #define SUBOPT_ATTRIBDIR 2
662621Sllai1 "attrdir",
672621Sllai1 #define SUBOPT_REMOUNT 3
682621Sllai1 "remount",
692621Sllai1 NULL
702621Sllai1 };
712621Sllai1
722621Sllai1
732621Sllai1 static void
usage(void)742621Sllai1 usage(void)
752621Sllai1 {
762621Sllai1 (void) fprintf(stderr, gettext(
772621Sllai1 "%s usage:\n%s [-F %s] [-r] [-o specific_options]"
782621Sllai1 " {special | mount_point}\n%s [-F %s] [-r] [-o specific_options]"
792621Sllai1 " special mount_point\n"), fstype, myname, fstype, myname, fstype);
802621Sllai1 exit(1);
812621Sllai1 }
822621Sllai1
832621Sllai1
842621Sllai1 static int
do_mount(void)852621Sllai1 do_mount(void)
862621Sllai1 {
872621Sllai1 int flags = MS_DATA;
882621Sllai1
892621Sllai1 if (readflag == READFLAG_RO)
902621Sllai1 flags |= MS_RDONLY;
912621Sllai1 if (overlay)
922621Sllai1 flags |= MS_OVERLAY;
932621Sllai1 if (remount)
942621Sllai1 flags |= MS_REMOUNT;
952621Sllai1
962621Sllai1 if (mount(special, mountpt, flags, fstype, &mountargs,
972621Sllai1 sizeof (mountargs), NULL, 0)) {
982621Sllai1 switch (errno) {
992621Sllai1 case EPERM:
1002621Sllai1 (void) fprintf(stderr, gettext("%s: not super user\n"),
1012621Sllai1 typename);
1022621Sllai1 break;
1032621Sllai1 case ENXIO:
1042621Sllai1 (void) fprintf(stderr, gettext("%s: %s no such "
1052621Sllai1 "device\n"), typename, special);
1062621Sllai1 break;
1072621Sllai1 case ENOTDIR:
1082621Sllai1 (void) fprintf(stderr, gettext("%s: %s "
1092621Sllai1 "not a directory\n"
1102621Sllai1 "\tor a component of %s is not a directory\n"),
1112621Sllai1 typename, mountpt, special);
1122621Sllai1 break;
1132621Sllai1 case ENOENT:
1142621Sllai1 (void) fprintf(stderr, gettext("%s: %s or %s, no such "
1152621Sllai1 "file or directory\n"),
1162621Sllai1 typename, special, mountpt);
1172621Sllai1 break;
1182621Sllai1 case EINVAL:
1192621Sllai1 (void) fprintf(stderr, gettext("%s: %s is not this "
1202621Sllai1 "filesystem type.\n"), typename, special);
1212621Sllai1 break;
1222621Sllai1 case EBUSY:
1232621Sllai1 (void) fprintf(stderr, gettext("%s: %s "
1242621Sllai1 "is already mounted, %s is busy,\n"
1252621Sllai1 "\tor allowable number of mount points exceeded\n"),
1262621Sllai1 typename, special, mountpt);
1272621Sllai1 break;
1282621Sllai1 case ENOTBLK:
1292621Sllai1 (void) fprintf(stderr, gettext("%s: %s not a block "
1302621Sllai1 "device\n"), typename, special);
1312621Sllai1 break;
1322621Sllai1 case EROFS:
1332621Sllai1 (void) fprintf(stderr, gettext("%s: %s read-only "
1342621Sllai1 "filesystem\n"), typename, special);
1352621Sllai1 break;
1362621Sllai1 case ENOSPC:
1372621Sllai1 (void) fprintf(stderr, gettext("%s: the state of %s "
1382621Sllai1 "is not okay\n"
1392621Sllai1 "\tand read/write mount was attempted\n"),
1402621Sllai1 typename, special);
1412621Sllai1 break;
1422621Sllai1 default:
1432621Sllai1 (void) fprintf(stderr, gettext("%s: cannot mount %s: "
1442621Sllai1 "%s\n"), typename, special, strerror(errno));
1452621Sllai1 break;
1462621Sllai1 }
1472621Sllai1 return (-1);
1482621Sllai1 }
1492621Sllai1 return (0);
1502621Sllai1 }
1512621Sllai1
1522621Sllai1
1532621Sllai1 /*
1542621Sllai1 * Wrapper around strdup().
1552621Sllai1 */
1562621Sllai1 static char *
do_strdup(const char * s1)1572621Sllai1 do_strdup(const char *s1)
1582621Sllai1 {
1592621Sllai1 char *str;
1602621Sllai1
1612621Sllai1 str = strdup(s1);
1622621Sllai1 if (str == NULL) {
1632621Sllai1 (void) fprintf(stderr, gettext("%s: strdup failed: %s\n"),
1642621Sllai1 typename, strerror(errno));
1652621Sllai1 }
1662621Sllai1 return (str);
1672621Sllai1 }
1682621Sllai1
1692621Sllai1
1702621Sllai1 /*
1712621Sllai1 * Wrapper around stat().
1722621Sllai1 */
1732621Sllai1 static int
do_stat(const char * path,struct stat * buf)1742621Sllai1 do_stat(const char *path, struct stat *buf)
1752621Sllai1 {
1762621Sllai1 int ret;
1772621Sllai1
1782621Sllai1 ret = stat(path, buf);
1792621Sllai1 if (ret < 0) {
1802621Sllai1 (void) fprintf(stderr, gettext("%s: can't stat %s: %s\n"),
1812621Sllai1 typename, path, strerror(errno));
1822621Sllai1 }
1832621Sllai1 return (ret);
1842621Sllai1 }
1852621Sllai1
1862621Sllai1
1872621Sllai1 /*
1882621Sllai1 * Wraper around realpath()
1892621Sllai1 */
1902621Sllai1 static char *
do_realpath(const char * path,char * resolved_path)1912621Sllai1 do_realpath(const char *path, char *resolved_path)
1922621Sllai1 {
1932621Sllai1 char *ret;
1942621Sllai1
1952621Sllai1 ret = realpath(path, resolved_path);
1962621Sllai1 if (ret == NULL) {
1972621Sllai1 (void) fprintf(stderr, gettext("%s: realpath %s failed: %s\n"),
1982621Sllai1 typename, path, strerror(errno));
1992621Sllai1 }
2002621Sllai1 return (ret);
2012621Sllai1 }
2022621Sllai1
2032621Sllai1
2042621Sllai1 static int
parse_subopts(char * subopts)2052621Sllai1 parse_subopts(char *subopts)
2062621Sllai1 {
2072621Sllai1 char *value;
2082621Sllai1 char path[PATH_MAX + 1];
2092621Sllai1
2102621Sllai1 while (*subopts != '\0') {
2112621Sllai1 switch (getsubopt(&subopts, myopts, &value)) {
2122621Sllai1 case SUBOPT_READONLY:
2132621Sllai1 if (readflag == READFLAG_RW) {
2142621Sllai1 (void) fprintf(stderr, gettext("%s: both "
2152621Sllai1 "read-only and read-write options "
2162621Sllai1 "specified\n"), typename);
2172621Sllai1 return (-1);
2182621Sllai1 }
2192621Sllai1 readflag = READFLAG_RO;
2202621Sllai1 break;
2212621Sllai1
2222621Sllai1 case SUBOPT_READWRITE:
2232621Sllai1 if (readflag == READFLAG_RO) {
2242621Sllai1 (void) fprintf(stderr, gettext("%s: both "
2252621Sllai1 "read-only and read-write options "
2262621Sllai1 "specified\n"), typename);
2272621Sllai1 return (-1);
2282621Sllai1 }
2292621Sllai1 readflag = READFLAG_RW;
2302621Sllai1 break;
2312621Sllai1
2322621Sllai1 case SUBOPT_ATTRIBDIR:
2332621Sllai1 if (value == NULL) {
2342621Sllai1 (void) fprintf(stderr, gettext("%s: no "
2352621Sllai1 "attribute directory\n"), typename);
2362621Sllai1 return (-1);
2372621Sllai1 } else {
2382621Sllai1 if (do_realpath(value, path) == NULL)
2392621Sllai1 return (-1);
2402621Sllai1 mountargs.sdev_attrdir =
2412621Sllai1 (uint64_t)(uintptr_t)do_strdup(path);
2422621Sllai1 if (mountargs.sdev_attrdir == NULL)
2432621Sllai1 return (-1);
2442621Sllai1 }
2452621Sllai1 break;
2462621Sllai1
2472621Sllai1 case SUBOPT_REMOUNT:
2482621Sllai1 remount = 1;
2492621Sllai1 break;
2502621Sllai1
2512621Sllai1 default:
2522621Sllai1 (void) fprintf(stderr, gettext("%s: illegal -o "
2532621Sllai1 "suboption: %s\n"), typename, value);
2542621Sllai1 return (-1);
2552621Sllai1 }
2562621Sllai1 }
2572621Sllai1 return (0);
2582621Sllai1 }
2592621Sllai1
2602621Sllai1
2612621Sllai1 int
main(int argc,char ** argv)2622621Sllai1 main(int argc, char **argv)
2632621Sllai1 {
2642621Sllai1 struct stat st;
2652621Sllai1 char mntpath[PATH_MAX + 1];
2662621Sllai1 int cc;
2672621Sllai1
2682621Sllai1 (void) setlocale(LC_ALL, "");
2692621Sllai1
2702621Sllai1 #if !defined(TEXT_DOMAIN)
2712621Sllai1 #define TEXT_DOMAIN "SYS_TEST"
2722621Sllai1 #endif
2732621Sllai1 (void) textdomain(TEXT_DOMAIN);
2742621Sllai1
2752621Sllai1 if (myname = strrchr(argv[0], '/'))
2762621Sllai1 myname++;
2772621Sllai1 else
2782621Sllai1 myname = argv[0];
2792621Sllai1 (void) snprintf(typename, sizeof (typename), "%s %s", fstype, myname);
2802621Sllai1 argv[0] = typename;
2812621Sllai1
2822621Sllai1 while ((cc = getopt(argc, argv, "?o:rmO")) != -1) {
2832621Sllai1 switch (cc) {
2842621Sllai1 case 'r':
2852621Sllai1 if (readflag == READFLAG_RW) {
2862621Sllai1 (void) fprintf(stderr, gettext("%s: both "
2872621Sllai1 "read-only and read-write options "
2882621Sllai1 "specified\n"), typename);
2892621Sllai1 return (1);
2902621Sllai1 }
2912621Sllai1 readflag = READFLAG_RO;
2922621Sllai1 break;
2932621Sllai1
2942621Sllai1 case 'O':
2952621Sllai1 overlay = 1;
2962621Sllai1 break;
2972621Sllai1
2982621Sllai1 case 'o':
2992621Sllai1 if (parse_subopts(optarg))
3002621Sllai1 return (1);
3012621Sllai1 break;
3022621Sllai1
3032621Sllai1 default:
3042621Sllai1 usage();
3052621Sllai1 break;
3062621Sllai1 }
3072621Sllai1 }
3082621Sllai1
3092621Sllai1 /*
3102621Sllai1 * There must be at least 2 more arguments, the
3112621Sllai1 * special file and the directory.
3122621Sllai1 */
3132621Sllai1 if ((argc - optind) != 2)
3142621Sllai1 usage();
3152621Sllai1
3162621Sllai1 special = argv[optind++];
3172621Sllai1
3182621Sllai1 if (do_realpath(argv[optind++], mntpath) == NULL)
3192621Sllai1 return (1);
3202621Sllai1 mountpt = mntpath;
3212621Sllai1
3222621Sllai1 if (mountpt) {
3232621Sllai1 if (do_stat(mountpt, &st) < 0)
3242621Sllai1 return (1);
3252621Sllai1 if (! S_ISDIR(st.st_mode)) {
3262621Sllai1 (void) fprintf(stderr, gettext("%s: %s is not a "
3272621Sllai1 "directory\n"), typename, mountpt);
3282621Sllai1 return (1);
3292621Sllai1 }
3302621Sllai1 }
3312621Sllai1
3322621Sllai1 if (mountargs.sdev_attrdir) {
3332621Sllai1 if (do_stat((const char *)(uintptr_t)mountargs.sdev_attrdir,
3342621Sllai1 &st) < 0)
3352621Sllai1 return (1);
3362621Sllai1 if (! S_ISDIR(st.st_mode)) {
3372621Sllai1 (void) fprintf(stderr, gettext("%s: %s is not a "
3382621Sllai1 "directory\n"), typename, mountargs.sdev_attrdir);
3392621Sllai1 return (1);
3402621Sllai1 }
3412621Sllai1 }
3422621Sllai1
3432621Sllai1 /* Special checks if /dev is the mount point */
3442621Sllai1 /* Remount of /dev requires an attribute directory */
3452621Sllai1 if (strcmp(mountpt, "/dev") == 0 && remount &&
3462621Sllai1 mountargs.sdev_attrdir == NULL) {
3472621Sllai1 (void) fprintf(stderr, gettext("%s: missing attribute "
3482621Sllai1 "directory\n"), typename);
3492621Sllai1 return (1);
3502621Sllai1 }
3512621Sllai1
3522621Sllai1 (void) signal(SIGHUP, SIG_IGN);
3532621Sllai1 (void) signal(SIGQUIT, SIG_IGN);
3542621Sllai1 (void) signal(SIGINT, SIG_IGN);
3552621Sllai1
3562621Sllai1 /* Perform the mount */
3572621Sllai1 if (do_mount())
3582621Sllai1 return (1);
3592621Sllai1
3602621Sllai1 return (0);
3612621Sllai1 }
362