

/*
 * $Id: rmnt.frag,v 1.9 96/01/09 08:27:50 abe Exp $
 */


/*
 * The caller must define an EXPDEV macro to expand (ala EP/IX)
 * device numbers.  If no expansion is required, use:
 *
 *	#define EXPDEV(n) n
 *
 * EP/IX, for example, uses:
 *
 *	#define EXPDEV(n) expdev(n)
 *
 * The caller may define a custom macro for making decisions to
 * skip entries -- e.g., ones whose mnt_type is MNTTYPE_IGNORE.
 */


/*
 * readmnt() - read mount table
 */

int
readmnt()
{
	char *dn = NULL;
	int err = 0;
	char *ln;
	FILE *mfp;
	struct mntent *mp;
	struct mounts *mtp;
	char *opt, *opte;
	struct stat sb;
/*
 * Open access to the mount table.
 */
	if ((mfp = setmntent(MOUNTED, "r")) == NULL) {
		(void) fprintf(stderr, "%s: can't access %s\n", Pn, MOUNTED);
		return(0);
	}
/*
 * Read mount table entries.
 */
	while ((mp = getmntent(mfp)) != NULL) {

#if	defined(MNTSKIP)
	/*
	 * Specfy in the MNTSKIP macro the decisions needed to determine
	 * that this entry should be skipped.
	 *
	 * Typically entries whose mnt_type is MNTTYPE_IGNORE are skipped.
	 *
	 * The MNTSKIP macro allows the caller to use other tests.
	 */
		MNTSKIP
#endif	/* MNTSKIP */

	/*
	 * Interpolate a possible symbolic directory link.
	 */
		if (dn)
			(void) free((FREE_P *)dn);
		if ((dn = (char *)malloc((MALLOC_S)(strlen(mp->mnt_dir) + 1)))
		== NULL) {
			err = 1;
			break;
		}
		(void) strcpy(dn, mp->mnt_dir);
		if ((ln = Readlink(dn)) == NULL) {
		    if (!Fwarn){
			(void) fprintf(stderr,
			    "      Output information may be incomplete.\n");
		    }
		    err = 2;
		    continue;
		}
		if (ln != dn) {
			(void) free((FREE_P *)dn);
			dn = ln;
		}
	/*
	 * Stat() the directory.
	 */
		if (statsafely(dn, &sb)) {
		    if (!Fwarn) {
			(void) fprintf(stderr,
			    "%s: WARNING: can't stat() %s file system %s\n",
			    Pn, mp->mnt_type, mp->mnt_dir);
			(void) fprintf(stderr,
			    "      Output information may be incomplete.\n");
		    }
		    err = 2;
		    if ((opt = strstr(mp->mnt_opts, "dev=")) != NULL) {
			(void) zeromem(&sb, sizeof(sb));
			if ((opte = x2dev(opt + 4, &sb.st_dev)) != NULL) {
			    sb.st_mode = S_IFDIR | 0777;

#if	defined(HASFSTYPE)
			    (void) strncpy(sb.st_fstype, mp->mnt_type,
				sizeof(sb.st_fstype));
			    sb.st_fstype[sizeof(sb.st_fstype) - 1 ] = '\0';
#endif	/* defined(HASFSTYPE */

			    if (!Fwarn)
				(void) fprintf(stderr,
				    "      assuming \"%.*s\" from %s\n",
				    (opte - opt), opt, MOUNTED);
			} else
			    opt = NULL;
		    }
		    if (opt == NULL)
			continue;
		}
	/*
	 * Allocate and fill a local mount structure.
	 */
		if ((mtp = (struct mounts *)malloc(sizeof(struct mounts)))
		== NULL) {
			err = 1;
			break;
		}
		if ((mtp->fsname =
			(char *)malloc((MALLOC_S)(strlen(mp->mnt_fsname)+1)))
		== NULL) {
			err = 1;
			break;
		}
		(void) strcpy(mtp->fsname, mp->mnt_fsname);
		mtp->dir = dn;
		dn = NULL;
		mtp->next = Mtab;
		mtp->dev = EXPDEV(sb.st_dev);
		mtp->rdev = EXPDEV(sb.st_rdev);
		mtp->inode = sb.st_ino;
		mtp->mode = sb.st_mode;
		Mtab = mtp;
	}
	(void) endmntent(mfp);
	if (dn)
		(void) free((FREE_P *)dn);
/*
 * Handle errors.
 */
	switch (err) {
	case 1:
		(void) fprintf(stderr, "%s: no space for mount at %s (%s)\n",
			Pn, mp->mnt_fsname, mp->mnt_dir);
		return(0);
	case 2:
		return(1);
	}
	return(1);
}
