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