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