1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1989-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * <mnt.h> based mount/umount
26 */
27
28 #include "FEATURE/unmount"
29
30 #if _lib_mount && ( _lib_umount || _lib_unmount )
31
32 static const char mount_usage[] =
33 "[-?\n@(#)$Id: mount (AT&T Research) 2011-02-11 $\n]"
34 USAGE_LICENSE
35 "[+NAME?mount - mount and display filesystems]"
36 "[+DESCRIPTION?\bmount\b attaches a named filesystem \afs\a to the"
37 " directory \adir\a, which must already exist. The contents of \adir\a"
38 " are hidden until the filesystem is unmounted. The filesystem mount"
39 " table is consulted if either of \afs\a or \adir\a are omitted."
40 " Information on all mounted filesystems is displayed if both"
41 " \afs\a and \adir\a are omitted.]"
42
43 "[a:all?Operate on all filesystems in the filesystem table. The \b--host\b"
44 " and \b--type\b options can be used to match parts of the table.]"
45 "[f:show|fake?Display but do not execute the underlying \bmount\b(2)"
46 " system calls.]"
47 "[h:hosts?Limit the filesystem table scan to entries matching the \ahost\a"
48 " names. A leading \b!\b inverts the match sense.]:[[!]]host,...]"
49 "[M:mtab|fstab?Use \afile\a instead of the default filesystem table.]:[file]"
50 "[b:omit?Omit filesystem table entries matching any of the \atype\a"
51 " names.]:[[!]]type,...]"
52 "[o:options?Specify filesystem specific mount options. Options are a comma"
53 " separated list of words preceded by an optional \bno\b to turn the"
54 " option off, or \aname=value\a pairs. Multiple \b--options\b are"
55 " concatenated with a \bcomma\b separator. See \bfstab\b(4) for"
56 " a detailed description of mount options.]:[[no]]name[=value]][,...]]]"
57 "[p:portable?Print information in \bfstab\b(4) format.]"
58 "[r:readonly?Mount the filesystems read only. Equivalent to \b--option=ro\b.]"
59 "[t|T:types?Limit the filesystem table scan to entries matching the \atype\a"
60 " names. A leading \b!\b inverts the match sense.]:[[!]]type,...]"
61 "[u:unmount|umount?Unmount the matched filesystems.]"
62
63 "[c:check?Ignored by this implementation.]"
64 "[m:multiplex|nproc?Distribute multiple mounts across \anproc\a processes."
65 " Ignored by this implementation.]"
66 "[P:prefix?Ignored by this implementation.]:[string]"
67 "[n!:tab?Ignored by this implementation.]"
68 "[v:verbose?Ignored by this implementation.]"
69
70 "\n"
71 "\n[ fs [ dir ] ]\n"
72 "\n"
73
74 "[+SEE ALSO?\bdf\b(1), \bumount\b(1), \bmount\b(2), \bfstab\b(4)]"
75 ;
76
77 static const char unmount_usage[] =
78 "[-?\n@(#)$Id: umount (AT&T Research) 1999-11-19 $\n]"
79 USAGE_LICENSE
80 "[+NAME?umount - unmount filesystems]"
81 "[+DESCRIPTION?\bumount\b unmounts one or more currently mounted filesystems,"
82 " which can be specified either as mounted-on directories or"
83 " filesystems.]"
84
85 "[a:all?Operate on all filesystems in the filesystem table. The \b--host\b"
86 " and \b--type\b options can be used to match parts of the table.]"
87 "[f:show|fake?Display but do not execute the underlying \bumount\b(2)"
88 " system calls.]"
89 "[h:hosts?Limit the filesystem table scan to entries matching the \ahost\a"
90 " names. A leading \b!\b inverts the match sense.]:[[!]]host,...]"
91 "[M:mtab|fstab?Use \afile\a instead of the default filesystem table.]:[file]"
92 "[b:omit?Omit filesystem table entries matching any of the \atype\a"
93 " names.]:[[!]]type,...]"
94 "[t|T:types?Limit the filesystem table scan to entries matching the \atype\a"
95 " names. A leading \b!\b inverts the match sense.]:[[!]]type,...]"
96
97 "[m:multiplex|nproc?Distribute multiple mounts across \anproc\a processes."
98 " Ignored by this implementation.]"
99 "[P:prefix?Ignored by this implementation.]:[string]"
100 "[v:verbose?Ignored by this implementation.]"
101
102 "\n"
103 "\n[ fs | dir ]\n"
104 "\n"
105
106 "[+SEE ALSO?\bdf\b(1), \bmount\b(1), \bumount\b(2), \bfstab\b(4)]"
107 ;
108
109 #if defined(__STDPP__directive) && defined(__STDPP__hide)
110 __STDPP__directive pragma pp:hide mount umount unmount
111 #else
112 #define mount ______mount
113 #define umount ______umount
114 #define unmount ______unmount
115 #endif
116
117 #include <ast.h>
118 #include <error.h>
119 #include <cdt.h>
120 #include <ctype.h>
121 #include <ls.h>
122 #include <mnt.h>
123 #include <ast_fs.h>
124
125 #if _sys_mount
126 #if __bsdi__ || __bsdi || bsdi
127 #include <sys/param.h>
128 #endif
129 #ifndef NGROUPS
130 #define NGROUPS NGROUPS_MAX
131 #endif
132 #include <sys/mount.h>
133 #endif
134
135 #if defined(__STDPP__directive) && defined(__STDPP__hide)
136 __STDPP__directive pragma pp:nohide mount umount unmount
137 #else
138 #undef mount
139 #undef umount
140 #undef unmount
141 #endif
142
143 extern int mount(const char*, const char*, int, const char*, const char*, int);
144 extern int umount(const char*, int);
145 extern int unmount(const char*);
146
147 #if _lib_unmount && !_lib_umount
148 #define umount(a,b) unmount(a)
149 #endif
150
151 #ifndef FSTAB
152 #define FSTAB "/etc/fstab"
153 #endif
154
155 #ifndef MS_DATA
156 #define MS_DATA (1L<<28)
157 #endif
158
159 #define MATCH_HOST 001
160 #define MATCH_NOHOST 002
161 #define MATCH_TYPE 004
162 #define MATCH_NOTYPE 010
163
164 typedef int (*Cmp_f)(const char*, const char*);
165
166 typedef struct
167 {
168 Dtlink_t link;
169 int flags;
170 char name[1];
171 } Match_t;
172
173 typedef struct
174 {
175 int all;
176 int check;
177 int fake;
178 int fstabable;
179 int notab;
180 int nproc;
181 int unmount;
182 int verbose;
183
184 char* host;
185 char* mtab;
186 char* options;
187 char* prefix;
188 char* type;
189
190 Dt_t* match;
191 Dtdisc_t matchdisc;
192 int matchflags;
193
194 Sfio_t* tmp;
195 } State_t;
196
197 static State_t state;
198
199 static int
matchcmp(Dt_t * dt,void * k1,void * k2,Dtdisc_t * disc)200 matchcmp(Dt_t* dt, void* k1, void* k2, Dtdisc_t* disc)
201 {
202 NoP(dt);
203 NoP(disc);
204 return strcasecmp((char*)k1, (char*)k2);
205 }
206
207 static void
matchset(register char * s,int flags)208 matchset(register char* s, int flags)
209 {
210 register int c;
211 register char* b;
212 register Match_t* p;
213
214 if (!state.match)
215 {
216 state.matchdisc.key = offsetof(Match_t, name);
217 state.matchdisc.comparf = matchcmp;
218 if (!(state.match = dtopen(&state.matchdisc, Dtoset)))
219 error(ERROR_SYSTEM|3, "out of space [match table]");
220 }
221 if (*s == '!')
222 {
223 s++;
224 flags <<= 1;
225 }
226 state.matchflags |= flags;
227 for (;;)
228 {
229 while (isspace(*s))
230 s++;
231 for (b = s; (c = *s) && c != ',' && !isspace(c); s++);
232 if (s == b)
233 break;
234 if (c)
235 *s = 0;
236 if (!(p = (Match_t*)dtmatch(state.match, b)))
237 {
238 if (!(p = newof(0, Match_t, 1, s - b)))
239 error(ERROR_SYSTEM|3, "out of space [match entry]");
240 memcpy(p->name, b, s - b);
241 dtinsert(state.match, p);
242 }
243 p->flags |= flags;
244 if (!c)
245 break;
246 *s++ = c;
247 }
248 }
249
250 static int
matchhost(char * s)251 matchhost(char* s)
252 {
253 char* t;
254 char* u;
255 char* v;
256 Match_t* p;
257
258 if (!state.match || !(state.matchflags & (MATCH_HOST|MATCH_NOHOST)))
259 return 1;
260 if (!(t = strchr(s, ':')))
261 return 0;
262 *t = 0;
263 if (!(p = (Match_t*)dtmatch(state.match, s)))
264 for (u = s; v = strchr(u, '.'); u = v)
265 {
266 *v = 0;
267 p = (Match_t*)dtmatch(state.match, s);
268 *v++ = '.';
269 if (p)
270 break;
271 u = v;
272 }
273 *t = ':';
274 if (state.matchflags & MATCH_HOST)
275 return p && (p->flags & MATCH_HOST);
276 return !p || !(p->flags & MATCH_NOHOST);
277 }
278
279 static int
matchtype(char * s)280 matchtype(char* s)
281 {
282 Match_t* p;
283
284 if (!state.match || !(state.matchflags & (MATCH_TYPE|MATCH_NOTYPE)))
285 return 1;
286 p = (Match_t*)dtmatch(state.match, s);
287 if (state.matchflags & MATCH_TYPE)
288 return p && (p->flags & MATCH_TYPE);
289 return !p || !(p->flags & MATCH_NOTYPE);
290 }
291
292 static void
mountop(register Mnt_t * mnt,char * options)293 mountop(register Mnt_t* mnt, char* options)
294 {
295 char* s;
296 int n;
297
298 if (state.unmount)
299 {
300 if (state.fake)
301 sfprintf(sfstderr, "umount(%s)\n", mnt->fs);
302 else if (umount(mnt->fs, 0))
303 error(ERROR_SYSTEM|2, "%s: cannot unmount", mnt->fs);
304 }
305 else
306 {
307 n = (s = options ? options : mnt->options) ? strlen(s) : 0;
308 if (state.fake)
309 sfprintf(sfstderr, "mount(\"%s\",\"%s\",0x%08x,\"%s\",\"%s\",%d)\n", mnt->fs, mnt->dir, mnt->flags|MS_DATA, mnt->type, s, n);
310 else if (mount(mnt->fs, mnt->dir, mnt->flags|MS_DATA, mnt->type, s, n))
311 error(ERROR_SYSTEM|2, "%s: cannot mount", mnt->fs);
312 }
313 }
314
315 int
main(int argc,register char ** argv)316 main(int argc, register char** argv)
317 {
318 register char* s;
319 register Mnt_t* mnt;
320 const char* usage;
321 void* mp;
322 char* p;
323 int trydefault;
324 Cmp_f cmp;
325 Mnt_t ent;
326
327 NoP(argc);
328 if (s = strrchr(*argv, '/'))
329 s++;
330 else
331 s = *argv;
332 error_info.id = s;
333 usage = (state.unmount = strmatch(s, "*u?(n)mount")) ? unmount_usage : mount_usage;
334 state.matchflags = 0;
335 if (!(state.tmp = sfstropen()))
336 error(ERROR_SYSTEM|3, "out of space [tmp string stream]");
337 for (;;)
338 {
339 switch (optget(argv, usage))
340 {
341 case 'a':
342 state.all = 1;
343 continue;
344 case 'b':
345 matchset(opt_info.arg, MATCH_NOTYPE);
346 continue;
347 case 'c':
348 state.check = 1;
349 continue;
350 case 'f':
351 state.fake = 1;
352 continue;
353 case 'h':
354 matchset(opt_info.arg, MATCH_HOST);
355 continue;
356 case 'm':
357 state.nproc = opt_info.num;
358 continue;
359 case 'n':
360 state.notab = 1;
361 continue;
362 case 'o':
363 if (sfstrtell(state.tmp))
364 sfputc(state.tmp, ',');
365 sfputr(state.tmp, opt_info.arg, -1);
366 continue;
367 case 'p':
368 state.fstabable = 1;
369 continue;
370 case 'r':
371 if (sfstrtell(state.tmp))
372 sfputc(state.tmp, ',');
373 sfputr(state.tmp, "ro", -1);
374 continue;
375 case 't':
376 case 'T':
377 state.type = opt_info.arg;
378 matchset(state.type, MATCH_TYPE);
379 continue;
380 case 'u':
381 state.unmount = 1;
382 continue;
383 case 'v':
384 state.verbose = 1;
385 continue;
386 case 'M':
387 state.mtab = opt_info.arg;
388 continue;
389 case 'P':
390 state.prefix = opt_info.arg;
391 continue;
392 case '?':
393 error(ERROR_USAGE|4, "%s", opt_info.arg);
394 break;
395 case ':':
396 error(2, "%s", opt_info.arg);
397 break;
398 case 0:
399 break;
400 default:
401 error(2, "%s: option not implemented", opt_info.option);
402 break;
403 }
404 break;
405 }
406 if (error_info.errors)
407 error(ERROR_USAGE|4, "%s", optusage(NiL));
408 trydefault = !state.mtab;
409 argv += opt_info.index;
410 if ((s = *argv) && !*++argv && !state.mtab || state.mtab && (!*state.mtab || streq(state.mtab, "-")) || !state.mtab && (state.all || state.match))
411 state.mtab = FSTAB;
412 if (state.unmount && (!s || *argv))
413 error(ERROR_SYSTEM|3, "one argument expected");
414 if (!(mp = mntopen(state.mtab, "r")) && (!trydefault || !(mp = mntopen(state.mtab = 0, "r"))))
415 {
416 if (state.mtab && !trydefault)
417 error(ERROR_SYSTEM|3, "%s: cannot open fs table", state.mtab);
418 else
419 error(ERROR_SYSTEM|3, "cannot open default mount table");
420 }
421 if (sfstrtell(state.tmp) && !(state.options = strdup(sfstruse(state.tmp))))
422 error(ERROR_SYSTEM|3, "out of space [option string]");
423 if (!s)
424 {
425 if (state.all || state.match)
426 {
427 while (mnt = mntread(mp))
428 if (matchhost(mnt->fs) && matchtype(mnt->type))
429 mountop(mnt, state.options);
430 }
431 else if (state.fstabable)
432 {
433 while (mnt = mntread(mp))
434 sfprintf(sfstdout, "%s %s %s %s %d %d\n",
435 mnt->fs,
436 mnt->dir,
437 mnt->type,
438 mnt->options,
439 mnt->freq,
440 mnt->npass);
441 }
442 else
443 {
444 while (mnt = mntread(mp))
445 sfprintf(sfstdout, "%s on %s type %s (%s)\n",
446 mnt->fs,
447 mnt->dir,
448 mnt->type,
449 mnt->options);
450 }
451 }
452 else if (!*argv)
453 {
454 for (;;)
455 {
456 while (mnt = mntread(mp))
457 {
458 cmp = (Cmp_f)strcmp;
459 if (p = mnt->options)
460 while (*p)
461 {
462 if (*p == 'i' && (!memcmp(p, "ic", 2) || !memcmp(p, "icase", 5) || !memcmp(p, "ignorecase", 10)))
463 {
464 cmp = (Cmp_f)strcasecmp;
465 break;
466 }
467 while (*p && *p++ != ',');
468 }
469 if (!(*cmp)(mnt->fs, s) || !(*cmp)(mnt->dir, s))
470 {
471 mountop(mnt, state.options);
472 break;
473 }
474 }
475 if (!mnt)
476 {
477 if (trydefault && state.mtab)
478 {
479 trydefault = 0;
480 mntclose(mp);
481 if (mp = mntopen(NiL, "r"))
482 continue;
483 }
484 error(3, "%s: file system or mount point not found", s);
485 }
486 break;
487 }
488 }
489 else if (!*(argv + 1))
490 {
491 mnt = &ent;
492 memset(mnt, 0, sizeof(*mnt));
493 mnt->fs = s;
494 mnt->dir = *argv;
495 mnt->type = state.type;
496 mountop(mnt, state.options);
497 }
498 else
499 error(ERROR_USAGE|4, "%s", optusage(NiL));
500 mntclose(mp);
501 exit(0);
502 }
503
504 #else
505
506 int
main(int argc,register char ** argv)507 main(int argc, register char** argv)
508 {
509 register char* s;
510
511 if (s = strrchr(*argv, '/'))
512 s++;
513 else
514 s = *argv;
515 execv(*s == 'u' ? "/etc/umount" : "/etc/mount", argv);
516 exit(EXIT_NOTFOUND);
517 }
518
519 #endif
520