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
main(int argc,char ** argv)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
rpterr(char * bs,char * mp)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
usage()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