This source file includes following definitions.
- me_remote
- statvfs_works
- free_mount_entry
- fstype_to_string
- fsp_to_string
- fstype_to_string
- dev_from_mount_options
- unescape_tab
- read_file_system_list
- read_file_system_list
- get_fs_usage
- free_my_statfs
- init_my_statfs
- my_statfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 #include <config.h>
28
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdint.h>
34 #include <sys/types.h>
35
36 #include <errno.h>
37
38
39 #ifdef HAVE_SYS_PARAM_H
40 #include <sys/param.h>
41 #endif
42
43 #if defined STAT_STATVFS || defined STAT_STATVFS64
44 #include <sys/statvfs.h>
45 #else
46
47
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <sys/stat.h>
51
52 #ifdef MOUNTED_GETFSSTAT
53 #ifdef HAVE_SYS_UCRED_H
54 #include <grp.h>
55
56 #include <sys/ucred.h>
57 #endif
58 #ifdef HAVE_SYS_MOUNT_H
59 #include <sys/mount.h>
60 #endif
61 #ifdef HAVE_SYS_FS_TYPES_H
62 #include <sys/fs_types.h>
63 #endif
64 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
65 #define FS_TYPE(Ent) ((Ent).f_fstypename)
66 #else
67 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
68 #endif
69 #endif
70 #endif
71
72 #ifdef HAVE_SYS_VFS_H
73 #include <sys/vfs.h>
74 #endif
75 #ifdef HAVE_SYS_FS_S5PARAM_H
76 #include <sys/fs/s5param.h>
77 #endif
78 #ifdef HAVE_SYS_STATFS_H
79 #include <sys/statfs.h>
80 #endif
81
82 #ifdef MOUNTED_GETMNTENT1
83
84 #include <mntent.h>
85 #include <sys/types.h>
86 #if defined __ANDROID__
87
88
89 #undef MOUNTED
90 #define MOUNTED "/proc/mounts"
91 #elif !defined MOUNTED
92 #ifdef _PATH_MOUNTED
93 #define MOUNTED _PATH_MOUNTED
94 #endif
95 #ifdef MNT_MNTTAB
96 #define MOUNTED MNT_MNTTAB
97 #endif
98 #endif
99 #endif
100
101 #ifdef MOUNTED_GETMNTINFO
102 #include <sys/mount.h>
103 #endif
104
105 #ifdef MOUNTED_GETMNTINFO2
106 #include <sys/statvfs.h>
107 #endif
108
109 #ifdef MOUNTED_FS_STAT_DEV
110 #include <fs_info.h>
111 #include <dirent.h>
112 #endif
113
114 #ifdef MOUNTED_FREAD_FSTYP
115 #include <mnttab.h>
116 #include <sys/fstyp.h>
117 #include <sys/statfs.h>
118 #endif
119
120 #ifdef MOUNTED_GETEXTMNTENT
121 #include <sys/mnttab.h>
122 #endif
123
124 #ifdef MOUNTED_GETMNTENT2
125 #include <sys/mnttab.h>
126 #endif
127
128 #ifdef MOUNTED_VMOUNT
129 #include <fshelp.h>
130 #include <sys/vfs.h>
131 #endif
132
133 #ifdef MOUNTED_INTERIX_STATVFS
134 #include <sys/statvfs.h>
135 #include <dirent.h>
136 #endif
137
138 #ifdef HAVE_SYS_MNTENT_H
139
140 #include <sys/mntent.h>
141 #endif
142
143 #ifdef MOUNTED_GETMNTENT1
144 #if !HAVE_SETMNTENT
145 #define setmntent(fp, mode) fopen (fp, mode)
146 #endif
147 #if !HAVE_ENDMNTENT
148 #define endmntent(fp) fclose (fp)
149 #endif
150 #endif
151
152 #ifndef HAVE_HASMNTOPT
153 #define hasmntopt(mnt, opt) ((char *) 0)
154 #endif
155
156 #undef MNT_IGNORE
157 #ifdef MNTOPT_IGNORE
158 #if defined __sun && defined __SVR4
159
160
161 #define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
162 #else
163 #define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
164 #endif
165 #else
166 #define MNT_IGNORE(M) 0
167 #endif
168
169 #ifdef HAVE_INFOMOUNT_QNX
170 #include <sys/disk.h>
171 #include <sys/fsys.h>
172 #endif
173
174 #ifdef HAVE_SYS_STATVFS_H
175 #include <sys/statvfs.h>
176 #endif
177
178 #include "lib/global.h"
179 #include "lib/strutil.h"
180 #include "lib/unixcompat.h"
181 #include "mountlist.h"
182
183
184
185
186
187 #if defined(__QNX__) && !defined(__QNXNTO__) && !defined(HAVE_INFOMOUNT_LIST)
188 #define HAVE_INFOMOUNT_QNX
189 #endif
190
191 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
192 #define HAVE_INFOMOUNT
193 #endif
194
195
196
197 #undef opendir
198 #undef closedir
199
200 #define ME_DUMMY_0(Fs_name, Fs_type) \
201 (strcmp (Fs_type, "autofs") == 0 || strcmp (Fs_type, "proc") == 0 \
202 || strcmp (Fs_type, "subfs") == 0 \
203 || strcmp (Fs_type, "debugfs") == 0 || strcmp (Fs_type, "devpts") == 0 \
204 || strcmp (Fs_type, "fusectl") == 0 || strcmp (Fs_type, "fuse.portal") == 0 \
205 || strcmp (Fs_type, "mqueue") == 0 || strcmp (Fs_type, "rpc_pipefs") == 0 \
206 || strcmp (Fs_type, "sysfs") == 0 \
207 || strcmp (Fs_type, "devfs") == 0 \
208 || strcmp (Fs_type, "kernfs") == 0 \
209 || strcmp (Fs_type, "ignore") == 0)
210
211
212
213
214
215 #ifdef MOUNTED_GETMNTENT1
216 #define ME_DUMMY(Fs_name, Fs_type, Bind) \
217 (ME_DUMMY_0 (Fs_name, Fs_type) || (strcmp (Fs_type, "none") == 0 && !Bind))
218 #else
219 #define ME_DUMMY(Fs_name, Fs_type) (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
220 #endif
221
222 #ifdef __CYGWIN__
223 #include <windows.h>
224 #define ME_REMOTE me_remote
225
226
227 static int
228 me_remote (char const *fs_name, char const *fs_type)
229 {
230 (void) fs_type;
231
232 if (fs_name[0] && fs_name[1] == ':')
233 {
234 char drive[4];
235 sprintf (drive, "%c:\\", fs_name[0]);
236 switch (GetDriveType (drive))
237 {
238 case DRIVE_REMOVABLE:
239 case DRIVE_FIXED:
240 case DRIVE_CDROM:
241 case DRIVE_RAMDISK:
242 return 0;
243 }
244 }
245 return 1;
246 }
247 #endif
248 #ifndef ME_REMOTE
249
250
251
252
253
254 #define ME_REMOTE(Fs_name, Fs_type) \
255 (strchr (Fs_name, ':') != NULL \
256 || ((Fs_name)[0] == '/' && (Fs_name)[1] == '/' \
257 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "smb3") == 0 \
258 || strcmp (Fs_type, "cifs") == 0)) \
259 || strcmp (Fs_type, "acfs") == 0 || strcmp (Fs_type, "afs") == 0 \
260 || strcmp (Fs_type, "coda") == 0 || strcmp (Fs_type, "auristorfs") == 0 \
261 || strcmp (Fs_type, "fhgfs") == 0 || strcmp (Fs_type, "gpfs") == 0 \
262 || strcmp (Fs_type, "ibrix") == 0 || strcmp (Fs_type, "ocfs2") == 0 \
263 || strcmp (Fs_type, "vxfs") == 0 || strcmp ("-hosts", Fs_name) == 0)
264 #endif
265
266
267
268
269
270 #define PROPAGATE_ALL_ONES(x) \
271 ((sizeof (x) < sizeof (uintmax_t) \
272 && (~(x) == (sizeof (x) < sizeof (int) ? -(1 << (sizeof (x) * CHAR_BIT)) : 0))) \
273 ? UINTMAX_MAX \
274 : (uintmax_t) (x))
275
276
277 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
278
279
280
281
282
283
284
285
286 #define PROPAGATE_TOP_BIT(x) ((x) | ~(EXTRACT_TOP_BIT (x) - 1))
287
288 #ifdef STAT_STATVFS
289 #if !(defined __linux__ && (defined __GLIBC__ || defined __UCLIBC__))
290
291 #undef STAT_STATFS2_FRSIZE
292 #else
293 #include <sys/utsname.h>
294 #include <sys/statfs.h>
295 #define STAT_STATFS2_BSIZE 1
296 #endif
297 #endif
298
299
300
301
302 struct mount_entry
303 {
304 char *me_devname;
305 char *me_mountdir;
306 char *me_mntroot;
307
308 char *me_type;
309 dev_t me_dev;
310 unsigned int me_dummy : 1;
311 unsigned int me_remote : 1;
312 unsigned int me_type_malloced : 1;
313 };
314
315 struct fs_usage
316 {
317 uintmax_t fsu_blocksize;
318 uintmax_t fsu_blocks;
319 uintmax_t fsu_bfree;
320 uintmax_t fsu_bavail;
321 int fsu_bavail_top_bit_set;
322 uintmax_t fsu_files;
323 uintmax_t fsu_ffree;
324 };
325
326
327
328
329
330 #ifdef HAVE_INFOMOUNT_LIST
331 static GSList *mc_mount_list = NULL;
332 #endif
333
334
335
336
337
338 #ifdef STAT_STATVFS
339
340
341
342
343 static int
344 statvfs_works (void)
345 {
346 #if !(defined __linux__ && (defined __GLIBC__ || defined __UCLIBC__))
347 return 1;
348 #else
349 static int statvfs_works_cache = -1;
350 struct utsname name;
351
352 if (statvfs_works_cache < 0)
353 statvfs_works_cache = (uname (&name) == 0 && 0 <= str_verscmp (name.release, "2.6.36"));
354 return statvfs_works_cache;
355 #endif
356 }
357 #endif
358
359
360
361 #ifdef HAVE_INFOMOUNT_LIST
362 static void
363 free_mount_entry (struct mount_entry *me)
364 {
365 if (me == NULL)
366 return;
367 g_free (me->me_devname);
368 g_free (me->me_mountdir);
369 g_free (me->me_mntroot);
370 if (me->me_type_malloced)
371 g_free (me->me_type);
372 g_free (me);
373 }
374
375
376
377 #ifdef MOUNTED_GETMNTINFO
378
379 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
380 static char *
381 fstype_to_string (short int t)
382 {
383 switch (t)
384 {
385 #ifdef MOUNT_PC
386 case MOUNT_PC:
387 return "pc";
388 #endif
389 #ifdef MOUNT_MFS
390 case MOUNT_MFS:
391 return "mfs";
392 #endif
393 #ifdef MOUNT_LO
394 case MOUNT_LO:
395 return "lo";
396 #endif
397 #ifdef MOUNT_TFS
398 case MOUNT_TFS:
399 return "tfs";
400 #endif
401 #ifdef MOUNT_TMP
402 case MOUNT_TMP:
403 return "tmp";
404 #endif
405 #ifdef MOUNT_UFS
406 case MOUNT_UFS:
407 return "ufs";
408 #endif
409 #ifdef MOUNT_NFS
410 case MOUNT_NFS:
411 return "nfs";
412 #endif
413 #ifdef MOUNT_MSDOS
414 case MOUNT_MSDOS:
415 return "msdos";
416 #endif
417 #ifdef MOUNT_LFS
418 case MOUNT_LFS:
419 return "lfs";
420 #endif
421 #ifdef MOUNT_LOFS
422 case MOUNT_LOFS:
423 return "lofs";
424 #endif
425 #ifdef MOUNT_FDESC
426 case MOUNT_FDESC:
427 return "fdesc";
428 #endif
429 #ifdef MOUNT_PORTAL
430 case MOUNT_PORTAL:
431 return "portal";
432 #endif
433 #ifdef MOUNT_NULL
434 case MOUNT_NULL:
435 return "null";
436 #endif
437 #ifdef MOUNT_UMAP
438 case MOUNT_UMAP:
439 return "umap";
440 #endif
441 #ifdef MOUNT_KERNFS
442 case MOUNT_KERNFS:
443 return "kernfs";
444 #endif
445 #ifdef MOUNT_PROCFS
446 case MOUNT_PROCFS:
447 return "procfs";
448 #endif
449 #ifdef MOUNT_AFS
450 case MOUNT_AFS:
451 return "afs";
452 #endif
453 #ifdef MOUNT_CD9660
454 case MOUNT_CD9660:
455 return "cd9660";
456 #endif
457 #ifdef MOUNT_UNION
458 case MOUNT_UNION:
459 return "union";
460 #endif
461 #ifdef MOUNT_DEVFS
462 case MOUNT_DEVFS:
463 return "devfs";
464 #endif
465 #ifdef MOUNT_EXT2FS
466 case MOUNT_EXT2FS:
467 return "ext2fs";
468 #endif
469 default:
470 return "?";
471 }
472 }
473 #endif
474
475
476
477 static char *
478 fsp_to_string (const struct statfs *fsp)
479 {
480 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
481 return (char *) (fsp->f_fstypename);
482 #else
483 return fstype_to_string (fsp->f_type);
484 #endif
485 }
486 #endif
487
488
489
490 #ifdef MOUNTED_VMOUNT
491 static char *
492 fstype_to_string (int t)
493 {
494 struct vfs_ent *e;
495
496 e = getvfsbytype (t);
497 if (!e || !e->vfsent_name)
498 return "none";
499 else
500 return e->vfsent_name;
501 }
502 #endif
503
504
505
506 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
507
508
509
510
511
512
513 static dev_t
514 dev_from_mount_options (char const *mount_options)
515 {
516
517
518
519 #ifndef __linux__
520 static char const dev_pattern[] = ",dev=";
521 char const *devopt = strstr (mount_options, dev_pattern);
522
523 if (devopt)
524 {
525 char const *optval = devopt + sizeof (dev_pattern) - 1;
526 char *optvalend;
527 unsigned long int dev;
528 errno = 0;
529 dev = strtoul (optval, &optvalend, 16);
530 if (optval != optvalend && (*optvalend == '\0' || *optvalend == ',')
531 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
532 return dev;
533 }
534 #endif
535
536 (void) mount_options;
537 return -1;
538 }
539
540 #endif
541
542
543
544 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__)
545
546
547
548 static void
549 unescape_tab (char *str)
550 {
551 size_t i, j = 0;
552 size_t len;
553
554 len = strlen (str) + 1;
555
556 for (i = 0; i < len; i++)
557 {
558 if (str[i] == '\\' && (i + 4 < len) && str[i + 1] >= '0' && str[i + 1] <= '3'
559 && str[i + 2] >= '0' && str[i + 2] <= '7' && str[i + 3] >= '0' && str[i + 3] <= '7')
560 {
561 str[j++] = (str[i + 1] - '0') * 64 + (str[i + 2] - '0') * 8 + (str[i + 3] - '0');
562 i += 3;
563 }
564 else
565 str[j++] = str[i];
566 }
567 }
568 #endif
569
570
571
572
573
574
575 static GSList *
576 read_file_system_list (void)
577 {
578 GSList *mount_list = NULL;
579 struct mount_entry *me;
580
581 #ifdef MOUNTED_GETMNTENT1
582
583 {
584 FILE *fp;
585
586 #if defined __linux__ || defined __ANDROID__
587
588
589
590
591 char const *mountinfo = "/proc/self/mountinfo";
592
593 fp = fopen (mountinfo, "r");
594 if (fp != NULL)
595 {
596 char *line = NULL;
597 size_t buf_size = 0;
598
599 while (getline (&line, &buf_size, fp) != -1)
600 {
601 unsigned int devmaj, devmin;
602 int target_s, target_e, type_s, type_e;
603 int source_s, source_e, mntroot_s, mntroot_e;
604 char test;
605 char *dash;
606 int rc;
607
608 rc = sscanf (line,
609 "%*u "
610 "%*u "
611 "%u:%u "
612 "%n%*s%n "
613 "%n%*s%n"
614 "%c",
615 &devmaj, &devmin, &mntroot_s, &mntroot_e, &target_s, &target_e, &test);
616
617 if (rc != 3 && rc != 7)
618 continue;
619
620
621 dash = strstr (line + target_e, " - ");
622 if (dash == NULL)
623 continue;
624
625 rc = sscanf (dash,
626 " - "
627 "%n%*s%n "
628 "%n%*s%n "
629 "%c",
630 &type_s, &type_e, &source_s, &source_e, &test);
631 if (rc != 1 && rc != 5)
632 continue;
633
634
635 line[mntroot_e] = '\0';
636 line[target_e] = '\0';
637 dash[type_e] = '\0';
638 dash[source_e] = '\0';
639 unescape_tab (dash + source_s);
640 unescape_tab (line + target_s);
641 unescape_tab (line + mntroot_s);
642
643 me = g_malloc (sizeof *me);
644
645 me->me_devname = g_strdup (dash + source_s);
646 me->me_mountdir = g_strdup (line + target_s);
647 me->me_mntroot = g_strdup (line + mntroot_s);
648 me->me_type = g_strdup (dash + type_s);
649 me->me_type_malloced = 1;
650 me->me_dev = makedev (devmaj, devmin);
651
652
653
654
655 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, FALSE);
656 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
657
658 mount_list = g_slist_prepend (mount_list, me);
659 }
660
661 free (line);
662
663 if (ferror (fp) != 0)
664 {
665 int saved_errno = errno;
666
667 fclose (fp);
668 errno = saved_errno;
669 goto free_then_fail;
670 }
671
672 if (fclose (fp) == EOF)
673 goto free_then_fail;
674 }
675 else
676 #endif
677 {
678 struct mntent *mnt;
679 const char *table = MOUNTED;
680
681 fp = setmntent (table, "r");
682 if (fp == NULL)
683 return NULL;
684
685 while ((mnt = getmntent (fp)) != NULL)
686 {
687 gboolean bind;
688
689 bind = hasmntopt (mnt, "bind") != NULL;
690
691 me = g_malloc (sizeof (*me));
692 me->me_devname = g_strdup (mnt->mnt_fsname);
693 me->me_mountdir = g_strdup (mnt->mnt_dir);
694 me->me_mntroot = NULL;
695 me->me_type = g_strdup (mnt->mnt_type);
696 me->me_type_malloced = 1;
697 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
698 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
699 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
700
701 mount_list = g_slist_prepend (mount_list, me);
702 }
703
704 if (endmntent (fp) == 0)
705 goto free_then_fail;
706 }
707 }
708 #endif
709
710 #ifdef MOUNTED_GETMNTINFO
711 {
712 struct statfs *fsp;
713 int entries;
714
715 entries = getmntinfo (&fsp, MNT_NOWAIT);
716 if (entries < 0)
717 return NULL;
718 for (; entries-- > 0; fsp++)
719 {
720 char *fs_type = fsp_to_string (fsp);
721
722 me = g_malloc (sizeof (*me));
723 me->me_devname = g_strdup (fsp->f_mntfromname);
724 me->me_mountdir = g_strdup (fsp->f_mntonname);
725 me->me_mntroot = NULL;
726 me->me_type = fs_type;
727 me->me_type_malloced = 0;
728 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
729 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
730 me->me_dev = (dev_t) (-1);
731
732 mount_list = g_slist_prepend (mount_list, me);
733 }
734 }
735 #endif
736
737 #ifdef MOUNTED_GETMNTINFO2
738 {
739 struct statvfs *fsp;
740 int entries;
741
742 entries = getmntinfo (&fsp, MNT_NOWAIT);
743 if (entries < 0)
744 return NULL;
745 for (; entries-- > 0; fsp++)
746 {
747 me = g_malloc (sizeof (*me));
748 me->me_devname = g_strdup (fsp->f_mntfromname);
749 me->me_mountdir = g_strdup (fsp->f_mntonname);
750 me->me_mntroot = NULL;
751 me->me_type = g_strdup (fsp->f_fstypename);
752 me->me_type_malloced = 1;
753 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
754 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
755 me->me_dev = (dev_t) (-1);
756
757 mount_list = g_slist_prepend (mount_list, me);
758 }
759 }
760 #endif
761
762 #if defined MOUNTED_FS_STAT_DEV
763 {
764
765
766
767
768
769
770
771
772
773
774 DIR *dirp;
775 struct rootdir_entry
776 {
777 char *name;
778 dev_t dev;
779 ino_t ino;
780 struct rootdir_entry *next;
781 };
782 struct rootdir_entry *rootdir_list;
783 struct rootdir_entry **rootdir_tail;
784 int32 pos;
785 dev_t dev;
786 fs_info fi;
787
788
789 rootdir_list = NULL;
790 rootdir_tail = &rootdir_list;
791 dirp = opendir (PATH_SEP_STR);
792 if (dirp)
793 {
794 struct dirent *d;
795
796 while ((d = readdir (dirp)) != NULL)
797 {
798 char *name;
799 struct stat statbuf;
800
801 if (DIR_IS_DOT (d->d_name))
802 continue;
803
804 if (DIR_IS_DOTDOT (d->d_name))
805 name = g_strdup (PATH_SEP_STR);
806 else
807 name = g_strconcat (PATH_SEP_STR, d->d_name, (char *) NULL);
808
809 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
810 {
811 struct rootdir_entry *re = g_malloc (sizeof (*re));
812 re->name = name;
813 re->dev = statbuf.st_dev;
814 re->ino = statbuf.st_ino;
815
816
817 *rootdir_tail = re;
818 rootdir_tail = &re->next;
819 }
820 else
821 g_free (name);
822 }
823 closedir (dirp);
824 }
825 *rootdir_tail = NULL;
826
827 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
828 if (fs_stat_dev (dev, &fi) >= 0)
829 {
830
831 struct rootdir_entry *re;
832
833 for (re = rootdir_list; re; re = re->next)
834 if (re->dev == fi.dev && re->ino == fi.root)
835 break;
836
837 me = g_malloc (sizeof (*me));
838 me->me_devname =
839 g_strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
840 me->me_mountdir = g_strdup (re != NULL ? re->name : fi.fsh_name);
841 me->me_mntroot = NULL;
842 me->me_type = g_strdup (fi.fsh_name);
843 me->me_type_malloced = 1;
844 me->me_dev = fi.dev;
845 me->me_dummy = 0;
846 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
847
848 mount_list = g_slist_prepend (mount_list, me);
849 }
850
851 while (rootdir_list != NULL)
852 {
853 struct rootdir_entry *re = rootdir_list;
854
855 rootdir_list = re->next;
856 g_free (re->name);
857 g_free (re);
858 }
859 }
860 #endif
861
862 #ifdef MOUNTED_GETFSSTAT
863 {
864 int numsys, counter;
865 size_t bufsize;
866 struct statfs *stats;
867
868 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
869 if (numsys < 0)
870 return NULL;
871 if (SIZE_MAX / sizeof (*stats) <= numsys)
872 {
873 fprintf (stderr, "%s\n", _ ("Memory exhausted!"));
874 exit (EXIT_FAILURE);
875 }
876
877 bufsize = (1 + numsys) * sizeof (*stats);
878 stats = g_malloc (bufsize);
879 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
880
881 if (numsys < 0)
882 {
883 g_free (stats);
884 return NULL;
885 }
886
887 for (counter = 0; counter < numsys; counter++)
888 {
889 me = g_malloc (sizeof (*me));
890 me->me_devname = g_strdup (stats[counter].f_mntfromname);
891 me->me_mountdir = g_strdup (stats[counter].f_mntonname);
892 me->me_mntroot = NULL;
893 me->me_type = g_strdup (FS_TYPE (stats[counter]));
894 me->me_type_malloced = 1;
895 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
896 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
897 me->me_dev = (dev_t) (-1);
898
899 mount_list = g_slist_prepend (mount_list, me);
900 }
901
902 g_free (stats);
903 }
904 #endif
905
906 #if defined MOUNTED_FREAD_FSTYP
907 {
908 struct mnttab mnt;
909 char *table = "/etc/mnttab";
910 FILE *fp;
911
912 fp = fopen (table, "r");
913 if (fp == NULL)
914 return NULL;
915
916 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
917 {
918 me = g_malloc (sizeof (*me));
919 me->me_devname = g_strdup (mnt.mt_dev);
920 me->me_mountdir = g_strdup (mnt.mt_filsys);
921 me->me_mntroot = NULL;
922 me->me_dev = (dev_t) (-1);
923 me->me_type = "";
924 me->me_type_malloced = 0;
925 {
926 struct statfs fsd;
927 char typebuf[FSTYPSZ];
928
929 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
930 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
931 {
932 me->me_type = g_strdup (typebuf);
933 me->me_type_malloced = 1;
934 }
935 }
936 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
937 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
938
939 mount_list = g_slist_prepend (mount_list, me);
940 }
941
942 if (ferror (fp))
943 {
944
945 int saved_errno = errno;
946
947 fclose (fp);
948 errno = saved_errno;
949 goto free_then_fail;
950 }
951
952 if (fclose (fp) == EOF)
953 goto free_then_fail;
954 }
955 #endif
956
957 #ifdef MOUNTED_GETEXTMNTENT
958 {
959 struct extmnttab mnt;
960 const char *table = MNTTAB;
961 FILE *fp;
962 int ret;
963
964
965
966 errno = 0;
967 fp = fopen (table, "r");
968 if (fp == NULL)
969 ret = errno;
970 else
971 {
972 while ((ret = getextmntent (fp, &mnt, 1)) == 0)
973 {
974 me = g_malloc (sizeof *me);
975 me->me_devname = g_strdup (mnt.mnt_special);
976 me->me_mountdir = g_strdup (mnt.mnt_mountp);
977 me->me_mntroot = NULL;
978 me->me_type = g_strdup (mnt.mnt_fstype);
979 me->me_type_malloced = 1;
980 me->me_dummy = MNT_IGNORE (&mnt) != 0;
981 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
982 me->me_dev = makedev (mnt.mnt_major, mnt.mnt_minor);
983
984 mount_list = g_slist_prepend (mount_list, me);
985 }
986
987 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
988
989 }
990
991 if (ret >= 0)
992 {
993 errno = ret;
994 goto free_then_fail;
995 }
996 }
997 #endif
998
999 #ifdef MOUNTED_GETMNTENT2
1000 {
1001 struct mnttab mnt;
1002 const char *table = MNTTAB;
1003 FILE *fp;
1004 int ret;
1005 int lockfd = -1;
1006
1007 #if defined F_RDLCK && defined F_SETLKW
1008
1009
1010
1011
1012 #ifndef MNTTAB_LOCK
1013 #define MNTTAB_LOCK "/etc/.mnttab.lock"
1014 #endif
1015 lockfd = open (MNTTAB_LOCK, O_RDONLY);
1016 if (lockfd >= 0)
1017 {
1018 struct flock flock;
1019
1020 flock.l_type = F_RDLCK;
1021 flock.l_whence = SEEK_SET;
1022 flock.l_start = 0;
1023 flock.l_len = 0;
1024 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
1025 if (errno != EINTR)
1026 {
1027 int saved_errno = errno;
1028 close (lockfd);
1029 errno = saved_errno;
1030 return NULL;
1031 }
1032 }
1033 else if (errno != ENOENT)
1034 return NULL;
1035 #endif
1036
1037 errno = 0;
1038 fp = fopen (table, "r");
1039 if (fp == NULL)
1040 ret = errno;
1041 else
1042 {
1043 while ((ret = getmntent (fp, &mnt)) == 0)
1044 {
1045 me = g_malloc (sizeof (*me));
1046 me->me_devname = g_strdup (mnt.mnt_special);
1047 me->me_mountdir = g_strdup (mnt.mnt_mountp);
1048 me->me_mntroot = NULL;
1049 me->me_type = g_strdup (mnt.mnt_fstype);
1050 me->me_type_malloced = 1;
1051 me->me_dummy = MNT_IGNORE (&mnt) != 0;
1052 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1053 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
1054
1055 mount_list = g_slist_prepend (mount_list, me);
1056 }
1057
1058 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
1059
1060 }
1061
1062 if (lockfd >= 0 && close (lockfd) != 0)
1063 ret = errno;
1064
1065 if (ret >= 0)
1066 {
1067 errno = ret;
1068 goto free_then_fail;
1069 }
1070 }
1071 #endif
1072
1073 #ifdef MOUNTED_VMOUNT
1074 {
1075 int bufsize;
1076 void *entries;
1077 char *thisent;
1078 struct vmount *vmp;
1079 int n_entries;
1080 int i;
1081
1082
1083 entries = &bufsize;
1084 if (mntctl (MCTL_QUERY, sizeof (bufsize), entries) != 0)
1085 return NULL;
1086 entries = g_malloc (bufsize);
1087
1088
1089 n_entries = mntctl (MCTL_QUERY, bufsize, entries);
1090 if (n_entries < 0)
1091 {
1092 int saved_errno = errno;
1093
1094 g_free (entries);
1095 errno = saved_errno;
1096 return NULL;
1097 }
1098
1099 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1100 {
1101 char *options, *ignore;
1102
1103 vmp = (struct vmount *) thisent;
1104 me = g_malloc (sizeof (*me));
1105 if (vmp->vmt_flags & MNT_REMOTE)
1106 {
1107 char *host, *dir;
1108
1109 me->me_remote = 1;
1110
1111 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1112 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1113 me->me_devname = g_strconcat (host, ":", dir, (char *) NULL);
1114 }
1115 else
1116 {
1117 me->me_remote = 0;
1118 me->me_devname = g_strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1119 }
1120 me->me_mountdir = g_strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1121 me->me_mntroot = NULL;
1122 me->me_type = g_strdup (fstype_to_string (vmp->vmt_gfstype));
1123 me->me_type_malloced = 1;
1124 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1125 ignore = strstr (options, "ignore");
1126 me->me_dummy = (ignore && (ignore == options || ignore[-1] == ',')
1127 && (ignore[sizeof ("ignore") - 1] == ','
1128 || ignore[sizeof ("ignore") - 1] == '\0'));
1129 me->me_dev = (dev_t) (-1);
1130
1131 mount_list = g_slist_prepend (mount_list, me);
1132 }
1133 g_free (entries);
1134 }
1135 #endif
1136
1137 #ifdef MOUNTED_INTERIX_STATVFS
1138 {
1139 DIR *dirp = opendir ("/dev/fs");
1140 char node[9 + NAME_MAX];
1141
1142 if (!dirp)
1143 goto free_then_fail;
1144
1145 while (1)
1146 {
1147 struct statvfs dev;
1148 struct dirent entry;
1149 struct dirent *result;
1150
1151 if (readdir_r (dirp, &entry, &result) || result == NULL)
1152 break;
1153
1154 strcpy (node, "/dev/fs/");
1155 strcat (node, entry.d_name);
1156
1157 if (statvfs (node, &dev) == 0)
1158 {
1159 me = g_malloc (sizeof *me);
1160 me->me_devname = g_strdup (dev.f_mntfromname);
1161 me->me_mountdir = g_strdup (dev.f_mntonname);
1162 me->me_mntroot = NULL;
1163 me->me_type = g_strdup (dev.f_fstypename);
1164 me->me_type_malloced = 1;
1165 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1166 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1167 me->me_dev = (dev_t) (-1);
1168
1169 mount_list = g_slist_prepend (mount_list, me);
1170 }
1171 }
1172 closedir (dirp);
1173 }
1174 #endif
1175
1176 return g_slist_reverse (mount_list);
1177
1178 free_then_fail:
1179 MC_UNUSED;
1180 {
1181 int saved_errno = errno;
1182
1183 g_slist_free_full (mount_list, (GDestroyNotify) free_mount_entry);
1184
1185 errno = saved_errno;
1186 return NULL;
1187 }
1188 }
1189 #endif
1190
1191
1192
1193 #ifdef HAVE_INFOMOUNT_QNX
1194
1195
1196
1197
1198
1199
1200
1201 static GSList *
1202 read_file_system_list (void)
1203 {
1204 struct _disk_entry de;
1205 struct statfs fs;
1206 int i, fd;
1207 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1208 struct mount_entry *me = NULL;
1209 static GSList *list = NULL;
1210
1211 if (list != NULL)
1212 {
1213 me = (struct mount_entry *) list->data;
1214
1215 g_free (me->me_devname);
1216 g_free (me->me_mountdir);
1217 g_free (me->me_mntroot);
1218 g_free (me->me_type);
1219 }
1220 else
1221 {
1222 me = (struct mount_entry *) g_malloc (sizeof (struct mount_entry));
1223 list = g_slist_prepend (list, me);
1224 }
1225
1226 if (!getcwd (dir, _POSIX_PATH_MAX))
1227 return (NULL);
1228
1229 fd = open (dir, O_RDONLY);
1230 if (fd == -1)
1231 return (NULL);
1232
1233 i = disk_get_entry (fd, &de);
1234
1235 close (fd);
1236
1237 if (i == -1)
1238 return (NULL);
1239
1240 switch (de.disk_type)
1241 {
1242 case _UNMOUNTED:
1243 tp = "unmounted";
1244 break;
1245 case _FLOPPY:
1246 tp = "Floppy";
1247 break;
1248 case _HARD:
1249 tp = "Hard";
1250 break;
1251 case _RAMDISK:
1252 tp = "Ram";
1253 break;
1254 case _REMOVABLE:
1255 tp = "Removable";
1256 break;
1257 case _TAPE:
1258 tp = "Tape";
1259 break;
1260 case _CDROM:
1261 tp = "CDROM";
1262 break;
1263 default:
1264 tp = "unknown";
1265 }
1266
1267 if (fsys_get_mount_dev (dir, &dev) == -1)
1268 return (NULL);
1269
1270 if (fsys_get_mount_pt (dev, &dir) == -1)
1271 return (NULL);
1272
1273 me->me_devname = g_strdup (dev);
1274 me->me_mountdir = g_strdup (dir);
1275 me->me_mntroot = NULL;
1276 me->me_type = g_strdup (tp);
1277 me->me_dev = de.disk_type;
1278
1279 #ifdef DEBUG
1280 fprintf (stderr,
1281 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1282 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1283 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1284 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1285 #endif
1286
1287 return (list);
1288 }
1289 #endif
1290
1291
1292
1293 #ifdef HAVE_INFOMOUNT
1294
1295
1296
1297
1298
1299
1300
1301 static int
1302 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1303 {
1304 #ifdef STAT_STATVFS
1305
1306 if (statvfs_works ())
1307 {
1308 struct statvfs vfsd;
1309
1310 if (statvfs (file, &vfsd) < 0)
1311 return -1;
1312
1313
1314 fsp->fsu_blocksize = (vfsd.f_frsize ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
1315 : PROPAGATE_ALL_ONES (vfsd.f_bsize));
1316
1317 fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
1318 fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
1319 fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
1320 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
1321 fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
1322 fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
1323 }
1324 else
1325 #endif
1326
1327 {
1328 #if defined STAT_STATVFS64
1329
1330 struct statvfs64 fsd;
1331
1332 if (statvfs64 (file, &fsd) < 0)
1333 return -1;
1334
1335
1336 fsp->fsu_blocksize =
1337 fsd.f_frsize ? PROPAGATE_ALL_ONES (fsd.f_frsize) : PROPAGATE_ALL_ONES (fsd.f_bsize);
1338
1339 #elif defined STAT_STATFS3_OSF1
1340
1341 struct statfs fsd;
1342
1343 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1344 return -1;
1345
1346 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1347
1348 #elif defined STAT_STATFS2_FRSIZE
1349
1350 struct statfs fsd;
1351
1352 if (statfs (file, &fsd) < 0)
1353 return -1;
1354
1355 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
1356
1357 #elif defined STAT_STATFS2_BSIZE
1358
1359
1360
1361 struct statfs fsd;
1362
1363 if (statfs (file, &fsd) < 0)
1364 return -1;
1365
1366 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1367
1368 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1369
1370
1371
1372
1373
1374
1375 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1376 {
1377 fsd.f_blocks = fsd.f_spare[0];
1378 fsd.f_bfree = fsd.f_spare[1];
1379 fsd.f_bavail = fsd.f_spare[2];
1380 }
1381 #endif
1382
1383 #elif defined STAT_STATFS2_FSIZE
1384
1385 struct statfs fsd;
1386
1387 if (statfs (file, &fsd) < 0)
1388 return -1;
1389
1390 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1391
1392 #elif defined STAT_STATFS4
1393
1394 struct statfs fsd;
1395
1396 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1397 return -1;
1398
1399
1400
1401
1402 fsp->fsu_blocksize = 512;
1403 #endif
1404
1405 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 || defined STAT_STATFS2_FRSIZE \
1406 || defined STAT_STATFS2_BSIZE || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1407
1408 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1409 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1410 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1411 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1412 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1413 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1414
1415 #endif
1416 }
1417
1418 (void) disk;
1419
1420 return 0;
1421 }
1422 #endif
1423
1424
1425
1426
1427
1428 void
1429 free_my_statfs (void)
1430 {
1431 #ifdef HAVE_INFOMOUNT_LIST
1432 g_clear_slist (&mc_mount_list, (GDestroyNotify) free_mount_entry);
1433 #endif
1434 }
1435
1436
1437
1438 void
1439 init_my_statfs (void)
1440 {
1441 #ifdef HAVE_INFOMOUNT_LIST
1442 free_my_statfs ();
1443 mc_mount_list = read_file_system_list ();
1444 #endif
1445 }
1446
1447
1448
1449 void
1450 my_statfs (struct my_statfs *myfs_stats, const char *path)
1451 {
1452 #ifdef HAVE_INFOMOUNT_LIST
1453 size_t len = 0;
1454 struct mount_entry *entry = NULL;
1455 GSList *temp;
1456 struct fs_usage fs_use;
1457
1458 for (temp = mc_mount_list; temp != NULL; temp = g_slist_next (temp))
1459 {
1460 struct mount_entry *me;
1461 size_t i;
1462
1463 me = (struct mount_entry *) temp->data;
1464 i = strlen (me->me_mountdir);
1465 if (i > len && (strncmp (path, me->me_mountdir, i) == 0)
1466 && (entry == NULL || IS_PATH_SEP (path[i]) || path[i] == '\0'))
1467 {
1468 len = i;
1469 entry = me;
1470 }
1471 }
1472
1473 if (entry != NULL)
1474 {
1475 memset (&fs_use, 0, sizeof (fs_use));
1476 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1477
1478 myfs_stats->type = entry->me_dev;
1479 myfs_stats->typename = entry->me_type;
1480 myfs_stats->mpoint = entry->me_mountdir;
1481 myfs_stats->mroot = entry->me_mntroot;
1482 myfs_stats->device = entry->me_devname;
1483 myfs_stats->avail =
1484 ((uintmax_t) (getuid () ? fs_use.fsu_bavail : fs_use.fsu_bfree) * fs_use.fsu_blocksize)
1485 >> 10;
1486 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1487 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1488 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1489 }
1490 else
1491 #endif
1492
1493 #ifdef HAVE_INFOMOUNT_QNX
1494
1495
1496
1497
1498
1499 struct mount_entry *entry;
1500 struct fs_usage fs_use;
1501
1502 entry = read_file_system_list ();
1503 if (entry != NULL)
1504 {
1505 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1506
1507 myfs_stats->type = entry->me_dev;
1508 myfs_stats->typename = entry->me_type;
1509 myfs_stats->mpoint = entry->me_mountdir;
1510 myfs_stats->mroot = entry->me_mntroot;
1511 myfs_stats->device = entry->me_devname;
1512
1513 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1514 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1515 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1516 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1517 }
1518 else
1519 #endif
1520 {
1521 myfs_stats->type = 0;
1522 myfs_stats->mpoint = "unknown";
1523 myfs_stats->device = "unknown";
1524 myfs_stats->avail = 0;
1525 myfs_stats->total = 0;
1526 myfs_stats->nfree = 0;
1527 myfs_stats->nodes = 0;
1528 }
1529 }
1530
1531