gunixmounts.c revision 3690cb75a67377a169264e226655d8fa3a5d003a
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2 3/* GIO - GLib Input, Output and Streaming Library 4 * 5 * Copyright (C) 2006-2007 Red Hat, Inc. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General 18 * Public License along with this library; if not, write to the 19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 20 * Boston, MA 02111-1307, USA. 21 * 22 * Author: Alexander Larsson <alexl@redhat.com> 23 */ 24 25#include <config.h> 26 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <sys/wait.h> 30#ifndef HAVE_SYSCTLBYNAME 31#ifdef HAVE_SYS_PARAM_H 32#include <sys/param.h> 33#endif 34#ifdef HAVE_SYS_POLL_H 35#include <sys/poll.h> 36#endif 37#endif 38#ifdef HAVE_POLL_H 39#include <poll.h> 40#endif 41#include <stdio.h> 42#include <unistd.h> 43#include <sys/time.h> 44#include <errno.h> 45#include <string.h> 46#include <signal.h> 47 48#include "gunixmounts.h" 49#include "gfile.h" 50#include "gfilemonitor.h" 51#include "glibintl.h" 52#include "gthemedicon.h" 53 54#include "gioalias.h" 55 56static const char *_resolve_dev_root (void); 57 58/** 59 * SECTION:gunixmounts 60 * @include: gio/gunixmounts.h 61 * @short_description: Unix Mounts 62 * 63 * Routines for managing mounted UNIX mount points and paths. 64 * 65 **/ 66 67/* 68 * GUnixMountType: 69 * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type. 70 * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type. 71 * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type. 72 * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type. 73 * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type. 74 * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type. 75 * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type. 76 * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type. 77 * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type. 78 * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type. 79 * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type. 80 * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type. 81 * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type. 82 * 83 * Types of UNIX mounts. 84 **/ 85typedef enum { 86 G_UNIX_MOUNT_TYPE_UNKNOWN, 87 G_UNIX_MOUNT_TYPE_FLOPPY, 88 G_UNIX_MOUNT_TYPE_CDROM, 89 G_UNIX_MOUNT_TYPE_NFS, 90 G_UNIX_MOUNT_TYPE_ZIP, 91 G_UNIX_MOUNT_TYPE_JAZ, 92 G_UNIX_MOUNT_TYPE_MEMSTICK, 93 G_UNIX_MOUNT_TYPE_CF, 94 G_UNIX_MOUNT_TYPE_SM, 95 G_UNIX_MOUNT_TYPE_SDMMC, 96 G_UNIX_MOUNT_TYPE_IPOD, 97 G_UNIX_MOUNT_TYPE_CAMERA, 98 G_UNIX_MOUNT_TYPE_HD 99} GUnixMountType; 100 101struct _GUnixMountEntry { 102 char *mount_path; 103 char *device_path; 104 char *filesystem_type; 105 gboolean is_read_only; 106 gboolean is_system_internal; 107}; 108 109struct _GUnixMountPoint { 110 char *mount_path; 111 char *device_path; 112 char *filesystem_type; 113 gboolean is_read_only; 114 gboolean is_user_mountable; 115 gboolean is_loopback; 116}; 117 118enum { 119 MOUNTS_CHANGED, 120 MOUNTPOINTS_CHANGED, 121 LAST_SIGNAL 122}; 123 124static guint signals[LAST_SIGNAL]; 125 126struct _GUnixMountMonitor { 127 GObject parent; 128 129 GFileMonitor *fstab_monitor; 130 GFileMonitor *mtab_monitor; 131}; 132 133struct _GUnixMountMonitorClass { 134 GObjectClass parent_class; 135}; 136 137static GUnixMountMonitor *the_mount_monitor = NULL; 138 139static GList *_g_get_unix_mounts (void); 140static GList *_g_get_unix_mount_points (void); 141 142G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT); 143 144#define MOUNT_POLL_INTERVAL 4000 145 146#ifdef HAVE_SYS_MNTTAB_H 147#define MNTOPT_RO "ro" 148#endif 149 150#ifdef HAVE_MNTENT_H 151#include <mntent.h> 152#elif defined (HAVE_SYS_MNTTAB_H) 153#include <sys/mnttab.h> 154#endif 155 156#ifdef HAVE_SYS_VFSTAB_H 157#include <sys/vfstab.h> 158#endif 159 160#if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H) 161#include <sys/mntctl.h> 162#include <sys/vfs.h> 163#include <sys/vmount.h> 164#include <fshelp.h> 165#endif 166 167#if defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H) 168#include <sys/ucred.h> 169#include <sys/mount.h> 170#include <fstab.h> 171#ifdef HAVE_SYS_SYSCTL_H 172#include <sys/sysctl.h> 173#endif 174#endif 175 176#ifndef HAVE_SETMNTENT 177#define setmntent(f,m) fopen(f,m) 178#endif 179#ifndef HAVE_ENDMNTENT 180#define endmntent(f) fclose(f) 181#endif 182 183static gboolean 184is_in (const char *value, const char *set[]) 185{ 186 int i; 187 for (i = 0; set[i] != NULL; i++) 188 { 189 if (strcmp (set[i], value) == 0) 190 return TRUE; 191 } 192 return FALSE; 193} 194 195/** 196 * g_unix_is_mount_path_system_internal: 197 * @mount_path: a mount path, e.g. <filename>/media/disk</filename> 198 * or <filename>/usr</filename> 199 * 200 * Determines if @mount_path is considered an implementation of the 201 * OS. This is primarily used for hiding mountable and mounted volumes 202 * that only are used in the OS and has little to no relevance to the 203 * casual user. 204 * 205 * Returns: %TRUE if @mount_path is considered an implementation detail 206 * of the OS. 207 **/ 208gboolean 209g_unix_is_mount_path_system_internal (const char *mount_path) 210{ 211 const char *ignore_mountpoints[] = { 212 /* Includes all FHS 2.3 toplevel dirs and other specilized 213 * directories that we want to hide from the user. 214 */ 215 "/", /* we already have "Filesystem root" in Nautilus */ 216 "/bin", 217 "/boot", 218 "/dev", 219 "/etc", 220 "/home", 221 "/lib", 222 "/lib64", 223 "/media", 224 "/mnt", 225 "/opt", 226 "/root", 227 "/sbin", 228 "/srv", 229 "/tmp", 230 "/usr", 231 "/usr/local", 232 "/var", 233 "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */ 234 "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */ 235 "/proc", 236 "/sbin", 237 "/net", 238 NULL 239 }; 240 241 if (is_in (mount_path, ignore_mountpoints)) 242 return TRUE; 243 244 if (g_str_has_prefix (mount_path, "/dev") || 245 g_str_has_prefix (mount_path, "/proc") || 246 g_str_has_prefix (mount_path, "/sys")) 247 return TRUE; 248 249 if (strstr (mount_path, "/.gvfs") != NULL) 250 return TRUE; 251 252 return FALSE; 253} 254 255static gboolean 256guess_system_internal (const char *mountpoint, 257 const char *fs, 258 const char *device) 259{ 260 const char *ignore_fs[] = { 261 "auto", 262 "autofs", 263 "devfs", 264 "devpts", 265 "kernfs", 266 "linprocfs", 267 "proc", 268 "procfs", 269 "ptyfs", 270 "rootfs", 271 "selinuxfs", 272 "sysfs", 273 "tmpfs", 274 "usbfs", 275 "nfsd", 276 "rpc_pipefs", 277 NULL 278 }; 279 const char *ignore_devices[] = { 280 "none", 281 "sunrpc", 282 "devpts", 283 "nfsd", 284 "/dev/loop", 285 "/dev/vn", 286 NULL 287 }; 288 289 if (is_in (fs, ignore_fs)) 290 return TRUE; 291 292 if (is_in (device, ignore_devices)) 293 return TRUE; 294 295 if (g_unix_is_mount_path_system_internal (mountpoint)) 296 return TRUE; 297 298 return FALSE; 299} 300 301#ifdef HAVE_MNTENT_H 302 303static char * 304get_mtab_read_file (void) 305{ 306#ifdef _PATH_MOUNTED 307# ifdef __linux__ 308 return "/proc/mounts"; 309# else 310 return _PATH_MOUNTED; 311# endif 312#else 313 return "/etc/mtab"; 314#endif 315} 316 317static char * 318get_mtab_monitor_file (void) 319{ 320#ifdef _PATH_MOUNTED 321 return _PATH_MOUNTED; 322#else 323 return "/etc/mtab"; 324#endif 325} 326 327G_LOCK_DEFINE_STATIC(getmntent); 328 329static GList * 330_g_get_unix_mounts () 331{ 332 struct mntent *mntent; 333 FILE *file; 334 char *read_file; 335 GUnixMountEntry *mount_entry; 336 GHashTable *mounts_hash; 337 GList *return_list; 338 339 read_file = get_mtab_read_file (); 340 341 file = setmntent (read_file, "r"); 342 if (file == NULL) 343 return NULL; 344 345 return_list = NULL; 346 347 mounts_hash = g_hash_table_new (g_str_hash, g_str_equal); 348 349 G_LOCK (getmntent); 350 while ((mntent = getmntent (file)) != NULL) 351 { 352 /* ignore any mnt_fsname that is repeated and begins with a '/' 353 * 354 * We do this to avoid being fooled by --bind mounts, since 355 * these have the same device as the location they bind to. 356 * Its not an ideal solution to the problem, but its likely that 357 * the most important mountpoint is first and the --bind ones after 358 * that aren't as important. So it should work. 359 * 360 * The '/' is to handle procfs, tmpfs and other no device mounts. 361 */ 362 if (mntent->mnt_fsname != NULL && 363 mntent->mnt_fsname[0] == '/' && 364 g_hash_table_lookup (mounts_hash, mntent->mnt_fsname)) 365 continue; 366 367 mount_entry = g_new0 (GUnixMountEntry, 1); 368 mount_entry->mount_path = g_strdup (mntent->mnt_dir); 369 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0) 370 mount_entry->device_path = g_strdup (_resolve_dev_root ()); 371 else 372 mount_entry->device_path = g_strdup (mntent->mnt_fsname); 373 mount_entry->filesystem_type = g_strdup (mntent->mnt_type); 374 375#if defined (HAVE_HASMNTOPT) 376 if (hasmntopt (mntent, MNTOPT_RO) != NULL) 377 mount_entry->is_read_only = TRUE; 378#endif 379 380 mount_entry->is_system_internal = 381 guess_system_internal (mount_entry->mount_path, 382 mount_entry->filesystem_type, 383 mount_entry->device_path); 384 385 g_hash_table_insert (mounts_hash, 386 mount_entry->device_path, 387 mount_entry->device_path); 388 389 return_list = g_list_prepend (return_list, mount_entry); 390 } 391 g_hash_table_destroy (mounts_hash); 392 393 endmntent (file); 394 395 G_UNLOCK (getmntent); 396 397 return g_list_reverse (return_list); 398} 399 400#elif defined (HAVE_SYS_MNTTAB_H) 401 402G_LOCK_DEFINE_STATIC(getmntent); 403 404static char * 405get_mtab_read_file (void) 406{ 407#ifdef _PATH_MOUNTED 408 return _PATH_MOUNTED; 409#else 410 return "/etc/mnttab"; 411#endif 412} 413 414static char * 415get_mtab_monitor_file (void) 416{ 417 return get_mtab_read_file (); 418} 419 420static GList * 421_g_get_unix_mounts (void) 422{ 423 struct mnttab mntent; 424 FILE *file; 425 char *read_file; 426 GUnixMountEntry *mount_entry; 427 GList *return_list; 428 429 read_file = get_mtab_read_file (); 430 431 file = setmntent (read_file, "r"); 432 if (file == NULL) 433 return NULL; 434 435 return_list = NULL; 436 437 G_LOCK (getmntent); 438 while (! getmntent (file, &mntent)) 439 { 440 mount_entry = g_new0 (GUnixMountEntry, 1); 441 442 mount_entry->mount_path = g_strdup (mntent.mnt_mountp); 443 mount_entry->device_path = g_strdup (mntent.mnt_special); 444 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype); 445 446#if defined (HAVE_HASMNTOPT) 447 if (hasmntopt (&mntent, MNTOPT_RO) != NULL) 448 mount_entry->is_read_only = TRUE; 449#endif 450 451 mount_entry->is_system_internal = 452 guess_system_internal (mount_entry->mount_path, 453 mount_entry->filesystem_type, 454 mount_entry->device_path); 455 456 return_list = g_list_prepend (return_list, mount_entry); 457 } 458 459 endmntent (file); 460 461 G_UNLOCK (getmntent); 462 463 return g_list_reverse (return_list); 464} 465 466#elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H) 467 468static char * 469get_mtab_monitor_file (void) 470{ 471 return NULL; 472} 473 474static GList * 475_g_get_unix_mounts (void) 476{ 477 struct vfs_ent *fs_info; 478 struct vmount *vmount_info; 479 int vmount_number; 480 unsigned int vmount_size; 481 int current; 482 GList *return_list; 483 484 if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0) 485 { 486 g_warning ("Unable to know the number of mounted volumes\n"); 487 488 return NULL; 489 } 490 491 vmount_info = (struct vmount*)g_malloc (vmount_size); 492 493 vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info); 494 495 if (vmount_info->vmt_revision != VMT_REVISION) 496 g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision); 497 498 if (vmount_number < 0) 499 { 500 g_warning ("Unable to recover mounted volumes information\n"); 501 502 g_free (vmount_info); 503 return NULL; 504 } 505 506 return_list = NULL; 507 while (vmount_number > 0) 508 { 509 mount_entry = g_new0 (GUnixMountEntry, 1); 510 511 mount_entry->device_path = g_strdup (vmt2dataptr (vmount_info, VMT_OBJECT)); 512 mount_entry->mount_path = g_strdup (vmt2dataptr (vmount_info, VMT_STUB)); 513 /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */ 514 mount_entry->is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0; 515 516 fs_info = getvfsbytype (vmount_info->vmt_gfstype); 517 518 if (fs_info == NULL) 519 mount_entry->filesystem_type = g_strdup ("unknown"); 520 else 521 mount_entry->filesystem_type = g_strdup (fs_info->vfsent_name); 522 523 mount_entry->is_system_internal = 524 guess_system_internal (mount_entry->mount_path, 525 mount_entry->filesystem_type, 526 mount_entry->device_path); 527 528 return_list = g_list_prepend (return_list, mount_entry); 529 530 vmount_info = (struct vmount *)( (char*)vmount_info 531 + vmount_info->vmt_length); 532 vmount_number--; 533 } 534 535 536 g_free (vmount_info); 537 538 return g_list_reverse (return_list); 539} 540 541#elif defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H) 542 543static char * 544get_mtab_monitor_file (void) 545{ 546 return NULL; 547} 548 549static GList * 550_g_get_unix_mounts (void) 551{ 552 struct statfs *mntent = NULL; 553 int num_mounts, i; 554 GUnixMountEntry *mount_entry; 555 GList *return_list; 556 557 /* Pass MNT_NOWAIT to avoid blocking trying to update NFS mounts. */ 558 if ((num_mounts = getmntinfo (&mntent, MNT_NOWAIT)) == 0) 559 return NULL; 560 561 return_list = NULL; 562 563 for (i = 0; i < num_mounts; i++) 564 { 565 mount_entry = g_new0 (GUnixMountEntry, 1); 566 567 mount_entry->mount_path = g_strdup (mntent[i].f_mntonname); 568 mount_entry->device_path = g_strdup (mntent[i].f_mntfromname); 569 mount_entry->filesystem_type = g_strdup (mntent[i].f_fstypename); 570 if (mntent[i].f_flags & MNT_RDONLY) 571 mount_entry->is_read_only = TRUE; 572 573 mount_entry->is_system_internal = 574 guess_system_internal (mount_entry->mount_path, 575 mount_entry->filesystem_type, 576 mount_entry->device_path); 577 578 return_list = g_list_prepend (return_list, mount_entry); 579 } 580 581 return g_list_reverse (return_list); 582} 583#else 584#error No _g_get_unix_mounts() implementation for system 585#endif 586 587/* _g_get_unix_mount_points(): 588 * read the fstab. 589 * don't return swap and ignore mounts. 590 */ 591 592static char * 593get_fstab_file (void) 594{ 595#if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H) 596 /* AIX */ 597 return "/etc/filesystems"; 598#elif defined(_PATH_MNTTAB) 599 return _PATH_MNTTAB; 600#elif defined(VFSTAB) 601 return VFSTAB; 602#else 603 return "/etc/fstab"; 604#endif 605} 606 607#ifdef HAVE_MNTENT_H 608static GList * 609_g_get_unix_mount_points (void) 610{ 611 struct mntent *mntent; 612 FILE *file; 613 char *read_file; 614 GUnixMountPoint *mount_entry; 615 GList *return_list; 616 617 read_file = get_fstab_file (); 618 619 file = setmntent (read_file, "r"); 620 if (file == NULL) 621 return NULL; 622 623 return_list = NULL; 624 625 G_LOCK (getmntent); 626 while ((mntent = getmntent (file)) != NULL) 627 { 628 if ((strcmp (mntent->mnt_dir, "ignore") == 0) || 629 (strcmp (mntent->mnt_dir, "swap") == 0)) 630 continue; 631 632 mount_entry = g_new0 (GUnixMountPoint, 1); 633 mount_entry->mount_path = g_strdup (mntent->mnt_dir); 634 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0) 635 mount_entry->device_path = g_strdup (_resolve_dev_root ()); 636 else 637 mount_entry->device_path = g_strdup (mntent->mnt_fsname); 638 mount_entry->filesystem_type = g_strdup (mntent->mnt_type); 639 640#ifdef HAVE_HASMNTOPT 641 if (hasmntopt (mntent, MNTOPT_RO) != NULL) 642 mount_entry->is_read_only = TRUE; 643 644 if (hasmntopt (mntent, "loop") != NULL) 645 mount_entry->is_loopback = TRUE; 646 647#endif 648 649 if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0) 650#ifdef HAVE_HASMNTOPT 651 || (hasmntopt (mntent, "user") != NULL 652 && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr")) 653 || hasmntopt (mntent, "pamconsole") != NULL 654 || hasmntopt (mntent, "users") != NULL 655 || hasmntopt (mntent, "owner") != NULL 656#endif 657 ) 658 mount_entry->is_user_mountable = TRUE; 659 660 return_list = g_list_prepend (return_list, mount_entry); 661 } 662 663 endmntent (file); 664 G_UNLOCK (getmntent); 665 666 return g_list_reverse (return_list); 667} 668 669#elif defined (HAVE_SYS_MNTTAB_H) 670 671static GList * 672_g_get_unix_mount_points (void) 673{ 674 struct mnttab mntent; 675 FILE *file; 676 char *read_file; 677 GUnixMountPoint *mount_entry; 678 GList *return_list; 679 680 read_file = get_fstab_file (); 681 682 file = setmntent (read_file, "r"); 683 if (file == NULL) 684 return NULL; 685 686 return_list = NULL; 687 688 G_LOCK (getmntent); 689 while (! getmntent (file, &mntent)) 690 { 691 if ((strcmp (mntent.mnt_mountp, "ignore") == 0) || 692 (strcmp (mntent.mnt_mountp, "swap") == 0)) 693 continue; 694 695 mount_entry = g_new0 (GUnixMountPoint, 1); 696 697 mount_entry->mount_path = g_strdup (mntent.mnt_mountp); 698 mount_entry->device_path = g_strdup (mntent.mnt_special); 699 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype); 700 701#ifdef HAVE_HASMNTOPT 702 if (hasmntopt (&mntent, MNTOPT_RO) != NULL) 703 mount_entry->is_read_only = TRUE; 704 705 if (hasmntopt (&mntent, "lofs") != NULL) 706 mount_entry->is_loopback = TRUE; 707#endif 708 709 if ((mntent.mnt_fstype != NULL) 710#ifdef HAVE_HASMNTOPT 711 || (hasmntopt (&mntent, "user") != NULL 712 && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr")) 713 || hasmntopt (&mntent, "pamconsole") != NULL 714 || hasmntopt (&mntent, "users") != NULL 715 || hasmntopt (&mntent, "owner") != NULL 716#endif 717 ) 718 mount_entry->is_user_mountable = TRUE; 719 720 721 return_list = g_list_prepend (return_list, mount_entry); 722 } 723 724 endmntent (file); 725 G_UNLOCK (getmntent); 726 727 return g_list_reverse (return_list); 728} 729#elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H) 730 731/* functions to parse /etc/filesystems on aix */ 732 733/* read character, ignoring comments (begin with '*', end with '\n' */ 734static int 735aix_fs_getc (FILE *fd) 736{ 737 int c; 738 739 while ((c = getc (fd)) == '*') 740 { 741 while (((c = getc (fd)) != '\n') && (c != EOF)) 742 ; 743 } 744} 745 746/* eat all continuous spaces in a file */ 747static int 748aix_fs_ignorespace (FILE *fd) 749{ 750 int c; 751 752 while ((c = aix_fs_getc (fd)) != EOF) 753 { 754 if (!g_ascii_isspace (c)) 755 { 756 ungetc (c,fd); 757 return c; 758 } 759 } 760 761 return EOF; 762} 763 764/* read one word from file */ 765static int 766aix_fs_getword (FILE *fd, 767 char *word) 768{ 769 int c; 770 771 aix_fs_ignorespace (fd); 772 773 while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c)) 774 { 775 if (c == '"') 776 { 777 while (((c = aix_fs_getc (fd)) != EOF) && (c != '"')) 778 *word++ = c; 779 else 780 *word++ = c; 781 } 782 } 783 *word = 0; 784 785 return c; 786} 787 788typedef struct { 789 char mnt_mount[PATH_MAX]; 790 char mnt_special[PATH_MAX]; 791 char mnt_fstype[16]; 792 char mnt_options[128]; 793} AixMountTableEntry; 794 795/* read mount points properties */ 796static int 797aix_fs_get (FILE *fd, 798 AixMountTableEntry *prop) 799{ 800 static char word[PATH_MAX] = { 0 }; 801 char value[PATH_MAX]; 802 803 /* read stanza */ 804 if (word[0] == 0) 805 { 806 if (aix_fs_getword (fd, word) == EOF) 807 return EOF; 808 } 809 810 word[strlen(word) - 1] = 0; 811 strcpy (prop->mnt_mount, word); 812 813 /* read attributes and value */ 814 815 while (aix_fs_getword (fd, word) != EOF) 816 { 817 /* test if is attribute or new stanza */ 818 if (word[strlen(word) - 1] == ':') 819 return 0; 820 821 /* read "=" */ 822 aix_fs_getword (fd, value); 823 824 /* read value */ 825 aix_fs_getword (fd, value); 826 827 if (strcmp (word, "dev") == 0) 828 strcpy (prop->mnt_special, value); 829 else if (strcmp (word, "vfs") == 0) 830 strcpy (prop->mnt_fstype, value); 831 else if (strcmp (word, "options") == 0) 832 strcpy(prop->mnt_options, value); 833 } 834 835 return 0; 836} 837 838static GList * 839_g_get_unix_mount_points (void) 840{ 841 struct mntent *mntent; 842 FILE *file; 843 char *read_file; 844 GUnixMountPoint *mount_entry; 845 AixMountTableEntry mntent; 846 GList *return_list; 847 848 read_file = get_fstab_file (); 849 850 file = setmntent (read_file, "r"); 851 if (file == NULL) 852 return NULL; 853 854 return_list = NULL; 855 856 while (!aix_fs_get (file, &mntent)) 857 { 858 if (strcmp ("cdrfs", mntent.mnt_fstype) == 0) 859 { 860 mount_entry = g_new0 (GUnixMountPoint, 1); 861 862 863 mount_entry->mount_path = g_strdup (mntent.mnt_mount); 864 mount_entry->device_path = g_strdup (mntent.mnt_special); 865 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype); 866 mount_entry->is_read_only = TRUE; 867 mount_entry->is_user_mountable = TRUE; 868 869 return_list = g_list_prepend (return_list, mount_entry); 870 } 871 } 872 873 endmntent (file); 874 875 return g_list_reverse (return_list); 876} 877 878#elif defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H) 879 880static GList * 881_g_get_unix_mount_points (void) 882{ 883 struct fstab *fstab = NULL; 884 GUnixMountPoint *mount_entry; 885 GList *return_list; 886#ifdef HAVE_SYS_SYSCTL_H 887 int usermnt = 0; 888 size_t len = sizeof(usermnt); 889 struct stat sb; 890#endif 891 892 if (!setfsent ()) 893 return NULL; 894 895 return_list = NULL; 896 897#ifdef HAVE_SYS_SYSCTL_H 898#if defined(HAVE_SYSCTLBYNAME) 899 sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0); 900#elif defined(CTL_VFS) && defined(VFS_USERMOUNT) 901 { 902 int mib[2]; 903 904 mib[0] = CTL_VFS; 905 mib[1] = VFS_USERMOUNT; 906 sysctl (mib, 2, &usermnt, &len, NULL, 0); 907 } 908#elif defined(CTL_KERN) && defined(KERN_USERMOUNT) 909 { 910 int mib[2]; 911 912 mib[0] = CTL_KERN; 913 mib[1] = KERN_USERMOUNT; 914 sysctl (mib, 2, &usermnt, &len, NULL, 0); 915 } 916#endif 917#endif 918 919 while ((fstab = getfsent ()) != NULL) 920 { 921 if (strcmp (fstab->fs_vfstype, "swap") == 0) 922 continue; 923 924 mount_entry = g_new0 (GUnixMountPoint, 1); 925 926 mount_entry->mount_path = g_strdup (fstab->fs_file); 927 mount_entry->device_path = g_strdup (fstab->fs_spec); 928 mount_entry->filesystem_type = g_strdup (fstab->fs_vfstype); 929 930 if (strcmp (fstab->fs_type, "ro") == 0) 931 mount_entry->is_read_only = TRUE; 932 933#ifdef HAVE_SYS_SYSCTL_H 934 if (usermnt != 0) 935 { 936 uid_t uid = getuid (); 937 if (stat (fstab->fs_file, &sb) == 0) 938 { 939 if (uid == 0 || sb.st_uid == uid) 940 mount_entry->is_user_mountable = TRUE; 941 } 942 } 943#endif 944 945 return_list = g_list_prepend (return_list, mount_entry); 946 } 947 948 endfsent (); 949 950 return g_list_reverse (return_list); 951} 952#else 953#error No g_get_mount_table() implementation for system 954#endif 955 956static guint64 957get_mounts_timestamp (void) 958{ 959 const char *monitor_file; 960 struct stat buf; 961 962 monitor_file = get_mtab_monitor_file (); 963 if (monitor_file) 964 { 965 if (stat (monitor_file, &buf) == 0) 966 return (guint64)buf.st_mtime; 967 } 968 return 0; 969} 970 971static guint64 972get_mount_points_timestamp (void) 973{ 974 const char *monitor_file; 975 struct stat buf; 976 977 monitor_file = get_fstab_file (); 978 if (monitor_file) 979 { 980 if (stat (monitor_file, &buf) == 0) 981 return (guint64)buf.st_mtime; 982 } 983 return 0; 984} 985 986/** 987 * g_unix_mounts_get: 988 * @time_read: guint64 to contain a timestamp. 989 * 990 * Gets a #GList of strings containing the unix mounts. 991 * If @time_read is set, it will be filled with the mount 992 * timestamp, allowing for checking if the mounts have changed 993 * with g_unix_mounts_changed_since(). 994 * 995 * Returns: a #GList of the UNIX mounts. 996 **/ 997GList * 998g_unix_mounts_get (guint64 *time_read) 999{ 1000 if (time_read) 1001 *time_read = get_mounts_timestamp (); 1002 1003 return _g_get_unix_mounts (); 1004} 1005 1006/** 1007 * g_unix_mount_at: 1008 * @mount_path: path for a possible unix mount. 1009 * @time_read: guint64 to contain a timestamp. 1010 * 1011 * Gets a #GUnixMountEntry for a given mount path. If @time_read 1012 * is set, it will be filled with a unix timestamp for checking 1013 * if the mounts have changed since with g_unix_mounts_changed_since(). 1014 * 1015 * Returns: a #GUnixMount. 1016 **/ 1017GUnixMountEntry * 1018g_unix_mount_at (const char *mount_path, 1019 guint64 *time_read) 1020{ 1021 GList *mounts, *l; 1022 GUnixMountEntry *mount_entry, *found; 1023 1024 mounts = g_unix_mounts_get (time_read); 1025 1026 found = NULL; 1027 for (l = mounts; l != NULL; l = l->next) 1028 { 1029 mount_entry = l->data; 1030 1031 if (strcmp (mount_path, mount_entry->mount_path) == 0) 1032 found = mount_entry; 1033 else 1034 g_unix_mount_free (mount_entry); 1035 1036 } 1037 g_list_free (mounts); 1038 1039 return found; 1040} 1041 1042/** 1043 * g_unix_mount_points_get: 1044 * @time_read: guint64 to contain a timestamp. 1045 * 1046 * Gets a #GList of strings containing the unix mount points. 1047 * If @time_read is set, it will be filled with the mount timestamp, 1048 * allowing for checking if the mounts have changed with 1049 * g_unix_mounts_points_changed_since(). 1050 * 1051 * Returns: a #GList of the UNIX mountpoints. 1052 **/ 1053GList * 1054g_unix_mount_points_get (guint64 *time_read) 1055{ 1056 if (time_read) 1057 *time_read = get_mount_points_timestamp (); 1058 1059 return _g_get_unix_mount_points (); 1060} 1061 1062/** 1063 * g_unix_mounts_changed_since: 1064 * @time: guint64 to contain a timestamp. 1065 * 1066 * Checks if the unix mounts have changed since a given unix time. 1067 * 1068 * Returns: %TRUE if the mounts have changed since @time. 1069 **/ 1070gboolean 1071g_unix_mounts_changed_since (guint64 time) 1072{ 1073 return get_mounts_timestamp () != time; 1074} 1075 1076/** 1077 * g_unix_mount_points_changed_since: 1078 * @time: guint64 to contain a timestamp. 1079 * 1080 * Checks if the unix mount points have changed since a given unix time. 1081 * 1082 * Returns: %TRUE if the mount points have changed since @time. 1083 **/ 1084gboolean 1085g_unix_mount_points_changed_since (guint64 time) 1086{ 1087 return get_mount_points_timestamp () != time; 1088} 1089 1090static void 1091g_unix_mount_monitor_finalize (GObject *object) 1092{ 1093 GUnixMountMonitor *monitor; 1094 1095 monitor = G_UNIX_MOUNT_MONITOR (object); 1096 1097 if (monitor->fstab_monitor) 1098 { 1099 g_file_monitor_cancel (monitor->fstab_monitor); 1100 g_object_unref (monitor->fstab_monitor); 1101 } 1102 1103 if (monitor->mtab_monitor) 1104 { 1105 g_file_monitor_cancel (monitor->mtab_monitor); 1106 g_object_unref (monitor->mtab_monitor); 1107 } 1108 1109 the_mount_monitor = NULL; 1110 1111 if (G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize) 1112 (*G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize) (object); 1113} 1114 1115 1116static void 1117g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass) 1118{ 1119 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 1120 1121 gobject_class->finalize = g_unix_mount_monitor_finalize; 1122 /** 1123 * GUnixMountMonitor::mounts-changed: 1124 * 1125 * Emitted when the unix mounts have changed. 1126 **/ 1127 signals[MOUNTS_CHANGED] = 1128 g_signal_new ("mounts_changed", 1129 G_TYPE_FROM_CLASS (klass), 1130 G_SIGNAL_RUN_LAST, 1131 0, 1132 NULL, NULL, 1133 g_cclosure_marshal_VOID__VOID, 1134 G_TYPE_NONE, 0); 1135 /** 1136 * GUnixMountMonitor::mountpoints-changed: 1137 * 1138 * Emitted when the unix mount points have changed. 1139 **/ 1140 signals[MOUNTPOINTS_CHANGED] = 1141 g_signal_new ("mountpoints_changed", 1142 G_TYPE_FROM_CLASS (klass), 1143 G_SIGNAL_RUN_LAST, 1144 0, 1145 NULL, NULL, 1146 g_cclosure_marshal_VOID__VOID, 1147 G_TYPE_NONE, 0); 1148} 1149 1150static void 1151fstab_file_changed (GFileMonitor *monitor, 1152 GFile *file, 1153 GFile *other_file, 1154 GFileMonitorEvent event_type, 1155 gpointer user_data) 1156{ 1157 GUnixMountMonitor *mount_monitor; 1158 1159 if (event_type != G_FILE_MONITOR_EVENT_CHANGED && 1160 event_type != G_FILE_MONITOR_EVENT_CREATED && 1161 event_type != G_FILE_MONITOR_EVENT_DELETED) 1162 return; 1163 1164 mount_monitor = user_data; 1165 g_signal_emit (mount_monitor, signals[MOUNTPOINTS_CHANGED], 0); 1166} 1167 1168static void 1169mtab_file_changed (GFileMonitor *monitor, 1170 GFile *file, 1171 GFile *other_file, 1172 GFileMonitorEvent event_type, 1173 gpointer user_data) 1174{ 1175 GUnixMountMonitor *mount_monitor; 1176 1177 if (event_type != G_FILE_MONITOR_EVENT_CHANGED && 1178 event_type != G_FILE_MONITOR_EVENT_CREATED && 1179 event_type != G_FILE_MONITOR_EVENT_DELETED) 1180 return; 1181 1182 mount_monitor = user_data; 1183 g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0); 1184} 1185 1186static void 1187g_unix_mount_monitor_init (GUnixMountMonitor *monitor) 1188{ 1189 GFile *file; 1190 1191 if (get_fstab_file () != NULL) 1192 { 1193 file = g_file_new_for_path (get_fstab_file ()); 1194 monitor->fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL); 1195 g_object_unref (file); 1196 1197 g_signal_connect (monitor->fstab_monitor, "changed", (GCallback)fstab_file_changed, monitor); 1198 } 1199 1200 if (get_mtab_monitor_file () != NULL) 1201 { 1202 file = g_file_new_for_path (get_mtab_monitor_file ()); 1203 monitor->mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL); 1204 g_object_unref (file); 1205 1206 g_signal_connect (monitor->mtab_monitor, "changed", (GCallback)mtab_file_changed, monitor); 1207 } 1208} 1209 1210/** 1211 * g_unix_mount_monitor_new: 1212 * 1213 * Gets a new #GUnixMountMonitor. 1214 * 1215 * Returns: a #GUnixMountMonitor. 1216 **/ 1217GUnixMountMonitor * 1218g_unix_mount_monitor_new (void) 1219{ 1220 if (the_mount_monitor == NULL) 1221 { 1222 the_mount_monitor = g_object_new (G_TYPE_UNIX_MOUNT_MONITOR, NULL); 1223 return the_mount_monitor; 1224 } 1225 1226 return g_object_ref (the_mount_monitor); 1227} 1228 1229/** 1230 * g_unix_mount_free: 1231 * @mount_entry: a #GUnixMount. 1232 * 1233 * Frees a unix mount. 1234 **/ 1235void 1236g_unix_mount_free (GUnixMountEntry *mount_entry) 1237{ 1238 g_return_if_fail (mount_entry != NULL); 1239 1240 g_free (mount_entry->mount_path); 1241 g_free (mount_entry->device_path); 1242 g_free (mount_entry->filesystem_type); 1243 g_free (mount_entry); 1244} 1245 1246/** 1247 * g_unix_mount_point_free: 1248 * @mount_point: unix mount point to free. 1249 * 1250 * Frees a unix mount point. 1251 **/ 1252void 1253g_unix_mount_point_free (GUnixMountPoint *mount_point) 1254{ 1255 g_return_if_fail (mount_point != NULL); 1256 1257 g_free (mount_point->mount_path); 1258 g_free (mount_point->device_path); 1259 g_free (mount_point->filesystem_type); 1260 g_free (mount_point); 1261} 1262 1263static int 1264strcmp_null (const char *str1, 1265 const char *str2) 1266{ 1267 if (str1 == str2) 1268 return 0; 1269 if (str1 == NULL && str2 != NULL) 1270 return -1; 1271 if (str1 != NULL && str2 == NULL) 1272 return 1; 1273 return strcmp (str1, str2); 1274} 1275 1276/** 1277 * g_unix_mount_compare: 1278 * @mount1: first #GUnixMountEntry to compare. 1279 * @mount2: second #GUnixMountEntry to compare. 1280 * 1281 * Compares two unix mounts. 1282 * 1283 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to, 1284 * or less than @mount2, respectively. 1285 **/ 1286gint 1287g_unix_mount_compare (GUnixMountEntry *mount1, 1288 GUnixMountEntry *mount2) 1289{ 1290 int res; 1291 1292 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0); 1293 1294 res = strcmp_null (mount1->mount_path, mount2->mount_path); 1295 if (res != 0) 1296 return res; 1297 1298 res = strcmp_null (mount1->device_path, mount2->device_path); 1299 if (res != 0) 1300 return res; 1301 1302 res = strcmp_null (mount1->filesystem_type, mount2->filesystem_type); 1303 if (res != 0) 1304 return res; 1305 1306 res = mount1->is_read_only - mount2->is_read_only; 1307 if (res != 0) 1308 return res; 1309 1310 return 0; 1311} 1312 1313/** 1314 * g_unix_mount_get_mount_path: 1315 * @mount_entry: input #GUnixMountEntry to get the mount path for. 1316 * 1317 * Gets the mount path for a unix mount. 1318 * 1319 * Returns: the mount path for @mount_entry. 1320 **/ 1321const char * 1322g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry) 1323{ 1324 g_return_val_if_fail (mount_entry != NULL, NULL); 1325 1326 return mount_entry->mount_path; 1327} 1328 1329/** 1330 * g_unix_mount_get_device_path: 1331 * @mount_entry: a #GUnixMount. 1332 * 1333 * Gets the device path for a unix mount. 1334 * 1335 * Returns: a string containing the device path. 1336 **/ 1337const char * 1338g_unix_mount_get_device_path (GUnixMountEntry *mount_entry) 1339{ 1340 g_return_val_if_fail (mount_entry != NULL, NULL); 1341 1342 return mount_entry->device_path; 1343} 1344 1345/** 1346 * g_unix_mount_get_fs_type: 1347 * @mount_entry: a #GUnixMount. 1348 * 1349 * Gets the filesystem type for the unix mount. 1350 * 1351 * Returns: a string containing the file system type. 1352 **/ 1353const char * 1354g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry) 1355{ 1356 g_return_val_if_fail (mount_entry != NULL, NULL); 1357 1358 return mount_entry->filesystem_type; 1359} 1360 1361/** 1362 * g_unix_mount_is_readonly: 1363 * @mount_entry: a #GUnixMount. 1364 * 1365 * Checks if a unix mount is mounted read only. 1366 * 1367 * Returns: %TRUE if @mount_entry is read only. 1368 **/ 1369gboolean 1370g_unix_mount_is_readonly (GUnixMountEntry *mount_entry) 1371{ 1372 g_return_val_if_fail (mount_entry != NULL, FALSE); 1373 1374 return mount_entry->is_read_only; 1375} 1376 1377/** 1378 * g_unix_mount_is_system_internal: 1379 * @mount_entry: a #GUnixMount. 1380 * 1381 * Checks if a unix mount is a system path. 1382 * 1383 * Returns: %TRUE if the unix mount is for a system path. 1384 **/ 1385gboolean 1386g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry) 1387{ 1388 g_return_val_if_fail (mount_entry != NULL, FALSE); 1389 1390 return mount_entry->is_system_internal; 1391} 1392 1393/** 1394 * g_unix_mount_point_compare: 1395 * @mount1: a #GUnixMount. 1396 * @mount2: a #GUnixMount. 1397 * 1398 * Compares two unix mount points. 1399 * 1400 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to, 1401 * or less than @mount2, respectively. 1402 **/ 1403gint 1404g_unix_mount_point_compare (GUnixMountPoint *mount1, 1405 GUnixMountPoint *mount2) 1406{ 1407 int res; 1408 1409 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0); 1410 1411 res = strcmp_null (mount1->mount_path, mount2->mount_path); 1412 if (res != 0) 1413 return res; 1414 1415 res = strcmp_null (mount1->device_path, mount2->device_path); 1416 if (res != 0) 1417 return res; 1418 1419 res = strcmp_null (mount1->filesystem_type, mount2->filesystem_type); 1420 if (res != 0) 1421 return res; 1422 1423 res = mount1->is_read_only - mount2->is_read_only; 1424 if (res != 0) 1425 return res; 1426 1427 res = mount1->is_user_mountable - mount2->is_user_mountable; 1428 if (res != 0) 1429 return res; 1430 1431 res = mount1->is_loopback - mount2->is_loopback; 1432 if (res != 0) 1433 return res; 1434 1435 return 0; 1436} 1437 1438/** 1439 * g_unix_mount_point_get_mount_path: 1440 * @mount_point: a #GUnixMountPoint. 1441 * 1442 * Gets the mount path for a unix mount point. 1443 * 1444 * Returns: a string containing the mount path. 1445 **/ 1446const char * 1447g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point) 1448{ 1449 g_return_val_if_fail (mount_point != NULL, NULL); 1450 1451 return mount_point->mount_path; 1452} 1453 1454/** 1455 * g_unix_mount_point_get_device_path: 1456 * @mount_point: a #GUnixMountPoint. 1457 * 1458 * Gets the device path for a unix mount point. 1459 * 1460 * Returns: a string containing the device path. 1461 **/ 1462const char * 1463g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point) 1464{ 1465 g_return_val_if_fail (mount_point != NULL, NULL); 1466 1467 return mount_point->device_path; 1468} 1469 1470/** 1471 * g_unix_mount_point_get_fs_type: 1472 * @mount_point: a #GUnixMountPoint. 1473 * 1474 * Gets the file system type for the mount point. 1475 * 1476 * Returns: a string containing the file system type. 1477 **/ 1478const char * 1479g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point) 1480{ 1481 g_return_val_if_fail (mount_point != NULL, NULL); 1482 1483 return mount_point->filesystem_type; 1484} 1485 1486/** 1487 * g_unix_mount_point_is_readonly: 1488 * @mount_point: a #GUnixMountPoint. 1489 * 1490 * Checks if a unix mount point is read only. 1491 * 1492 * Returns: %TRUE if a mount point is read only. 1493 **/ 1494gboolean 1495g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point) 1496{ 1497 g_return_val_if_fail (mount_point != NULL, FALSE); 1498 1499 return mount_point->is_read_only; 1500} 1501 1502/** 1503 * g_unix_mount_point_is_user_mountable: 1504 * @mount_point: a #GUnixMountPoint. 1505 * 1506 * Checks if a unix mount point is mountable by the user. 1507 * 1508 * Returns: %TRUE if the mount point is user mountable. 1509 **/ 1510gboolean 1511g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point) 1512{ 1513 g_return_val_if_fail (mount_point != NULL, FALSE); 1514 1515 return mount_point->is_user_mountable; 1516} 1517 1518/** 1519 * g_unix_mount_point_is_loopback: 1520 * @mount_point: a #GUnixMountPoint. 1521 * 1522 * Checks if a unix mount point is a loopback device. 1523 * 1524 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise. 1525 **/ 1526gboolean 1527g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point) 1528{ 1529 g_return_val_if_fail (mount_point != NULL, FALSE); 1530 1531 return mount_point->is_loopback; 1532} 1533 1534static GUnixMountType 1535guess_mount_type (const char *mount_path, 1536 const char *device_path, 1537 const char *filesystem_type) 1538{ 1539 GUnixMountType type; 1540 char *basename; 1541 1542 type = G_UNIX_MOUNT_TYPE_UNKNOWN; 1543 1544 if ((strcmp (filesystem_type, "udf") == 0) || 1545 (strcmp (filesystem_type, "iso9660") == 0) || 1546 (strcmp (filesystem_type, "cd9660") == 0)) 1547 type = G_UNIX_MOUNT_TYPE_CDROM; 1548 else if (strcmp (filesystem_type, "nfs") == 0) 1549 type = G_UNIX_MOUNT_TYPE_NFS; 1550 else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") || 1551 g_str_has_prefix (device_path, "/dev/fd") || 1552 g_str_has_prefix (device_path, "/dev/floppy")) 1553 type = G_UNIX_MOUNT_TYPE_FLOPPY; 1554 else if (g_str_has_prefix (device_path, "/dev/cdrom") || 1555 g_str_has_prefix (device_path, "/dev/acd") || 1556 g_str_has_prefix (device_path, "/dev/cd")) 1557 type = G_UNIX_MOUNT_TYPE_CDROM; 1558 else if (g_str_has_prefix (device_path, "/vol/")) 1559 { 1560 const char *name = mount_path + strlen ("/"); 1561 1562 if (g_str_has_prefix (name, "cdrom")) 1563 type = G_UNIX_MOUNT_TYPE_CDROM; 1564 else if (g_str_has_prefix (name, "floppy") || 1565 g_str_has_prefix (device_path, "/vol/dev/diskette/")) 1566 type = G_UNIX_MOUNT_TYPE_FLOPPY; 1567 else if (g_str_has_prefix (name, "rmdisk")) 1568 type = G_UNIX_MOUNT_TYPE_ZIP; 1569 else if (g_str_has_prefix (name, "jaz")) 1570 type = G_UNIX_MOUNT_TYPE_JAZ; 1571 else if (g_str_has_prefix (name, "memstick")) 1572 type = G_UNIX_MOUNT_TYPE_MEMSTICK; 1573 } 1574 else 1575 { 1576 basename = g_path_get_basename (mount_path); 1577 1578 if (g_str_has_prefix (basename, "cdrom") || 1579 g_str_has_prefix (basename, "cdwriter") || 1580 g_str_has_prefix (basename, "burn") || 1581 g_str_has_prefix (basename, "cdr") || 1582 g_str_has_prefix (basename, "cdrw") || 1583 g_str_has_prefix (basename, "dvdrom") || 1584 g_str_has_prefix (basename, "dvdram") || 1585 g_str_has_prefix (basename, "dvdr") || 1586 g_str_has_prefix (basename, "dvdrw") || 1587 g_str_has_prefix (basename, "cdrom_dvdrom") || 1588 g_str_has_prefix (basename, "cdrom_dvdram") || 1589 g_str_has_prefix (basename, "cdrom_dvdr") || 1590 g_str_has_prefix (basename, "cdrom_dvdrw") || 1591 g_str_has_prefix (basename, "cdr_dvdrom") || 1592 g_str_has_prefix (basename, "cdr_dvdram") || 1593 g_str_has_prefix (basename, "cdr_dvdr") || 1594 g_str_has_prefix (basename, "cdr_dvdrw") || 1595 g_str_has_prefix (basename, "cdrw_dvdrom") || 1596 g_str_has_prefix (basename, "cdrw_dvdram") || 1597 g_str_has_prefix (basename, "cdrw_dvdr") || 1598 g_str_has_prefix (basename, "cdrw_dvdrw")) 1599 type = G_UNIX_MOUNT_TYPE_CDROM; 1600 else if (g_str_has_prefix (basename, "floppy")) 1601 type = G_UNIX_MOUNT_TYPE_FLOPPY; 1602 else if (g_str_has_prefix (basename, "zip")) 1603 type = G_UNIX_MOUNT_TYPE_ZIP; 1604 else if (g_str_has_prefix (basename, "jaz")) 1605 type = G_UNIX_MOUNT_TYPE_JAZ; 1606 else if (g_str_has_prefix (basename, "camera")) 1607 type = G_UNIX_MOUNT_TYPE_CAMERA; 1608 else if (g_str_has_prefix (basename, "memstick") || 1609 g_str_has_prefix (basename, "memory_stick") || 1610 g_str_has_prefix (basename, "ram")) 1611 type = G_UNIX_MOUNT_TYPE_MEMSTICK; 1612 else if (g_str_has_prefix (basename, "compact_flash")) 1613 type = G_UNIX_MOUNT_TYPE_CF; 1614 else if (g_str_has_prefix (basename, "smart_media")) 1615 type = G_UNIX_MOUNT_TYPE_SM; 1616 else if (g_str_has_prefix (basename, "sd_mmc")) 1617 type = G_UNIX_MOUNT_TYPE_SDMMC; 1618 else if (g_str_has_prefix (basename, "ipod")) 1619 type = G_UNIX_MOUNT_TYPE_IPOD; 1620 1621 g_free (basename); 1622 } 1623 1624 if (type == G_UNIX_MOUNT_TYPE_UNKNOWN) 1625 type = G_UNIX_MOUNT_TYPE_HD; 1626 1627 return type; 1628} 1629 1630/* 1631 * g_unix_mount_guess_type: 1632 * @mount_entry: a #GUnixMount. 1633 * 1634 * Guesses the type of a unix mount. If the mount type cannot be 1635 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN. 1636 * 1637 * Returns: a #GUnixMountType. 1638 **/ 1639static GUnixMountType 1640g_unix_mount_guess_type (GUnixMountEntry *mount_entry) 1641{ 1642 g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); 1643 g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); 1644 g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); 1645 g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); 1646 1647 return guess_mount_type (mount_entry->mount_path, 1648 mount_entry->device_path, 1649 mount_entry->filesystem_type); 1650} 1651 1652/* 1653 * g_unix_mount_point_guess_type: 1654 * @mount_point: a #GUnixMountPoint. 1655 * 1656 * Guesses the type of a unix mount point. 1657 * If the mount type cannot be determined, 1658 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN. 1659 * 1660 * Returns: a #GUnixMountType. 1661 **/ 1662static GUnixMountType 1663g_unix_mount_point_guess_type (GUnixMountPoint *mount_point) 1664{ 1665 g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); 1666 g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); 1667 g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); 1668 g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN); 1669 1670 return guess_mount_type (mount_point->mount_path, 1671 mount_point->device_path, 1672 mount_point->filesystem_type); 1673} 1674 1675static const char * 1676type_to_icon (GUnixMountType type, gboolean is_mount_point) 1677{ 1678 const char *icon_name; 1679 1680 switch (type) 1681 { 1682 case G_UNIX_MOUNT_TYPE_HD: 1683 if (is_mount_point) 1684 icon_name = "drive-removable-media"; 1685 else 1686 icon_name = "drive-harddisk"; 1687 break; 1688 case G_UNIX_MOUNT_TYPE_FLOPPY: 1689 case G_UNIX_MOUNT_TYPE_ZIP: 1690 case G_UNIX_MOUNT_TYPE_JAZ: 1691 if (is_mount_point) 1692 icon_name = "drive-removable-media"; 1693 else 1694 icon_name = "media-floppy"; 1695 break; 1696 case G_UNIX_MOUNT_TYPE_CDROM: 1697 if (is_mount_point) 1698 icon_name = "drive-optical"; 1699 else 1700 icon_name = "media-optical"; 1701 break; 1702 case G_UNIX_MOUNT_TYPE_NFS: 1703 /* TODO: Would like a better icon here... */ 1704 if (is_mount_point) 1705 icon_name = "drive-removable-media"; 1706 else 1707 icon_name = "drive-harddisk"; 1708 break; 1709 case G_UNIX_MOUNT_TYPE_MEMSTICK: 1710 if (is_mount_point) 1711 icon_name = "drive-removable-media"; 1712 else 1713 icon_name = "media-flash"; 1714 break; 1715 case G_UNIX_MOUNT_TYPE_CAMERA: 1716 if (is_mount_point) 1717 icon_name = "drive-removable-media"; 1718 else 1719 icon_name = "camera-photo"; 1720 break; 1721 case G_UNIX_MOUNT_TYPE_IPOD: 1722 if (is_mount_point) 1723 icon_name = "drive-removable-media"; 1724 else 1725 icon_name = "multimedia-player"; 1726 break; 1727 case G_UNIX_MOUNT_TYPE_UNKNOWN: 1728 default: 1729 if (is_mount_point) 1730 icon_name = "drive-removable-media"; 1731 else 1732 icon_name = "drive-harddisk"; 1733 break; 1734 } 1735 1736 return icon_name; 1737} 1738 1739/** 1740 * g_unix_mount_guess_name: 1741 * @mount_entry: a #GUnixMountEntry 1742 * 1743 * Guesses the name of a Unix mount. 1744 * The result is a translated string. 1745 * 1746 * Returns: A newly allocated string that must 1747 * be freed with g_free() 1748 */ 1749char * 1750g_unix_mount_guess_name (GUnixMountEntry *mount_entry) 1751{ 1752 char *name; 1753 1754 if (strcmp (mount_entry->mount_path, "/") == 0) 1755 name = g_strdup (_("Filesystem root")); 1756 else 1757 name = g_filename_display_basename (mount_entry->mount_path); 1758 1759 return name; 1760} 1761 1762/** 1763 * g_unix_mount_guess_icon: 1764 * @mount_entry: a #GUnixMountEntry 1765 * 1766 * Guesses the icon of a Unix mount. 1767 * 1768 * Returns: a #GIcon 1769 */ 1770GIcon * 1771g_unix_mount_guess_icon (GUnixMountEntry *mount_entry) 1772{ 1773 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE)); 1774} 1775 1776/** 1777 * g_unix_mount_point_guess_name: 1778 * @mount_point: a #GUnixMountPoint 1779 * 1780 * Guesses the name of a Unix mount point. 1781 * The result is a translated string. 1782 * 1783 * Returns: A newly allocated string that must 1784 * be freed with g_free() 1785 */ 1786char * 1787g_unix_mount_point_guess_name (GUnixMountPoint *mount_point) 1788{ 1789 char *name; 1790 1791 if (strcmp (mount_point->mount_path, "/") == 0) 1792 name = g_strdup (_("Filesystem root")); 1793 else 1794 name = g_filename_display_basename (mount_point->mount_path); 1795 1796 return name; 1797} 1798 1799/** 1800 * g_unix_mount_point_guess_icon: 1801 * @mount_point: a #GUnixMountPoint 1802 * 1803 * Guesses the icon of a Unix mount point. 1804 * 1805 * Returns: a #GIcon 1806 */ 1807GIcon * 1808g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point) 1809{ 1810 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE)); 1811} 1812 1813/** 1814 * g_unix_mount_guess_can_eject: 1815 * @mount_entry: a #GUnixMountEntry 1816 * 1817 * Guesses whether a Unix mount can be ejected. 1818 * 1819 * Returns: %TRUE if @mount_entry is deemed to be ejectable. 1820 */ 1821gboolean 1822g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry) 1823{ 1824 GUnixMountType guessed_type; 1825 1826 guessed_type = g_unix_mount_guess_type (mount_entry); 1827 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD || 1828 guessed_type == G_UNIX_MOUNT_TYPE_CDROM) 1829 return TRUE; 1830 1831 return FALSE; 1832} 1833 1834/** 1835 * g_unix_mount_guess_should_display: 1836 * @mount_entry: a #GUnixMountEntry 1837 * 1838 * Guesses whether a Unix mount should be displayed in the UI. 1839 * 1840 * Returns: %TRUE if @mount_entry is deemed to be displayable. 1841 */ 1842gboolean 1843g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry) 1844{ 1845 GUnixMountType guessed_type; 1846 1847 /* Never display internal mountpoints */ 1848 if (g_unix_mount_is_system_internal (mount_entry)) 1849 return FALSE; 1850 1851 /* Only display things that look "removable" or 1852 things in /media (which are generally user mountable) */ 1853 guessed_type = g_unix_mount_guess_type (mount_entry); 1854 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD || 1855 guessed_type == G_UNIX_MOUNT_TYPE_CDROM || 1856 guessed_type == G_UNIX_MOUNT_TYPE_FLOPPY || 1857 guessed_type == G_UNIX_MOUNT_TYPE_ZIP || 1858 guessed_type == G_UNIX_MOUNT_TYPE_JAZ || 1859 guessed_type == G_UNIX_MOUNT_TYPE_CAMERA || 1860 guessed_type == G_UNIX_MOUNT_TYPE_MEMSTICK || 1861 (mount_entry->mount_path != NULL && 1862 g_str_has_prefix (mount_entry->mount_path, "/media"))) 1863 return TRUE; 1864 1865 return FALSE; 1866} 1867 1868/** 1869 * g_unix_mount_point_guess_can_eject: 1870 * @mount_point: a #GUnixMountPoint 1871 * 1872 * Guesses whether a Unix mount point can be ejected. 1873 * 1874 * Returns: %TRUE if @mount_point is deemed to be ejectable. 1875 */ 1876gboolean 1877g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point) 1878{ 1879 GUnixMountType guessed_type; 1880 1881 guessed_type = g_unix_mount_point_guess_type (mount_point); 1882 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD || 1883 guessed_type == G_UNIX_MOUNT_TYPE_CDROM) 1884 return TRUE; 1885 1886 return FALSE; 1887} 1888 1889 1890/* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */ 1891static void 1892_canonicalize_filename (gchar *filename) 1893{ 1894 gchar *p, *q; 1895 gboolean last_was_slash = FALSE; 1896 1897 p = filename; 1898 q = filename; 1899 1900 while (*p) 1901 { 1902 if (*p == G_DIR_SEPARATOR) 1903 { 1904 if (!last_was_slash) 1905 *q++ = G_DIR_SEPARATOR; 1906 1907 last_was_slash = TRUE; 1908 } 1909 else 1910 { 1911 if (last_was_slash && *p == '.') 1912 { 1913 if (*(p + 1) == G_DIR_SEPARATOR || 1914 *(p + 1) == '\0') 1915 { 1916 if (*(p + 1) == '\0') 1917 break; 1918 1919 p += 1; 1920 } 1921 else if (*(p + 1) == '.' && 1922 (*(p + 2) == G_DIR_SEPARATOR || 1923 *(p + 2) == '\0')) 1924 { 1925 if (q > filename + 1) 1926 { 1927 q--; 1928 while (q > filename + 1 && 1929 *(q - 1) != G_DIR_SEPARATOR) 1930 q--; 1931 } 1932 1933 if (*(p + 2) == '\0') 1934 break; 1935 1936 p += 2; 1937 } 1938 else 1939 { 1940 *q++ = *p; 1941 last_was_slash = FALSE; 1942 } 1943 } 1944 else 1945 { 1946 *q++ = *p; 1947 last_was_slash = FALSE; 1948 } 1949 } 1950 1951 p++; 1952 } 1953 1954 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR) 1955 q--; 1956 1957 *q = '\0'; 1958} 1959 1960static char * 1961_resolve_symlink (const char *file) 1962{ 1963 GError *error; 1964 char *dir; 1965 char *link; 1966 char *f; 1967 char *f1; 1968 1969 f = g_strdup (file); 1970 1971 while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) { 1972 link = g_file_read_link (f, &error); 1973 if (link == NULL) { 1974 g_error_free (error); 1975 g_free (f); 1976 f = NULL; 1977 goto out; 1978 } 1979 1980 dir = g_path_get_dirname (f); 1981 f1 = g_strdup_printf ("%s/%s", dir, link); 1982 g_free (dir); 1983 g_free (link); 1984 g_free (f); 1985 f = f1; 1986 } 1987 1988 out: 1989 if (f != NULL) 1990 _canonicalize_filename (f); 1991 return f; 1992} 1993 1994#ifdef HAVE_MNTENT_H 1995static const char * 1996_resolve_dev_root (void) 1997{ 1998 static gboolean have_real_dev_root = FALSE; 1999 static char real_dev_root[256]; 2000 struct stat statbuf; 2001 2002 /* see if it's cached already */ 2003 if (have_real_dev_root) 2004 goto found; 2005 2006 /* otherwise we're going to find it right away.. */ 2007 have_real_dev_root = TRUE; 2008 2009 if (stat ("/dev/root", &statbuf) == 0) { 2010 if (! S_ISLNK (statbuf.st_mode)) { 2011 dev_t root_dev = statbuf.st_dev; 2012 FILE *f; 2013 char buf[1024]; 2014 2015 /* see if device with similar major:minor as /dev/root is mention 2016 * in /etc/mtab (it usually is) 2017 */ 2018 f = fopen ("/etc/mtab", "r"); 2019 if (f != NULL) { 2020 struct mntent ent; 2021 2022 while (getmntent_r (f, &ent, buf, sizeof (buf)) != NULL) { 2023 2024 if (stat (ent.mnt_fsname, &statbuf) == 0 && 2025 statbuf.st_dev == root_dev) { 2026 strncpy (real_dev_root, ent.mnt_fsname, sizeof (real_dev_root) - 1); 2027 real_dev_root[sizeof (real_dev_root) - 1] = '\0'; 2028 fclose (f); 2029 goto found; 2030 } 2031 } 2032 fclose (f); 2033 } 2034 2035 /* no, that didn't work.. next we could scan /dev ... but I digress.. */ 2036 2037 } else { 2038 char *resolved; 2039 resolved = _resolve_symlink ("/dev/root"); 2040 if (resolved != NULL) { 2041 strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1); 2042 real_dev_root[sizeof (real_dev_root) - 1] = '\0'; 2043 g_free (resolved); 2044 goto found; 2045 } 2046 } 2047 } 2048 2049 /* bah sucks.. */ 2050 strcpy (real_dev_root, "/dev/root"); 2051 2052 found: 2053 return real_dev_root; 2054} 2055#endif 2056 2057#define __G_UNIX_MOUNTS_C__ 2058#include "gioaliasdef.c" 2059