1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-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 <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24  * Glenn Fowler
25  * AT&T Research
26  *
27  * mounted filesystem scan support
28  * where are the standards when you really need them
29  */
30 
31 #include <ast.h>
32 #include <mnt.h>
33 #include <ls.h>
34 
35 #if _lib_mntopen && _lib_mntread && _lib_mntclose
36 
37 NoN(mnt)
38 
39 #else
40 
41 /*
42  * the original interface just had mode
43  */
44 
45 #define FIXARGS(p,m,s)		do {					\
46 					if ((p)&&*(p)!='/') {		\
47 						mode = p;		\
48 						path = 0;		\
49 					}				\
50 					if (!path)			\
51 						path = s;		\
52 				} while (0)
53 typedef struct
54 {
55 	Mnt_t	mnt;
56 	char	buf[128];
57 #if __CYGWIN__
58 	char	typ[128];
59 	char	opt[128];
60 #endif
61 } Header_t;
62 
63 #if __CYGWIN__
64 #include <ast_windows.h>
65 #endif
66 
67 static void
68 set(register Header_t* hp, const char* fs, const char* dir, const char* type, const char* options)
69 {
70 	const char*	x;
71 
72 	hp->mnt.flags = 0;
73 	if (x = (const char*)strchr(fs, ':'))
74 	{
75 		if (*++x && *x != '\\')
76 		{
77 			hp->mnt.flags |= MNT_REMOTE;
78 			if (*x == '(')
79 			{
80 				fs = x;
81 				type = "auto";
82 			}
83 		}
84 	}
85 	else if (x = (const char*)strchr(fs, '@'))
86 	{
87 		hp->mnt.flags |= MNT_REMOTE;
88 		sfsprintf(hp->buf, sizeof(hp->buf) - 1, "%s:%*.*s", x + 1, x - fs, x - fs, fs);
89 		fs = (const char*)hp->buf;
90 	}
91 	else if (strmatch(type, "[aAnN][fF][sS]*"))
92 		hp->mnt.flags |= MNT_REMOTE;
93 	if (streq(fs, "none"))
94 		fs = dir;
95 	hp->mnt.fs = (char*)fs;
96 	hp->mnt.dir = (char*)dir;
97 	hp->mnt.type = (char*)type;
98 	hp->mnt.options = (char*)options;
99 #if __CYGWIN__
100 	if (streq(type, "system") || streq(type, "user"))
101 	{
102 		char*	s;
103 		int	mode;
104 		DWORD	vser;
105 		DWORD	flags;
106 		DWORD	len;
107 		char	drive[4];
108 
109 		mode = SetErrorMode(SEM_FAILCRITICALERRORS);
110 		drive[0] = fs[0];
111 		drive[1] = ':';
112 		drive[2] = '\\';
113 		drive[3] = 0;
114 		if (GetVolumeInformation(drive, 0, 0, &vser, &len, &flags, hp->typ, sizeof(hp->typ) - 1))
115 			hp->mnt.type = hp->typ;
116 		else
117 			flags = 0;
118 		SetErrorMode(mode);
119 		s = strcopy(hp->mnt.options = hp->opt, type);
120 		s = strcopy(s, ",ignorecase");
121 		if (options)
122 		{
123 			*s++ = ',';
124 			strcpy(s, options);
125 		}
126 	}
127 #endif
128 }
129 
130 #undef	MNT_REMOTE
131 
132 #if _sys_mount && ( _lib_getfsstat || _lib_getmntinfo )
133 
134 /*
135  * 4.4 bsd getmntinfo
136  *
137  * what a crappy interface
138  * data returned in static buffer -- ok
139  * big chunk of allocated memory that cannot be freed -- come on
140  * *and* netbsd changed the interface somewhere along the line
141  * private interface? my bad -- public interface? par for the bsd course
142  *
143  * we assume getfsstat may suffer the same statfs/statvfs confusion
144  */
145 
146 #include <sys/param.h>		/* expect some macro redefinitions here */
147 #include <sys/mount.h>
148 
149 #if _lib_getfsstat
150 #if _lib_getfsstat_statvfs
151 #define statfs		statvfs
152 #define f_flags		f_flag
153 #endif
154 #else
155 #if _lib_getmntinfo_statvfs
156 #define statfs		statvfs
157 #define f_flags		f_flag
158 #endif
159 #endif
160 
161 typedef struct
162 {
163 	Header_t	hdr;
164 	struct statfs*	next;
165 	struct statfs*	last;
166 	char		opt[256];
167 #if _lib_getfsstat
168 	struct statfs	buf[1];
169 #endif
170 } Handle_t;
171 
172 #ifdef MFSNAMELEN
173 #define TYPE(f)		((f)->f_fstypename)
174 #else
175 #ifdef INITMOUNTNAMES
176 #define TYPE(f)		((char*)type[(f)->f_type])
177 static const char*	type[] = INITMOUNTNAMES;
178 #else
179 #if _sys_fs_types
180 #define TYPE(f)		((char*)mnt_names[(f)->f_type])
181 #include <sys/fs_types.h>
182 #else
183 #define TYPE(f)		(strchr((f)->f_mntfromname,':')?"nfs":"ufs")
184 #endif
185 #endif
186 #endif
187 
188 static struct Mnt_options_t
189 {
190 	unsigned long	flag;
191 	const char*	name;
192 }
193 options[] =
194 {
195 #ifdef MNT_RDONLY
196 	MNT_RDONLY,	"rdonly",
197 #endif
198 #ifdef MNT_SYNCHRONOUS
199 	MNT_SYNCHRONOUS,"synchronous",
200 #endif
201 #ifdef MNT_NOEXEC
202 	MNT_NOEXEC,	"noexec",
203 #endif
204 #ifdef MNT_NOSUID
205 	MNT_NOSUID,	"nosuid",
206 #endif
207 #ifdef MNT_NODEV
208 	MNT_NODEV,	"nodev",
209 #endif
210 #ifdef MNT_UNION
211 	MNT_UNION,	"union",
212 #endif
213 #ifdef MNT_ASYNC
214 	MNT_ASYNC,	"async",
215 #endif
216 #ifdef MNT_NOCOREDUMP
217 	MNT_NOCOREDUMP,	"nocoredump",
218 #endif
219 #ifdef MNT_NOATIME
220 	MNT_NOATIME,	"noatime",
221 #endif
222 #ifdef MNT_SYMPERM
223 	MNT_SYMPERM,	"symperm",
224 #endif
225 #ifdef MNT_NODEVMTIME
226 	MNT_NODEVMTIME,	"nodevmtime",
227 #endif
228 #ifdef MNT_SOFTDEP
229 	MNT_SOFTDEP,	"softdep",
230 #endif
231 #ifdef MNT_EXRDONLY
232 	MNT_EXRDONLY,	"exrdonly",
233 #endif
234 #ifdef MNT_EXPORTED
235 	MNT_EXPORTED,	"exported",
236 #endif
237 #ifdef MNT_DEFEXPORTED
238 	MNT_DEFEXPORTED,"defexported",
239 #endif
240 #ifdef MNT_EXPORTANON
241 	MNT_EXPORTANON,	"exportanon",
242 #endif
243 #ifdef MNT_EXKERB
244 	MNT_EXKERB,	"exkerb",
245 #endif
246 #ifdef MNT_EXNORESPORT
247 	MNT_EXNORESPORT,"exnoresport",
248 #endif
249 #ifdef MNT_EXPUBLIC
250 	MNT_EXPUBLIC,	"expublic",
251 #endif
252 #ifdef MNT_LOCAL
253 	MNT_LOCAL,	"local",
254 #endif
255 #ifdef MNT_QUOTA
256 	MNT_QUOTA,	"quota",
257 #endif
258 #ifdef MNT_ROOTFS
259 	MNT_ROOTFS,	"rootfs",
260 #endif
261 	0,		"unknown",
262 };
263 
264 void*
265 mntopen(const char* path, const char* mode)
266 {
267 	register Handle_t*	mp;
268 	register int		n;
269 
270 	FIXARGS(path, mode, 0);
271 #if _lib_getfsstat
272 	if ((n = getfsstat(NiL, 0, MNT_WAIT)) <= 0)
273 		return 0;
274 	n = (n - 1) * sizeof(struct statfs);
275 #else
276 	n = 0;
277 #endif
278 	if (!(mp = newof(0, Handle_t, 1, n)))
279 		return 0;
280 #if _lib_getfsstat
281 	n = getfsstat(mp->next = mp->buf, n + sizeof(struct statfs), MNT_WAIT);
282 #else
283 	n = getmntinfo(&mp->next, 0);
284 #endif
285 	if (n <= 0)
286 	{
287 		free(mp);
288 		return 0;
289 	}
290 	mp->last = mp->next + n;
291 	return (void*)mp;
292 }
293 
294 Mnt_t*
295 mntread(void* handle)
296 {
297 	register Handle_t*	mp = (Handle_t*)handle;
298 	register int		i;
299 	register int		n;
300 	register unsigned long	flags;
301 
302 	if (mp->next < mp->last)
303 	{
304 		flags = mp->next->f_flags;
305 		n = 0;
306 		for (i = 0; i < elementsof(options); i++)
307 			if (flags & options[i].flag)
308 				n += sfsprintf(mp->opt + n, sizeof(mp->opt) - n - 1, ",%s", options[i].name);
309 		set(&mp->hdr, mp->next->f_mntfromname, mp->next->f_mntonname, TYPE(mp->next), n ? (mp->opt + 1) : (char*)0);
310 		mp->next++;
311 		return &mp->hdr.mnt;
312 	}
313 	return 0;
314 }
315 
316 int
317 mntclose(void* handle)
318 {
319 	register Handle_t*	mp = (Handle_t*)handle;
320 
321 	if (!mp)
322 		return -1;
323 	free(mp);
324 	return 0;
325 }
326 
327 #else
328 
329 #if _lib_mntctl && _sys_vmount
330 
331 /*
332  * aix
333  */
334 
335 #include <sys/vmount.h>
336 
337 #define SIZE		(16 * 1024)
338 
339 static const char*	type[] =
340 {
341 	"aix", "aix#1", "nfs", "jfs", "aix#4", "cdrom"
342 };
343 
344 typedef struct
345 {
346 	Header_t	hdr;
347 	long		count;
348 	struct vmount*	next;
349 	char		remote[128];
350 	char		type[16];
351 	struct vmount	info[1];
352 } Handle_t;
353 
354 void*
355 mntopen(const char* path, const char* mode)
356 {
357 	register Handle_t*	mp;
358 
359 	FIXARGS(path, mode, 0);
360 	if (!(mp = newof(0, Handle_t, 1, SIZE)))
361 		return 0;
362 	if ((mp->count = mntctl(MCTL_QUERY, sizeof(Handle_t) + SIZE, &mp->info)) <= 0)
363 	{
364 		free(mp);
365 		return 0;
366 	}
367 	mp->next = mp->info;
368 	return (void*)mp;
369 }
370 
371 Mnt_t*
372 mntread(void* handle)
373 {
374 	register Handle_t*	mp = (Handle_t*)handle;
375 	register char*		s;
376 	register char*		t;
377 	register char*		o;
378 
379 	if (mp->count > 0)
380 	{
381 		if (vmt2datasize(mp->next, VMT_HOST) && (s = vmt2dataptr(mp->next, VMT_HOST)) && !streq(s, "-"))
382 		{
383 			sfsprintf(mp->remote, sizeof(mp->remote) - 1, "%s:%s", s, vmt2dataptr(mp->next, VMT_OBJECT));
384 			s = mp->remote;
385 		}
386 		else
387 			s = vmt2dataptr(mp->next, VMT_OBJECT);
388 		if (vmt2datasize(mp->next, VMT_ARGS))
389 			o = vmt2dataptr(mp->next, VMT_ARGS);
390 		else
391 			o = NiL;
392 		switch (mp->next->vmt_gfstype)
393 		{
394 #ifdef MNT_AIX
395 		case MNT_AIX:
396 			t = "aix";
397 			break;
398 #endif
399 #ifdef MNT_NFS
400 		case MNT_NFS:
401 			t = "nfs";
402 			break;
403 #endif
404 #ifdef MNT_JFS
405 		case MNT_JFS:
406 			t = "jfs";
407 			break;
408 #endif
409 #ifdef MNT_CDROM
410 		case MNT_CDROM:
411 			t = "cdrom";
412 			break;
413 #endif
414 #ifdef MNT_SFS
415 		case MNT_SFS:
416 			t = "sfs";
417 			break;
418 #endif
419 #ifdef MNT_NFS3
420 		case MNT_NFS3:
421 			t = "nfs3";
422 			break;
423 #endif
424 #ifdef MNT_AUTOFS
425 		case MNT_AUTOFS:
426 			t = "autofs";
427 			break;
428 #endif
429 		default:
430 			sfsprintf(t = mp->type, sizeof(mp->type), "aix%+d", mp->next->vmt_gfstype);
431 			break;
432 		}
433 		set(&mp->hdr, s, vmt2dataptr(mp->next, VMT_STUB), t, o);
434 		if (--mp->count > 0)
435 			mp->next = (struct vmount*)((char*)mp->next + mp->next->vmt_length);
436 		return &mp->hdr.mnt;
437 	}
438 	return 0;
439 }
440 
441 int
442 mntclose(void* handle)
443 {
444 	register Handle_t*	mp = (Handle_t*)handle;
445 
446 	if (!mp)
447 		return -1;
448 	free(mp);
449 	return 0;
450 }
451 
452 #else
453 
454 #if !_lib_setmntent
455 #undef	_lib_getmntent
456 #if !_SCO_COFF && !_SCO_ELF && !_UTS
457 #undef	_hdr_mnttab
458 #endif
459 #endif
460 
461 #if _lib_getmntent && ( _hdr_mntent || _sys_mntent && !_sys_mnttab )
462 
463 #if defined(__STDPP__directive) && defined(__STDPP__hide)
464 __STDPP__directive pragma pp:hide endmntent getmntent
465 #else
466 #define endmntent	______endmntent
467 #define getmntent	______getmntent
468 #endif
469 
470 #include <stdio.h>
471 #if _hdr_mntent
472 #include <mntent.h>
473 #else
474 #include <sys/mntent.h>
475 #endif
476 
477 #if defined(__STDPP__directive) && defined(__STDPP__hide)
478 __STDPP__directive pragma pp:nohide endmntent getmntent
479 #else
480 #undef	endmntent
481 #undef	getmntent
482 #endif
483 
484 extern int		endmntent(FILE*);
485 extern struct mntent*	getmntent(FILE*);
486 
487 #else
488 
489 #undef	_lib_getmntent
490 
491 #if _hdr_mnttab
492 #include <mnttab.h>
493 #else
494 #if _sys_mnttab
495 #include <sys/mnttab.h>
496 #endif
497 #endif
498 
499 #endif
500 
501 #ifndef MOUNTED
502 #ifdef	MNT_MNTTAB
503 #define MOUNTED		MNT_MNTTAB
504 #else
505 #if _hdr_mnttab || _sys_mnttab
506 #define MOUNTED		"/etc/mnttab"
507 #else
508 #define MOUNTED		"/etc/mtab"
509 #endif
510 #endif
511 #endif
512 
513 #ifdef __Lynx__
514 #undef	MOUNTED
515 #define MOUNTED		"/etc/fstab"
516 #define SEP		':'
517 #endif
518 
519 #if _lib_getmntent
520 
521 typedef struct
522 #if _mem_mnt_opts_mntent
523 #define OPTIONS(p)	((p)->mnt_opts)
524 #else
525 #define OPTIONS(p)	NiL
526 #endif
527 
528 {
529 	Header_t	hdr;
530 	FILE*		fp;
531 } Handle_t;
532 
533 void*
534 mntopen(const char* path, const char* mode)
535 {
536 	register Handle_t*	mp;
537 
538 	FIXARGS(path, mode, MOUNTED);
539 	if (!(mp = newof(0, Handle_t, 1, 0)))
540 		return 0;
541 	if (!(mp->fp = setmntent(path, mode)))
542 	{
543 		free(mp);
544 		return 0;
545 	}
546 	return (void*)mp;
547 }
548 
549 Mnt_t*
550 mntread(void* handle)
551 {
552 	register Handle_t*	mp = (Handle_t*)handle;
553 	register struct mntent*	mnt;
554 
555 	if (mnt = getmntent(mp->fp))
556 	{
557 		set(&mp->hdr, mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, OPTIONS(mnt));
558 		return &mp->hdr.mnt;
559 	}
560 	return 0;
561 }
562 
563 int
564 mntclose(void* handle)
565 {
566 	register Handle_t*	mp = (Handle_t*)handle;
567 
568 	if (!mp)
569 		return -1;
570 	endmntent(mp->fp);
571 	free(mp);
572 	return 0;
573 }
574 
575 #else
576 
577 #if _sys_mntent && _lib_w_getmntent
578 
579 #include <sys/mntent.h>
580 
581 #define mntent		w_mntent
582 
583 #define mnt_dir		mnt_mountpoint
584 #define mnt_type	mnt_fstname
585 
586 #define MNTBUFSIZE	(sizeof(struct w_mnth)+16*sizeof(struct w_mntent))
587 
588 #if _mem_mnt_opts_w_mntent
589 #define OPTIONS(p)	((p)->mnt_opts)
590 #else
591 #define OPTIONS(p)	NiL
592 #endif
593 
594 #else
595 
596 #undef _lib_w_getmntent
597 
598 #define MNTBUFSIZE	sizeof(struct mntent)
599 
600 #if !_mem_mt_dev_mnttab || !_mem_mt_filsys_mnttab
601 #undef	_hdr_mnttab
602 #endif
603 
604 #if _hdr_mnttab
605 
606 #define mntent	mnttab
607 
608 #define mnt_fsname	mt_dev
609 #define mnt_dir		mt_filsys
610 #if _mem_mt_fstyp_mnttab
611 #define mnt_type	mt_fstyp
612 #endif
613 
614 #if _mem_mnt_opts_mnttab
615 #define OPTIONS(p)	((p)->mnt_opts)
616 #else
617 #define OPTIONS(p)	NiL
618 #endif
619 
620 #else
621 
622 struct mntent
623 {
624 	char	mnt_fsname[256];
625 	char	mnt_dir[256];
626 	char	mnt_type[32];
627 	char	mnt_opts[64];
628 };
629 
630 #define OPTIONS(p)	((p)->mnt_opts)
631 
632 #endif
633 
634 #endif
635 
636 typedef struct
637 {
638 	Header_t	hdr;
639 	Sfio_t*		fp;
640 	struct mntent*	mnt;
641 #if _lib_w_getmntent
642 	int		count;
643 #endif
644 	char		buf[MNTBUFSIZE];
645 } Handle_t;
646 
647 void*
648 mntopen(const char* path, const char* mode)
649 {
650 	register Handle_t*	mp;
651 
652 	FIXARGS(path, mode, MOUNTED);
653 	if (!(mp = newof(0, Handle_t, 1, 0)))
654 		return 0;
655 #if _lib_w_getmntent
656 	if ((mp->count = w_getmntent(mp->buf, sizeof(mp->buf))) > 0)
657 		mp->mnt = (struct mntent*)(((struct w_mnth*)mp->buf) + 1);
658 	else
659 #else
660 	mp->mnt = (struct mntent*)mp->buf;
661 	if (!(mp->fp = sfopen(NiL, path, mode)))
662 #endif
663 	{
664 		free(mp);
665 		return 0;
666 	}
667 	return (void*)mp;
668 }
669 
670 Mnt_t*
671 mntread(void* handle)
672 {
673 	register Handle_t*	mp = (Handle_t*)handle;
674 
675 #if _lib_w_getmntent
676 
677 	if (mp->count-- <= 0)
678 	{
679 		if ((mp->count = w_getmntent(mp->buf, sizeof(mp->buf))) <= 0)
680 			return 0;
681 		mp->count--;
682 		mp->mnt = (struct mntent*)(((struct w_mnth*)mp->buf) + 1);
683 	}
684 	set(&mp->hdr, mp->mnt->mnt_fsname, mp->mnt->mnt_dir, mp->mnt->mnt_type, OPTIONS(mp->mnt));
685 	mp->mnt++;
686 	return &mp->hdr.mnt;
687 
688 #else
689 
690 #if _hdr_mnttab
691 
692 	while (sfread(mp->fp, &mp->buf, sizeof(mp->buf)) == sizeof(mp->buf))
693 		if (*mp->mnt->mnt_fsname && *mp->mnt->mnt_dir)
694 		{
695 #ifndef mnt_type
696 			struct stat	st;
697 
698 			static char	typ[32];
699 
700 			set(&mp->hdr, mp->mnt->mnt_fsname, mp->mnt->mnt_dir, stat(mp->mnt->mnt_dir, &st) ? FS_default : strlcpy(typ, fmtfs(&st), sizeof(typ)), OPTIONS(mp->mnt));
701 #else
702 			set(&mp->hdr, mp->mnt->mnt_fsname, mp->mnt->mnt_dir, mp->mnt->mnt_type, OPTIONS(mp->mnt));
703 #endif
704 			return &mp->hdr.mnt;
705 		}
706 	return 0;
707 
708 #else
709 
710 	register int		c;
711 	register char*		s;
712 	register char*		m;
713 	register char*		b;
714 	register int		q;
715 	register int		x;
716 
717  again:
718 	q = 0;
719 	x = 0;
720 	b = s = mp->mnt->mnt_fsname;
721 	m = s + sizeof(mp->mnt->mnt_fsname) - 1;
722 	for (;;) switch (c = sfgetc(mp->fp))
723 	{
724 	case EOF:
725 		return 0;
726 	case '"':
727 	case '\'':
728 		if (q == c)
729 			q = 0;
730 		else if (!q)
731 			q = c;
732 		break;
733 #ifdef SEP
734 	case SEP:
735 #else
736 	case ' ':
737 	case '\t':
738 #endif
739 		if (s != b && !q) switch (++x)
740 		{
741 		case 1:
742 			*s = 0;
743 			b = s = mp->mnt->mnt_dir;
744 			m = s + sizeof(mp->mnt->mnt_dir) - 1;
745 			break;
746 		case 2:
747 			*s = 0;
748 			b = s = mp->mnt->mnt_type;
749 			m = s + sizeof(mp->mnt->mnt_type) - 1;
750 			break;
751 		case 3:
752 			*s = 0;
753 			b = s = mp->mnt->mnt_opts;
754 			m = s + sizeof(mp->mnt->mnt_opts) - 1;
755 			break;
756 		case 4:
757 			*s = 0;
758 			b = s = m = 0;
759 			break;
760 		}
761 		break;
762 	case '\n':
763 		if (x >= 3)
764 		{
765 			set(&mp->hdr, mp->mnt->mnt_fsname, mp->mnt->mnt_dir, mp->mnt->mnt_type, OPTIONS(mp->mnt));
766 			return &mp->hdr.mnt;
767 		}
768 		goto again;
769 	default:
770 		if (s < m)
771 			*s++ = c;
772 		break;
773 	}
774 
775 #endif
776 
777 #endif
778 
779 }
780 
781 int
782 mntclose(void* handle)
783 {
784 	register Handle_t*	mp = (Handle_t*)handle;
785 
786 	if (!mp)
787 		return -1;
788 	sfclose(mp->fp);
789 	free(mp);
790 	return 0;
791 }
792 
793 #endif
794 
795 #endif
796 
797 #endif
798 
799 /*
800  * currently no write
801  */
802 
803 int
804 mntwrite(void* handle, const Mnt_t* mnt)
805 {
806 	NoP(handle);
807 	NoP(mnt);
808 	return -1;
809 }
810 
811 #endif
812