GNU file utilities
[gnulib.git] / lib / mountlist.c
1 /* mountlist.c -- return a list of mounted filesystems
2    Copyright (C) 1991, 1992 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
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 #ifdef HAVE_CONFIG_H
19 #if defined (CONFIG_BROKETS)
20 /* We use <config.h> instead of "config.h" so that a compilation
21    using -I. -I will use ./config.h rather than /config.h
22    (which it would do because it found this file in ).  */
23 #include <config.h>
24 #else
25 #include "config.h"
26 #endif
27 #endif
28
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include "mountlist.h"
32
33 #ifdef STDC_HEADERS
34 #include <stdlib.h>
35 #else
36 void free ();
37 #endif
38 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
39 #include <string.h>
40 #else
41 #include <strings.h>
42 #endif
43
44 char *strstr ();
45 char *xmalloc ();
46 char *xrealloc ();
47 char *xstrdup ();
48 void error ();
49
50 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
51 #  include <sys/mount.h>
52 #  include <sys/fs_types.h>
53 #endif /* MOUNTED_GETFSSTAT */
54
55 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
56 #include <mntent.h>
57 #if !defined(MOUNTED)
58 #  if defined(MNT_MNTTAB)       /* HP-UX.  */
59 #    define MOUNTED MNT_MNTTAB
60 #  endif
61 #  if defined(MNTTABNAME)       /* Dynix.  */
62 #    define MOUNTED MNTTABNAME
63 #  endif
64 #endif
65 #endif
66
67 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
68 #include <sys/mount.h>
69 #endif
70
71 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
72 #include <sys/param.h>
73 #include <sys/mount.h>
74 #include <sys/fs_types.h>
75 #endif
76
77 #ifdef MOUNTED_FREAD            /* SVR2.  */
78 #include <mnttab.h>
79 #endif
80
81 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
82 #include <mnttab.h>
83 #include <sys/fstyp.h>
84 #include <sys/statfs.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 MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
103 /* Return the value of the hexadecimal number represented by CP.
104    No prefix (like '0x') or suffix (like 'h') is expected to be
105    part of CP. */
106
107 static int
108 xatoi (cp)
109      char *cp;
110 {
111   int val;
112
113   val = 0;
114   while (*cp)
115     {
116       if (*cp >= 'a' && *cp <= 'f')
117         val = val * 16 + *cp - 'a' + 10;
118       else if (*cp >= 'A' && *cp <= 'F')
119         val = val * 16 + *cp - 'A' + 10;
120       else if (*cp >= '0' && *cp <= '9')
121         val = val * 16 + *cp - '0';
122       else
123         break;
124       cp++;
125     }
126   return val;
127 }
128 #endif /* MOUNTED_GETMNTENT1.  */
129
130 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
131 static char *
132 fstype_to_string (t)
133      short t;
134 {
135   switch (t)
136     {
137     case MOUNT_UFS:
138       return "ufs";
139     case MOUNT_NFS:
140       return "nfs";
141 #ifdef MOUNT_PC
142     case MOUNT_PC:
143       return "pc";
144 #endif
145 #ifdef MOUNT_MFS
146     case MOUNT_MFS:
147       return "mfs";
148 #endif
149 #ifdef MOUNT_LO
150     case MOUNT_LO:
151       return "lo";
152 #endif
153 #ifdef MOUNT_TFS
154     case MOUNT_TFS:
155       return "tfs";
156 #endif
157 #ifdef MOUNT_TMP
158     case MOUNT_TMP:
159       return "tmp";
160 #endif
161     default:
162       return "?";
163     }
164 }
165 #endif /* MOUNTED_GETMNTINFO */
166
167 #ifdef MOUNTED_VMOUNT           /* AIX.  */
168 static char *
169 fstype_to_string (t)
170      int t;
171 {
172   struct vfs_ent *e;
173
174   e = getvfsbytype (t);
175   if (!e || !e->vfsent_name)
176     return "none";
177   else
178     return e->vfsent_name;
179 }
180 #endif /* MOUNTED_VMOUNT */
181
182 /* Return a list of the currently mounted filesystems, or NULL on error.
183    Add each entry to the tail of the list so that they stay in order.
184    If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
185    the returned list are valid.  Otherwise, they might not be.
186    If ALL_FS is zero, do not return entries for filesystems that
187    are automounter (dummy) entries.  */
188
189 struct mount_entry *
190 read_filesystem_list (need_fs_type, all_fs)
191      int need_fs_type, all_fs;
192 {
193   struct mount_entry *mount_list;
194   struct mount_entry *me;
195   struct mount_entry *mtail;
196
197   /* Start the list off with a dummy entry. */
198   me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
199   me->me_next = NULL;
200   mount_list = mtail = me;
201
202 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
203   {
204     struct mntent *mnt;
205     char *table = MOUNTED;
206     FILE *fp;
207     char *devopt;
208
209     fp = setmntent (table, "r");
210     if (fp == NULL)
211       return NULL;
212
213     while ((mnt = getmntent (fp)))
214       {
215         if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
216                         || !strcmp (mnt->mnt_type, "auto")))
217           continue;
218
219         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
220         me->me_devname = xstrdup (mnt->mnt_fsname);
221         me->me_mountdir = xstrdup (mnt->mnt_dir);
222         me->me_type = xstrdup (mnt->mnt_type);
223         devopt = strstr (mnt->mnt_opts, "dev=");
224         if (devopt)
225           {
226             if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
227               me->me_dev = xatoi (devopt + 6);
228             else
229               me->me_dev = xatoi (devopt + 4);
230           }
231         else
232           me->me_dev = -1;      /* Magic; means not known yet. */
233         me->me_next = NULL;
234
235         /* Add to the linked list. */
236         mtail->me_next = me;
237         mtail = me;
238       }
239
240     if (endmntent (fp) == 0)
241       return NULL;
242   }
243 #endif /* MOUNTED_GETMNTENT1. */
244
245 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
246   {
247     struct statfs *fsp;
248     int entries;
249
250     entries = getmntinfo (&fsp, MNT_NOWAIT);
251     if (entries < 0)
252       return NULL;
253     while (entries-- > 0)
254       {
255         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
256         me->me_devname = xstrdup (fsp->f_mntfromname);
257         me->me_mountdir = xstrdup (fsp->f_mntonname);
258         me->me_type = fstype_to_string (fsp->f_type);
259         me->me_dev = -1;        /* Magic; means not known yet. */
260         me->me_next = NULL;
261
262         /* Add to the linked list. */
263         mtail->me_next = me;
264         mtail = me;
265         fsp++;
266       }
267   }
268 #endif /* MOUNTED_GETMNTINFO */
269
270 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
271   {
272     int offset = 0;
273     int val;
274     struct fs_data fsd;
275
276     while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
277                           (char *) 0)) > 0)
278       {
279         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
280         me->me_devname = xstrdup (fsd.fd_req.devname);
281         me->me_mountdir = xstrdup (fsd.fd_req.path);
282         me->me_type = gt_names[fsd.fd_req.fstype];
283         me->me_dev = fsd.fd_req.dev;
284         me->me_next = NULL;
285
286         /* Add to the linked list. */
287         mtail->me_next = me;
288         mtail = me;
289       }
290     if (val < 0)
291       return NULL;
292   }
293 #endif /* MOUNTED_GETMNT. */
294
295 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
296   {
297     int numsys, counter, bufsize;
298     struct statfs *stats;
299
300     numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
301     if (numsys < 0)
302       return (NULL);
303
304     bufsize = (1 + numsys) * sizeof (struct statfs);
305     stats = (struct statfs *)xmalloc (bufsize);
306     numsys = getfsstat (stats, bufsize, MNT_WAIT);
307
308     if (numsys < 0)
309       {
310         free (stats);
311         return (NULL);
312       }
313
314     for (counter = 0; counter < numsys; counter++)
315       {
316         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
317         me->me_devname = xstrdup (stats[counter].f_mntfromname);
318         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
319         me->me_type = mnt_names[stats[counter].f_type];
320         me->me_dev = -1;        /* Magic; means not known yet. */
321         me->me_next = NULL;
322
323         /* Add to the linked list. */
324         mtail->me_next = me;
325         mtail = me;
326       }
327
328     free (stats);
329   }
330 #endif /* MOUNTED_GETFSSTAT */
331
332 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23].  */
333   {
334     struct mnttab mnt;
335     char *table = "/etc/mnttab";
336     FILE *fp;
337
338     fp = fopen (table, "r");
339     if (fp == NULL)
340       return NULL;
341
342     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
343       {
344         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
345 #ifdef GETFSTYP                 /* SVR3.  */
346         me->me_devname = xstrdup (mnt.mt_dev);
347 #else
348         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
349         strcpy (me->me_devname, "/dev/");
350         strcpy (me->me_devname + 5, mnt.mt_dev);
351 #endif
352         me->me_mountdir = xstrdup (mnt.mt_filsys);
353         me->me_dev = -1;        /* Magic; means not known yet. */
354         me->me_type = "";
355 #ifdef GETFSTYP                 /* SVR3.  */
356         if (need_fs_type)
357           {
358             struct statfs fsd;
359             char typebuf[FSTYPSZ];
360
361             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
362                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
363               me->me_type = xstrdup (typebuf);
364           }
365 #endif
366         me->me_next = NULL;
367
368         /* Add to the linked list. */
369         mtail->me_next = me;
370         mtail = me;
371       }
372
373     if (fclose (fp) == EOF)
374       return NULL;
375   }
376 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
377
378 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
379   {
380     struct mntent **mnttbl=getmnttbl(),**ent;
381     for (ent=mnttbl;*ent;ent++)
382       {
383         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
384         me->me_devname = xstrdup ( (*ent)->mt_resource);
385         me->me_mountdir = xstrdup( (*ent)->mt_directory);
386         me->me_type =  xstrdup ((*ent)->mt_fstype);
387         me->me_dev = -1;        /* Magic; means not known yet. */
388         me->me_next = NULL;
389
390         /* Add to the linked list. */
391         mtail->me_next = me;
392         mtail = me;
393       }
394     endmnttbl();
395   }
396 #endif
397
398 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
399   {
400     struct mnttab mnt;
401     char *table = MNTTAB;
402     FILE *fp;
403     int ret;
404
405     fp = fopen (table, "r");
406     if (fp == NULL)
407       return NULL;
408
409     while ((ret = getmntent (fp, &mnt)) == 0)
410       {
411         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
412         me->me_devname = xstrdup (mnt.mnt_special);
413         me->me_mountdir = xstrdup (mnt.mnt_mountp);
414         me->me_type = xstrdup (mnt.mnt_fstype);
415         me->me_dev = -1;        /* Magic; means not known yet. */
416         me->me_next = NULL;
417
418         /* Add to the linked list. */
419         mtail->me_next = me;
420         mtail = me;
421       }
422
423     if (ret > 0)
424       return NULL;
425    if (fclose (fp) == EOF)
426       return NULL;
427   }
428 #endif /* MOUNTED_GETMNTENT2.  */
429
430 #ifdef MOUNTED_VMOUNT           /* AIX.  */
431   {
432     int bufsize;
433     char *entries, *thisent;
434     struct vmount *vmp;
435
436     /* Ask how many bytes to allocate for the mounted filesystem info.  */
437     mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
438     entries = xmalloc (bufsize);
439
440     /* Get the list of mounted filesystems.  */
441     mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
442
443     for (thisent = entries; thisent < entries + bufsize;
444          thisent += vmp->vmt_length)
445       {
446         vmp = (struct vmount *) thisent;
447         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
448         if (vmp->vmt_flags & MNT_REMOTE)
449           {
450             char *host, *path;
451
452             /* Prepend the remote pathname.  */
453             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
454             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
455             me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
456             strcpy (me->me_devname, host);
457             strcat (me->me_devname, ":");
458             strcat (me->me_devname, path);
459           }
460         else
461           {
462             me->me_devname = xstrdup (thisent +
463                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
464           }
465         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
466         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
467         me->me_dev = -1;        /* vmt_fsid might be the info we want.  */
468         me->me_next = NULL;
469
470         /* Add to the linked list. */
471         mtail->me_next = me;
472         mtail = me;
473       }
474     free (entries);
475   }
476 #endif /* MOUNTED_VMOUNT. */
477
478   /* Free the dummy head. */
479   me = mount_list;
480   mount_list = mount_list->me_next;
481   free (me);
482   return mount_list;
483 }