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