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