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