*** empty log message ***
[midnight-commander.git] / src / mountlist.c
blobf4a4a8c15e9e187ae3fadfd7e7d9bc7a112ffea0
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>
24 #include <fcntl.h>
26 #ifdef STDC_HEADERS
27 #include <stdlib.h>
28 #else
29 void free (void *ptr);
30 #endif
31 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
32 #include <string.h>
33 #else
34 #include <strings.h>
35 #endif
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
41 #ifdef HAVE_SYS_PARAM_H
42 #include <sys/param.h>
43 #endif
45 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
46 #include <sys/mount.h>
47 #include <sys/fs_types.h>
48 #endif /* MOUNTED_GETFSSTAT */
50 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
51 #include <mntent.h>
52 #if !defined(MOUNTED)
53 #if defined(MNT_MNTTAB) /* HP-UX. */
54 #define MOUNTED MNT_MNTTAB
55 #endif
56 #if defined(MNTTABNAME) /* Dynix. */
57 #define MOUNTED MNTTABNAME
58 #endif
59 #endif
60 #endif
62 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
63 #include <sys/mount.h>
64 #endif
66 #ifdef MOUNTED_GETMNT /* Ultrix. */
67 #include <sys/mount.h>
68 #include <sys/fs_types.h>
69 #endif
71 #ifdef MOUNTED_FREAD /* SVR2. */
72 #include <mnttab.h>
73 #endif
75 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
76 #include <mnttab.h>
77 #include <sys/fstyp.h>
78 #include <sys/statfs.h>
79 #endif
81 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
82 #include <sys/mnttab.h>
83 #endif
85 #ifdef MOUNTED_VMOUNT /* AIX. */
86 #include <fshelp.h>
87 #include <sys/vfs.h>
88 #endif
90 #ifdef HAVE_SYS_STATFS_H
91 #include <sys/statfs.h>
92 #endif
94 #ifdef HAVE_INFOMOUNT_QNX
95 #include <sys/disk.h>
96 #include <sys/fsys.h>
97 #endif
99 #include "global.h"
100 #include "mountlist.h"
101 #include "fsusage.h"
102 #include "util.h"
104 /* void error (void); FIXME -- needed? */
106 #ifdef DOLPHIN
107 /* So special that it's not worth putting this in autoconf. */
108 #undef MOUNTED_FREAD_FSTYP
109 #define MOUNTED_GETMNTTBL
110 #endif
112 #ifdef HAVE_INFOMOUNT_LIST
114 static struct mount_entry *mount_list = NULL;
116 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
117 /* Return the value of the hexadecimal number represented by CP.
118 No prefix (like '0x') or suffix (like 'h') is expected to be
119 part of CP. */
121 static int xatoi (char *cp)
123 int val;
125 val = 0;
126 while (*cp) {
127 if (*cp >= 'a' && *cp <= 'f')
128 val = val * 16 + *cp - 'a' + 10;
129 else if (*cp >= 'A' && *cp <= 'F')
130 val = val * 16 + *cp - 'A' + 10;
131 else if (*cp >= '0' && *cp <= '9')
132 val = val * 16 + *cp - '0';
133 else
134 break;
135 cp++;
137 return val;
139 #endif /* MOUNTED_GETMNTENT1 */
141 #if defined (MOUNTED_GETMNTINFO) && !defined (HAVE_F_FSTYPENAME)
142 static char *fstype_to_string (short t)
144 switch (t) {
145 case MOUNT_UFS:
146 return "ufs";
147 case MOUNT_NFS:
148 return "nfs";
149 #ifdef MOUNT_PC
150 case MOUNT_PC:
151 return "pc";
152 #endif
153 #ifdef MOUNT_MFS
154 case MOUNT_MFS:
155 return "mfs";
156 #endif
157 #ifdef MOUNT_LO
158 case MOUNT_LO:
159 return "lo";
160 #endif
161 #ifdef MOUNT_TFS
162 case MOUNT_TFS:
163 return "tfs";
164 #endif
165 #ifdef MOUNT_TMP
166 case MOUNT_TMP:
167 return "tmp";
168 #endif
169 default:
170 return "?";
173 #endif /* MOUNTED_GETMNTINFO && !HAVE_F_FSTYPENAME */
175 #ifdef MOUNTED_VMOUNT /* AIX. */
176 static char *fstype_to_string (int t)
178 struct vfs_ent *e;
180 e = getvfsbytype (t);
181 if (!e || !e->vfsent_name)
182 return "none";
183 else
184 return e->vfsent_name;
186 #endif /* MOUNTED_VMOUNT */
188 /* Return a list of the currently mounted filesystems, or NULL on error.
189 Add each entry to the tail of the list so that they stay in order.
190 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
191 the returned list are valid. Otherwise, they might not be.
192 If ALL_FS is zero, do not return entries for filesystems that
193 are automounter (dummy) entries. */
195 struct mount_entry *read_filesystem_list (int need_fs_type, int all_fs)
197 struct mount_entry *mlist;
198 struct mount_entry *me;
199 struct mount_entry *mtail;
201 /* Start the list off with a dummy entry. */
202 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
203 me->me_next = NULL;
204 mlist = mtail = me;
206 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
208 struct mntent *mnt;
209 char *table = MOUNTED;
210 FILE *fp;
211 char *devopt;
213 fp = setmntent (table, "r");
214 if (fp == NULL)
215 return NULL;
217 while ((mnt = getmntent (fp))) {
218 if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
219 || !strcmp (mnt->mnt_type, "auto")))
220 continue;
222 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
223 me->me_devname = strdup (mnt->mnt_fsname);
224 me->me_mountdir = strdup (mnt->mnt_dir);
225 me->me_type = strdup (mnt->mnt_type);
226 devopt = strstr (mnt->mnt_opts, "dev=");
227 if (devopt) {
228 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
229 me->me_dev = xatoi (devopt + 6);
230 else
231 me->me_dev = xatoi (devopt + 4);
232 } else
233 me->me_dev = -1; /* Magic; means not known yet. */
234 me->me_next = NULL;
236 /* Add to the linked list. */
237 mtail->me_next = me;
238 mtail = me;
241 if (endmntent (fp) == 0)
242 return NULL;
244 #endif /* MOUNTED_GETMNTENT1 */
246 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
248 struct statfs *fsp;
249 int entries;
251 entries = getmntinfo (&fsp, MNT_NOWAIT);
252 if (entries < 0)
253 return NULL;
254 while (entries-- > 0) {
255 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
256 me->me_devname = strdup (fsp->f_mntfromname);
257 me->me_mountdir = strdup (fsp->f_mntonname);
258 #ifdef HAVE_F_FSTYPENAME
259 me->me_type = strdup (fsp->f_fstypename);
260 #else
261 me->me_type = fstype_to_string (fsp->f_type);
262 #endif
263 me->me_dev = -1; /* Magic; means not known yet. */
264 me->me_next = NULL;
266 /* Add to the linked list. */
267 mtail->me_next = me;
268 mtail = me;
269 fsp++;
272 #endif /* MOUNTED_GETMNTINFO */
274 #ifdef MOUNTED_GETMNT /* Ultrix. */
276 int offset = 0;
277 int val;
278 struct fs_data fsd;
280 while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
281 (char *) 0)) > 0) {
282 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
283 me->me_devname = strdup (fsd.fd_req.devname);
284 me->me_mountdir = strdup (fsd.fd_req.path);
285 me->me_type = gt_names[fsd.fd_req.fstype];
286 me->me_dev = fsd.fd_req.dev;
287 me->me_next = NULL;
289 /* Add to the linked list. */
290 mtail->me_next = me;
291 mtail = me;
293 if (val < 0)
294 return NULL;
296 #endif /* MOUNTED_GETMNT */
298 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
300 int numsys, counter, bufsize;
301 struct statfs *stats;
303 numsys = getfsstat ((struct statfs *) 0, 0L, MNT_WAIT);
304 if (numsys < 0)
305 return (NULL);
307 bufsize = (1 + numsys) * sizeof (struct statfs);
308 stats = (struct statfs *) malloc (bufsize);
309 numsys = getfsstat (stats, bufsize, MNT_WAIT);
311 if (numsys < 0) {
312 free (stats);
313 return (NULL);
315 for (counter = 0; counter < numsys; counter++) {
316 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
317 me->me_devname = strdup (stats[counter].f_mntfromname);
318 me->me_mountdir = strdup (stats[counter].f_mntonname);
319 me->me_type = mnt_names[stats[counter].f_type];
320 me->me_dev = -1; /* Magic; means not known yet. */
321 me->me_next = NULL;
323 /* Add to the linked list. */
324 mtail->me_next = me;
325 mtail = me;
328 free (stats);
330 #endif /* MOUNTED_GETFSSTAT */
332 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
334 struct mnttab mnt;
335 char *table = "/etc/mnttab";
336 FILE *fp;
338 fp = fopen (table, "r");
339 if (fp == NULL)
340 return NULL;
342 while (fread (&mnt, sizeof mnt, 1, fp) > 0) {
343 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
344 #ifdef GETFSTYP /* SVR3. */
345 me->me_devname = strdup (mnt.mt_dev);
346 #else
347 me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
348 strcpy (me->me_devname, "/dev/");
349 strcpy (me->me_devname + 5, mnt.mt_dev);
350 #endif
351 me->me_mountdir = strdup (mnt.mt_filsys);
352 me->me_dev = -1; /* Magic; means not known yet. */
353 me->me_type = "";
354 #ifdef GETFSTYP /* SVR3. */
355 if (need_fs_type) {
356 struct statfs fsd;
357 char typebuf[FSTYPSZ];
359 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
360 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
361 me->me_type = strdup (typebuf);
363 #endif
364 me->me_next = NULL;
366 /* Add to the linked list. */
367 mtail->me_next = me;
368 mtail = me;
371 if (fclose (fp) == EOF)
372 return NULL;
374 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP */
376 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
378 struct mntent **mnttbl = getmnttbl (), **ent;
379 for (ent = mnttbl; *ent; ent++) {
380 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
381 me->me_devname = strdup ((*ent)->mt_resource);
382 me->me_mountdir = strdup ((*ent)->mt_directory);
383 me->me_type = strdup ((*ent)->mt_fstype);
384 me->me_dev = -1; /* Magic; means not known yet. */
385 me->me_next = NULL;
387 /* Add to the linked list. */
388 mtail->me_next = me;
389 mtail = me;
391 endmnttbl ();
393 #endif /* MOUNTED_GETMNTTBL */
395 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
397 struct mnttab mnt;
398 char *table = MNTTAB;
399 FILE *fp;
400 int ret;
402 fp = fopen (table, "r");
403 if (fp == NULL)
404 return NULL;
406 while ((ret = getmntent (fp, &mnt)) == 0) {
407 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
408 me->me_devname = strdup (mnt.mnt_special);
409 me->me_mountdir = strdup (mnt.mnt_mountp);
410 me->me_type = strdup (mnt.mnt_fstype);
411 me->me_dev = -1; /* Magic; means not known yet. */
412 me->me_next = NULL;
413 /* Add to the linked list. */
414 mtail->me_next = me;
415 mtail = me;
418 if (ret > 0)
419 return NULL;
420 if (fclose (fp) == EOF)
421 return NULL;
423 #endif /* MOUNTED_GETMNTENT2 */
425 #ifdef MOUNTED_VMOUNT /* AIX. */
427 int bufsize;
428 char *entries, *thisent;
429 struct vmount *vmp;
431 /* Ask how many bytes to allocate for the mounted filesystem info. */
432 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
433 entries = malloc (bufsize);
435 /* Get the list of mounted filesystems. */
436 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
438 for (thisent = entries; thisent < entries + bufsize;
439 thisent += vmp->vmt_length) {
440 vmp = (struct vmount *) thisent;
441 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
442 if (vmp->vmt_flags & MNT_REMOTE) {
443 char *host, *path;
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 = malloc (strlen (host) + strlen (path) + 2);
449 strcpy (me->me_devname, host);
450 strcat (me->me_devname, ":");
451 strcat (me->me_devname, path);
452 } else {
453 me->me_devname = strdup (thisent +
454 vmp->vmt_data[VMT_OBJECT].vmt_off);
456 me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
457 me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
458 me->me_dev = -1; /* vmt_fsid might be the info we want. */
459 me->me_next = NULL;
461 /* Add to the linked list. */
462 mtail->me_next = me;
463 mtail = me;
465 free (entries);
467 #endif /* MOUNTED_VMOUNT */
469 /* Free the dummy head. */
470 me = mlist;
471 mlist = mlist->me_next;
472 free (me);
473 return mlist;
475 #endif /* HAVE_INFOMOUNT_LIST */
477 #ifdef HAVE_INFOMOUNT_QNX
479 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
480 ** this via the following code.
481 ** Note that, as this is based on CWD, it only fills one mount_entry
482 ** structure. See my_statfs() in utilunix.c for the "other side" of
483 ** this hack.
486 struct mount_entry *read_filesystem_list(int need_fs_type, int all_fs)
488 struct _disk_entry de;
489 struct statfs fs;
490 int i, fd;
491 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
493 static struct mount_entry *me = NULL;
495 if (me)
497 if (me->me_devname) free(me->me_devname);
498 if (me->me_mountdir) free(me->me_mountdir);
499 if (me->me_type) free(me->me_type);
501 else
502 me = (struct mount_entry *)malloc(sizeof(struct mount_entry));
504 if (!getcwd(dir, _POSIX_PATH_MAX)) return (NULL);
506 if ((fd = open(dir, O_RDONLY)) == -1) return (NULL);
508 i = disk_get_entry(fd, &de);
510 close(fd);
512 if (i == -1) return (NULL);
514 switch (de.disk_type)
516 case _UNMOUNTED: tp = "unmounted"; break;
517 case _FLOPPY: tp = "Floppy"; break;
518 case _HARD: tp = "Hard"; break;
519 case _RAMDISK: tp = "Ram"; break;
520 case _REMOVABLE: tp = "Removable"; break;
521 case _TAPE: tp = "Tape"; break;
522 case _CDROM: tp = "CDROM"; break;
523 default: tp = "unknown";
526 if (fsys_get_mount_dev(dir, &dev) == -1) return (NULL);
528 if (fsys_get_mount_pt(dev, &dir) == -1) return (NULL);
530 me->me_devname = strdup(dev);
531 me->me_mountdir = strdup(dir);
532 me->me_type = strdup(tp);
533 me->me_dev = de.disk_type;
535 #ifdef DEBUG
536 fprintf(stderr, "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
537 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
538 fprintf(stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
539 fprintf(stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
540 #endif /* DEBUG */
542 return (me);
544 #endif /* HAVE_INFOMOUNT_QNX */
546 void init_my_statfs (void)
548 #ifdef HAVE_INFOMOUNT_LIST
549 mount_list = read_filesystem_list (1, 1);
550 #endif /* HAVE_INFOMOUNT_LIST */
553 void my_statfs (struct my_statfs *myfs_stats, char *path)
555 #ifdef HAVE_INFOMOUNT_LIST
556 int i, len = 0;
557 struct mount_entry *entry = NULL;
558 struct mount_entry *temp = mount_list;
559 struct fs_usage fs_use;
561 while (temp){
562 i = strlen (temp->me_mountdir);
563 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
564 if (!entry || (path [i] == PATH_SEP || path [i] == 0)){
565 len = i;
566 entry = temp;
568 temp = temp->me_next;
571 if (entry){
572 get_fs_usage (entry->me_mountdir, &fs_use);
574 myfs_stats->type = entry->me_dev;
575 myfs_stats->typename = entry->me_type;
576 myfs_stats->mpoint = entry->me_mountdir;
577 myfs_stats->device = entry->me_devname;
578 myfs_stats->avail = getuid () ? fs_use.fsu_bavail/2 : fs_use.fsu_bfree/2;
579 myfs_stats->total = fs_use.fsu_blocks/2;
580 myfs_stats->nfree = fs_use.fsu_ffree;
581 myfs_stats->nodes = fs_use.fsu_files;
582 } else
583 #endif /* HAVE_INFOMOUNT_LIST */
585 #ifdef HAVE_INFOMOUNT_QNX
587 ** This is the "other side" of the hack to read_filesystem_list() in
588 ** mountlist.c.
589 ** It's not the most efficient approach, but consumes less memory. It
590 ** also accomodates QNX's ability to mount filesystems on the fly.
592 struct mount_entry *entry;
593 struct fs_usage fs_use;
595 if ((entry = read_filesystem_list(0, 0)) != NULL)
597 get_fs_usage(entry->me_mountdir, &fs_use);
599 myfs_stats->type = entry->me_dev;
600 myfs_stats->typename = entry->me_type;
601 myfs_stats->mpoint = entry->me_mountdir;
602 myfs_stats->device = entry->me_devname;
604 myfs_stats->avail = fs_use.fsu_bfree / 2;
605 myfs_stats->total = fs_use.fsu_blocks / 2;
606 myfs_stats->nfree = fs_use.fsu_ffree;
607 myfs_stats->nodes = fs_use.fsu_files;
609 else
610 #endif /* HAVE_INFOMOUNT_QNX */
612 myfs_stats->type = 0;
613 myfs_stats->mpoint = "unknown";
614 myfs_stats->device = "unknown";
615 myfs_stats->avail = 0;
616 myfs_stats->total = 0;
617 myfs_stats->nfree = 0;
618 myfs_stats->nodes = 0;