xref: /titanic_53/usr/src/cmd/fs.d/dev/mount.c (revision facf4a8d7b59fde89a8662b4f4c73a758e6c402c)
1*facf4a8dSllai1 /*
2*facf4a8dSllai1  * CDDL HEADER START
3*facf4a8dSllai1  *
4*facf4a8dSllai1  * The contents of this file are subject to the terms of the
5*facf4a8dSllai1  * Common Development and Distribution License (the "License").
6*facf4a8dSllai1  * You may not use this file except in compliance with the License.
7*facf4a8dSllai1  *
8*facf4a8dSllai1  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*facf4a8dSllai1  * or http://www.opensolaris.org/os/licensing.
10*facf4a8dSllai1  * See the License for the specific language governing permissions
11*facf4a8dSllai1  * and limitations under the License.
12*facf4a8dSllai1  *
13*facf4a8dSllai1  * When distributing Covered Code, include this CDDL HEADER in each
14*facf4a8dSllai1  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*facf4a8dSllai1  * If applicable, add the following below this CDDL HEADER, with the
16*facf4a8dSllai1  * fields enclosed by brackets "[]" replaced with your own identifying
17*facf4a8dSllai1  * information: Portions Copyright [yyyy] [name of copyright owner]
18*facf4a8dSllai1  *
19*facf4a8dSllai1  * CDDL HEADER END
20*facf4a8dSllai1  */
21*facf4a8dSllai1 
22*facf4a8dSllai1 /*
23*facf4a8dSllai1  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*facf4a8dSllai1  * Use is subject to license terms.
25*facf4a8dSllai1  */
26*facf4a8dSllai1 
27*facf4a8dSllai1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*facf4a8dSllai1 
29*facf4a8dSllai1 #include <sys/types.h>
30*facf4a8dSllai1 #include <limits.h>
31*facf4a8dSllai1 #include <stdio.h>
32*facf4a8dSllai1 #include <stdlib.h>
33*facf4a8dSllai1 #include <unistd.h>
34*facf4a8dSllai1 #include <signal.h>
35*facf4a8dSllai1 #include <errno.h>
36*facf4a8dSllai1 #include <string.h>
37*facf4a8dSllai1 #include <locale.h>
38*facf4a8dSllai1 #include <sys/stat.h>
39*facf4a8dSllai1 #include <sys/mount.h>
40*facf4a8dSllai1 #include <sys/mntent.h>
41*facf4a8dSllai1 #include <sys/fs/sdev_node.h>
42*facf4a8dSllai1 
43*facf4a8dSllai1 
44*facf4a8dSllai1 #define	READFLAG_RO	1
45*facf4a8dSllai1 #define	READFLAG_RW	2
46*facf4a8dSllai1 
47*facf4a8dSllai1 
48*facf4a8dSllai1 extern int	optind;
49*facf4a8dSllai1 extern char	*optarg;
50*facf4a8dSllai1 
51*facf4a8dSllai1 static char	typename[64], *myname;
52*facf4a8dSllai1 static char	fstype[] = MNTTYPE_DEV;
53*facf4a8dSllai1 
54*facf4a8dSllai1 static int	readflag;
55*facf4a8dSllai1 static int	overlay;
56*facf4a8dSllai1 static int	remount;
57*facf4a8dSllai1 
58*facf4a8dSllai1 static char	*special;
59*facf4a8dSllai1 static char	*mountpt;
60*facf4a8dSllai1 static struct sdev_mountargs	mountargs;
61*facf4a8dSllai1 
62*facf4a8dSllai1 static char	*myopts[] = {
63*facf4a8dSllai1 #define	SUBOPT_READONLY		0
64*facf4a8dSllai1 	"ro",
65*facf4a8dSllai1 #define	SUBOPT_READWRITE	1
66*facf4a8dSllai1 	"rw",
67*facf4a8dSllai1 #define	SUBOPT_ATTRIBDIR	2
68*facf4a8dSllai1 	"attrdir",
69*facf4a8dSllai1 #define	SUBOPT_REMOUNT		3
70*facf4a8dSllai1 	"remount",
71*facf4a8dSllai1 	NULL
72*facf4a8dSllai1 };
73*facf4a8dSllai1 
74*facf4a8dSllai1 
75*facf4a8dSllai1 static void
76*facf4a8dSllai1 usage(void)
77*facf4a8dSllai1 {
78*facf4a8dSllai1 	(void) fprintf(stderr, gettext(
79*facf4a8dSllai1 	    "%s usage:\n%s [-F %s] [-r] [-o specific_options]"
80*facf4a8dSllai1 	    " {special | mount_point}\n%s [-F %s] [-r] [-o specific_options]"
81*facf4a8dSllai1 	    " special mount_point\n"), fstype, myname, fstype, myname, fstype);
82*facf4a8dSllai1 	exit(1);
83*facf4a8dSllai1 }
84*facf4a8dSllai1 
85*facf4a8dSllai1 
86*facf4a8dSllai1 static int
87*facf4a8dSllai1 do_mount(void)
88*facf4a8dSllai1 {
89*facf4a8dSllai1 	int	flags = MS_DATA;
90*facf4a8dSllai1 
91*facf4a8dSllai1 	if (readflag == READFLAG_RO)
92*facf4a8dSllai1 		flags |= MS_RDONLY;
93*facf4a8dSllai1 	if (overlay)
94*facf4a8dSllai1 		flags |= MS_OVERLAY;
95*facf4a8dSllai1 	if (remount)
96*facf4a8dSllai1 		flags |= MS_REMOUNT;
97*facf4a8dSllai1 
98*facf4a8dSllai1 	if (mount(special, mountpt, flags, fstype, &mountargs,
99*facf4a8dSllai1 	    sizeof (mountargs), NULL, 0)) {
100*facf4a8dSllai1 		switch (errno) {
101*facf4a8dSllai1 		case EPERM:
102*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: not super user\n"),
103*facf4a8dSllai1 			    typename);
104*facf4a8dSllai1 			break;
105*facf4a8dSllai1 		case ENXIO:
106*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s no such "
107*facf4a8dSllai1 			    "device\n"), typename, special);
108*facf4a8dSllai1 			break;
109*facf4a8dSllai1 		case ENOTDIR:
110*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s "
111*facf4a8dSllai1 			    "not a directory\n"
112*facf4a8dSllai1 			    "\tor a component of %s is not a directory\n"),
113*facf4a8dSllai1 			    typename, mountpt, special);
114*facf4a8dSllai1 			break;
115*facf4a8dSllai1 		case ENOENT:
116*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s or %s, no such "
117*facf4a8dSllai1 			    "file or directory\n"),
118*facf4a8dSllai1 			    typename, special, mountpt);
119*facf4a8dSllai1 			break;
120*facf4a8dSllai1 		case EINVAL:
121*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s is not this "
122*facf4a8dSllai1 			    "filesystem type.\n"), typename, special);
123*facf4a8dSllai1 			break;
124*facf4a8dSllai1 		case EBUSY:
125*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s "
126*facf4a8dSllai1 			    "is already mounted, %s is busy,\n"
127*facf4a8dSllai1 			    "\tor allowable number of mount points exceeded\n"),
128*facf4a8dSllai1 			    typename, special, mountpt);
129*facf4a8dSllai1 			break;
130*facf4a8dSllai1 		case ENOTBLK:
131*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s not a block "
132*facf4a8dSllai1 			    "device\n"), typename, special);
133*facf4a8dSllai1 			break;
134*facf4a8dSllai1 		case EROFS:
135*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s read-only "
136*facf4a8dSllai1 			    "filesystem\n"), typename, special);
137*facf4a8dSllai1 			break;
138*facf4a8dSllai1 		case ENOSPC:
139*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: the state of %s "
140*facf4a8dSllai1 			    "is not okay\n"
141*facf4a8dSllai1 			    "\tand read/write mount was attempted\n"),
142*facf4a8dSllai1 			    typename, special);
143*facf4a8dSllai1 			break;
144*facf4a8dSllai1 		default:
145*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: cannot mount %s: "
146*facf4a8dSllai1 			    "%s\n"), typename, special, strerror(errno));
147*facf4a8dSllai1 			break;
148*facf4a8dSllai1 		}
149*facf4a8dSllai1 		return (-1);
150*facf4a8dSllai1 	}
151*facf4a8dSllai1 	return (0);
152*facf4a8dSllai1 }
153*facf4a8dSllai1 
154*facf4a8dSllai1 
155*facf4a8dSllai1 /*
156*facf4a8dSllai1  * Wrapper around strdup().
157*facf4a8dSllai1  */
158*facf4a8dSllai1 static char *
159*facf4a8dSllai1 do_strdup(const char *s1)
160*facf4a8dSllai1 {
161*facf4a8dSllai1 	char	*str;
162*facf4a8dSllai1 
163*facf4a8dSllai1 	str = strdup(s1);
164*facf4a8dSllai1 	if (str == NULL) {
165*facf4a8dSllai1 		(void) fprintf(stderr, gettext("%s: strdup failed: %s\n"),
166*facf4a8dSllai1 		    typename, strerror(errno));
167*facf4a8dSllai1 	}
168*facf4a8dSllai1 	return (str);
169*facf4a8dSllai1 }
170*facf4a8dSllai1 
171*facf4a8dSllai1 
172*facf4a8dSllai1 /*
173*facf4a8dSllai1  * Wrapper around stat().
174*facf4a8dSllai1  */
175*facf4a8dSllai1 static int
176*facf4a8dSllai1 do_stat(const char *path, struct stat *buf)
177*facf4a8dSllai1 {
178*facf4a8dSllai1 	int	ret;
179*facf4a8dSllai1 
180*facf4a8dSllai1 	ret = stat(path, buf);
181*facf4a8dSllai1 	if (ret < 0) {
182*facf4a8dSllai1 		(void) fprintf(stderr, gettext("%s: can't stat %s: %s\n"),
183*facf4a8dSllai1 		    typename, path, strerror(errno));
184*facf4a8dSllai1 	}
185*facf4a8dSllai1 	return (ret);
186*facf4a8dSllai1 }
187*facf4a8dSllai1 
188*facf4a8dSllai1 
189*facf4a8dSllai1 /*
190*facf4a8dSllai1  * Wraper around realpath()
191*facf4a8dSllai1  */
192*facf4a8dSllai1 static char *
193*facf4a8dSllai1 do_realpath(const char *path, char *resolved_path)
194*facf4a8dSllai1 {
195*facf4a8dSllai1 	char	*ret;
196*facf4a8dSllai1 
197*facf4a8dSllai1 	ret = realpath(path, resolved_path);
198*facf4a8dSllai1 	if (ret == NULL) {
199*facf4a8dSllai1 		(void) fprintf(stderr, gettext("%s: realpath %s failed: %s\n"),
200*facf4a8dSllai1 		    typename, path, strerror(errno));
201*facf4a8dSllai1 	}
202*facf4a8dSllai1 	return (ret);
203*facf4a8dSllai1 }
204*facf4a8dSllai1 
205*facf4a8dSllai1 
206*facf4a8dSllai1 static int
207*facf4a8dSllai1 parse_subopts(char *subopts)
208*facf4a8dSllai1 {
209*facf4a8dSllai1 	char	*value;
210*facf4a8dSllai1 	char	path[PATH_MAX + 1];
211*facf4a8dSllai1 
212*facf4a8dSllai1 	while (*subopts != '\0') {
213*facf4a8dSllai1 		switch (getsubopt(&subopts, myopts, &value)) {
214*facf4a8dSllai1 		case SUBOPT_READONLY:
215*facf4a8dSllai1 			if (readflag == READFLAG_RW) {
216*facf4a8dSllai1 				(void) fprintf(stderr, gettext("%s: both "
217*facf4a8dSllai1 				    "read-only and read-write options "
218*facf4a8dSllai1 				    "specified\n"), typename);
219*facf4a8dSllai1 				return (-1);
220*facf4a8dSllai1 			}
221*facf4a8dSllai1 			readflag = READFLAG_RO;
222*facf4a8dSllai1 			break;
223*facf4a8dSllai1 
224*facf4a8dSllai1 		case SUBOPT_READWRITE:
225*facf4a8dSllai1 			if (readflag == READFLAG_RO) {
226*facf4a8dSllai1 				(void) fprintf(stderr, gettext("%s: both "
227*facf4a8dSllai1 				    "read-only and read-write options "
228*facf4a8dSllai1 				    "specified\n"), typename);
229*facf4a8dSllai1 				return (-1);
230*facf4a8dSllai1 			}
231*facf4a8dSllai1 			readflag = READFLAG_RW;
232*facf4a8dSllai1 			break;
233*facf4a8dSllai1 
234*facf4a8dSllai1 		case SUBOPT_ATTRIBDIR:
235*facf4a8dSllai1 			if (value == NULL) {
236*facf4a8dSllai1 				(void) fprintf(stderr, gettext("%s: no "
237*facf4a8dSllai1 				    "attribute directory\n"), typename);
238*facf4a8dSllai1 				return (-1);
239*facf4a8dSllai1 			} else {
240*facf4a8dSllai1 				if (do_realpath(value, path) == NULL)
241*facf4a8dSllai1 					return (-1);
242*facf4a8dSllai1 				mountargs.sdev_attrdir =
243*facf4a8dSllai1 				    (uint64_t)(uintptr_t)do_strdup(path);
244*facf4a8dSllai1 				if (mountargs.sdev_attrdir == NULL)
245*facf4a8dSllai1 					return (-1);
246*facf4a8dSllai1 			}
247*facf4a8dSllai1 			break;
248*facf4a8dSllai1 
249*facf4a8dSllai1 		case SUBOPT_REMOUNT:
250*facf4a8dSllai1 			remount = 1;
251*facf4a8dSllai1 			break;
252*facf4a8dSllai1 
253*facf4a8dSllai1 		default:
254*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: illegal -o "
255*facf4a8dSllai1 			    "suboption: %s\n"), typename, value);
256*facf4a8dSllai1 			return (-1);
257*facf4a8dSllai1 		}
258*facf4a8dSllai1 	}
259*facf4a8dSllai1 	return (0);
260*facf4a8dSllai1 }
261*facf4a8dSllai1 
262*facf4a8dSllai1 
263*facf4a8dSllai1 int
264*facf4a8dSllai1 main(int argc, char **argv)
265*facf4a8dSllai1 {
266*facf4a8dSllai1 	struct stat	st;
267*facf4a8dSllai1 	char		mntpath[PATH_MAX + 1];
268*facf4a8dSllai1 	int		cc;
269*facf4a8dSllai1 
270*facf4a8dSllai1 	(void) setlocale(LC_ALL, "");
271*facf4a8dSllai1 
272*facf4a8dSllai1 #if !defined(TEXT_DOMAIN)
273*facf4a8dSllai1 #define	TEXT_DOMAIN "SYS_TEST"
274*facf4a8dSllai1 #endif
275*facf4a8dSllai1 	(void) textdomain(TEXT_DOMAIN);
276*facf4a8dSllai1 
277*facf4a8dSllai1 	if (myname = strrchr(argv[0], '/'))
278*facf4a8dSllai1 		myname++;
279*facf4a8dSllai1 	else
280*facf4a8dSllai1 		myname = argv[0];
281*facf4a8dSllai1 	(void) snprintf(typename, sizeof (typename), "%s %s", fstype, myname);
282*facf4a8dSllai1 	argv[0] = typename;
283*facf4a8dSllai1 
284*facf4a8dSllai1 	while ((cc = getopt(argc, argv, "?o:rmO")) != -1) {
285*facf4a8dSllai1 		switch (cc) {
286*facf4a8dSllai1 		case 'r':
287*facf4a8dSllai1 			if (readflag == READFLAG_RW) {
288*facf4a8dSllai1 				(void) fprintf(stderr, gettext("%s: both "
289*facf4a8dSllai1 				    "read-only and read-write options "
290*facf4a8dSllai1 				    "specified\n"), typename);
291*facf4a8dSllai1 				return (1);
292*facf4a8dSllai1 			}
293*facf4a8dSllai1 			readflag = READFLAG_RO;
294*facf4a8dSllai1 			break;
295*facf4a8dSllai1 
296*facf4a8dSllai1 		case 'O':
297*facf4a8dSllai1 			overlay = 1;
298*facf4a8dSllai1 			break;
299*facf4a8dSllai1 
300*facf4a8dSllai1 		case 'o':
301*facf4a8dSllai1 			if (parse_subopts(optarg))
302*facf4a8dSllai1 				return (1);
303*facf4a8dSllai1 			break;
304*facf4a8dSllai1 
305*facf4a8dSllai1 		default:
306*facf4a8dSllai1 			usage();
307*facf4a8dSllai1 			break;
308*facf4a8dSllai1 		}
309*facf4a8dSllai1 	}
310*facf4a8dSllai1 
311*facf4a8dSllai1 	/*
312*facf4a8dSllai1 	 * There must be at least 2 more arguments, the
313*facf4a8dSllai1 	 * special file and the directory.
314*facf4a8dSllai1 	 */
315*facf4a8dSllai1 	if ((argc - optind) != 2)
316*facf4a8dSllai1 		usage();
317*facf4a8dSllai1 
318*facf4a8dSllai1 	special = argv[optind++];
319*facf4a8dSllai1 
320*facf4a8dSllai1 	if (do_realpath(argv[optind++], mntpath) == NULL)
321*facf4a8dSllai1 		return (1);
322*facf4a8dSllai1 	mountpt = mntpath;
323*facf4a8dSllai1 
324*facf4a8dSllai1 	if (mountpt) {
325*facf4a8dSllai1 		if (do_stat(mountpt, &st) < 0)
326*facf4a8dSllai1 			return (1);
327*facf4a8dSllai1 		if (! S_ISDIR(st.st_mode)) {
328*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s is not a "
329*facf4a8dSllai1 			    "directory\n"), typename, mountpt);
330*facf4a8dSllai1 			return (1);
331*facf4a8dSllai1 		}
332*facf4a8dSllai1 	}
333*facf4a8dSllai1 
334*facf4a8dSllai1 	if (mountargs.sdev_attrdir) {
335*facf4a8dSllai1 		if (do_stat((const char *)(uintptr_t)mountargs.sdev_attrdir,
336*facf4a8dSllai1 		    &st) < 0)
337*facf4a8dSllai1 			return (1);
338*facf4a8dSllai1 		if (! S_ISDIR(st.st_mode)) {
339*facf4a8dSllai1 			(void) fprintf(stderr, gettext("%s: %s is not a "
340*facf4a8dSllai1 			    "directory\n"), typename, mountargs.sdev_attrdir);
341*facf4a8dSllai1 			return (1);
342*facf4a8dSllai1 		}
343*facf4a8dSllai1 	}
344*facf4a8dSllai1 
345*facf4a8dSllai1 	/* Special checks if /dev is the mount point */
346*facf4a8dSllai1 	/* Remount of /dev requires an attribute directory */
347*facf4a8dSllai1 	if (strcmp(mountpt, "/dev") == 0 && remount &&
348*facf4a8dSllai1 	    mountargs.sdev_attrdir == NULL) {
349*facf4a8dSllai1 		(void) fprintf(stderr, gettext("%s: missing attribute "
350*facf4a8dSllai1 		    "directory\n"), typename);
351*facf4a8dSllai1 		return (1);
352*facf4a8dSllai1 	}
353*facf4a8dSllai1 
354*facf4a8dSllai1 	(void) signal(SIGHUP,  SIG_IGN);
355*facf4a8dSllai1 	(void) signal(SIGQUIT, SIG_IGN);
356*facf4a8dSllai1 	(void) signal(SIGINT,  SIG_IGN);
357*facf4a8dSllai1 
358*facf4a8dSllai1 	/* Perform the mount  */
359*facf4a8dSllai1 	if (do_mount())
360*facf4a8dSllai1 		return (1);
361*facf4a8dSllai1 
362*facf4a8dSllai1 	return (0);
363*facf4a8dSllai1 }
364