Declare stpcpy only if not defined as macro.
[gnulib.git] / lib / mountlist.c
1 /* mountlist.c -- return a list of mounted filesystems
2    Copyright (C) 1991, 1992, 1997 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 #ifndef strstr
38 char *strstr ();
39 #endif
40 char *xmalloc ();
41 char *xrealloc ();
42 char *xstrdup ();
43 void error ();
44
45 #ifdef HAVE_SYS_PARAM_H
46 # include <sys/param.h>
47 #endif
48
49 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
50 # include <sys/mount.h>
51 # include <sys/fs_types.h>
52 #endif /* MOUNTED_GETFSSTAT */
53
54 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
55 # include <mntent.h>
56 # if !defined(MOUNTED)
57 #  if defined(MNT_MNTTAB)       /* HP-UX.  */
58 #   define MOUNTED MNT_MNTTAB
59 #  endif
60 #  if defined(MNTTABNAME)       /* Dynix.  */
61 #   define MOUNTED MNTTABNAME
62 #  endif
63 # endif
64 #endif
65
66 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
67 # include <sys/mount.h>
68 #endif
69
70 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
71 # include <sys/mount.h>
72 # include <sys/fs_types.h>
73 #endif
74
75 #ifdef MOUNTED_FREAD            /* SVR2.  */
76 # include <mnttab.h>
77 #endif
78
79 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
80 # include <mnttab.h>
81 # include <sys/fstyp.h>
82 # include <sys/statfs.h>
83 #endif
84
85 #ifdef MOUNTED_LISTMNTENT
86 # include <mntent.h>
87 #endif
88
89 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
90 # include <sys/mnttab.h>
91 #endif
92
93 #ifdef MOUNTED_VMOUNT           /* AIX.  */
94 # include <fshelp.h>
95 # include <sys/vfs.h>
96 #endif
97
98 #ifdef DOLPHIN
99 /* So special that it's not worth putting this in autoconf.  */
100 # undef MOUNTED_FREAD_FSTYP
101 # define MOUNTED_GETMNTTBL
102 #endif
103
104 #ifdef HAVE_SYS_MNTENT_H
105 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
106 # include <sys/mntent.h>
107 #endif
108
109 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
110 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
111 #else
112 # define MNT_IGNORE(M) 0
113 #endif
114
115 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
116 /* Return the value of the hexadecimal number represented by CP.
117    No prefix (like '0x') or suffix (like 'h') is expected to be
118    part of CP. */
119
120 static int
121 xatoi (cp)
122      char *cp;
123 {
124   int val;
125
126   val = 0;
127   while (*cp)
128     {
129       if (*cp >= 'a' && *cp <= 'f')
130         val = val * 16 + *cp - 'a' + 10;
131       else if (*cp >= 'A' && *cp <= 'F')
132         val = val * 16 + *cp - 'A' + 10;
133       else if (*cp >= '0' && *cp <= '9')
134         val = val * 16 + *cp - '0';
135       else
136         break;
137       cp++;
138     }
139   return val;
140 }
141 #endif /* MOUNTED_GETMNTENT1.  */
142
143 #if defined (MOUNTED_GETMNTINFO) && !defined (__NetBSD__) && !defined (__OpenBSD__)
144 static char *
145 fstype_to_string (t)
146      short t;
147 {
148   switch (t)
149     {
150 # ifdef MOUNT_PC
151     case MOUNT_PC:
152       return "pc";
153 # endif
154 # ifdef MOUNT_MFS
155     case MOUNT_MFS:
156       return "mfs";
157 # endif
158 # ifdef MOUNT_LO
159     case MOUNT_LO:
160       return "lo";
161 # endif
162 # ifdef MOUNT_TFS
163     case MOUNT_TFS:
164       return "tfs";
165 # endif
166 # ifdef MOUNT_TMP
167     case MOUNT_TMP:
168       return "tmp";
169 # endif
170 # ifdef MOUNT_UFS
171    case MOUNT_UFS:
172      return "ufs" ;
173 # endif
174 # ifdef MOUNT_NFS
175    case MOUNT_NFS:
176      return "nfs" ;
177 # endif
178 # ifdef MOUNT_MSDOS
179    case MOUNT_MSDOS:
180      return "msdos" ;
181 # endif
182 # ifdef MOUNT_LFS
183    case MOUNT_LFS:
184      return "lfs" ;
185 # endif
186 # ifdef MOUNT_LOFS
187    case MOUNT_LOFS:
188      return "lofs" ;
189 # endif
190 # ifdef MOUNT_FDESC
191    case MOUNT_FDESC:
192      return "fdesc" ;
193 # endif
194 # ifdef MOUNT_PORTAL
195    case MOUNT_PORTAL:
196      return "portal" ;
197 # endif
198 # ifdef MOUNT_NULL
199    case MOUNT_NULL:
200      return "null" ;
201 # endif
202 # ifdef MOUNT_UMAP
203    case MOUNT_UMAP:
204      return "umap" ;
205 # endif
206 # ifdef MOUNT_KERNFS
207    case MOUNT_KERNFS:
208      return "kernfs" ;
209 # endif
210 # ifdef MOUNT_PROCFS
211    case MOUNT_PROCFS:
212      return "procfs" ;
213 # endif
214 # ifdef MOUNT_AFS
215    case MOUNT_AFS:
216      return "afs" ;
217 # endif
218 # ifdef MOUNT_CD9660
219    case MOUNT_CD9660:
220      return "cd9660" ;
221 # endif
222 # ifdef MOUNT_UNION
223    case MOUNT_UNION:
224      return "union" ;
225 # endif
226 # ifdef MOUNT_DEVFS
227    case MOUNT_DEVFS:
228      return "devfs" ;
229 # endif
230 # ifdef MOUNT_EXT2FS
231    case MOUNT_EXT2FS:
232      return "ext2fs" ;
233 # endif
234     default:
235       return "?";
236     }
237 }
238 #endif /* MOUNTED_GETMNTINFO */
239
240 #ifdef MOUNTED_VMOUNT           /* AIX.  */
241 static char *
242 fstype_to_string (t)
243      int t;
244 {
245   struct vfs_ent *e;
246
247   e = getvfsbytype (t);
248   if (!e || !e->vfsent_name)
249     return "none";
250   else
251     return e->vfsent_name;
252 }
253 #endif /* MOUNTED_VMOUNT */
254
255 /* Return a list of the currently mounted filesystems, or NULL on error.
256    Add each entry to the tail of the list so that they stay in order.
257    If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
258    the returned list are valid.  Otherwise, they might not be.
259    If ALL_FS is zero, do not return entries for filesystems that
260    are automounter (dummy) entries.  */
261
262 struct mount_entry *
263 read_filesystem_list (need_fs_type, all_fs)
264      int need_fs_type, all_fs;
265 {
266   struct mount_entry *mount_list;
267   struct mount_entry *me;
268   struct mount_entry *mtail;
269
270   /* Start the list off with a dummy entry. */
271   me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
272   me->me_next = NULL;
273   mount_list = mtail = me;
274
275 #ifdef MOUNTED_LISTMNTENT
276   {
277     struct tabmntent *mntlist, *p;
278     struct mntent *mnt;
279     struct mount_entry *me;
280
281     /* the third and fourth arguments could be used to filter mounts,
282        but Crays doesn't seem to have any mounts that we want to
283        remove. Specifically, automount create normal NFS mounts.
284        */
285
286     if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
287       return NULL;
288     p = mntlist;
289     while(p){
290       mnt = p->ment;
291       me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
292       me->me_devname = xstrdup(mnt->mnt_fsname);
293       me->me_mountdir = xstrdup(mnt->mnt_dir);
294       me->me_type = xstrdup(mnt->mnt_type);
295       me->me_dev = -1;
296       me->me_next = NULL;
297       mtail->me_next = me;
298       mtail = me;
299       p = p->next;
300     }
301     freemntlist(mntlist);
302   }
303 #endif
304
305 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
306   {
307     struct mntent *mnt;
308     char *table = MOUNTED;
309     FILE *fp;
310     char *devopt;
311
312     fp = setmntent (table, "r");
313     if (fp == NULL)
314       return NULL;
315
316     while ((mnt = getmntent (fp)))
317       {
318         if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
319                         || !strcmp (mnt->mnt_type, "auto")))
320           continue;
321
322         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
323         me->me_devname = xstrdup (mnt->mnt_fsname);
324         me->me_mountdir = xstrdup (mnt->mnt_dir);
325         me->me_type = xstrdup (mnt->mnt_type);
326         devopt = strstr (mnt->mnt_opts, "dev=");
327         if (devopt)
328           {
329             if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
330               me->me_dev = xatoi (devopt + 6);
331             else
332               me->me_dev = xatoi (devopt + 4);
333           }
334         else
335           me->me_dev = (dev_t) -1;      /* Magic; means not known yet. */
336         me->me_next = NULL;
337
338         /* Add to the linked list. */
339         mtail->me_next = me;
340         mtail = me;
341       }
342
343     if (endmntent (fp) == 0)
344       return NULL;
345   }
346 #endif /* MOUNTED_GETMNTENT1. */
347
348 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
349   {
350     struct statfs *fsp;
351     int entries;
352
353     entries = getmntinfo (&fsp, MNT_NOWAIT);
354     if (entries < 0)
355       return NULL;
356     while (entries-- > 0)
357       {
358         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
359         me->me_devname = xstrdup (fsp->f_mntfromname);
360         me->me_mountdir = xstrdup (fsp->f_mntonname);
361 # if defined (__NetBSD__) || defined (__OpenBSD__)
362         me->me_type = xstrdup (fsp->f_fstypename);
363 # else
364         me->me_type = fstype_to_string (fsp->f_type);
365 # endif
366         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
367         me->me_next = NULL;
368
369         /* Add to the linked list. */
370         mtail->me_next = me;
371         mtail = me;
372         fsp++;
373       }
374   }
375 #endif /* MOUNTED_GETMNTINFO */
376
377 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
378   {
379     int offset = 0;
380     int val;
381     struct fs_data fsd;
382
383     while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
384                           (char *) 0)) > 0)
385       {
386         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
387         me->me_devname = xstrdup (fsd.fd_req.devname);
388         me->me_mountdir = xstrdup (fsd.fd_req.path);
389         me->me_type = gt_names[fsd.fd_req.fstype];
390         me->me_dev = fsd.fd_req.dev;
391         me->me_next = NULL;
392
393         /* Add to the linked list. */
394         mtail->me_next = me;
395         mtail = me;
396       }
397     if (val < 0)
398       return NULL;
399   }
400 #endif /* MOUNTED_GETMNT. */
401
402 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
403   {
404     int numsys, counter, bufsize;
405     struct statfs *stats;
406
407     numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
408     if (numsys < 0)
409       return (NULL);
410
411     bufsize = (1 + numsys) * sizeof (struct statfs);
412     stats = (struct statfs *)xmalloc (bufsize);
413     numsys = getfsstat (stats, bufsize, MNT_WAIT);
414
415     if (numsys < 0)
416       {
417         free (stats);
418         return (NULL);
419       }
420
421     for (counter = 0; counter < numsys; counter++)
422       {
423         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
424         me->me_devname = xstrdup (stats[counter].f_mntfromname);
425         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
426         me->me_type = mnt_names[stats[counter].f_type];
427         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
428         me->me_next = NULL;
429
430         /* Add to the linked list. */
431         mtail->me_next = me;
432         mtail = me;
433       }
434
435     free (stats);
436   }
437 #endif /* MOUNTED_GETFSSTAT */
438
439 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23].  */
440   {
441     struct mnttab mnt;
442     char *table = "/etc/mnttab";
443     FILE *fp;
444
445     fp = fopen (table, "r");
446     if (fp == NULL)
447       return NULL;
448
449     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
450       {
451         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
452 # ifdef GETFSTYP                        /* SVR3.  */
453         me->me_devname = xstrdup (mnt.mt_dev);
454 # else
455         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
456         strcpy (me->me_devname, "/dev/");
457         strcpy (me->me_devname + 5, mnt.mt_dev);
458 # endif
459         me->me_mountdir = xstrdup (mnt.mt_filsys);
460         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
461         me->me_type = "";
462 # ifdef GETFSTYP                        /* SVR3.  */
463         if (need_fs_type)
464           {
465             struct statfs fsd;
466             char typebuf[FSTYPSZ];
467
468             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
469                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
470               me->me_type = xstrdup (typebuf);
471           }
472 # endif
473         me->me_next = NULL;
474
475         /* Add to the linked list. */
476         mtail->me_next = me;
477         mtail = me;
478       }
479
480     if (fclose (fp) == EOF)
481       return NULL;
482   }
483 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
484
485 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
486   {
487     struct mntent **mnttbl=getmnttbl(),**ent;
488     for (ent=mnttbl;*ent;ent++)
489       {
490         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
491         me->me_devname = xstrdup ( (*ent)->mt_resource);
492         me->me_mountdir = xstrdup( (*ent)->mt_directory);
493         me->me_type =  xstrdup ((*ent)->mt_fstype);
494         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
495         me->me_next = NULL;
496
497         /* Add to the linked list. */
498         mtail->me_next = me;
499         mtail = me;
500       }
501     endmnttbl();
502   }
503 #endif
504
505 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
506   {
507     struct mnttab mnt;
508     char *table = MNTTAB;
509     FILE *fp;
510     int ret;
511
512     fp = fopen (table, "r");
513     if (fp == NULL)
514       return NULL;
515
516     while ((ret = getmntent (fp, &mnt)) == 0)
517       {
518         /* Don't show automounted filesystems twice on e.g., Solaris.  */
519         if (!all_fs && MNT_IGNORE (&mnt))
520           continue;
521
522         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
523         me->me_devname = xstrdup (mnt.mnt_special);
524         me->me_mountdir = xstrdup (mnt.mnt_mountp);
525         me->me_type = xstrdup (mnt.mnt_fstype);
526         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
527         me->me_next = NULL;
528
529         /* Add to the linked list. */
530         mtail->me_next = me;
531         mtail = me;
532       }
533
534     if (ret > 0)
535       return NULL;
536    if (fclose (fp) == EOF)
537       return NULL;
538   }
539 #endif /* MOUNTED_GETMNTENT2.  */
540
541 #ifdef MOUNTED_VMOUNT           /* AIX.  */
542   {
543     int bufsize;
544     char *entries, *thisent;
545     struct vmount *vmp;
546
547     /* Ask how many bytes to allocate for the mounted filesystem info.  */
548     mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
549     entries = xmalloc (bufsize);
550
551     /* Get the list of mounted filesystems.  */
552     mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
553
554     for (thisent = entries; thisent < entries + bufsize;
555          thisent += vmp->vmt_length)
556       {
557         vmp = (struct vmount *) thisent;
558         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
559         if (vmp->vmt_flags & MNT_REMOTE)
560           {
561             char *host, *path;
562
563             /* Prepend the remote pathname.  */
564             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
565             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
566             me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
567             strcpy (me->me_devname, host);
568             strcat (me->me_devname, ":");
569             strcat (me->me_devname, path);
570           }
571         else
572           {
573             me->me_devname = xstrdup (thisent +
574                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
575           }
576         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
577         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
578         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
579         me->me_next = NULL;
580
581         /* Add to the linked list. */
582         mtail->me_next = me;
583         mtail = me;
584       }
585     free (entries);
586   }
587 #endif /* MOUNTED_VMOUNT. */
588
589   /* Free the dummy head. */
590   me = mount_list;
591   mount_list = mount_list->me_next;
592   free (me);
593   return mount_list;
594 }