1 /* mountlist.c -- return a list of mounted filesystems
2 Copyright (C) 1991, 1992, 1997, 1998, 1999 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 #include <sys/types.h>
24 #include "mountlist.h"
31 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
59 # include <sys/param.h>
62 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
63 # include <sys/mount.h>
64 # include <sys/fs_types.h>
65 #endif /* MOUNTED_GETFSSTAT */
67 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
69 # if !defined(MOUNTED)
70 # if defined(MNT_MNTTAB) /* HP-UX. */
71 # define MOUNTED MNT_MNTTAB
73 # if defined(MNTTABNAME) /* Dynix. */
74 # define MOUNTED MNTTABNAME
79 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
80 # include <sys/mount.h>
83 #ifdef MOUNTED_GETMNT /* Ultrix. */
84 # include <sys/mount.h>
85 # include <sys/fs_types.h>
88 #ifdef MOUNTED_FREAD /* SVR2. */
92 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
94 # include <sys/fstyp.h>
95 # include <sys/statfs.h>
98 #ifdef MOUNTED_LISTMNTENT
102 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
103 # include <sys/mnttab.h>
106 #ifdef MOUNTED_VMOUNT /* AIX. */
108 # include <sys/vfs.h>
112 /* So special that it's not worth putting this in autoconf. */
113 # undef MOUNTED_FREAD_FSTYP
114 # define MOUNTED_GETMNTTBL
117 #if HAVE_SYS_MNTENT_H
118 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
119 # include <sys/mntent.h>
122 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
123 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
125 # define MNT_IGNORE(M) 0
128 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
129 /* Return the value of the hexadecimal number represented by CP.
130 No prefix (like '0x') or suffix (like 'h') is expected to be
132 /* FIXME: this can overflow */
142 if (*cp >= 'a' && *cp <= 'f')
143 val = val * 16 + *cp - 'a' + 10;
144 else if (*cp >= 'A' && *cp <= 'F')
145 val = val * 16 + *cp - 'A' + 10;
146 else if (*cp >= '0' && *cp <= '9')
147 val = val * 16 + *cp - '0';
155 /* Convert, in place, each unambiguous `\040' sequence in the NUL-terminated
156 string, STR, to a single space. `unambiguous' means that it must not be
157 immediately preceded by an odd number of backslash characters. */
158 /* FIXME: should any other backslash-escaped sequences be translated? */
159 /* FIXME: is the backslash counting necessary? */
162 translate_040_to_space (char *str)
167 char *backslash = strstr (str, "\\040");
168 unsigned int backslash_count = 0;
170 if (backslash == NULL)
173 /* Count preceding backslashes, going no further than str. */
174 for (p = backslash - 1; p >= str && *p == '\\'; p--)
177 if (backslash_count % 2 == 1)
179 /* The backslash is escaped; advance past the 040 and
180 continue searching. */
185 /* We found an unambiguous `\040'. Replace the `/' with a space
186 and shift the string after `040' so that it starts where the
187 first zero was. The source and destination regions may overlap,
191 /* Be sure to copy the trailing NUL byte, too. */
192 memmove (str, backslash + 4, strlen (backslash + 4) + 1);
196 #endif /* MOUNTED_GETMNTENT1. */
198 #if MOUNTED_GETMNTINFO
200 # if ! HAVE_F_FSTYPENAME_IN_STATFS
202 fstype_to_string (short t)
294 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
296 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
298 fsp_to_string (const struct statfs *fsp)
300 # if defined HAVE_F_FSTYPENAME_IN_STATFS
301 return fsp->f_fstypename;
303 return fstype_to_string (fsp->f_type);
307 #endif /* MOUNTED_GETMNTINFO */
309 #ifdef MOUNTED_VMOUNT /* AIX. */
311 fstype_to_string (int t)
315 e = getvfsbytype (t);
316 if (!e || !e->vfsent_name)
319 return e->vfsent_name;
321 #endif /* MOUNTED_VMOUNT */
323 /* Return a list of the currently mounted filesystems, or NULL on error.
324 Add each entry to the tail of the list so that they stay in order.
325 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
326 the returned list are valid. Otherwise, they might not be. */
329 read_filesystem_list (int need_fs_type)
331 struct mount_entry *mount_list;
332 struct mount_entry *me;
333 struct mount_entry **mtail = &mount_list;
335 #ifdef MOUNTED_LISTMNTENT
337 struct tabmntent *mntlist, *p;
339 struct mount_entry *me;
341 /* the third and fourth arguments could be used to filter mounts,
342 but Crays doesn't seem to have any mounts that we want to
343 remove. Specifically, automount create normal NFS mounts.
346 if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
348 for (p = mntlist; p; p = p->next) {
350 me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
351 me->me_devname = xstrdup(mnt->mnt_fsname);
352 me->me_mountdir = xstrdup(mnt->mnt_dir);
353 me->me_type = xstrdup(mnt->mnt_type);
354 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
355 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
358 mtail = &me->me_next;
360 freemntlist(mntlist);
364 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
367 char *table = MOUNTED;
371 fp = setmntent (table, "r");
375 while ((mnt = getmntent (fp)))
377 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
378 me->me_devname = xstrdup (mnt->mnt_fsname);
379 me->me_mountdir = xstrdup (mnt->mnt_dir);
380 me->me_type = xstrdup (mnt->mnt_type);
381 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
382 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
383 devopt = strstr (mnt->mnt_opts, "dev=");
386 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
387 me->me_dev = xatoi (devopt + 6);
389 me->me_dev = xatoi (devopt + 4);
392 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
394 /* FIXME: do the conversion only if we're using some version of
395 GNU libc -- which one? */
396 /* Convert each `\040' string to a space. */
397 translate_040_to_space (me->me_mountdir);
399 /* Add to the linked list. */
401 mtail = &me->me_next;
404 if (endmntent (fp) == 0)
407 #endif /* MOUNTED_GETMNTENT1. */
409 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
414 entries = getmntinfo (&fsp, MNT_NOWAIT);
417 for (; entries-- > 0; fsp++)
419 char *fs_type = fsp_to_string (fsp);
421 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
422 me->me_devname = xstrdup (fsp->f_mntfromname);
423 me->me_mountdir = xstrdup (fsp->f_mntonname);
424 me->me_type = fs_type;
425 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
426 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
427 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
429 /* Add to the linked list. */
431 mtail = &me->me_next;
434 #endif /* MOUNTED_GETMNTINFO */
436 #ifdef MOUNTED_GETMNT /* Ultrix. */
443 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
446 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
447 me->me_devname = xstrdup (fsd.fd_req.devname);
448 me->me_mountdir = xstrdup (fsd.fd_req.path);
449 me->me_type = gt_names[fsd.fd_req.fstype];
450 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
451 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
452 me->me_dev = fsd.fd_req.dev;
454 /* Add to the linked list. */
456 mtail = &me->me_next;
461 #endif /* MOUNTED_GETMNT. */
463 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
465 int numsys, counter, bufsize;
466 struct statfs *stats;
468 numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
472 bufsize = (1 + numsys) * sizeof (struct statfs);
473 stats = (struct statfs *)xmalloc (bufsize);
474 numsys = getfsstat (stats, bufsize, MNT_WAIT);
482 for (counter = 0; counter < numsys; counter++)
484 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
485 me->me_devname = xstrdup (stats[counter].f_mntfromname);
486 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
487 me->me_type = mnt_names[stats[counter].f_type];
488 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
489 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
490 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
492 /* Add to the linked list. */
494 mtail = &me->me_next;
499 #endif /* MOUNTED_GETFSSTAT */
501 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
504 char *table = "/etc/mnttab";
507 fp = fopen (table, "r");
511 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
513 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
514 # ifdef GETFSTYP /* SVR3. */
515 me->me_devname = xstrdup (mnt.mt_dev);
517 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
518 strcpy (me->me_devname, "/dev/");
519 strcpy (me->me_devname + 5, mnt.mt_dev);
521 me->me_mountdir = xstrdup (mnt.mt_filsys);
522 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
524 # ifdef GETFSTYP /* SVR3. */
528 char typebuf[FSTYPSZ];
530 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
531 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
532 me->me_type = xstrdup (typebuf);
535 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
536 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
538 /* Add to the linked list. */
540 mtail = &me->me_next;
545 int saved_errno = errno;
551 if (fclose (fp) == EOF)
554 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
556 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
558 struct mntent **mnttbl=getmnttbl(),**ent;
559 for (ent=mnttbl;*ent;ent++)
561 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
562 me->me_devname = xstrdup ( (*ent)->mt_resource);
563 me->me_mountdir = xstrdup( (*ent)->mt_directory);
564 me->me_type = xstrdup ((*ent)->mt_fstype);
565 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
566 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
567 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
569 /* Add to the linked list. */
571 mtail = &me->me_next;
577 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
580 char *table = MNTTAB;
585 # if defined F_RDLCK && defined F_SETLKW
586 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
587 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
588 for this file name, we should use their macro name instead.
589 (Why not just lock MNTTAB directly? We don't know.) */
591 # define MNTTAB_LOCK "/etc/.mnttab.lock"
593 lockfd = open (MNTTAB_LOCK, O_RDONLY);
597 flock.l_type = F_RDLCK;
598 flock.l_whence = SEEK_SET;
601 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
604 int saved_errno = errno;
610 else if (errno != ENOENT)
615 fp = fopen (table, "r");
620 while ((ret = getmntent (fp, &mnt)) == 0)
622 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
623 me->me_devname = xstrdup (mnt.mnt_special);
624 me->me_mountdir = xstrdup (mnt.mnt_mountp);
625 me->me_type = xstrdup (mnt.mnt_fstype);
626 me->me_dummy = MNT_IGNORE (&mnt) != 0;
627 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
628 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
630 /* Add to the linked list. */
632 mtail = &me->me_next;
635 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
638 if (0 <= lockfd && close (lockfd) != 0)
647 #endif /* MOUNTED_GETMNTENT2. */
649 #ifdef MOUNTED_VMOUNT /* AIX. */
652 char *entries, *thisent;
655 /* Ask how many bytes to allocate for the mounted filesystem info. */
656 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
657 entries = xmalloc (bufsize);
659 /* Get the list of mounted filesystems. */
660 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
662 for (thisent = entries; thisent < entries + bufsize;
663 thisent += vmp->vmt_length)
665 vmp = (struct vmount *) thisent;
666 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
667 if (vmp->vmt_flags & MNT_REMOTE)
672 /* Prepend the remote pathname. */
673 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
674 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
675 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
676 strcpy (me->me_devname, host);
677 strcat (me->me_devname, ":");
678 strcat (me->me_devname, path);
683 me->me_devname = xstrdup (thisent +
684 vmp->vmt_data[VMT_OBJECT].vmt_off);
686 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
687 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
688 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
689 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
691 /* Add to the linked list. */
693 mtail = &me->me_next;
697 #endif /* MOUNTED_VMOUNT. */
705 int saved_errno = errno;
710 me = mount_list->me_next;
711 free (mount_list->me_devname);
712 free (mount_list->me_mountdir);
713 /* FIXME: me_type is not always malloced. */
725 main (int argc, char **argv)
728 for (i = 1; i < argc; i++)
730 char *p = xstrdup (argv[i]);
731 translate_040_to_space (p);
732 printf ("%s: %s\n", argv[i], p);