(read_filesystem_list):
[gnulib.git] / lib / mountlist.c
1 /* mountlist.c -- return a list of mounted filesystems
2    Copyright (C) 1991, 1992, 1997, 1998 Free Software Foundation, Inc.
3
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)
7    any later version.
8
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.
13
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.  */
17
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include "mountlist.h"
25
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 #else
29 void free ();
30 #endif
31 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
32 # include <string.h>
33 #else
34 # include <strings.h>
35 #endif
36
37 #ifndef strstr
38 char *strstr ();
39 #endif
40 char *xmalloc ();
41 char *xrealloc ();
42 char *xstrdup ();
43 void error ();
44
45 #include <errno.h>
46 #ifndef errno
47 extern int errno;
48 #endif
49
50 #ifdef HAVE_FCNTL_H
51 # include <fcntl.h>
52 #endif
53
54 #ifdef HAVE_UNISTD_H
55 # include <unistd.h>
56 #endif
57
58 #if HAVE_SYS_PARAM_H
59 # include <sys/param.h>
60 #endif
61
62 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
63 # include <sys/mount.h>
64 # include <sys/fs_types.h>
65 #endif /* MOUNTED_GETFSSTAT */
66
67 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
68 # include <mntent.h>
69 # if !defined(MOUNTED)
70 #  if defined(MNT_MNTTAB)       /* HP-UX.  */
71 #   define MOUNTED MNT_MNTTAB
72 #  endif
73 #  if defined(MNTTABNAME)       /* Dynix.  */
74 #   define MOUNTED MNTTABNAME
75 #  endif
76 # endif
77 #endif
78
79 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
80 # include <sys/mount.h>
81 #endif
82
83 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
84 # include <sys/mount.h>
85 # include <sys/fs_types.h>
86 #endif
87
88 #ifdef MOUNTED_FREAD            /* SVR2.  */
89 # include <mnttab.h>
90 #endif
91
92 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
93 # include <mnttab.h>
94 # include <sys/fstyp.h>
95 # include <sys/statfs.h>
96 #endif
97
98 #ifdef MOUNTED_LISTMNTENT
99 # include <mntent.h>
100 #endif
101
102 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
103 # include <sys/mnttab.h>
104 #endif
105
106 #ifdef MOUNTED_VMOUNT           /* AIX.  */
107 # include <fshelp.h>
108 # include <sys/vfs.h>
109 #endif
110
111 #ifdef DOLPHIN
112 /* So special that it's not worth putting this in autoconf.  */
113 # undef MOUNTED_FREAD_FSTYP
114 # define MOUNTED_GETMNTTBL
115 #endif
116
117 #if HAVE_SYS_MNTENT_H
118 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
119 # include <sys/mntent.h>
120 #endif
121
122 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
123 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
124 #else
125 # define MNT_IGNORE(M) 0
126 #endif
127
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
131    part of CP. */
132
133 static int
134 xatoi (cp)
135      char *cp;
136 {
137   int val;
138
139   val = 0;
140   while (*cp)
141     {
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';
148       else
149         break;
150       cp++;
151     }
152   return val;
153 }
154 #endif /* MOUNTED_GETMNTENT1.  */
155
156 #if MOUNTED_GETMNTINFO
157
158 # if ! HAVE_F_FSTYPENAME_IN_STATFS
159 static char *
160 fstype_to_string (short t)
161 {
162   switch (t)
163     {
164 #  ifdef MOUNT_PC
165     case MOUNT_PC:
166       return "pc";
167 #  endif
168 #  ifdef MOUNT_MFS
169     case MOUNT_MFS:
170       return "mfs";
171 #  endif
172 #  ifdef MOUNT_LO
173     case MOUNT_LO:
174       return "lo";
175 #  endif
176 #  ifdef MOUNT_TFS
177     case MOUNT_TFS:
178       return "tfs";
179 #  endif
180 #  ifdef MOUNT_TMP
181     case MOUNT_TMP:
182       return "tmp";
183 #  endif
184 #  ifdef MOUNT_UFS
185    case MOUNT_UFS:
186      return "ufs" ;
187 #  endif
188 #  ifdef MOUNT_NFS
189    case MOUNT_NFS:
190      return "nfs" ;
191 #  endif
192 #  ifdef MOUNT_MSDOS
193    case MOUNT_MSDOS:
194      return "msdos" ;
195 #  endif
196 #  ifdef MOUNT_LFS
197    case MOUNT_LFS:
198      return "lfs" ;
199 #  endif
200 #  ifdef MOUNT_LOFS
201    case MOUNT_LOFS:
202      return "lofs" ;
203 #  endif
204 #  ifdef MOUNT_FDESC
205    case MOUNT_FDESC:
206      return "fdesc" ;
207 #  endif
208 #  ifdef MOUNT_PORTAL
209    case MOUNT_PORTAL:
210      return "portal" ;
211 #  endif
212 #  ifdef MOUNT_NULL
213    case MOUNT_NULL:
214      return "null" ;
215 #  endif
216 #  ifdef MOUNT_UMAP
217    case MOUNT_UMAP:
218      return "umap" ;
219 #  endif
220 #  ifdef MOUNT_KERNFS
221    case MOUNT_KERNFS:
222      return "kernfs" ;
223 #  endif
224 #  ifdef MOUNT_PROCFS
225    case MOUNT_PROCFS:
226      return "procfs" ;
227 #  endif
228 #  ifdef MOUNT_AFS
229    case MOUNT_AFS:
230      return "afs" ;
231 #  endif
232 #  ifdef MOUNT_CD9660
233    case MOUNT_CD9660:
234      return "cd9660" ;
235 #  endif
236 #  ifdef MOUNT_UNION
237    case MOUNT_UNION:
238      return "union" ;
239 #  endif
240 #  ifdef MOUNT_DEVFS
241    case MOUNT_DEVFS:
242      return "devfs" ;
243 #  endif
244 #  ifdef MOUNT_EXT2FS
245    case MOUNT_EXT2FS:
246      return "ext2fs" ;
247 #  endif
248     default:
249       return "?";
250     }
251 }
252 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
253
254 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
255 static char *
256 fsp_to_string (const struct statfs *fsp)
257 {
258 # if defined HAVE_F_FSTYPENAME_IN_STATFS
259   return xstrdup (fsp->f_fstypename);
260 # else
261   return fstype_to_string (fsp->f_type);
262 # endif
263 }
264
265 #endif /* MOUNTED_GETMNTINFO */
266
267 #ifdef MOUNTED_VMOUNT           /* AIX.  */
268 static char *
269 fstype_to_string (t)
270      int t;
271 {
272   struct vfs_ent *e;
273
274   e = getvfsbytype (t);
275   if (!e || !e->vfsent_name)
276     return "none";
277   else
278     return e->vfsent_name;
279 }
280 #endif /* MOUNTED_VMOUNT */
281
282 /* Return a list of the currently mounted filesystems, or NULL on error.
283    Add each entry to the tail of the list so that they stay in order.
284    If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
285    the returned list are valid.  Otherwise, they might not be.
286    If ALL_FS is zero, do not return entries for filesystems that
287    are automounter (dummy) entries.  */
288
289 struct mount_entry *
290 read_filesystem_list (need_fs_type, all_fs)
291      int need_fs_type, all_fs;
292 {
293   struct mount_entry *mount_list;
294   struct mount_entry *me;
295   struct mount_entry *mtail;
296
297   /* Start the list off with a dummy entry. */
298   me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
299   me->me_next = NULL;
300   mount_list = mtail = me;
301
302 #ifdef MOUNTED_LISTMNTENT
303   {
304     struct tabmntent *mntlist, *p;
305     struct mntent *mnt;
306     struct mount_entry *me;
307
308     /* the third and fourth arguments could be used to filter mounts,
309        but Crays doesn't seem to have any mounts that we want to
310        remove. Specifically, automount create normal NFS mounts.
311        */
312
313     if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
314       return NULL;
315     p = mntlist;
316     while(p){
317       mnt = p->ment;
318       me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
319       me->me_devname = xstrdup(mnt->mnt_fsname);
320       me->me_mountdir = xstrdup(mnt->mnt_dir);
321       me->me_type = xstrdup(mnt->mnt_type);
322       me->me_dev = -1;
323       me->me_next = NULL;
324       mtail->me_next = me;
325       mtail = me;
326       p = p->next;
327     }
328     freemntlist(mntlist);
329   }
330 #endif
331
332 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
333   {
334     struct mntent *mnt;
335     char *table = MOUNTED;
336     FILE *fp;
337     char *devopt;
338
339     fp = setmntent (table, "r");
340     if (fp == NULL)
341       return NULL;
342
343     while ((mnt = getmntent (fp)))
344       {
345         if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
346                         || !strcmp (mnt->mnt_type, "auto")))
347           continue;
348
349         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
350         me->me_devname = xstrdup (mnt->mnt_fsname);
351         me->me_mountdir = xstrdup (mnt->mnt_dir);
352         me->me_type = xstrdup (mnt->mnt_type);
353         devopt = strstr (mnt->mnt_opts, "dev=");
354         if (devopt)
355           {
356             if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
357               me->me_dev = xatoi (devopt + 6);
358             else
359               me->me_dev = xatoi (devopt + 4);
360           }
361         else
362           me->me_dev = (dev_t) -1;      /* Magic; means not known yet. */
363         me->me_next = NULL;
364
365         /* Add to the linked list. */
366         mtail->me_next = me;
367         mtail = me;
368       }
369
370     if (endmntent (fp) == 0)
371       return NULL;
372   }
373 #endif /* MOUNTED_GETMNTENT1. */
374
375 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
376   {
377     struct statfs *fsp;
378     int entries;
379
380     entries = getmntinfo (&fsp, MNT_NOWAIT);
381     if (entries < 0)
382       return NULL;
383     while (entries-- > 0)
384       {
385         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
386         me->me_devname = xstrdup (fsp->f_mntfromname);
387         me->me_mountdir = xstrdup (fsp->f_mntonname);
388         me->me_type = fsp_to_string (fsp);
389         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
390         me->me_next = NULL;
391
392         /* Add to the linked list. */
393         mtail->me_next = me;
394         mtail = me;
395         fsp++;
396       }
397   }
398 #endif /* MOUNTED_GETMNTINFO */
399
400 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
401   {
402     int offset = 0;
403     int val;
404     struct fs_data fsd;
405
406     while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
407                           (char *) 0)) > 0)
408       {
409         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
410         me->me_devname = xstrdup (fsd.fd_req.devname);
411         me->me_mountdir = xstrdup (fsd.fd_req.path);
412         me->me_type = gt_names[fsd.fd_req.fstype];
413         me->me_dev = fsd.fd_req.dev;
414         me->me_next = NULL;
415
416         /* Add to the linked list. */
417         mtail->me_next = me;
418         mtail = me;
419       }
420     if (val < 0)
421       return NULL;
422   }
423 #endif /* MOUNTED_GETMNT. */
424
425 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
426   {
427     int numsys, counter, bufsize;
428     struct statfs *stats;
429
430     numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
431     if (numsys < 0)
432       return (NULL);
433
434     bufsize = (1 + numsys) * sizeof (struct statfs);
435     stats = (struct statfs *)xmalloc (bufsize);
436     numsys = getfsstat (stats, bufsize, MNT_WAIT);
437
438     if (numsys < 0)
439       {
440         free (stats);
441         return (NULL);
442       }
443
444     for (counter = 0; counter < numsys; counter++)
445       {
446         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
447         me->me_devname = xstrdup (stats[counter].f_mntfromname);
448         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
449         me->me_type = mnt_names[stats[counter].f_type];
450         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
451         me->me_next = NULL;
452
453         /* Add to the linked list. */
454         mtail->me_next = me;
455         mtail = me;
456       }
457
458     free (stats);
459   }
460 #endif /* MOUNTED_GETFSSTAT */
461
462 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23].  */
463   {
464     struct mnttab mnt;
465     char *table = "/etc/mnttab";
466     FILE *fp;
467
468     fp = fopen (table, "r");
469     if (fp == NULL)
470       return NULL;
471
472     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
473       {
474         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
475 # ifdef GETFSTYP                        /* SVR3.  */
476         me->me_devname = xstrdup (mnt.mt_dev);
477 # else
478         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
479         strcpy (me->me_devname, "/dev/");
480         strcpy (me->me_devname + 5, mnt.mt_dev);
481 # endif
482         me->me_mountdir = xstrdup (mnt.mt_filsys);
483         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
484         me->me_type = "";
485 # ifdef GETFSTYP                        /* SVR3.  */
486         if (need_fs_type)
487           {
488             struct statfs fsd;
489             char typebuf[FSTYPSZ];
490
491             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
492                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
493               me->me_type = xstrdup (typebuf);
494           }
495 # endif
496         me->me_next = NULL;
497
498         /* Add to the linked list. */
499         mtail->me_next = me;
500         mtail = me;
501       }
502
503     if (fclose (fp) == EOF)
504       return NULL;
505   }
506 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
507
508 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
509   {
510     struct mntent **mnttbl=getmnttbl(),**ent;
511     for (ent=mnttbl;*ent;ent++)
512       {
513         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
514         me->me_devname = xstrdup ( (*ent)->mt_resource);
515         me->me_mountdir = xstrdup( (*ent)->mt_directory);
516         me->me_type =  xstrdup ((*ent)->mt_fstype);
517         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
518         me->me_next = NULL;
519
520         /* Add to the linked list. */
521         mtail->me_next = me;
522         mtail = me;
523       }
524     endmnttbl();
525   }
526 #endif
527
528 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
529   {
530     struct mnttab mnt;
531     char *table = MNTTAB;
532     FILE *fp;
533     int ret;
534     int lockfd = -1;
535
536 # if defined F_RDLCK && defined F_SETLKW
537     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
538        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
539        for this file name, we should use their macro name instead.
540        (Why not just lock MNTTAB directly?  We don't know.)  */
541 #  ifndef MNTTAB_LOCK
542 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
543 #  endif
544     lockfd = open (MNTTAB_LOCK, O_RDONLY);
545     if (0 <= lockfd)
546       {
547         struct flock flock;
548         flock.l_type = F_RDLCK;
549         flock.l_whence = SEEK_SET;
550         flock.l_start = 0;
551         flock.l_len = 0;
552         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
553           if (errno != EINTR)
554             return NULL;
555       }
556 # endif
557
558     fp = fopen (table, "r");
559     if (fp == NULL)
560       ret = 1;
561     else
562       {
563         while ((ret = getmntent (fp, &mnt)) == 0)
564           {
565             /* Don't show automounted filesystems twice on e.g., Solaris.  */
566             if (!all_fs && MNT_IGNORE (&mnt))
567               continue;
568
569             me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
570             me->me_devname = xstrdup (mnt.mnt_special);
571             me->me_mountdir = xstrdup (mnt.mnt_mountp);
572             me->me_type = xstrdup (mnt.mnt_fstype);
573             me->me_dev = (dev_t) -1;    /* Magic; means not known yet. */
574             me->me_next = NULL;
575
576             /* Add to the linked list. */
577             mtail->me_next = me;
578             mtail = me;
579           }
580
581         if (fclose (fp) == EOF)
582           ret = 1;
583       }
584
585     if (0 <= lockfd && close (lockfd) != 0)
586       return NULL;
587
588     if (ret > 0)
589       return NULL;
590   }
591 #endif /* MOUNTED_GETMNTENT2.  */
592
593 #ifdef MOUNTED_VMOUNT           /* AIX.  */
594   {
595     int bufsize;
596     char *entries, *thisent;
597     struct vmount *vmp;
598
599     /* Ask how many bytes to allocate for the mounted filesystem info.  */
600     mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
601     entries = xmalloc (bufsize);
602
603     /* Get the list of mounted filesystems.  */
604     mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
605
606     for (thisent = entries; thisent < entries + bufsize;
607          thisent += vmp->vmt_length)
608       {
609         vmp = (struct vmount *) thisent;
610         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
611         if (vmp->vmt_flags & MNT_REMOTE)
612           {
613             char *host, *path;
614
615             /* Prepend the remote pathname.  */
616             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
617             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
618             me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
619             strcpy (me->me_devname, host);
620             strcat (me->me_devname, ":");
621             strcat (me->me_devname, path);
622           }
623         else
624           {
625             me->me_devname = xstrdup (thisent +
626                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
627           }
628         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
629         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
630         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
631         me->me_next = NULL;
632
633         /* Add to the linked list. */
634         mtail->me_next = me;
635         mtail = me;
636       }
637     free (entries);
638   }
639 #endif /* MOUNTED_VMOUNT. */
640
641   /* Free the dummy head. */
642   me = mount_list;
643   mount_list = mount_list->me_next;
644   free (me);
645   return mount_list;
646 }