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