xref: /illumos-gate/usr/src/cmd/fs.d/hsfs/mount/mount.c (revision 533affcbc7fc4d0c8132976ea454aaa715fe2307)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <ctype.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <unistd.h>	/* defines F_LOCK for lockf */
31 #include <stdlib.h>	/* for getopt(3) */
32 #include <signal.h>
33 #include <locale.h>
34 #include <fslib.h>
35 #include <sys/types.h>
36 #include <errno.h>
37 #include <sys/mnttab.h>
38 #include <sys/mntent.h>
39 #include <sys/mount.h>
40 #include <sys/vfs.h>
41 #include <sys/fs/hsfs_susp.h>
42 #include <sys/fs/hsfs_rrip.h>
43 
44 extern int optind;
45 extern char *optarg;
46 
47 #define	NAME_MAX	64
48 #define	GLOBAL		0
49 #define	NOGLOBAL	1
50 
51 #ifndef	MNTOPT_NOGLOBAL
52 #define	MNTOPT_NOGLOBAL	"noglobal"
53 #endif	/* MNTOPT_NOGLOBAL */
54 
55 static int gflg		= 0;	/* mount into global name space: flag form */
56 static int global	= 0;	/* mount into global name space: option form */
57 static int havegblopt	= 0;	/* global value supercedes gflg value */
58 static int qflg		= 0;	/* quiet option - don't flag bad options */
59 
60 static char fstype[] = MNTTYPE_HSFS;
61 
62 static char typename[NAME_MAX], *myname;
63 /*
64  * Mount options that require special handling
65  */
66 static char *myopts[] = {
67 	MNTOPT_GLOBAL,
68 	MNTOPT_NOGLOBAL,
69 	NULL
70 };
71 
72 
73 static void rpterr(char *, char *);
74 static void usage(void);
75 
76 int
77 main(int argc, char **argv)
78 {
79 	char *options, *value;
80 	char *special, *mountp;
81 	char *gopt;
82 	struct mnttab mm;
83 	int c;
84 	char	obuff[MAX_MNTOPT_STR];
85 	char	saved_input_options[MAX_MNTOPT_STR];
86 	int hsfs_flags;
87 
88 	int flags;
89 	int Oflg = 0;   /* Overlay mounts */
90 
91 	(void) setlocale(LC_ALL, "");
92 
93 #if !defined(TEXT_DOMAIN)
94 #define	TEXT_DOMAIN "SYS_TEST"
95 #endif
96 	(void) textdomain(TEXT_DOMAIN);
97 
98 	myname = strrchr(argv[0], '/');
99 	if (myname)
100 		myname++;
101 	else
102 		myname = argv[0];
103 	snprintf(typename, sizeof (typename), "%s %s", fstype, myname);
104 	argv[0] = typename;
105 
106 	/*
107 	 * Check for arguments requiring special handling.  Ignore
108 	 * unrecognized options.
109 	 */
110 	strcpy(obuff, "ro");	/* default */
111 	while ((c = getopt(argc, argv, "o:rmOgq")) != EOF) {
112 		switch (c) {
113 			case 'o':
114 				if (strlen(optarg) > MAX_MNTOPT_STR) {
115 					(void) fprintf(stderr, gettext(
116 					    "%s: option set too long\n"),
117 					    myname);
118 					exit(1);
119 				}
120 				if (strlen(optarg) == 0) {
121 					(void) fprintf(stderr, gettext(
122 					    "%s: missing suboptions\n"),
123 					    myname);
124 					exit(1);
125 				}
126 				strcpy(obuff, optarg);
127 				options = optarg;
128 				while (*options != '\0') {
129 					switch (getsubopt(&options, myopts,
130 					    &value)) {
131 					case GLOBAL:
132 						havegblopt = 1;
133 						global = 1;
134 						break;
135 					case NOGLOBAL:
136 						havegblopt = 1;
137 						global = 0;
138 						break;
139 					}
140 				}
141 				break;
142 			case 'O':
143 				Oflg++;
144 				break;
145 			case 'r':
146 				/* accept for backwards compatibility */
147 				break;
148 			case 'm':
149 				break;
150 			case 'g':
151 				gflg++;
152 				break;
153 			case 'q':
154 				qflg++;
155 				break;
156 
157 		}
158 	}
159 
160 	if ((argc - optind) != 2)
161 		usage();
162 
163 	special = argv[optind++];
164 	mountp = argv[optind++];
165 
166 	/*
167 	 * Force readonly.  obuff is guaranteed to have something in
168 	 * it.  We might end up with "ro,ro", but that's acceptable.
169 	 */
170 	flags = MS_RDONLY;
171 
172 	if ((strlen(obuff) + strlen(MNTOPT_RO) + 2) > MAX_MNTOPT_STR) {
173 		(void) fprintf(stderr, gettext("%s: option set too long\n"),
174 		    myname);
175 		exit(1);
176 	}
177 
178 	strcat(obuff, ",");
179 	strcat(obuff, MNTOPT_RO);
180 
181 	flags |= Oflg ? MS_OVERLAY : 0;
182 
183 	/*
184 	 * xxx it's not clear if should just put MS_GLOBAL in flags,
185 	 * or provide it as a string.  Be safe, do both.  The subopt
186 	 * version has precedence over the switch version.
187 	 */
188 	gopt = NULL;
189 	if ((havegblopt && global) || gflg) {
190 		gopt = MNTOPT_GLOBAL;
191 		flags |= MS_GLOBAL;
192 	} else if (havegblopt) {
193 		gopt = MNTOPT_NOGLOBAL;
194 	}
195 
196 	if (gopt != NULL) {
197 		if ((strlen(obuff) + strlen(gopt) + 2) > MAX_MNTOPT_STR) {
198 			(void) fprintf(stderr,
199 			    gettext("%s: option set too long\n"), myname);
200 			exit(1);
201 		}
202 
203 		strcat(obuff, ",");
204 		strcat(obuff, gopt);
205 	}
206 
207 	signal(SIGHUP,  SIG_IGN);
208 	signal(SIGQUIT, SIG_IGN);
209 	signal(SIGINT,  SIG_IGN);
210 
211 	/*
212 	 * Save a copy of the options to compare with the options that
213 	 * were actually recognized and supported by the kernel.
214 	 */
215 
216 	(void) strcpy(saved_input_options, obuff);
217 
218 	/*
219 	 * Perform the mount.
220 	 */
221 
222 	if (mount(special, mountp, flags | MS_OPTIONSTR, fstype, NULL, 0,
223 		obuff, sizeof (obuff)) == -1) {
224 		rpterr(special, mountp);
225 		exit(31+2);
226 	}
227 
228 	if (!qflg) {
229 		cmp_requested_to_actual_options(saved_input_options, obuff,
230 			special, mountp);
231 	}
232 
233 	exit(0);
234 	/* NOTREACHED */
235 }
236 
237 
238 static void
239 rpterr(char *bs, char *mp)
240 {
241 	switch (errno) {
242 	case EPERM:
243 		(void) fprintf(stderr, gettext("%s: insufficient privileges\n"),
244 		    myname);
245 		break;
246 	case ENXIO:
247 		(void) fprintf(stderr, gettext("%s: %s no such device\n"),
248 		    myname, bs);
249 		break;
250 	case ENOTDIR:
251 		(void) fprintf(stderr, gettext("%s: %s not a directory\n\tor a "
252 		    "component of %s is not a directory\n"), myname, mp, bs);
253 		break;
254 	case ENOENT:
255 		(void) fprintf(stderr,
256 		    gettext("%s: %s or %s, no such file or directory\n"),
257 		    myname, bs, mp);
258 		break;
259 	case EINVAL:
260 		(void) fprintf(stderr, gettext("%s: %s is not an hsfs file "
261 		    "system.\n"), typename, bs);
262 		break;
263 	case EBUSY:
264 		(void) fprintf(stderr,
265 		    gettext("%s: %s is already mounted or %s is busy\n"),
266 		    myname, bs, mp);
267 		break;
268 	case ENOTBLK:
269 		(void) fprintf(stderr,
270 		    gettext("%s: %s not a block device\n"), myname, bs);
271 		break;
272 	case EROFS:
273 		(void) fprintf(stderr, gettext("%s: %s write-protected\n"),
274 		    myname, bs);
275 		break;
276 	case ENOSPC:
277 		(void) fprintf(stderr,
278 		    gettext("%s: %s is corrupted. needs checking\n"),
279 		    myname, bs);
280 		break;
281 	default:
282 		perror(myname);
283 		(void) fprintf(stderr, gettext("%s: cannot mount %s\n"), myname,
284 		    bs);
285 	}
286 }
287 
288 
289 static void
290 usage()
291 {
292 	char *opts;
293 
294 opts = "{-r | -o ro | -o nrr | -o nosuid | -o notraildot | -o nomaplcase}";
295 	(void) fprintf(stdout,
296 gettext("hsfs usage: mount [-F hsfs] %s {special | mount_point}\n"), opts);
297 	(void) fprintf(stdout,
298 gettext("hsfs usage: mount [-F hsfs] %s special mount_point\n"), opts);
299 	exit(32);
300 }
301