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. */
160 translate_040_to_space (char *str)
165 char *backslash = strstr (str, "\\040");
166 unsigned int backslash_count = 0;
168 if (backslash == NULL)
171 /* Count preceding backslashes, going no further than str. */
172 for (p = backslash - 1; p >= str && *p == '\\'; p--)
175 if (backslash_count % 2 == 1)
177 /* The backslash is escaped; advance past the 040 and
178 continue searching. */
183 /* We found an unambiguous `\040'. Replace it with a space
184 and move everything following it back by 3 bytes.
185 The source and destination regions may overlap, so we have
189 /* Be sure to copy the trailing NUL byte, too. */
190 memmove (str, backslash + 4, strlen (backslash + 4) + 1);
194 #endif /* MOUNTED_GETMNTENT1. */
196 #if MOUNTED_GETMNTINFO
198 # if ! HAVE_F_FSTYPENAME_IN_STATFS
200 fstype_to_string (short t)
292 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
294 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
296 fsp_to_string (const struct statfs *fsp)
298 # if defined HAVE_F_FSTYPENAME_IN_STATFS
299 return fsp->f_fstypename;
301 return fstype_to_string (fsp->f_type);
305 #endif /* MOUNTED_GETMNTINFO */
307 #ifdef MOUNTED_VMOUNT /* AIX. */
309 fstype_to_string (int t)
313 e = getvfsbytype (t);
314 if (!e || !e->vfsent_name)
317 return e->vfsent_name;
319 #endif /* MOUNTED_VMOUNT */
321 /* Return a list of the currently mounted filesystems, or NULL on error.
322 Add each entry to the tail of the list so that they stay in order.
323 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
324 the returned list are valid. Otherwise, they might not be. */
327 read_filesystem_list (int need_fs_type)
329 struct mount_entry *mount_list;
330 struct mount_entry *me;
331 struct mount_entry **mtail = &mount_list;
333 #ifdef MOUNTED_LISTMNTENT
335 struct tabmntent *mntlist, *p;
337 struct mount_entry *me;
339 /* the third and fourth arguments could be used to filter mounts,
340 but Crays doesn't seem to have any mounts that we want to
341 remove. Specifically, automount create normal NFS mounts.
344 if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
346 for (p = mntlist; p; p = p->next) {
348 me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
349 me->me_devname = xstrdup(mnt->mnt_fsname);
350 me->me_mountdir = xstrdup(mnt->mnt_dir);
351 me->me_type = xstrdup(mnt->mnt_type);
352 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
353 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
356 mtail = &me->me_next;
358 freemntlist(mntlist);
362 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
365 char *table = MOUNTED;
369 fp = setmntent (table, "r");
373 while ((mnt = getmntent (fp)))
375 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
376 me->me_devname = xstrdup (mnt->mnt_fsname);
377 me->me_mountdir = xstrdup (mnt->mnt_dir);
378 me->me_type = xstrdup (mnt->mnt_type);
379 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
380 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
381 devopt = strstr (mnt->mnt_opts, "dev=");
384 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
385 me->me_dev = xatoi (devopt + 6);
387 me->me_dev = xatoi (devopt + 4);
390 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
392 /* FIXME: do the conversion only if we're using some version of
393 GNU libc -- which one? */
394 /* Convert each `\040' string to a space. */
395 translate_040_to_space (me->me_mountdir);
397 /* Add to the linked list. */
399 mtail = &me->me_next;
402 if (endmntent (fp) == 0)
405 #endif /* MOUNTED_GETMNTENT1. */
407 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
412 entries = getmntinfo (&fsp, MNT_NOWAIT);
415 for (; entries-- > 0; fsp++)
417 char *fs_type = fsp_to_string (fsp);
419 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
420 me->me_devname = xstrdup (fsp->f_mntfromname);
421 me->me_mountdir = xstrdup (fsp->f_mntonname);
422 me->me_type = fs_type;
423 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
424 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
425 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
427 /* Add to the linked list. */
429 mtail = &me->me_next;
432 #endif /* MOUNTED_GETMNTINFO */
434 #ifdef MOUNTED_GETMNT /* Ultrix. */
441 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
444 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
445 me->me_devname = xstrdup (fsd.fd_req.devname);
446 me->me_mountdir = xstrdup (fsd.fd_req.path);
447 me->me_type = gt_names[fsd.fd_req.fstype];
448 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
449 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
450 me->me_dev = fsd.fd_req.dev;
452 /* Add to the linked list. */
454 mtail = &me->me_next;
459 #endif /* MOUNTED_GETMNT. */
461 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
463 int numsys, counter, bufsize;
464 struct statfs *stats;
466 numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
470 bufsize = (1 + numsys) * sizeof (struct statfs);
471 stats = (struct statfs *)xmalloc (bufsize);
472 numsys = getfsstat (stats, bufsize, MNT_WAIT);
480 for (counter = 0; counter < numsys; counter++)
482 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
483 me->me_devname = xstrdup (stats[counter].f_mntfromname);
484 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
485 me->me_type = mnt_names[stats[counter].f_type];
486 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
487 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
488 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
490 /* Add to the linked list. */
492 mtail = &me->me_next;
497 #endif /* MOUNTED_GETFSSTAT */
499 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
502 char *table = "/etc/mnttab";
505 fp = fopen (table, "r");
509 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
511 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
512 # ifdef GETFSTYP /* SVR3. */
513 me->me_devname = xstrdup (mnt.mt_dev);
515 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
516 strcpy (me->me_devname, "/dev/");
517 strcpy (me->me_devname + 5, mnt.mt_dev);
519 me->me_mountdir = xstrdup (mnt.mt_filsys);
520 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
522 # ifdef GETFSTYP /* SVR3. */
526 char typebuf[FSTYPSZ];
528 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
529 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
530 me->me_type = xstrdup (typebuf);
533 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
534 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
536 /* Add to the linked list. */
538 mtail = &me->me_next;
543 int saved_errno = errno;
549 if (fclose (fp) == EOF)
552 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
554 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
556 struct mntent **mnttbl=getmnttbl(),**ent;
557 for (ent=mnttbl;*ent;ent++)
559 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
560 me->me_devname = xstrdup ( (*ent)->mt_resource);
561 me->me_mountdir = xstrdup( (*ent)->mt_directory);
562 me->me_type = xstrdup ((*ent)->mt_fstype);
563 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
564 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
565 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
567 /* Add to the linked list. */
569 mtail = &me->me_next;
575 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
578 char *table = MNTTAB;
583 # if defined F_RDLCK && defined F_SETLKW
584 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
585 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
586 for this file name, we should use their macro name instead.
587 (Why not just lock MNTTAB directly? We don't know.) */
589 # define MNTTAB_LOCK "/etc/.mnttab.lock"
591 lockfd = open (MNTTAB_LOCK, O_RDONLY);
595 flock.l_type = F_RDLCK;
596 flock.l_whence = SEEK_SET;
599 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
602 int saved_errno = errno;
608 else if (errno != ENOENT)
613 fp = fopen (table, "r");
618 while ((ret = getmntent (fp, &mnt)) == 0)
620 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
621 me->me_devname = xstrdup (mnt.mnt_special);
622 me->me_mountdir = xstrdup (mnt.mnt_mountp);
623 me->me_type = xstrdup (mnt.mnt_fstype);
624 me->me_dummy = MNT_IGNORE (&mnt) != 0;
625 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
626 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
628 /* Add to the linked list. */
630 mtail = &me->me_next;
633 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
636 if (0 <= lockfd && close (lockfd) != 0)
645 #endif /* MOUNTED_GETMNTENT2. */
647 #ifdef MOUNTED_VMOUNT /* AIX. */
650 char *entries, *thisent;
653 /* Ask how many bytes to allocate for the mounted filesystem info. */
654 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
655 entries = xmalloc (bufsize);
657 /* Get the list of mounted filesystems. */
658 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
660 for (thisent = entries; thisent < entries + bufsize;
661 thisent += vmp->vmt_length)
663 vmp = (struct vmount *) thisent;
664 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
665 if (vmp->vmt_flags & MNT_REMOTE)
670 /* Prepend the remote pathname. */
671 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
672 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
673 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
674 strcpy (me->me_devname, host);
675 strcat (me->me_devname, ":");
676 strcat (me->me_devname, path);
681 me->me_devname = xstrdup (thisent +
682 vmp->vmt_data[VMT_OBJECT].vmt_off);
684 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
685 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
686 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
687 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
689 /* Add to the linked list. */
691 mtail = &me->me_next;
695 #endif /* MOUNTED_VMOUNT. */
703 int saved_errno = errno;
708 me = mount_list->me_next;
709 free (mount_list->me_devname);
710 free (mount_list->me_mountdir);
711 /* FIXME: me_type is not always malloced. */
723 main (int argc, char **argv)
726 for (i = 1; i < argc; i++)
728 char *p = xstrdup (argv[i]);
729 translate_040_to_space (p);
730 printf ("%s: %s\n", argv[i], p);