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