another typo: too late at light corrections...:-(
[midnight-commander.git] / src / mountlist.c
blob9e4dc58f0a07be340703ab00e4de2d64e5e72d4a
1 /* mountlist.c -- return a list of mounted filesystems
2 Copyright (C) 1991, 1992 Free Software Foundation, Inc.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <sys/types.h>
23 #include <stdio.h>
25 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
26 #include <sys/mount.h>
27 #include <sys/fs_types.h>
28 #endif /* MOUNTED_GETFSSTAT */
30 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
31 #include <mntent.h>
32 #if !defined(MOUNTED)
33 #if defined(MNT_MNTTAB) /* HP-UX. */
34 #define MOUNTED MNT_MNTTAB
35 #endif
36 #if defined(MNTTABNAME) /* Dynix. */
37 #define MOUNTED MNTTABNAME
38 #endif
39 #endif
40 #endif
42 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
43 #include <sys/mount.h>
44 #endif
46 #ifdef MOUNTED_GETMNT /* Ultrix. */
47 #include <sys/mount.h>
48 #include <sys/fs_types.h>
49 #endif
51 #ifdef MOUNTED_FREAD /* SVR2. */
52 #include <mnttab.h>
53 #endif
55 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
56 #include <mnttab.h>
57 #include <sys/fstyp.h>
58 #include <sys/statfs.h>
59 #endif
61 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
62 #include <sys/mnttab.h>
63 #endif
65 #ifdef MOUNTED_VMOUNT /* AIX. */
66 #include <fshelp.h>
67 #include <sys/vfs.h>
68 #endif
70 #ifdef HAVE_SYS_STATFS_H
71 #include <sys/statfs.h>
72 #endif
74 #ifdef HAVE_INFOMOUNT_QNX
75 #include <sys/disk.h>
76 #include <sys/fsys.h>
77 #endif
79 #include "global.h"
80 #include "mountlist.h"
81 #include "fsusage.h"
82 #include "util.h"
84 /* void error (void); FIXME -- needed? */
86 #ifdef DOLPHIN
87 /* So special that it's not worth putting this in autoconf. */
88 #undef MOUNTED_FREAD_FSTYP
89 #define MOUNTED_GETMNTTBL
90 #endif
92 /* A mount table entry. */
93 struct mount_entry
95 char *me_devname; /* Device node pathname, including "/dev/". */
96 char *me_mountdir; /* Mount point directory pathname. */
97 char *me_type; /* "nfs", "4.2", etc. */
98 dev_t me_dev; /* Device number of me_mountdir. */
99 struct mount_entry *me_next;
102 #ifdef HAVE_INFOMOUNT_LIST
104 static struct mount_entry *mount_list = NULL;
106 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
107 /* Return the value of the hexadecimal number represented by CP.
108 No prefix (like '0x') or suffix (like 'h') is expected to be
109 part of CP. */
111 static int xatoi (char *cp)
113 int val;
115 val = 0;
116 while (*cp) {
117 if (*cp >= 'a' && *cp <= 'f')
118 val = val * 16 + *cp - 'a' + 10;
119 else if (*cp >= 'A' && *cp <= 'F')
120 val = val * 16 + *cp - 'A' + 10;
121 else if (*cp >= '0' && *cp <= '9')
122 val = val * 16 + *cp - '0';
123 else
124 break;
125 cp++;
127 return val;
129 #endif /* MOUNTED_GETMNTENT1 */
131 #if defined (MOUNTED_GETMNTINFO) && !defined (HAVE_F_FSTYPENAME)
132 static char *fstype_to_string (short t)
134 switch (t) {
135 case MOUNT_UFS:
136 return "ufs";
137 case MOUNT_NFS:
138 return "nfs";
139 #ifdef MOUNT_PC
140 case MOUNT_PC:
141 return "pc";
142 #endif
143 #ifdef MOUNT_MFS
144 case MOUNT_MFS:
145 return "mfs";
146 #endif
147 #ifdef MOUNT_LO
148 case MOUNT_LO:
149 return "lo";
150 #endif
151 #ifdef MOUNT_TFS
152 case MOUNT_TFS:
153 return "tfs";
154 #endif
155 #ifdef MOUNT_TMP
156 case MOUNT_TMP:
157 return "tmp";
158 #endif
159 default:
160 return "?";
163 #endif /* MOUNTED_GETMNTINFO && !HAVE_F_FSTYPENAME */
165 #ifdef MOUNTED_VMOUNT /* AIX. */
166 static char *
167 fstype_to_string (int t)
169 struct vfs_ent *e;
171 e = getvfsbytype (t);
172 if (!e || !e->vfsent_name)
173 return "none";
174 else
175 return e->vfsent_name;
177 #endif /* MOUNTED_VMOUNT */
179 /* Return a list of the currently mounted filesystems, or NULL on error.
180 Add each entry to the tail of the list so that they stay in order.
181 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
182 the returned list are valid. Otherwise, they might not be.
183 If ALL_FS is zero, do not return entries for filesystems that
184 are automounter (dummy) entries. */
186 static struct mount_entry *
187 read_filesystem_list (int need_fs_type, int all_fs)
189 struct mount_entry *mlist;
190 struct mount_entry *me;
191 struct mount_entry *mtail;
193 /* Start the list off with a dummy entry. */
194 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
195 me->me_next = NULL;
196 mlist = mtail = me;
198 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
200 struct mntent *mnt;
201 char *table = MOUNTED;
202 FILE *fp;
203 char *devopt;
205 fp = setmntent (table, "r");
206 if (fp == NULL)
207 return NULL;
209 while ((mnt = getmntent (fp))) {
210 if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
211 || !strcmp (mnt->mnt_type, "auto")))
212 continue;
214 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
215 me->me_devname = strdup (mnt->mnt_fsname);
216 me->me_mountdir = strdup (mnt->mnt_dir);
217 me->me_type = strdup (mnt->mnt_type);
218 devopt = strstr (mnt->mnt_opts, "dev=");
219 if (devopt) {
220 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
221 me->me_dev = xatoi (devopt + 6);
222 else
223 me->me_dev = xatoi (devopt + 4);
224 } else
225 me->me_dev = -1; /* Magic; means not known yet. */
226 me->me_next = NULL;
228 /* Add to the linked list. */
229 mtail->me_next = me;
230 mtail = me;
233 if (endmntent (fp) == 0)
234 return NULL;
236 #endif /* MOUNTED_GETMNTENT1 */
238 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
240 struct statfs *fsp;
241 int entries;
243 entries = getmntinfo (&fsp, MNT_NOWAIT);
244 if (entries < 0)
245 return NULL;
246 while (entries-- > 0) {
247 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
248 me->me_devname = strdup (fsp->f_mntfromname);
249 me->me_mountdir = strdup (fsp->f_mntonname);
250 #ifdef HAVE_F_FSTYPENAME
251 me->me_type = strdup (fsp->f_fstypename);
252 #else
253 me->me_type = fstype_to_string (fsp->f_type);
254 #endif
255 me->me_dev = -1; /* Magic; means not known yet. */
256 me->me_next = NULL;
258 /* Add to the linked list. */
259 mtail->me_next = me;
260 mtail = me;
261 fsp++;
264 #endif /* MOUNTED_GETMNTINFO */
266 #ifdef MOUNTED_GETMNT /* Ultrix. */
268 int offset = 0;
269 int val;
270 struct fs_data fsd;
272 while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
273 (char *) 0)) > 0) {
274 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
275 me->me_devname = strdup (fsd.fd_req.devname);
276 me->me_mountdir = strdup (fsd.fd_req.path);
277 me->me_type = gt_names[fsd.fd_req.fstype];
278 me->me_dev = fsd.fd_req.dev;
279 me->me_next = NULL;
281 /* Add to the linked list. */
282 mtail->me_next = me;
283 mtail = me;
285 if (val < 0)
286 return NULL;
288 #endif /* MOUNTED_GETMNT */
290 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
292 int numsys, counter, bufsize;
293 struct statfs *stats;
295 numsys = getfsstat ((struct statfs *) 0, 0L, MNT_WAIT);
296 if (numsys < 0)
297 return (NULL);
299 bufsize = (1 + numsys) * sizeof (struct statfs);
300 stats = (struct statfs *) malloc (bufsize);
301 numsys = getfsstat (stats, bufsize, MNT_WAIT);
303 if (numsys < 0) {
304 free (stats);
305 return (NULL);
307 for (counter = 0; counter < numsys; counter++) {
308 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
309 me->me_devname = strdup (stats[counter].f_mntfromname);
310 me->me_mountdir = strdup (stats[counter].f_mntonname);
311 me->me_type = mnt_names[stats[counter].f_type];
312 me->me_dev = -1; /* Magic; means not known yet. */
313 me->me_next = NULL;
315 /* Add to the linked list. */
316 mtail->me_next = me;
317 mtail = me;
320 free (stats);
322 #endif /* MOUNTED_GETFSSTAT */
324 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
326 struct mnttab mnt;
327 char *table = "/etc/mnttab";
328 FILE *fp;
330 fp = fopen (table, "r");
331 if (fp == NULL)
332 return NULL;
334 while (fread (&mnt, sizeof mnt, 1, fp) > 0) {
335 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
336 #ifdef GETFSTYP /* SVR3. */
337 me->me_devname = strdup (mnt.mt_dev);
338 #else
339 me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
340 strcpy (me->me_devname, "/dev/");
341 strcpy (me->me_devname + 5, mnt.mt_dev);
342 #endif
343 me->me_mountdir = strdup (mnt.mt_filsys);
344 me->me_dev = -1; /* Magic; means not known yet. */
345 me->me_type = "";
346 #ifdef GETFSTYP /* SVR3. */
347 if (need_fs_type) {
348 struct statfs fsd;
349 char typebuf[FSTYPSZ];
351 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
352 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
353 me->me_type = strdup (typebuf);
355 #endif
356 me->me_next = NULL;
358 /* Add to the linked list. */
359 mtail->me_next = me;
360 mtail = me;
363 if (fclose (fp) == EOF)
364 return NULL;
366 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP */
368 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
370 struct mntent **mnttbl = getmnttbl (), **ent;
371 for (ent = mnttbl; *ent; ent++) {
372 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
373 me->me_devname = strdup ((*ent)->mt_resource);
374 me->me_mountdir = strdup ((*ent)->mt_directory);
375 me->me_type = strdup ((*ent)->mt_fstype);
376 me->me_dev = -1; /* Magic; means not known yet. */
377 me->me_next = NULL;
379 /* Add to the linked list. */
380 mtail->me_next = me;
381 mtail = me;
383 endmnttbl ();
385 #endif /* MOUNTED_GETMNTTBL */
387 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
389 struct mnttab mnt;
390 char *table = MNTTAB;
391 FILE *fp;
392 int ret;
394 fp = fopen (table, "r");
395 if (fp == NULL)
396 return NULL;
398 while ((ret = getmntent (fp, &mnt)) == 0) {
399 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
400 me->me_devname = strdup (mnt.mnt_special);
401 me->me_mountdir = strdup (mnt.mnt_mountp);
402 me->me_type = strdup (mnt.mnt_fstype);
403 me->me_dev = -1; /* Magic; means not known yet. */
404 me->me_next = NULL;
405 /* Add to the linked list. */
406 mtail->me_next = me;
407 mtail = me;
410 if (ret > 0)
411 return NULL;
412 if (fclose (fp) == EOF)
413 return NULL;
415 #endif /* MOUNTED_GETMNTENT2 */
417 #ifdef MOUNTED_VMOUNT /* AIX. */
419 int bufsize;
420 char *entries, *thisent;
421 struct vmount *vmp;
423 /* Ask how many bytes to allocate for the mounted filesystem info. */
424 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
425 entries = malloc (bufsize);
427 /* Get the list of mounted filesystems. */
428 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
430 for (thisent = entries; thisent < entries + bufsize;
431 thisent += vmp->vmt_length) {
432 vmp = (struct vmount *) thisent;
433 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
434 if (vmp->vmt_flags & MNT_REMOTE) {
435 char *host, *path;
437 /* Prepend the remote pathname. */
438 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
439 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
440 me->me_devname = malloc (strlen (host) + strlen (path) + 2);
441 strcpy (me->me_devname, host);
442 strcat (me->me_devname, ":");
443 strcat (me->me_devname, path);
444 } else {
445 me->me_devname = strdup (thisent +
446 vmp->vmt_data[VMT_OBJECT].vmt_off);
448 me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
449 me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
450 me->me_dev = -1; /* vmt_fsid might be the info we want. */
451 me->me_next = NULL;
453 /* Add to the linked list. */
454 mtail->me_next = me;
455 mtail = me;
457 free (entries);
459 #endif /* MOUNTED_VMOUNT */
461 /* Free the dummy head. */
462 me = mlist;
463 mlist = mlist->me_next;
464 free (me);
465 return mlist;
467 #endif /* HAVE_INFOMOUNT_LIST */
469 #ifdef HAVE_INFOMOUNT_QNX
471 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
472 ** this via the following code.
473 ** Note that, as this is based on CWD, it only fills one mount_entry
474 ** structure. See my_statfs() in utilunix.c for the "other side" of
475 ** this hack.
478 static struct mount_entry *
479 read_filesystem_list(int need_fs_type, int all_fs)
481 struct _disk_entry de;
482 struct statfs fs;
483 int i, fd;
484 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
486 static struct mount_entry *me = NULL;
488 if (me)
490 if (me->me_devname) free(me->me_devname);
491 if (me->me_mountdir) free(me->me_mountdir);
492 if (me->me_type) free(me->me_type);
494 else
495 me = (struct mount_entry *)malloc(sizeof(struct mount_entry));
497 if (!getcwd(dir, _POSIX_PATH_MAX)) return (NULL);
499 if ((fd = open(dir, O_RDONLY)) == -1) return (NULL);
501 i = disk_get_entry(fd, &de);
503 close(fd);
505 if (i == -1) return (NULL);
507 switch (de.disk_type)
509 case _UNMOUNTED: tp = "unmounted"; break;
510 case _FLOPPY: tp = "Floppy"; break;
511 case _HARD: tp = "Hard"; break;
512 case _RAMDISK: tp = "Ram"; break;
513 case _REMOVABLE: tp = "Removable"; break;
514 case _TAPE: tp = "Tape"; break;
515 case _CDROM: tp = "CDROM"; break;
516 default: tp = "unknown";
519 if (fsys_get_mount_dev(dir, &dev) == -1) return (NULL);
521 if (fsys_get_mount_pt(dev, &dir) == -1) return (NULL);
523 me->me_devname = strdup(dev);
524 me->me_mountdir = strdup(dir);
525 me->me_type = strdup(tp);
526 me->me_dev = de.disk_type;
528 #ifdef DEBUG
529 fprintf(stderr, "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
530 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
531 fprintf(stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
532 fprintf(stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
533 #endif /* DEBUG */
535 return (me);
537 #endif /* HAVE_INFOMOUNT_QNX */
539 void
540 init_my_statfs (void)
542 #ifdef HAVE_INFOMOUNT_LIST
543 mount_list = read_filesystem_list (1, 1);
544 #endif /* HAVE_INFOMOUNT_LIST */
547 void
548 my_statfs (struct my_statfs *myfs_stats, char *path)
550 #ifdef HAVE_INFOMOUNT_LIST
551 int i, len = 0;
552 struct mount_entry *entry = NULL;
553 struct mount_entry *temp = mount_list;
554 struct fs_usage fs_use;
556 while (temp){
557 i = strlen (temp->me_mountdir);
558 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
559 if (!entry || (path [i] == PATH_SEP || path [i] == 0)){
560 len = i;
561 entry = temp;
563 temp = temp->me_next;
566 if (entry){
567 get_fs_usage (entry->me_mountdir, &fs_use);
569 myfs_stats->type = entry->me_dev;
570 myfs_stats->typename = entry->me_type;
571 myfs_stats->mpoint = entry->me_mountdir;
572 myfs_stats->device = entry->me_devname;
573 myfs_stats->avail = getuid () ? fs_use.fsu_bavail/2 : fs_use.fsu_bfree/2;
574 myfs_stats->total = fs_use.fsu_blocks/2;
575 myfs_stats->nfree = fs_use.fsu_ffree;
576 myfs_stats->nodes = fs_use.fsu_files;
577 } else
578 #endif /* HAVE_INFOMOUNT_LIST */
580 #ifdef HAVE_INFOMOUNT_QNX
582 ** This is the "other side" of the hack to read_filesystem_list() in
583 ** mountlist.c.
584 ** It's not the most efficient approach, but consumes less memory. It
585 ** also accomodates QNX's ability to mount filesystems on the fly.
587 struct mount_entry *entry;
588 struct fs_usage fs_use;
590 if ((entry = read_filesystem_list(0, 0)) != NULL)
592 get_fs_usage(entry->me_mountdir, &fs_use);
594 myfs_stats->type = entry->me_dev;
595 myfs_stats->typename = entry->me_type;
596 myfs_stats->mpoint = entry->me_mountdir;
597 myfs_stats->device = entry->me_devname;
599 myfs_stats->avail = fs_use.fsu_bfree / 2;
600 myfs_stats->total = fs_use.fsu_blocks / 2;
601 myfs_stats->nfree = fs_use.fsu_ffree;
602 myfs_stats->nodes = fs_use.fsu_files;
604 else
605 #endif /* HAVE_INFOMOUNT_QNX */
607 myfs_stats->type = 0;
608 myfs_stats->mpoint = "unknown";
609 myfs_stats->device = "unknown";
610 myfs_stats->avail = 0;
611 myfs_stats->total = 0;
612 myfs_stats->nfree = 0;
613 myfs_stats->nodes = 0;