corrected some file operations dialog msgs
[midnight-commander.git] / src / mountlist.c
blob3ad5953094412f40ed5f24a7a117d5357991dd1e
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 /* A mount table entry. */
113 struct mount_entry
115 char *me_devname; /* Device node pathname, including "/dev/". */
116 char *me_mountdir; /* Mount point directory pathname. */
117 char *me_type; /* "nfs", "4.2", etc. */
118 dev_t me_dev; /* Device number of me_mountdir. */
119 struct mount_entry *me_next;
122 #ifdef HAVE_INFOMOUNT_LIST
124 static struct mount_entry *mount_list = NULL;
126 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
127 /* Return the value of the hexadecimal number represented by CP.
128 No prefix (like '0x') or suffix (like 'h') is expected to be
129 part of CP. */
131 static int xatoi (char *cp)
133 int val;
135 val = 0;
136 while (*cp) {
137 if (*cp >= 'a' && *cp <= 'f')
138 val = val * 16 + *cp - 'a' + 10;
139 else if (*cp >= 'A' && *cp <= 'F')
140 val = val * 16 + *cp - 'A' + 10;
141 else if (*cp >= '0' && *cp <= '9')
142 val = val * 16 + *cp - '0';
143 else
144 break;
145 cp++;
147 return val;
149 #endif /* MOUNTED_GETMNTENT1 */
151 #if defined (MOUNTED_GETMNTINFO) && !defined (HAVE_F_FSTYPENAME)
152 static char *fstype_to_string (short t)
154 switch (t) {
155 case MOUNT_UFS:
156 return "ufs";
157 case MOUNT_NFS:
158 return "nfs";
159 #ifdef MOUNT_PC
160 case MOUNT_PC:
161 return "pc";
162 #endif
163 #ifdef MOUNT_MFS
164 case MOUNT_MFS:
165 return "mfs";
166 #endif
167 #ifdef MOUNT_LO
168 case MOUNT_LO:
169 return "lo";
170 #endif
171 #ifdef MOUNT_TFS
172 case MOUNT_TFS:
173 return "tfs";
174 #endif
175 #ifdef MOUNT_TMP
176 case MOUNT_TMP:
177 return "tmp";
178 #endif
179 default:
180 return "?";
183 #endif /* MOUNTED_GETMNTINFO && !HAVE_F_FSTYPENAME */
185 #ifdef MOUNTED_VMOUNT /* AIX. */
186 static char *
187 fstype_to_string (int t)
189 struct vfs_ent *e;
191 e = getvfsbytype (t);
192 if (!e || !e->vfsent_name)
193 return "none";
194 else
195 return e->vfsent_name;
197 #endif /* MOUNTED_VMOUNT */
199 /* Return a list of the currently mounted filesystems, or NULL on error.
200 Add each entry to the tail of the list so that they stay in order.
201 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
202 the returned list are valid. Otherwise, they might not be.
203 If ALL_FS is zero, do not return entries for filesystems that
204 are automounter (dummy) entries. */
206 static struct mount_entry *
207 read_filesystem_list (int need_fs_type, int all_fs)
209 struct mount_entry *mlist;
210 struct mount_entry *me;
211 struct mount_entry *mtail;
213 /* Start the list off with a dummy entry. */
214 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
215 me->me_next = NULL;
216 mlist = mtail = me;
218 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
220 struct mntent *mnt;
221 char *table = MOUNTED;
222 FILE *fp;
223 char *devopt;
225 fp = setmntent (table, "r");
226 if (fp == NULL)
227 return NULL;
229 while ((mnt = getmntent (fp))) {
230 if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
231 || !strcmp (mnt->mnt_type, "auto")))
232 continue;
234 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
235 me->me_devname = strdup (mnt->mnt_fsname);
236 me->me_mountdir = strdup (mnt->mnt_dir);
237 me->me_type = strdup (mnt->mnt_type);
238 devopt = strstr (mnt->mnt_opts, "dev=");
239 if (devopt) {
240 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
241 me->me_dev = xatoi (devopt + 6);
242 else
243 me->me_dev = xatoi (devopt + 4);
244 } else
245 me->me_dev = -1; /* Magic; means not known yet. */
246 me->me_next = NULL;
248 /* Add to the linked list. */
249 mtail->me_next = me;
250 mtail = me;
253 if (endmntent (fp) == 0)
254 return NULL;
256 #endif /* MOUNTED_GETMNTENT1 */
258 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
260 struct statfs *fsp;
261 int entries;
263 entries = getmntinfo (&fsp, MNT_NOWAIT);
264 if (entries < 0)
265 return NULL;
266 while (entries-- > 0) {
267 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
268 me->me_devname = strdup (fsp->f_mntfromname);
269 me->me_mountdir = strdup (fsp->f_mntonname);
270 #ifdef HAVE_F_FSTYPENAME
271 me->me_type = strdup (fsp->f_fstypename);
272 #else
273 me->me_type = fstype_to_string (fsp->f_type);
274 #endif
275 me->me_dev = -1; /* Magic; means not known yet. */
276 me->me_next = NULL;
278 /* Add to the linked list. */
279 mtail->me_next = me;
280 mtail = me;
281 fsp++;
284 #endif /* MOUNTED_GETMNTINFO */
286 #ifdef MOUNTED_GETMNT /* Ultrix. */
288 int offset = 0;
289 int val;
290 struct fs_data fsd;
292 while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
293 (char *) 0)) > 0) {
294 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
295 me->me_devname = strdup (fsd.fd_req.devname);
296 me->me_mountdir = strdup (fsd.fd_req.path);
297 me->me_type = gt_names[fsd.fd_req.fstype];
298 me->me_dev = fsd.fd_req.dev;
299 me->me_next = NULL;
301 /* Add to the linked list. */
302 mtail->me_next = me;
303 mtail = me;
305 if (val < 0)
306 return NULL;
308 #endif /* MOUNTED_GETMNT */
310 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
312 int numsys, counter, bufsize;
313 struct statfs *stats;
315 numsys = getfsstat ((struct statfs *) 0, 0L, MNT_WAIT);
316 if (numsys < 0)
317 return (NULL);
319 bufsize = (1 + numsys) * sizeof (struct statfs);
320 stats = (struct statfs *) malloc (bufsize);
321 numsys = getfsstat (stats, bufsize, MNT_WAIT);
323 if (numsys < 0) {
324 free (stats);
325 return (NULL);
327 for (counter = 0; counter < numsys; counter++) {
328 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
329 me->me_devname = strdup (stats[counter].f_mntfromname);
330 me->me_mountdir = strdup (stats[counter].f_mntonname);
331 me->me_type = mnt_names[stats[counter].f_type];
332 me->me_dev = -1; /* Magic; means not known yet. */
333 me->me_next = NULL;
335 /* Add to the linked list. */
336 mtail->me_next = me;
337 mtail = me;
340 free (stats);
342 #endif /* MOUNTED_GETFSSTAT */
344 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
346 struct mnttab mnt;
347 char *table = "/etc/mnttab";
348 FILE *fp;
350 fp = fopen (table, "r");
351 if (fp == NULL)
352 return NULL;
354 while (fread (&mnt, sizeof mnt, 1, fp) > 0) {
355 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
356 #ifdef GETFSTYP /* SVR3. */
357 me->me_devname = strdup (mnt.mt_dev);
358 #else
359 me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
360 strcpy (me->me_devname, "/dev/");
361 strcpy (me->me_devname + 5, mnt.mt_dev);
362 #endif
363 me->me_mountdir = strdup (mnt.mt_filsys);
364 me->me_dev = -1; /* Magic; means not known yet. */
365 me->me_type = "";
366 #ifdef GETFSTYP /* SVR3. */
367 if (need_fs_type) {
368 struct statfs fsd;
369 char typebuf[FSTYPSZ];
371 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
372 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
373 me->me_type = strdup (typebuf);
375 #endif
376 me->me_next = NULL;
378 /* Add to the linked list. */
379 mtail->me_next = me;
380 mtail = me;
383 if (fclose (fp) == EOF)
384 return NULL;
386 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP */
388 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
390 struct mntent **mnttbl = getmnttbl (), **ent;
391 for (ent = mnttbl; *ent; ent++) {
392 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
393 me->me_devname = strdup ((*ent)->mt_resource);
394 me->me_mountdir = strdup ((*ent)->mt_directory);
395 me->me_type = strdup ((*ent)->mt_fstype);
396 me->me_dev = -1; /* Magic; means not known yet. */
397 me->me_next = NULL;
399 /* Add to the linked list. */
400 mtail->me_next = me;
401 mtail = me;
403 endmnttbl ();
405 #endif /* MOUNTED_GETMNTTBL */
407 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
409 struct mnttab mnt;
410 char *table = MNTTAB;
411 FILE *fp;
412 int ret;
414 fp = fopen (table, "r");
415 if (fp == NULL)
416 return NULL;
418 while ((ret = getmntent (fp, &mnt)) == 0) {
419 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
420 me->me_devname = strdup (mnt.mnt_special);
421 me->me_mountdir = strdup (mnt.mnt_mountp);
422 me->me_type = strdup (mnt.mnt_fstype);
423 me->me_dev = -1; /* Magic; means not known yet. */
424 me->me_next = NULL;
425 /* Add to the linked list. */
426 mtail->me_next = me;
427 mtail = me;
430 if (ret > 0)
431 return NULL;
432 if (fclose (fp) == EOF)
433 return NULL;
435 #endif /* MOUNTED_GETMNTENT2 */
437 #ifdef MOUNTED_VMOUNT /* AIX. */
439 int bufsize;
440 char *entries, *thisent;
441 struct vmount *vmp;
443 /* Ask how many bytes to allocate for the mounted filesystem info. */
444 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
445 entries = malloc (bufsize);
447 /* Get the list of mounted filesystems. */
448 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
450 for (thisent = entries; thisent < entries + bufsize;
451 thisent += vmp->vmt_length) {
452 vmp = (struct vmount *) thisent;
453 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
454 if (vmp->vmt_flags & MNT_REMOTE) {
455 char *host, *path;
457 /* Prepend the remote pathname. */
458 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
459 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
460 me->me_devname = malloc (strlen (host) + strlen (path) + 2);
461 strcpy (me->me_devname, host);
462 strcat (me->me_devname, ":");
463 strcat (me->me_devname, path);
464 } else {
465 me->me_devname = strdup (thisent +
466 vmp->vmt_data[VMT_OBJECT].vmt_off);
468 me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
469 me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
470 me->me_dev = -1; /* vmt_fsid might be the info we want. */
471 me->me_next = NULL;
473 /* Add to the linked list. */
474 mtail->me_next = me;
475 mtail = me;
477 free (entries);
479 #endif /* MOUNTED_VMOUNT */
481 /* Free the dummy head. */
482 me = mlist;
483 mlist = mlist->me_next;
484 free (me);
485 return mlist;
487 #endif /* HAVE_INFOMOUNT_LIST */
489 #ifdef HAVE_INFOMOUNT_QNX
491 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
492 ** this via the following code.
493 ** Note that, as this is based on CWD, it only fills one mount_entry
494 ** structure. See my_statfs() in utilunix.c for the "other side" of
495 ** this hack.
498 static struct mount_entry *
499 read_filesystem_list(int need_fs_type, int all_fs)
501 struct _disk_entry de;
502 struct statfs fs;
503 int i, fd;
504 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
506 static struct mount_entry *me = NULL;
508 if (me)
510 if (me->me_devname) free(me->me_devname);
511 if (me->me_mountdir) free(me->me_mountdir);
512 if (me->me_type) free(me->me_type);
514 else
515 me = (struct mount_entry *)malloc(sizeof(struct mount_entry));
517 if (!getcwd(dir, _POSIX_PATH_MAX)) return (NULL);
519 if ((fd = open(dir, O_RDONLY)) == -1) return (NULL);
521 i = disk_get_entry(fd, &de);
523 close(fd);
525 if (i == -1) return (NULL);
527 switch (de.disk_type)
529 case _UNMOUNTED: tp = "unmounted"; break;
530 case _FLOPPY: tp = "Floppy"; break;
531 case _HARD: tp = "Hard"; break;
532 case _RAMDISK: tp = "Ram"; break;
533 case _REMOVABLE: tp = "Removable"; break;
534 case _TAPE: tp = "Tape"; break;
535 case _CDROM: tp = "CDROM"; break;
536 default: tp = "unknown";
539 if (fsys_get_mount_dev(dir, &dev) == -1) return (NULL);
541 if (fsys_get_mount_pt(dev, &dir) == -1) return (NULL);
543 me->me_devname = strdup(dev);
544 me->me_mountdir = strdup(dir);
545 me->me_type = strdup(tp);
546 me->me_dev = de.disk_type;
548 #ifdef DEBUG
549 fprintf(stderr, "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
550 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
551 fprintf(stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
552 fprintf(stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
553 #endif /* DEBUG */
555 return (me);
557 #endif /* HAVE_INFOMOUNT_QNX */
559 void
560 init_my_statfs (void)
562 #ifdef HAVE_INFOMOUNT_LIST
563 mount_list = read_filesystem_list (1, 1);
564 #endif /* HAVE_INFOMOUNT_LIST */
567 void
568 my_statfs (struct my_statfs *myfs_stats, char *path)
570 #ifdef HAVE_INFOMOUNT_LIST
571 int i, len = 0;
572 struct mount_entry *entry = NULL;
573 struct mount_entry *temp = mount_list;
574 struct fs_usage fs_use;
576 while (temp){
577 i = strlen (temp->me_mountdir);
578 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
579 if (!entry || (path [i] == PATH_SEP || path [i] == 0)){
580 len = i;
581 entry = temp;
583 temp = temp->me_next;
586 if (entry){
587 get_fs_usage (entry->me_mountdir, &fs_use);
589 myfs_stats->type = entry->me_dev;
590 myfs_stats->typename = entry->me_type;
591 myfs_stats->mpoint = entry->me_mountdir;
592 myfs_stats->device = entry->me_devname;
593 myfs_stats->avail = getuid () ? fs_use.fsu_bavail/2 : fs_use.fsu_bfree/2;
594 myfs_stats->total = fs_use.fsu_blocks/2;
595 myfs_stats->nfree = fs_use.fsu_ffree;
596 myfs_stats->nodes = fs_use.fsu_files;
597 } else
598 #endif /* HAVE_INFOMOUNT_LIST */
600 #ifdef HAVE_INFOMOUNT_QNX
602 ** This is the "other side" of the hack to read_filesystem_list() in
603 ** mountlist.c.
604 ** It's not the most efficient approach, but consumes less memory. It
605 ** also accomodates QNX's ability to mount filesystems on the fly.
607 struct mount_entry *entry;
608 struct fs_usage fs_use;
610 if ((entry = read_filesystem_list(0, 0)) != NULL)
612 get_fs_usage(entry->me_mountdir, &fs_use);
614 myfs_stats->type = entry->me_dev;
615 myfs_stats->typename = entry->me_type;
616 myfs_stats->mpoint = entry->me_mountdir;
617 myfs_stats->device = entry->me_devname;
619 myfs_stats->avail = fs_use.fsu_bfree / 2;
620 myfs_stats->total = fs_use.fsu_blocks / 2;
621 myfs_stats->nfree = fs_use.fsu_ffree;
622 myfs_stats->nodes = fs_use.fsu_files;
624 else
625 #endif /* HAVE_INFOMOUNT_QNX */
627 myfs_stats->type = 0;
628 myfs_stats->mpoint = "unknown";
629 myfs_stats->device = "unknown";
630 myfs_stats->avail = 0;
631 myfs_stats->total = 0;
632 myfs_stats->nfree = 0;
633 myfs_stats->nodes = 0;