xref: /onnv-gate/usr/src/cmd/fs.d/dev/mount.c (revision 10116:50f8607587c1)
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