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
387 case MOUNT_PC:
388 return "pc";
389 #endif
390 #ifdef MOUNT_MFS
391
392 case MOUNT_MFS:
393 return "mfs";
394 #endif
395 #ifdef MOUNT_LO
396
397 case MOUNT_LO:
398 return "lo";
399 #endif
400 #ifdef MOUNT_TFS
401
402 case MOUNT_TFS:
403 return "tfs";
404 #endif
405 #ifdef MOUNT_TMP
406
407 case MOUNT_TMP:
408 return "tmp";
409 #endif
410 #ifdef MOUNT_UFS
411
412 case MOUNT_UFS:
413 return "ufs";
414 #endif
415 #ifdef MOUNT_NFS
416
417 case MOUNT_NFS:
418 return "nfs";
419 #endif
420 #ifdef MOUNT_MSDOS
421
422 case MOUNT_MSDOS:
423 return "msdos";
424 #endif
425 #ifdef MOUNT_LFS
426
427 case MOUNT_LFS:
428 return "lfs";
429 #endif
430 #ifdef MOUNT_LOFS
431
432 case MOUNT_LOFS:
433 return "lofs";
434 #endif
435 #ifdef MOUNT_FDESC
436
437 case MOUNT_FDESC:
438 return "fdesc";
439 #endif
440 #ifdef MOUNT_PORTAL
441
442 case MOUNT_PORTAL:
443 return "portal";
444 #endif
445 #ifdef MOUNT_NULL
446
447 case MOUNT_NULL:
448 return "null";
449 #endif
450 #ifdef MOUNT_UMAP
451
452 case MOUNT_UMAP:
453 return "umap";
454 #endif
455 #ifdef MOUNT_KERNFS
456
457 case MOUNT_KERNFS:
458 return "kernfs";
459 #endif
460 #ifdef MOUNT_PROCFS
461
462 case MOUNT_PROCFS:
463 return "procfs";
464 #endif
465 #ifdef MOUNT_AFS
466
467 case MOUNT_AFS:
468 return "afs";
469 #endif
470 #ifdef MOUNT_CD9660
471
472 case MOUNT_CD9660:
473 return "cd9660";
474 #endif
475 #ifdef MOUNT_UNION
476
477 case MOUNT_UNION:
478 return "union";
479 #endif
480 #ifdef MOUNT_DEVFS
481
482 case MOUNT_DEVFS:
483 return "devfs";
484 #endif
485 #ifdef MOUNT_EXT2FS
486
487 case MOUNT_EXT2FS:
488 return "ext2fs";
489 #endif
490 default:
491 return "?";
492 }
493 }
494 #endif
495
496
497
498 static char *
499 fsp_to_string (const struct statfs *fsp)
500 {
501 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
502 return (char *) (fsp->f_fstypename);
503 #else
504 return fstype_to_string (fsp->f_type);
505 #endif
506 }
507 #endif
508
509
510
511 #ifdef MOUNTED_VMOUNT
512 static char *
513 fstype_to_string (int t)
514 {
515 struct vfs_ent *e;
516
517 e = getvfsbytype (t);
518 if (!e || !e->vfsent_name)
519 return "none";
520 else
521 return e->vfsent_name;
522 }
523 #endif
524
525
526
527 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
528
529
530
531
532
533
534 static dev_t
535 dev_from_mount_options (char const *mount_options)
536 {
537
538
539
540 #ifndef __linux__
541 static char const dev_pattern[] = ",dev=";
542 char const *devopt = strstr (mount_options, dev_pattern);
543
544 if (devopt)
545 {
546 char const *optval = devopt + sizeof (dev_pattern) - 1;
547 char *optvalend;
548 unsigned long int dev;
549 errno = 0;
550 dev = strtoul (optval, &optvalend, 16);
551 if (optval != optvalend && (*optvalend == '\0' || *optvalend == ',')
552 && !(dev == ULONG_MAX && errno == ERANGE) && dev == (dev_t) dev)
553 return dev;
554 }
555 #endif
556
557 (void) mount_options;
558 return -1;
559 }
560
561 #endif
562
563
564
565 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__)
566
567
568
569 static void
570 unescape_tab (char *str)
571 {
572 size_t i, j = 0;
573 size_t len;
574
575 len = strlen (str) + 1;
576
577 for (i = 0; i < len; i++)
578 {
579 if (str[i] == '\\' && (i + 4 < len) && str[i + 1] >= '0' && str[i + 1] <= '3'
580 && str[i + 2] >= '0' && str[i + 2] <= '7' && str[i + 3] >= '0' && str[i + 3] <= '7')
581 {
582 str[j++] = (str[i + 1] - '0') * 64 + (str[i + 2] - '0') * 8 + (str[i + 3] - '0');
583 i += 3;
584 }
585 else
586 str[j++] = str[i];
587 }
588 }
589 #endif
590
591
592
593
594
595
596 static GSList *
597 read_file_system_list (void)
598 {
599 GSList *mount_list = NULL;
600 struct mount_entry *me;
601
602 #ifdef MOUNTED_GETMNTENT1
603
604 {
605 FILE *fp;
606
607 #if defined __linux__ || defined __ANDROID__
608
609
610
611
612 char const *mountinfo = "/proc/self/mountinfo";
613
614 fp = fopen (mountinfo, "r");
615 if (fp != NULL)
616 {
617 char *line = NULL;
618 size_t buf_size = 0;
619
620 while (getline (&line, &buf_size, fp) != -1)
621 {
622 unsigned int devmaj, devmin;
623 int target_s, target_e, type_s, type_e;
624 int source_s, source_e, mntroot_s, mntroot_e;
625 char test;
626 char *dash;
627 int rc;
628
629 rc = sscanf (line,
630 "%*u "
631 "%*u "
632 "%u:%u "
633 "%n%*s%n "
634 "%n%*s%n"
635 "%c",
636 &devmaj, &devmin, &mntroot_s, &mntroot_e, &target_s, &target_e, &test);
637
638 if (rc != 3 && rc != 7)
639 continue;
640
641
642 dash = strstr (line + target_e, " - ");
643 if (dash == NULL)
644 continue;
645
646 rc = sscanf (dash,
647 " - "
648 "%n%*s%n "
649 "%n%*s%n "
650 "%c",
651 &type_s, &type_e, &source_s, &source_e, &test);
652 if (rc != 1 && rc != 5)
653 continue;
654
655
656 line[mntroot_e] = '\0';
657 line[target_e] = '\0';
658 dash[type_e] = '\0';
659 dash[source_e] = '\0';
660 unescape_tab (dash + source_s);
661 unescape_tab (line + target_s);
662 unescape_tab (line + mntroot_s);
663
664 me = g_malloc (sizeof *me);
665
666 me->me_devname = g_strdup (dash + source_s);
667 me->me_mountdir = g_strdup (line + target_s);
668 me->me_mntroot = g_strdup (line + mntroot_s);
669 me->me_type = g_strdup (dash + type_s);
670 me->me_type_malloced = 1;
671 me->me_dev = makedev (devmaj, devmin);
672
673
674
675
676 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, FALSE);
677 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
678
679 mount_list = g_slist_prepend (mount_list, me);
680 }
681
682 free (line);
683
684 if (ferror (fp) != 0)
685 {
686 int saved_errno = errno;
687
688 fclose (fp);
689 errno = saved_errno;
690 goto free_then_fail;
691 }
692
693 if (fclose (fp) == EOF)
694 goto free_then_fail;
695 }
696 else
697 #endif
698 {
699 struct mntent *mnt;
700 const char *table = MOUNTED;
701
702 fp = setmntent (table, "r");
703 if (fp == NULL)
704 return NULL;
705
706 while ((mnt = getmntent (fp)) != NULL)
707 {
708 gboolean bind;
709
710 bind = hasmntopt (mnt, "bind") != NULL;
711
712 me = g_malloc (sizeof (*me));
713 me->me_devname = g_strdup (mnt->mnt_fsname);
714 me->me_mountdir = g_strdup (mnt->mnt_dir);
715 me->me_mntroot = NULL;
716 me->me_type = g_strdup (mnt->mnt_type);
717 me->me_type_malloced = 1;
718 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
719 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
720 me->me_dev = dev_from_mount_options (mnt->mnt_opts);
721
722 mount_list = g_slist_prepend (mount_list, me);
723 }
724
725 if (endmntent (fp) == 0)
726 goto free_then_fail;
727 }
728 }
729 #endif
730
731 #ifdef MOUNTED_GETMNTINFO
732 {
733 struct statfs *fsp;
734 int entries;
735
736 entries = getmntinfo (&fsp, MNT_NOWAIT);
737 if (entries < 0)
738 return NULL;
739 for (; entries-- > 0; fsp++)
740 {
741 char *fs_type = fsp_to_string (fsp);
742
743 me = g_malloc (sizeof (*me));
744 me->me_devname = g_strdup (fsp->f_mntfromname);
745 me->me_mountdir = g_strdup (fsp->f_mntonname);
746 me->me_mntroot = NULL;
747 me->me_type = fs_type;
748 me->me_type_malloced = 0;
749 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
750 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
751 me->me_dev = (dev_t) (-1);
752
753 mount_list = g_slist_prepend (mount_list, me);
754 }
755 }
756 #endif
757
758 #ifdef MOUNTED_GETMNTINFO2
759 {
760 struct statvfs *fsp;
761 int entries;
762
763 entries = getmntinfo (&fsp, MNT_NOWAIT);
764 if (entries < 0)
765 return NULL;
766 for (; entries-- > 0; fsp++)
767 {
768 me = g_malloc (sizeof (*me));
769 me->me_devname = g_strdup (fsp->f_mntfromname);
770 me->me_mountdir = g_strdup (fsp->f_mntonname);
771 me->me_mntroot = NULL;
772 me->me_type = g_strdup (fsp->f_fstypename);
773 me->me_type_malloced = 1;
774 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
775 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
776 me->me_dev = (dev_t) (-1);
777
778 mount_list = g_slist_prepend (mount_list, me);
779 }
780 }
781 #endif
782
783 #if defined MOUNTED_FS_STAT_DEV
784 {
785
786
787
788
789
790
791
792
793
794
795 DIR *dirp;
796 struct rootdir_entry
797 {
798 char *name;
799 dev_t dev;
800 ino_t ino;
801 struct rootdir_entry *next;
802 };
803 struct rootdir_entry *rootdir_list;
804 struct rootdir_entry **rootdir_tail;
805 int32 pos;
806 dev_t dev;
807 fs_info fi;
808
809
810 rootdir_list = NULL;
811 rootdir_tail = &rootdir_list;
812 dirp = opendir (PATH_SEP_STR);
813 if (dirp)
814 {
815 struct dirent *d;
816
817 while ((d = readdir (dirp)) != NULL)
818 {
819 char *name;
820 struct stat statbuf;
821
822 if (DIR_IS_DOT (d->d_name))
823 continue;
824
825 if (DIR_IS_DOTDOT (d->d_name))
826 name = g_strdup (PATH_SEP_STR);
827 else
828 name = g_strconcat (PATH_SEP_STR, d->d_name, (char *) NULL);
829
830 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
831 {
832 struct rootdir_entry *re = g_malloc (sizeof (*re));
833 re->name = name;
834 re->dev = statbuf.st_dev;
835 re->ino = statbuf.st_ino;
836
837
838 *rootdir_tail = re;
839 rootdir_tail = &re->next;
840 }
841 else
842 g_free (name);
843 }
844 closedir (dirp);
845 }
846 *rootdir_tail = NULL;
847
848 for (pos = 0; (dev = next_dev (&pos)) >= 0;)
849 if (fs_stat_dev (dev, &fi) >= 0)
850 {
851
852 struct rootdir_entry *re;
853
854 for (re = rootdir_list; re; re = re->next)
855 if (re->dev == fi.dev && re->ino == fi.root)
856 break;
857
858 me = g_malloc (sizeof (*me));
859 me->me_devname =
860 g_strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
861 me->me_mountdir = g_strdup (re != NULL ? re->name : fi.fsh_name);
862 me->me_mntroot = NULL;
863 me->me_type = g_strdup (fi.fsh_name);
864 me->me_type_malloced = 1;
865 me->me_dev = fi.dev;
866 me->me_dummy = 0;
867 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
868
869 mount_list = g_slist_prepend (mount_list, me);
870 }
871
872 while (rootdir_list != NULL)
873 {
874 struct rootdir_entry *re = rootdir_list;
875
876 rootdir_list = re->next;
877 g_free (re->name);
878 g_free (re);
879 }
880 }
881 #endif
882
883 #ifdef MOUNTED_GETFSSTAT
884 {
885 int numsys, counter;
886 size_t bufsize;
887 struct statfs *stats;
888
889 numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
890 if (numsys < 0)
891 return NULL;
892 if (SIZE_MAX / sizeof (*stats) <= numsys)
893 {
894 fprintf (stderr, "%s\n", _ ("Memory exhausted!"));
895 exit (EXIT_FAILURE);
896 }
897
898 bufsize = (1 + numsys) * sizeof (*stats);
899 stats = g_malloc (bufsize);
900 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
901
902 if (numsys < 0)
903 {
904 g_free (stats);
905 return NULL;
906 }
907
908 for (counter = 0; counter < numsys; counter++)
909 {
910 me = g_malloc (sizeof (*me));
911 me->me_devname = g_strdup (stats[counter].f_mntfromname);
912 me->me_mountdir = g_strdup (stats[counter].f_mntonname);
913 me->me_mntroot = NULL;
914 me->me_type = g_strdup (FS_TYPE (stats[counter]));
915 me->me_type_malloced = 1;
916 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
917 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
918 me->me_dev = (dev_t) (-1);
919
920 mount_list = g_slist_prepend (mount_list, me);
921 }
922
923 g_free (stats);
924 }
925 #endif
926
927 #if defined MOUNTED_FREAD_FSTYP
928 {
929 struct mnttab mnt;
930 char *table = "/etc/mnttab";
931 FILE *fp;
932
933 fp = fopen (table, "r");
934 if (fp == NULL)
935 return NULL;
936
937 while (fread (&mnt, sizeof (mnt), 1, fp) > 0)
938 {
939 me = g_malloc (sizeof (*me));
940 me->me_devname = g_strdup (mnt.mt_dev);
941 me->me_mountdir = g_strdup (mnt.mt_filsys);
942 me->me_mntroot = NULL;
943 me->me_dev = (dev_t) (-1);
944 me->me_type = "";
945 me->me_type_malloced = 0;
946 {
947 struct statfs fsd;
948 char typebuf[FSTYPSZ];
949
950 if (statfs (me->me_mountdir, &fsd, sizeof (fsd), 0) != -1
951 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
952 {
953 me->me_type = g_strdup (typebuf);
954 me->me_type_malloced = 1;
955 }
956 }
957 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
958 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
959
960 mount_list = g_slist_prepend (mount_list, me);
961 }
962
963 if (ferror (fp))
964 {
965
966 int saved_errno = errno;
967
968 fclose (fp);
969 errno = saved_errno;
970 goto free_then_fail;
971 }
972
973 if (fclose (fp) == EOF)
974 goto free_then_fail;
975 }
976 #endif
977
978 #ifdef MOUNTED_GETEXTMNTENT
979 {
980 struct extmnttab mnt;
981 const char *table = MNTTAB;
982 FILE *fp;
983 int ret;
984
985
986
987 errno = 0;
988 fp = fopen (table, "r");
989 if (fp == NULL)
990 ret = errno;
991 else
992 {
993 while ((ret = getextmntent (fp, &mnt, 1)) == 0)
994 {
995 me = g_malloc (sizeof *me);
996 me->me_devname = g_strdup (mnt.mnt_special);
997 me->me_mountdir = g_strdup (mnt.mnt_mountp);
998 me->me_mntroot = NULL;
999 me->me_type = g_strdup (mnt.mnt_fstype);
1000 me->me_type_malloced = 1;
1001 me->me_dummy = MNT_IGNORE (&mnt) != 0;
1002 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1003 me->me_dev = makedev (mnt.mnt_major, mnt.mnt_minor);
1004
1005 mount_list = g_slist_prepend (mount_list, me);
1006 }
1007
1008 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
1009
1010 }
1011
1012 if (ret >= 0)
1013 {
1014 errno = ret;
1015 goto free_then_fail;
1016 }
1017 }
1018 #endif
1019
1020 #ifdef MOUNTED_GETMNTENT2
1021 {
1022 struct mnttab mnt;
1023 const char *table = MNTTAB;
1024 FILE *fp;
1025 int ret;
1026 int lockfd = -1;
1027
1028 #if defined F_RDLCK && defined F_SETLKW
1029
1030
1031
1032
1033 #ifndef MNTTAB_LOCK
1034 #define MNTTAB_LOCK "/etc/.mnttab.lock"
1035 #endif
1036 lockfd = open (MNTTAB_LOCK, O_RDONLY);
1037 if (lockfd >= 0)
1038 {
1039 struct flock flock;
1040
1041 flock.l_type = F_RDLCK;
1042 flock.l_whence = SEEK_SET;
1043 flock.l_start = 0;
1044 flock.l_len = 0;
1045 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
1046 if (errno != EINTR)
1047 {
1048 int saved_errno = errno;
1049 close (lockfd);
1050 errno = saved_errno;
1051 return NULL;
1052 }
1053 }
1054 else if (errno != ENOENT)
1055 return NULL;
1056 #endif
1057
1058 errno = 0;
1059 fp = fopen (table, "r");
1060 if (fp == NULL)
1061 ret = errno;
1062 else
1063 {
1064 while ((ret = getmntent (fp, &mnt)) == 0)
1065 {
1066 me = g_malloc (sizeof (*me));
1067 me->me_devname = g_strdup (mnt.mnt_special);
1068 me->me_mountdir = g_strdup (mnt.mnt_mountp);
1069 me->me_mntroot = NULL;
1070 me->me_type = g_strdup (mnt.mnt_fstype);
1071 me->me_type_malloced = 1;
1072 me->me_dummy = MNT_IGNORE (&mnt) != 0;
1073 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1074 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
1075
1076 mount_list = g_slist_prepend (mount_list, me);
1077 }
1078
1079 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
1080
1081 }
1082
1083 if (lockfd >= 0 && close (lockfd) != 0)
1084 ret = errno;
1085
1086 if (ret >= 0)
1087 {
1088 errno = ret;
1089 goto free_then_fail;
1090 }
1091 }
1092 #endif
1093
1094 #ifdef MOUNTED_VMOUNT
1095 {
1096 int bufsize;
1097 void *entries;
1098 char *thisent;
1099 struct vmount *vmp;
1100 int n_entries;
1101 int i;
1102
1103
1104 entries = &bufsize;
1105 if (mntctl (MCTL_QUERY, sizeof (bufsize), entries) != 0)
1106 return NULL;
1107 entries = g_malloc (bufsize);
1108
1109
1110 n_entries = mntctl (MCTL_QUERY, bufsize, entries);
1111 if (n_entries < 0)
1112 {
1113 int saved_errno = errno;
1114
1115 g_free (entries);
1116 errno = saved_errno;
1117 return NULL;
1118 }
1119
1120 for (i = 0, thisent = entries; i < n_entries; i++, thisent += vmp->vmt_length)
1121 {
1122 char *options, *ignore;
1123
1124 vmp = (struct vmount *) thisent;
1125 me = g_malloc (sizeof (*me));
1126 if (vmp->vmt_flags & MNT_REMOTE)
1127 {
1128 char *host, *dir;
1129
1130 me->me_remote = 1;
1131
1132 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1133 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1134 me->me_devname = g_strconcat (host, ":", dir, (char *) NULL);
1135 }
1136 else
1137 {
1138 me->me_remote = 0;
1139 me->me_devname = g_strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
1140 }
1141 me->me_mountdir = g_strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1142 me->me_mntroot = NULL;
1143 me->me_type = g_strdup (fstype_to_string (vmp->vmt_gfstype));
1144 me->me_type_malloced = 1;
1145 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1146 ignore = strstr (options, "ignore");
1147 me->me_dummy = (ignore && (ignore == options || ignore[-1] == ',')
1148 && (ignore[sizeof ("ignore") - 1] == ','
1149 || ignore[sizeof ("ignore") - 1] == '\0'));
1150 me->me_dev = (dev_t) (-1);
1151
1152 mount_list = g_slist_prepend (mount_list, me);
1153 }
1154 g_free (entries);
1155 }
1156 #endif
1157
1158 #ifdef MOUNTED_INTERIX_STATVFS
1159 {
1160 DIR *dirp = opendir ("/dev/fs");
1161 char node[9 + NAME_MAX];
1162
1163 if (!dirp)
1164 goto free_then_fail;
1165
1166 while (1)
1167 {
1168 struct statvfs dev;
1169 struct dirent entry;
1170 struct dirent *result;
1171
1172 if (readdir_r (dirp, &entry, &result) || result == NULL)
1173 break;
1174
1175 strcpy (node, "/dev/fs/");
1176 strcat (node, entry.d_name);
1177
1178 if (statvfs (node, &dev) == 0)
1179 {
1180 me = g_malloc (sizeof *me);
1181 me->me_devname = g_strdup (dev.f_mntfromname);
1182 me->me_mountdir = g_strdup (dev.f_mntonname);
1183 me->me_mntroot = NULL;
1184 me->me_type = g_strdup (dev.f_fstypename);
1185 me->me_type_malloced = 1;
1186 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1187 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1188 me->me_dev = (dev_t) (-1);
1189
1190 mount_list = g_slist_prepend (mount_list, me);
1191 }
1192 }
1193 closedir (dirp);
1194 }
1195 #endif
1196
1197 return g_slist_reverse (mount_list);
1198
1199 free_then_fail:
1200 MC_UNUSED;
1201 {
1202 int saved_errno = errno;
1203
1204 g_slist_free_full (mount_list, (GDestroyNotify) free_mount_entry);
1205
1206 errno = saved_errno;
1207 return NULL;
1208 }
1209 }
1210 #endif
1211
1212
1213
1214 #ifdef HAVE_INFOMOUNT_QNX
1215
1216
1217
1218
1219
1220
1221
1222 static GSList *
1223 read_file_system_list (void)
1224 {
1225 struct _disk_entry de;
1226 struct statfs fs;
1227 int i, fd;
1228 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
1229 struct mount_entry *me = NULL;
1230 static GSList *list = NULL;
1231
1232 if (list != NULL)
1233 {
1234 me = (struct mount_entry *) list->data;
1235
1236 g_free (me->me_devname);
1237 g_free (me->me_mountdir);
1238 g_free (me->me_mntroot);
1239 g_free (me->me_type);
1240 }
1241 else
1242 {
1243 me = (struct mount_entry *) g_malloc (sizeof (struct mount_entry));
1244 list = g_slist_prepend (list, me);
1245 }
1246
1247 if (!getcwd (dir, _POSIX_PATH_MAX))
1248 return (NULL);
1249
1250 fd = open (dir, O_RDONLY);
1251 if (fd == -1)
1252 return (NULL);
1253
1254 i = disk_get_entry (fd, &de);
1255
1256 close (fd);
1257
1258 if (i == -1)
1259 return (NULL);
1260
1261 switch (de.disk_type)
1262 {
1263 case _UNMOUNTED:
1264 tp = "unmounted";
1265 break;
1266 case _FLOPPY:
1267 tp = "Floppy";
1268 break;
1269 case _HARD:
1270 tp = "Hard";
1271 break;
1272 case _RAMDISK:
1273 tp = "Ram";
1274 break;
1275 case _REMOVABLE:
1276 tp = "Removable";
1277 break;
1278 case _TAPE:
1279 tp = "Tape";
1280 break;
1281 case _CDROM:
1282 tp = "CDROM";
1283 break;
1284 default:
1285 tp = "unknown";
1286 }
1287
1288 if (fsys_get_mount_dev (dir, &dev) == -1)
1289 return (NULL);
1290
1291 if (fsys_get_mount_pt (dev, &dir) == -1)
1292 return (NULL);
1293
1294 me->me_devname = g_strdup (dev);
1295 me->me_mountdir = g_strdup (dir);
1296 me->me_mntroot = NULL;
1297 me->me_type = g_strdup (tp);
1298 me->me_dev = de.disk_type;
1299
1300 #ifdef DEBUG
1301 fprintf (stderr,
1302 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1303 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
1304 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
1305 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
1306 #endif
1307
1308 return (list);
1309 }
1310 #endif
1311
1312
1313
1314 #ifdef HAVE_INFOMOUNT
1315
1316
1317
1318
1319
1320
1321
1322 static int
1323 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
1324 {
1325 #ifdef STAT_STATVFS
1326
1327 if (statvfs_works ())
1328 {
1329 struct statvfs vfsd;
1330
1331 if (statvfs (file, &vfsd) < 0)
1332 return -1;
1333
1334
1335 fsp->fsu_blocksize = (vfsd.f_frsize ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
1336 : PROPAGATE_ALL_ONES (vfsd.f_bsize));
1337
1338 fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
1339 fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
1340 fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
1341 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
1342 fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
1343 fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
1344 }
1345 else
1346 #endif
1347
1348 {
1349 #if defined STAT_STATVFS64
1350
1351 struct statvfs64 fsd;
1352
1353 if (statvfs64 (file, &fsd) < 0)
1354 return -1;
1355
1356
1357 fsp->fsu_blocksize =
1358 fsd.f_frsize ? PROPAGATE_ALL_ONES (fsd.f_frsize) : PROPAGATE_ALL_ONES (fsd.f_bsize);
1359
1360 #elif defined STAT_STATFS3_OSF1
1361
1362 struct statfs fsd;
1363
1364 if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
1365 return -1;
1366
1367 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1368
1369 #elif defined STAT_STATFS2_FRSIZE
1370
1371 struct statfs fsd;
1372
1373 if (statfs (file, &fsd) < 0)
1374 return -1;
1375
1376 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
1377
1378 #elif defined STAT_STATFS2_BSIZE
1379
1380
1381
1382 struct statfs fsd;
1383
1384 if (statfs (file, &fsd) < 0)
1385 return -1;
1386
1387 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
1388
1389 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1390
1391
1392
1393
1394
1395
1396 if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
1397 {
1398 fsd.f_blocks = fsd.f_spare[0];
1399 fsd.f_bfree = fsd.f_spare[1];
1400 fsd.f_bavail = fsd.f_spare[2];
1401 }
1402 #endif
1403
1404 #elif defined STAT_STATFS2_FSIZE
1405
1406 struct statfs fsd;
1407
1408 if (statfs (file, &fsd) < 0)
1409 return -1;
1410
1411 fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
1412
1413 #elif defined STAT_STATFS4
1414
1415 struct statfs fsd;
1416
1417 if (statfs (file, &fsd, sizeof (fsd), 0) < 0)
1418 return -1;
1419
1420
1421
1422
1423 fsp->fsu_blocksize = 512;
1424 #endif
1425
1426 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 || defined STAT_STATFS2_FRSIZE \
1427 || defined STAT_STATFS2_BSIZE || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1428
1429 fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
1430 fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
1431 fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
1432 fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
1433 fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
1434 fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
1435
1436 #endif
1437 }
1438
1439 (void) disk;
1440
1441 return 0;
1442 }
1443 #endif
1444
1445
1446
1447
1448
1449 void
1450 free_my_statfs (void)
1451 {
1452 #ifdef HAVE_INFOMOUNT_LIST
1453 g_clear_slist (&mc_mount_list, (GDestroyNotify) free_mount_entry);
1454 #endif
1455 }
1456
1457
1458
1459 void
1460 init_my_statfs (void)
1461 {
1462 #ifdef HAVE_INFOMOUNT_LIST
1463 free_my_statfs ();
1464 mc_mount_list = read_file_system_list ();
1465 #endif
1466 }
1467
1468
1469
1470 void
1471 my_statfs (struct my_statfs *myfs_stats, const char *path)
1472 {
1473 #ifdef HAVE_INFOMOUNT_LIST
1474 size_t len = 0;
1475 struct mount_entry *entry = NULL;
1476 GSList *temp;
1477 struct fs_usage fs_use;
1478
1479 for (temp = mc_mount_list; temp != NULL; temp = g_slist_next (temp))
1480 {
1481 struct mount_entry *me;
1482 size_t i;
1483
1484 me = (struct mount_entry *) temp->data;
1485 i = strlen (me->me_mountdir);
1486 if (i > len && (strncmp (path, me->me_mountdir, i) == 0)
1487 && (entry == NULL || IS_PATH_SEP (path[i]) || path[i] == '\0'))
1488 {
1489 len = i;
1490 entry = me;
1491 }
1492 }
1493
1494 if (entry != NULL)
1495 {
1496 memset (&fs_use, 0, sizeof (fs_use));
1497 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1498
1499 myfs_stats->type = entry->me_dev;
1500 myfs_stats->typename = entry->me_type;
1501 myfs_stats->mpoint = entry->me_mountdir;
1502 myfs_stats->mroot = entry->me_mntroot;
1503 myfs_stats->device = entry->me_devname;
1504 myfs_stats->avail =
1505 ((uintmax_t) (getuid () ? fs_use.fsu_bavail : fs_use.fsu_bfree) * fs_use.fsu_blocksize)
1506 >> 10;
1507 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1508 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1509 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1510 }
1511 else
1512 #endif
1513
1514 #ifdef HAVE_INFOMOUNT_QNX
1515
1516
1517
1518
1519
1520 struct mount_entry *entry;
1521 struct fs_usage fs_use;
1522
1523 entry = read_file_system_list ();
1524 if (entry != NULL)
1525 {
1526 get_fs_usage (entry->me_mountdir, NULL, &fs_use);
1527
1528 myfs_stats->type = entry->me_dev;
1529 myfs_stats->typename = entry->me_type;
1530 myfs_stats->mpoint = entry->me_mountdir;
1531 myfs_stats->mroot = entry->me_mntroot;
1532 myfs_stats->device = entry->me_devname;
1533
1534 myfs_stats->avail = ((uintmax_t) fs_use.fsu_bfree * fs_use.fsu_blocksize) >> 10;
1535 myfs_stats->total = ((uintmax_t) fs_use.fsu_blocks * fs_use.fsu_blocksize) >> 10;
1536 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
1537 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
1538 }
1539 else
1540 #endif
1541 {
1542 myfs_stats->type = 0;
1543 myfs_stats->mpoint = "unknown";
1544 myfs_stats->device = "unknown";
1545 myfs_stats->avail = 0;
1546 myfs_stats->total = 0;
1547 myfs_stats->nfree = 0;
1548 myfs_stats->nodes = 0;
1549 }
1550 }
1551
1552