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*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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
37NoN(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)
53typedef 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
67static void
68set(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
161typedef 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])
177static 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
188static struct Mnt_options_t
189{
190	unsigned long	flag;
191	const char*	name;
192}
193options[] =
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
264void*
265mntopen(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
294Mnt_t*
295mntread(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
316int
317mntclose(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
339static const char*	type[] =
340{
341	"aix", "aix#1", "nfs", "jfs", "aix#4", "cdrom"
342};
343
344typedef 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
354void*
355mntopen(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
371Mnt_t*
372mntread(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
446int
447mntclose(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
489extern int		endmntent(FILE*);
490extern 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
526typedef 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
538void*
539mntopen(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
554Mnt_t*
555mntread(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
568int
569mntclose(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
627struct 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
641typedef 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
652void*
653mntopen(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
675Mnt_t*
676mntread(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
786int
787mntclose(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
808int
809mntwrite(void* handle, const Mnt_t* mnt)
810{
811	NoP(handle);
812	NoP(mnt);
813	return -1;
814}
815
816#endif
817