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     case MOUNT_PC:
125       return "pc";
126 #ifdef MOUNT_MFS
127     case MOUNT_MFS:
128       return "mfs";
129 #endif
130 #ifdef MOUNT_LO
131     case MOUNT_LO:
132       return "lo";
133 #endif
134 #ifdef MOUNT_TFS
135     case MOUNT_TFS:
136       return "tfs";
137 #endif
138 #ifdef MOUNT_TMP
139     case MOUNT_TMP:
140       return "tmp";
141 #endif
142     default:
143       return "?";
144     }
145 }
146 #endif /* MOUNTED_GETMNTINFO */
147
148 #ifdef MOUNTED_VMOUNT           /* AIX.  */
149 static char *
150 fstype_to_string (t)
151      int t;
152 {
153   struct vfs_ent *e;
154
155   e = getvfsbytype (t);
156   if (!e || !e->vfsent_name)
157     return "none";
158   else
159     return e->vfsent_name;
160 }
161 #endif /* MOUNTED_VMOUNT */
162
163 /* Return a list of the currently mounted filesystems, or NULL on error.
164    Add each entry to the tail of the list so that they stay in order.
165    If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
166    the returned list are valid.  Otherwise, they might not be.
167    If ALL_FS is zero, do not return entries for filesystems that
168    are automounter (dummy) entries.  */
169
170 struct mount_entry *
171 read_filesystem_list (need_fs_type, all_fs)
172      int need_fs_type, all_fs;
173 {
174   struct mount_entry *mount_list;
175   struct mount_entry *me;
176   struct mount_entry *mtail;
177
178   /* Start the list off with a dummy entry. */
179   me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
180   me->me_next = NULL;
181   mount_list = mtail = me;
182
183 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
184   {
185     struct mntent *mnt;
186     char *table = MOUNTED;
187     FILE *fp;
188     char *devopt;
189
190     fp = setmntent (table, "r");
191     if (fp == NULL)
192       return NULL;
193
194     while ((mnt = getmntent (fp)))
195       {
196         if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
197                         || !strcmp (mnt->mnt_type, "auto")))
198           continue;
199
200         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
201         me->me_devname = xstrdup (mnt->mnt_fsname);
202         me->me_mountdir = xstrdup (mnt->mnt_dir);
203         me->me_type = xstrdup (mnt->mnt_type);
204         devopt = strstr (mnt->mnt_opts, "dev=");
205         if (devopt)
206           {
207             if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
208               me->me_dev = xatoi (devopt + 6);
209             else
210               me->me_dev = xatoi (devopt + 4);
211           }
212         else
213           me->me_dev = -1;      /* Magic; means not known yet. */
214         me->me_next = NULL;
215
216         /* Add to the linked list. */
217         mtail->me_next = me;
218         mtail = me;
219       }
220
221     if (endmntent (fp) == 0)
222       return NULL;
223   }
224 #endif /* MOUNTED_GETMNTENT1. */
225
226 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
227   {
228     struct statfs *fsp;
229     int entries;
230
231     entries = getmntinfo (&fsp, MNT_NOWAIT);
232     if (entries < 0)
233       return NULL;
234     while (entries-- > 0)
235       {
236         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
237         me->me_devname = xstrdup (fsp->f_mntfromname);
238         me->me_mountdir = xstrdup (fsp->f_mntonname);
239         me->me_type = fstype_to_string (fsp->f_type);
240         me->me_dev = -1;        /* Magic; means not known yet. */
241         me->me_next = NULL;
242
243         /* Add to the linked list. */
244         mtail->me_next = me;
245         mtail = me;
246         fsp++;
247       }
248   }
249 #endif /* MOUNTED_GETMNTINFO */
250
251 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
252   {
253     int offset = 0;
254     int val;
255     struct fs_data fsd;
256
257     while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
258                           (char *) 0)) > 0)
259       {
260         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
261         me->me_devname = xstrdup (fsd.fd_req.devname);
262         me->me_mountdir = xstrdup (fsd.fd_req.path);
263         me->me_type = gt_names[fsd.fd_req.fstype];
264         me->me_dev = fsd.fd_req.dev;
265         me->me_next = NULL;
266
267         /* Add to the linked list. */
268         mtail->me_next = me;
269         mtail = me;
270       }
271     if (val < 0)
272       return NULL;
273   }
274 #endif /* MOUNTED_GETMNT. */
275
276 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
277   {
278     int numsys, counter, bufsize;
279     struct statfs *stats;
280
281     numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
282     if (numsys < 0)
283       return (NULL);
284
285     bufsize = (1 + numsys) * sizeof (struct statfs);
286     stats = (struct statfs *)xmalloc (bufsize);
287     numsys = getfsstat (stats, bufsize, MNT_WAIT);
288
289     if (numsys < 0)
290       {
291         free (stats);
292         return (NULL);
293       }
294
295     for (counter = 0; counter < numsys; counter++)
296       {
297         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
298         me->me_devname = xstrdup (stats[counter].f_mntfromname);
299         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
300         me->me_type = mnt_names[stats[counter].f_type];
301         me->me_dev = -1;        /* Magic; means not known yet. */
302         me->me_next = NULL;
303
304         /* Add to the linked list. */
305         mtail->me_next = me;
306         mtail = me;
307       }
308
309     free (stats);
310   }
311 #endif /* MOUNTED_GETFSSTAT */
312
313 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23].  */
314   {
315     struct mnttab mnt;
316     char *table = "/etc/mnttab";
317     FILE *fp;
318
319     fp = fopen (table, "r");
320     if (fp == NULL)
321       return NULL;
322
323     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
324       {
325         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
326 #ifdef GETFSTYP                 /* SVR3.  */
327         me->me_devname = xstrdup (mnt.mt_dev);
328 #else
329         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
330         strcpy (me->me_devname, "/dev/");
331         strcpy (me->me_devname + 5, mnt.mt_dev);
332 #endif
333         me->me_mountdir = xstrdup (mnt.mt_filsys);
334         me->me_dev = -1;        /* Magic; means not known yet. */
335         me->me_type = "";
336 #ifdef GETFSTYP                 /* SVR3.  */
337         if (need_fs_type)
338           {
339             struct statfs fsd;
340             char typebuf[FSTYPSZ];
341
342             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
343                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
344               me->me_type = xstrdup (typebuf);
345           }
346 #endif
347         me->me_next = NULL;
348
349         /* Add to the linked list. */
350         mtail->me_next = me;
351         mtail = me;
352       }
353
354     if (fclose (fp) == EOF)
355       return NULL;
356   }
357 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
358
359 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
360   {
361     struct mnttab mnt;
362     char *table = MNTTAB;
363     FILE *fp;
364     int ret;
365
366     fp = fopen (table, "r");
367     if (fp == NULL)
368       return NULL;
369
370     while ((ret = getmntent (fp, &mnt)) == 0)
371       {
372         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
373         me->me_devname = xstrdup (mnt.mnt_special);
374         me->me_mountdir = xstrdup (mnt.mnt_mountp);
375         me->me_type = xstrdup (mnt.mnt_fstype);
376         me->me_dev = -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       }
383
384     if (ret > 0)
385       return NULL;
386    if (fclose (fp) == EOF)
387       return NULL;
388   }
389 #endif /* MOUNTED_GETMNTENT2.  */
390
391 #ifdef MOUNTED_VMOUNT           /* AIX.  */
392   {
393     int bufsize;
394     char *entries, *thisent;
395     struct vmount *vmp;
396
397     /* Ask how many bytes to allocate for the mounted filesystem info.  */
398     mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
399     entries = xmalloc (bufsize);
400
401     /* Get the list of mounted filesystems.  */
402     mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
403
404     for (thisent = entries; thisent < entries + bufsize;
405          thisent += vmp->vmt_length)
406       {
407         vmp = (struct vmount *) thisent;
408         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
409         if (vmp->vmt_flags & MNT_REMOTE)
410           {
411             char *host, *path;
412
413             /* Prepend the remote pathname.  */
414             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
415             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
416             me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
417             strcpy (me->me_devname, host);
418             strcat (me->me_devname, ":");
419             strcat (me->me_devname, path);
420           }
421         else
422           {
423             me->me_devname = xstrdup (thisent + 
424                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
425           }
426         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
427         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
428         me->me_dev = -1;        /* vmt_fsid might be the info we want.  */
429         me->me_next = NULL;
430
431         /* Add to the linked list. */
432         mtail->me_next = me;
433         mtail = me;
434       }
435     free (entries);
436   }
437 #endif /* MOUNTED_VMOUNT. */
438
439   /* Free the dummy head. */
440   me = mount_list;
441   mount_list = mount_list->me_next;
442   free (me);
443   return mount_list;
444 }