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_CACHEFS
420 		case MNT_CACHEFS:
421 			t = "cachefs";
422 			break;
423 #endif
424 #ifdef MNT_NFS3
425 		case MNT_NFS3:
426 			t = "nfs3";
427 			break;
428 #endif
429 #ifdef MNT_AUTOFS
430 		case MNT_AUTOFS:
431 			t = "autofs";
432 			break;
433 #endif
434 		default:
435 			sfsprintf(t = mp->type, sizeof(mp->type), "aix%+d", mp->next->vmt_gfstype);
436 			break;
437 		}
438 		set(&mp->hdr, s, vmt2dataptr(mp->next, VMT_STUB), t, o);
439 		if (--mp->count > 0)
440 			mp->next = (struct vmount*)((char*)mp->next + mp->next->vmt_length);
441 		return &mp->hdr.mnt;
442 	}
443 	return 0;
444 }
445 
446 int
447 mntclose(void* handle)
448 {
449 	register Handle_t*	mp = (Handle_t*)handle;
450 
451 	if (!mp)
452 		return -1;
453 	free(mp);
454 	return 0;
455 }
456 
457 #else
458 
459 #if !_lib_setmntent
460 #undef	_lib_getmntent
461 #if !_SCO_COFF && !_SCO_ELF && !_UTS
462 #undef	_hdr_mnttab
463 #endif
464 #endif
465 
466 #if _lib_getmntent && ( _hdr_mntent || _sys_mntent && !_sys_mnttab )
467 
468 #if defined(__STDPP__directive) && defined(__STDPP__hide)
469 __STDPP__directive pragma pp:hide endmntent getmntent
470 #else
471 #define endmntent	______endmntent
472 #define getmntent	______getmntent
473 #endif
474 
475 #include <stdio.h>
476 #if _hdr_mntent
477 #include <mntent.h>
478 #else
479 #include <sys/mntent.h>
480 #endif
481 
482 #if defined(__STDPP__directive) && defined(__STDPP__hide)
483 __STDPP__directive pragma pp:nohide endmntent getmntent
484 #else
485 #undef	endmntent
486 #undef	getmntent
487 #endif
488 
489 extern int		endmntent(FILE*);
490 extern struct mntent*	getmntent(FILE*);
491 
492 #else
493 
494 #undef	_lib_getmntent
495 
496 #if _hdr_mnttab
497 #include <mnttab.h>
498 #else
499 #if _sys_mnttab
500 #include <sys/mnttab.h>
501 #endif
502 #endif
503 
504 #endif
505 
506 #ifndef MOUNTED
507 #ifdef	MNT_MNTTAB
508 #define MOUNTED		MNT_MNTTAB
509 #else
510 #if _hdr_mnttab || _sys_mnttab
511 #define MOUNTED		"/etc/mnttab"
512 #else
513 #define MOUNTED		"/etc/mtab"
514 #endif
515 #endif
516 #endif
517 
518 #ifdef __Lynx__
519 #undef	MOUNTED
520 #define MOUNTED		"/etc/fstab"
521 #define SEP		':'
522 #endif
523 
524 #if _lib_getmntent
525 
526 typedef struct
527 #if _mem_mnt_opts_mntent
528 #define OPTIONS(p)	((p)->mnt_opts)
529 #else
530 #define OPTIONS(p)	NiL
531 #endif
532 
533 {
534 	Header_t	hdr;
535 	FILE*		fp;
536 } Handle_t;
537 
538 void*
539 mntopen(const char* path, const char* mode)
540 {
541 	register Handle_t*	mp;
542 
543 	FIXARGS(path, mode, MOUNTED);
544 	if (!(mp = newof(0, Handle_t, 1, 0)))
545 		return 0;
546 	if (!(mp->fp = setmntent(path, mode)))
547 	{
548 		free(mp);
549 		return 0;
550 	}
551 	return (void*)mp;
552 }
553 
554 Mnt_t*
555 mntread(void* handle)
556 {
557 	register Handle_t*	mp = (Handle_t*)handle;
558 	register struct mntent*	mnt;
559 
560 	if (mnt = getmntent(mp->fp))
561 	{
562 		set(&mp->hdr, mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, OPTIONS(mnt));
563 		return &mp->hdr.mnt;
564 	}
565 	return 0;
566 }
567 
568 int
569 mntclose(void* handle)
570 {
571 	register Handle_t*	mp = (Handle_t*)handle;
572 
573 	if (!mp)
574 		return -1;
575 	endmntent(mp->fp);
576 	free(mp);
577 	return 0;
578 }
579 
580 #else
581 
582 #if _sys_mntent && _lib_w_getmntent
583 
584 #include <sys/mntent.h>
585 
586 #define mntent		w_mntent
587 
588 #define mnt_dir		mnt_mountpoint
589 #define mnt_type	mnt_fstname
590 
591 #define MNTBUFSIZE	(sizeof(struct w_mnth)+16*sizeof(struct w_mntent))
592 
593 #if _mem_mnt_opts_w_mntent
594 #define OPTIONS(p)	((p)->mnt_opts)
595 #else
596 #define OPTIONS(p)	NiL
597 #endif
598 
599 #else
600 
601 #undef _lib_w_getmntent
602 
603 #define MNTBUFSIZE	sizeof(struct mntent)
604 
605 #if !_mem_mt_dev_mnttab || !_mem_mt_filsys_mnttab
606 #undef	_hdr_mnttab
607 #endif
608 
609 #if _hdr_mnttab
610 
611 #define mntent	mnttab
612 
613 #define mnt_fsname	mt_dev
614 #define mnt_dir		mt_filsys
615 #if _mem_mt_fstyp_mnttab
616 #define mnt_type	mt_fstyp
617 #endif
618 
619 #if _mem_mnt_opts_mnttab
620 #define OPTIONS(p)	((p)->mnt_opts)
621 #else
622 #define OPTIONS(p)	NiL
623 #endif
624 
625 #else
626 
627 struct mntent
628 {
629 	char	mnt_fsname[256];
630 	char	mnt_dir[256];
631 	char	mnt_type[32];
632 	char	mnt_opts[64];
633 };
634 
635 #define OPTIONS(p)	((p)->mnt_opts)
636 
637 #endif
638 
639 #endif
640 
641 typedef struct
642 {
643 	Header_t	hdr;
644 	Sfio_t*		fp;
645 	struct mntent*	mnt;
646 #if _lib_w_getmntent
647 	int		count;
648 #endif
649 	char		buf[MNTBUFSIZE];
650 } Handle_t;
651 
652 void*
653 mntopen(const char* path, const char* mode)
654 {
655 	register Handle_t*	mp;
656 
657 	FIXARGS(path, mode, MOUNTED);
658 	if (!(mp = newof(0, Handle_t, 1, 0)))
659 		return 0;
660 #if _lib_w_getmntent
661 	if ((mp->count = w_getmntent(mp->buf, sizeof(mp->buf))) > 0)
662 		mp->mnt = (struct mntent*)(((struct w_mnth*)mp->buf) + 1);
663 	else
664 #else
665 	mp->mnt = (struct mntent*)mp->buf;
666 	if (!(mp->fp = sfopen(NiL, path, mode)))
667 #endif
668 	{
669 		free(mp);
670 		return 0;
671 	}
672 	return (void*)mp;
673 }
674 
675 Mnt_t*
676 mntread(void* handle)
677 {
678 	register Handle_t*	mp = (Handle_t*)handle;
679 
680 #if _lib_w_getmntent
681 
682 	if (mp->count-- <= 0)
683 	{
684 		if ((mp->count = w_getmntent(mp->buf, sizeof(mp->buf))) <= 0)
685 			return 0;
686 		mp->count--;
687 		mp->mnt = (struct mntent*)(((struct w_mnth*)mp->buf) + 1);
688 	}
689 	set(&mp->hdr, mp->mnt->mnt_fsname, mp->mnt->mnt_dir, mp->mnt->mnt_type, OPTIONS(mp->mnt));
690 	mp->mnt++;
691 	return &mp->hdr.mnt;
692 
693 #else
694 
695 #if _hdr_mnttab
696 
697 	while (sfread(mp->fp, &mp->buf, sizeof(mp->buf)) == sizeof(mp->buf))
698 		if (*mp->mnt->mnt_fsname && *mp->mnt->mnt_dir)
699 		{
700 #ifndef mnt_type
701 			struct stat	st;
702 
703 			static char	typ[32];
704 
705 			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));
706 #else
707 			set(&mp->hdr, mp->mnt->mnt_fsname, mp->mnt->mnt_dir, mp->mnt->mnt_type, OPTIONS(mp->mnt));
708 #endif
709 			return &mp->hdr.mnt;
710 		}
711 	return 0;
712 
713 #else
714 
715 	register int		c;
716 	register char*		s;
717 	register char*		m;
718 	register char*		b;
719 	register int		q;
720 	register int		x;
721 
722  again:
723 	q = 0;
724 	x = 0;
725 	b = s = mp->mnt->mnt_fsname;
726 	m = s + sizeof(mp->mnt->mnt_fsname) - 1;
727 	for (;;) switch (c = sfgetc(mp->fp))
728 	{
729 	case EOF:
730 		return 0;
731 	case '"':
732 	case '\'':
733 		if (q == c)
734 			q = 0;
735 		else if (!q)
736 			q = c;
737 		break;
738 #ifdef SEP
739 	case SEP:
740 #else
741 	case ' ':
742 	case '\t':
743 #endif
744 		if (s != b && !q) switch (++x)
745 		{
746 		case 1:
747 			*s = 0;
748 			b = s = mp->mnt->mnt_dir;
749 			m = s + sizeof(mp->mnt->mnt_dir) - 1;
750 			break;
751 		case 2:
752 			*s = 0;
753 			b = s = mp->mnt->mnt_type;
754 			m = s + sizeof(mp->mnt->mnt_type) - 1;
755 			break;
756 		case 3:
757 			*s = 0;
758 			b = s = mp->mnt->mnt_opts;
759 			m = s + sizeof(mp->mnt->mnt_opts) - 1;
760 			break;
761 		case 4:
762 			*s = 0;
763 			b = s = m = 0;
764 			break;
765 		}
766 		break;
767 	case '\n':
768 		if (x >= 3)
769 		{
770 			set(&mp->hdr, mp->mnt->mnt_fsname, mp->mnt->mnt_dir, mp->mnt->mnt_type, OPTIONS(mp->mnt));
771 			return &mp->hdr.mnt;
772 		}
773 		goto again;
774 	default:
775 		if (s < m)
776 			*s++ = c;
777 		break;
778 	}
779 
780 #endif
781 
782 #endif
783 
784 }
785 
786 int
787 mntclose(void* handle)
788 {
789 	register Handle_t*	mp = (Handle_t*)handle;
790 
791 	if (!mp)
792 		return -1;
793 	sfclose(mp->fp);
794 	free(mp);
795 	return 0;
796 }
797 
798 #endif
799 
800 #endif
801 
802 #endif
803 
804 /*
805  * currently no write
806  */
807 
808 int
809 mntwrite(void* handle, const Mnt_t* mnt)
810 {
811 	NoP(handle);
812 	NoP(mnt);
813 	return -1;
814 }
815 
816 #endif
817