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