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