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