update FSF address in copyright
[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 Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 #ifdef HAVE_SYS_PARAM_H
44 #include <sys/param.h>
45 #endif
46
47 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
48 #  include <sys/mount.h>
49 #  include <sys/fs_types.h>
50 #endif /* MOUNTED_GETFSSTAT */
51
52 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
53 #include <mntent.h>
54 #if !defined(MOUNTED)
55 #  if defined(MNT_MNTTAB)       /* HP-UX.  */
56 #    define MOUNTED MNT_MNTTAB
57 #  endif
58 #  if defined(MNTTABNAME)       /* Dynix.  */
59 #    define MOUNTED MNTTABNAME
60 #  endif
61 #endif
62 #endif
63
64 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
65 #include <sys/mount.h>
66 #endif
67
68 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
69 #include <sys/mount.h>
70 #include <sys/fs_types.h>
71 #endif
72
73 #ifdef MOUNTED_FREAD            /* SVR2.  */
74 #include <mnttab.h>
75 #endif
76
77 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
78 #include <mnttab.h>
79 #include <sys/fstyp.h>
80 #include <sys/statfs.h>
81 #endif
82
83 #ifdef MOUNTED_LISTMNTENT
84 #include <mntent.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 #if defined (MOUNTED_GETMNTINFO) && !defined (__NetBSD__)
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_LISTMNTENT
203   {
204     struct tabmntent *mntlist, *p;
205     struct mntent *mnt;
206     struct mount_entry *me;
207     
208     /* the third and fourth arguments could be used to filter mounts,
209        but Crays doesn't seem to have any mounts that we want to
210        remove. Specifically, automount create normal NFS mounts.
211        */
212
213     if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
214       return NULL;
215     p = mntlist;
216     while(p){
217       mnt = p->ment;
218       me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
219       me->me_devname = xstrdup(mnt->mnt_fsname);
220       me->me_mountdir = xstrdup(mnt->mnt_dir);
221       me->me_type = xstrdup(mnt->mnt_type);
222       me->me_dev = -1;
223       me->me_next = NULL;
224       mtail->me_next = me;
225       mtail = me;
226       p = p->next;
227     }
228     freemntlist(mntlist);
229   }
230 #endif
231
232 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
233   {
234     struct mntent *mnt;
235     char *table = MOUNTED;
236     FILE *fp;
237     char *devopt;
238
239     fp = setmntent (table, "r");
240     if (fp == NULL)
241       return NULL;
242
243     while ((mnt = getmntent (fp)))
244       {
245         if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
246                         || !strcmp (mnt->mnt_type, "auto")))
247           continue;
248
249         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
250         me->me_devname = xstrdup (mnt->mnt_fsname);
251         me->me_mountdir = xstrdup (mnt->mnt_dir);
252         me->me_type = xstrdup (mnt->mnt_type);
253         devopt = strstr (mnt->mnt_opts, "dev=");
254         if (devopt)
255           {
256             if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
257               me->me_dev = xatoi (devopt + 6);
258             else
259               me->me_dev = xatoi (devopt + 4);
260           }
261         else
262           me->me_dev = (dev_t) -1;      /* Magic; means not known yet. */
263         me->me_next = NULL;
264
265         /* Add to the linked list. */
266         mtail->me_next = me;
267         mtail = me;
268       }
269
270     if (endmntent (fp) == 0)
271       return NULL;
272   }
273 #endif /* MOUNTED_GETMNTENT1. */
274
275 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
276   {
277     struct statfs *fsp;
278     int entries;
279
280     entries = getmntinfo (&fsp, MNT_NOWAIT);
281     if (entries < 0)
282       return NULL;
283     while (entries-- > 0)
284       {
285         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
286         me->me_devname = xstrdup (fsp->f_mntfromname);
287         me->me_mountdir = xstrdup (fsp->f_mntonname);
288 #ifdef __NetBSD__
289         me->me_type = xstrdup (fsp->f_fstypename);
290 #else
291         me->me_type = fstype_to_string (fsp->f_type);
292 #endif
293         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
294         me->me_next = NULL;
295
296         /* Add to the linked list. */
297         mtail->me_next = me;
298         mtail = me;
299         fsp++;
300       }
301   }
302 #endif /* MOUNTED_GETMNTINFO */
303
304 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
305   {
306     int offset = 0;
307     int val;
308     struct fs_data fsd;
309
310     while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
311                           (char *) 0)) > 0)
312       {
313         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
314         me->me_devname = xstrdup (fsd.fd_req.devname);
315         me->me_mountdir = xstrdup (fsd.fd_req.path);
316         me->me_type = gt_names[fsd.fd_req.fstype];
317         me->me_dev = fsd.fd_req.dev;
318         me->me_next = NULL;
319
320         /* Add to the linked list. */
321         mtail->me_next = me;
322         mtail = me;
323       }
324     if (val < 0)
325       return NULL;
326   }
327 #endif /* MOUNTED_GETMNT. */
328
329 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
330   {
331     int numsys, counter, bufsize;
332     struct statfs *stats;
333
334     numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
335     if (numsys < 0)
336       return (NULL);
337
338     bufsize = (1 + numsys) * sizeof (struct statfs);
339     stats = (struct statfs *)xmalloc (bufsize);
340     numsys = getfsstat (stats, bufsize, MNT_WAIT);
341
342     if (numsys < 0)
343       {
344         free (stats);
345         return (NULL);
346       }
347
348     for (counter = 0; counter < numsys; counter++)
349       {
350         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
351         me->me_devname = xstrdup (stats[counter].f_mntfromname);
352         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
353         me->me_type = mnt_names[stats[counter].f_type];
354         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
355         me->me_next = NULL;
356
357         /* Add to the linked list. */
358         mtail->me_next = me;
359         mtail = me;
360       }
361
362     free (stats);
363   }
364 #endif /* MOUNTED_GETFSSTAT */
365
366 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23].  */
367   {
368     struct mnttab mnt;
369     char *table = "/etc/mnttab";
370     FILE *fp;
371
372     fp = fopen (table, "r");
373     if (fp == NULL)
374       return NULL;
375
376     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
377       {
378         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
379 #ifdef GETFSTYP                 /* SVR3.  */
380         me->me_devname = xstrdup (mnt.mt_dev);
381 #else
382         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
383         strcpy (me->me_devname, "/dev/");
384         strcpy (me->me_devname + 5, mnt.mt_dev);
385 #endif
386         me->me_mountdir = xstrdup (mnt.mt_filsys);
387         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
388         me->me_type = "";
389 #ifdef GETFSTYP                 /* SVR3.  */
390         if (need_fs_type)
391           {
392             struct statfs fsd;
393             char typebuf[FSTYPSZ];
394
395             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
396                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
397               me->me_type = xstrdup (typebuf);
398           }
399 #endif
400         me->me_next = NULL;
401
402         /* Add to the linked list. */
403         mtail->me_next = me;
404         mtail = me;
405       }
406
407     if (fclose (fp) == EOF)
408       return NULL;
409   }
410 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
411
412 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
413   {
414     struct mntent **mnttbl=getmnttbl(),**ent;
415     for (ent=mnttbl;*ent;ent++)
416       {
417         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
418         me->me_devname = xstrdup ( (*ent)->mt_resource);
419         me->me_mountdir = xstrdup( (*ent)->mt_directory);
420         me->me_type =  xstrdup ((*ent)->mt_fstype);
421         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
422         me->me_next = NULL;
423
424         /* Add to the linked list. */
425         mtail->me_next = me;
426         mtail = me;
427       }
428     endmnttbl();
429   }
430 #endif
431
432 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
433   {
434     struct mnttab mnt;
435     char *table = MNTTAB;
436     FILE *fp;
437     int ret;
438
439     fp = fopen (table, "r");
440     if (fp == NULL)
441       return NULL;
442
443     while ((ret = getmntent (fp, &mnt)) == 0)
444       {
445         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
446         me->me_devname = xstrdup (mnt.mnt_special);
447         me->me_mountdir = xstrdup (mnt.mnt_mountp);
448         me->me_type = xstrdup (mnt.mnt_fstype);
449         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
450         me->me_next = NULL;
451
452         /* Add to the linked list. */
453         mtail->me_next = me;
454         mtail = me;
455       }
456
457     if (ret > 0)
458       return NULL;
459    if (fclose (fp) == EOF)
460       return NULL;
461   }
462 #endif /* MOUNTED_GETMNTENT2.  */
463
464 #ifdef MOUNTED_VMOUNT           /* AIX.  */
465   {
466     int bufsize;
467     char *entries, *thisent;
468     struct vmount *vmp;
469
470     /* Ask how many bytes to allocate for the mounted filesystem info.  */
471     mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
472     entries = xmalloc (bufsize);
473
474     /* Get the list of mounted filesystems.  */
475     mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
476
477     for (thisent = entries; thisent < entries + bufsize;
478          thisent += vmp->vmt_length)
479       {
480         vmp = (struct vmount *) thisent;
481         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
482         if (vmp->vmt_flags & MNT_REMOTE)
483           {
484             char *host, *path;
485
486             /* Prepend the remote pathname.  */
487             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
488             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
489             me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
490             strcpy (me->me_devname, host);
491             strcat (me->me_devname, ":");
492             strcat (me->me_devname, path);
493           }
494         else
495           {
496             me->me_devname = xstrdup (thisent +
497                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
498           }
499         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
500         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
501         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
502         me->me_next = NULL;
503
504         /* Add to the linked list. */
505         mtail->me_next = me;
506         mtail = me;
507       }
508     free (entries);
509   }
510 #endif /* MOUNTED_VMOUNT. */
511
512   /* Free the dummy head. */
513   me = mount_list;
514   mount_list = mount_list->me_next;
515   free (me);
516   return mount_list;
517 }