1/* mountlist.c -- return a list of mounted file systems 2 3 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 4 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19#include <config.h> 20 21#include "mountlist.h" 22 23#include <limits.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27 28#include "xalloc.h" 29 30#include <errno.h> 31 32#include <fcntl.h> 33 34#include <unistd.h> 35 36#if HAVE_SYS_PARAM_H 37# include <sys/param.h> 38#endif 39 40#if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ 41# if HAVE_SYS_UCRED_H 42# include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS, 43 NGROUPS is used as an array dimension in ucred.h */ 44# include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */ 45# endif 46# if HAVE_SYS_MOUNT_H 47# include <sys/mount.h> 48# endif 49# if HAVE_SYS_FS_TYPES_H 50# include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */ 51# endif 52# if HAVE_STRUCT_FSSTAT_F_FSTYPENAME 53# define FS_TYPE(Ent) ((Ent).f_fstypename) 54# else 55# define FS_TYPE(Ent) mnt_names[(Ent).f_type] 56# endif 57#endif /* MOUNTED_GETFSSTAT */ 58 59#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ 60# include <mntent.h> 61# if !defined MOUNTED 62# if defined _PATH_MOUNTED /* GNU libc */ 63# define MOUNTED _PATH_MOUNTED 64# endif 65# if defined MNT_MNTTAB /* HP-UX. */ 66# define MOUNTED MNT_MNTTAB 67# endif 68# if defined MNTTABNAME /* Dynix. */ 69# define MOUNTED MNTTABNAME 70# endif 71# endif 72#endif 73 74#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ 75# include <sys/mount.h> 76#endif 77 78#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ 79# include <sys/statvfs.h> 80#endif 81 82#ifdef MOUNTED_GETMNT /* Ultrix. */ 83# include <sys/mount.h> 84# include <sys/fs_types.h> 85#endif 86 87#ifdef MOUNTED_FS_STAT_DEV /* BeOS. */ 88# include <fs_info.h> 89# include <dirent.h> 90#endif 91 92#ifdef MOUNTED_FREAD /* SVR2. */ 93# include <mnttab.h> 94#endif 95 96#ifdef MOUNTED_FREAD_FSTYP /* SVR3. */ 97# include <mnttab.h> 98# include <sys/fstyp.h> 99# include <sys/statfs.h> 100#endif 101 102#ifdef MOUNTED_LISTMNTENT 103# include <mntent.h> 104#endif 105 106#ifdef MOUNTED_GETMNTENT2 /* SVR4. */ 107# include <sys/mnttab.h> 108#endif 109 110#ifdef MOUNTED_VMOUNT /* AIX. */ 111# include <fshelp.h> 112# include <sys/vfs.h> 113#endif 114 115#ifdef DOLPHIN 116/* So special that it's not worth putting this in autoconf. */ 117# undef MOUNTED_FREAD_FSTYP 118# define MOUNTED_GETMNTTBL 119#endif 120 121#if HAVE_SYS_MNTENT_H 122/* This is to get MNTOPT_IGNORE on e.g. SVR4. */ 123# include <sys/mntent.h> 124#endif 125 126#undef MNT_IGNORE 127#if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT 128# define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE) 129#else 130# define MNT_IGNORE(M) 0 131#endif 132 133#if USE_UNLOCKED_IO 134# include "unlocked-io.h" 135#endif 136 137#ifndef SIZE_MAX 138# define SIZE_MAX ((size_t) -1) 139#endif 140 141/* The results of open() in this file are not used with fchdir, 142 therefore save some unnecessary work in fchdir.c. */ 143#undef open 144#undef close 145 146/* The results of opendir() in this file are not used with dirfd and fchdir, 147 therefore save some unnecessary work in fchdir.c. */ 148#undef opendir 149#undef closedir 150 151#ifndef ME_DUMMY 152# define ME_DUMMY(Fs_name, Fs_type) \ 153 (strcmp (Fs_type, "autofs") == 0 \ 154 || strcmp (Fs_type, "none") == 0 \ 155 || strcmp (Fs_type, "proc") == 0 \ 156 || strcmp (Fs_type, "subfs") == 0 \ 157 /* for NetBSD 3.0 */ \ 158 || strcmp (Fs_type, "kernfs") == 0 \ 159 /* for Irix 6.5 */ \ 160 || strcmp (Fs_type, "ignore") == 0) 161#endif 162 163#ifndef ME_REMOTE 164/* A file system is `remote' if its Fs_name contains a `:' 165 or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */ 166# define ME_REMOTE(Fs_name, Fs_type) \ 167 (strchr (Fs_name, ':') != NULL \ 168 || ((Fs_name)[0] == '/' \ 169 && (Fs_name)[1] == '/' \ 170 && (strcmp (Fs_type, "smbfs") == 0 \ 171 || strcmp (Fs_type, "cifs") == 0))) 172#endif 173 174#if MOUNTED_GETMNTINFO 175 176# if ! HAVE_STRUCT_STATFS_F_FSTYPENAME 177static char * 178fstype_to_string (short int t) 179{ 180 switch (t) 181 { 182# ifdef MOUNT_PC 183 case MOUNT_PC: 184 return "pc"; 185# endif 186# ifdef MOUNT_MFS 187 case MOUNT_MFS: 188 return "mfs"; 189# endif 190# ifdef MOUNT_LO 191 case MOUNT_LO: 192 return "lo"; 193# endif 194# ifdef MOUNT_TFS 195 case MOUNT_TFS: 196 return "tfs"; 197# endif 198# ifdef MOUNT_TMP 199 case MOUNT_TMP: 200 return "tmp"; 201# endif 202# ifdef MOUNT_UFS 203 case MOUNT_UFS: 204 return "ufs" ; 205# endif 206# ifdef MOUNT_NFS 207 case MOUNT_NFS: 208 return "nfs" ; 209# endif 210# ifdef MOUNT_MSDOS 211 case MOUNT_MSDOS: 212 return "msdos" ; 213# endif 214# ifdef MOUNT_LFS 215 case MOUNT_LFS: 216 return "lfs" ; 217# endif 218# ifdef MOUNT_LOFS 219 case MOUNT_LOFS: 220 return "lofs" ; 221# endif 222# ifdef MOUNT_FDESC 223 case MOUNT_FDESC: 224 return "fdesc" ; 225# endif 226# ifdef MOUNT_PORTAL 227 case MOUNT_PORTAL: 228 return "portal" ; 229# endif 230# ifdef MOUNT_NULL 231 case MOUNT_NULL: 232 return "null" ; 233# endif 234# ifdef MOUNT_UMAP 235 case MOUNT_UMAP: 236 return "umap" ; 237# endif 238# ifdef MOUNT_KERNFS 239 case MOUNT_KERNFS: 240 return "kernfs" ; 241# endif 242# ifdef MOUNT_PROCFS 243 case MOUNT_PROCFS: 244 return "procfs" ; 245# endif 246# ifdef MOUNT_AFS 247 case MOUNT_AFS: 248 return "afs" ; 249# endif 250# ifdef MOUNT_CD9660 251 case MOUNT_CD9660: 252 return "cd9660" ; 253# endif 254# ifdef MOUNT_UNION 255 case MOUNT_UNION: 256 return "union" ; 257# endif 258# ifdef MOUNT_DEVFS 259 case MOUNT_DEVFS: 260 return "devfs" ; 261# endif 262# ifdef MOUNT_EXT2FS 263 case MOUNT_EXT2FS: 264 return "ext2fs" ; 265# endif 266 default: 267 return "?"; 268 } 269} 270# endif 271 272static char * 273fsp_to_string (const struct statfs *fsp) 274{ 275# if HAVE_STRUCT_STATFS_F_FSTYPENAME 276 return (char *) (fsp->f_fstypename); 277# else 278 return fstype_to_string (fsp->f_type); 279# endif 280} 281 282#endif /* MOUNTED_GETMNTINFO */ 283 284#ifdef MOUNTED_VMOUNT /* AIX. */ 285static char * 286fstype_to_string (int t) 287{ 288 struct vfs_ent *e; 289 290 e = getvfsbytype (t); 291 if (!e || !e->vfsent_name) 292 return "none"; 293 else 294 return e->vfsent_name; 295} 296#endif /* MOUNTED_VMOUNT */ 297 298 299#if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2 300 301/* Return the device number from MOUNT_OPTIONS, if possible. 302 Otherwise return (dev_t) -1. */ 303 304static dev_t 305dev_from_mount_options (char const *mount_options) 306{ 307 /* GNU/Linux allows file system implementations to define their own 308 meaning for "dev=" mount options, so don't trust the meaning 309 here. */ 310# ifndef __linux__ 311 312 static char const dev_pattern[] = ",dev="; 313 char const *devopt = strstr (mount_options, dev_pattern); 314 315 if (devopt) 316 { 317 char const *optval = devopt + sizeof dev_pattern - 1; 318 char *optvalend; 319 unsigned long int dev; 320 errno = 0; 321 dev = strtoul (optval, &optvalend, 16); 322 if (optval != optvalend 323 && (*optvalend == '\0' || *optvalend == ',') 324 && ! (dev == ULONG_MAX && errno == ERANGE) 325 && dev == (dev_t) dev) 326 return dev; 327 } 328 329# endif 330 331 return -1; 332} 333 334#endif 335 336/* Return a list of the currently mounted file systems, or NULL on error. 337 Add each entry to the tail of the list so that they stay in order. 338 If NEED_FS_TYPE is true, ensure that the file system type fields in 339 the returned list are valid. Otherwise, they might not be. */ 340 341struct mount_entry * 342read_file_system_list (bool need_fs_type) 343{ 344 struct mount_entry *mount_list; 345 struct mount_entry *me; 346 struct mount_entry **mtail = &mount_list; 347 348#ifdef MOUNTED_LISTMNTENT 349 { 350 struct tabmntent *mntlist, *p; 351 struct mntent *mnt; 352 struct mount_entry *me; 353 354 /* the third and fourth arguments could be used to filter mounts, 355 but Crays doesn't seem to have any mounts that we want to 356 remove. Specifically, automount create normal NFS mounts. 357 */ 358 359 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0) 360 return NULL; 361 for (p = mntlist; p; p = p->next) { 362 mnt = p->ment; 363 me = xmalloc (sizeof *me); 364 me->me_devname = xstrdup (mnt->mnt_fsname); 365 me->me_mountdir = xstrdup (mnt->mnt_dir); 366 me->me_type = xstrdup (mnt->mnt_type); 367 me->me_type_malloced = 1; 368 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); 369 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 370 me->me_dev = -1; 371 *mtail = me; 372 mtail = &me->me_next; 373 } 374 freemntlist (mntlist); 375 } 376#endif 377 378#ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ 379 { 380 struct mntent *mnt; 381 char *table = MOUNTED; 382 FILE *fp; 383 384 fp = setmntent (table, "r"); 385 if (fp == NULL) 386 return NULL; 387 388 while ((mnt = getmntent (fp))) 389 { 390 me = xmalloc (sizeof *me); 391 me->me_devname = xstrdup (mnt->mnt_fsname); 392 me->me_mountdir = xstrdup (mnt->mnt_dir); 393 me->me_type = xstrdup (mnt->mnt_type); 394 me->me_type_malloced = 1; 395 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); 396 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 397 me->me_dev = dev_from_mount_options (mnt->mnt_opts); 398 399 /* Add to the linked list. */ 400 *mtail = me; 401 mtail = &me->me_next; 402 } 403 404 if (endmntent (fp) == 0) 405 goto free_then_fail; 406 } 407#endif /* MOUNTED_GETMNTENT1. */ 408 409#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ 410 { 411 struct statfs *fsp; 412 int entries; 413 414 entries = getmntinfo (&fsp, MNT_NOWAIT); 415 if (entries < 0) 416 return NULL; 417 for (; entries-- > 0; fsp++) 418 { 419 char *fs_type = fsp_to_string (fsp); 420 421 me = xmalloc (sizeof *me); 422 me->me_devname = xstrdup (fsp->f_mntfromname); 423 me->me_mountdir = xstrdup (fsp->f_mntonname); 424 me->me_type = fs_type; 425 me->me_type_malloced = 0; 426 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); 427 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 428 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ 429 430 /* Add to the linked list. */ 431 *mtail = me; 432 mtail = &me->me_next; 433 } 434 } 435#endif /* MOUNTED_GETMNTINFO */ 436 437#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ 438 { 439 struct statvfs *fsp; 440 int entries; 441 442 entries = getmntinfo (&fsp, MNT_NOWAIT); 443 if (entries < 0) 444 return NULL; 445 for (; entries-- > 0; fsp++) 446 { 447 me = xmalloc (sizeof *me); 448 me->me_devname = xstrdup (fsp->f_mntfromname); 449 me->me_mountdir = xstrdup (fsp->f_mntonname); 450 me->me_type = xstrdup (fsp->f_fstypename); 451 me->me_type_malloced = 1; 452 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); 453 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 454 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ 455 456 /* Add to the linked list. */ 457 *mtail = me; 458 mtail = &me->me_next; 459 } 460 } 461#endif /* MOUNTED_GETMNTINFO2 */ 462 463#ifdef MOUNTED_GETMNT /* Ultrix. */ 464 { 465 int offset = 0; 466 int val; 467 struct fs_data fsd; 468 469 while (errno = 0, 470 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 471 (char *) 0))) 472 { 473 me = xmalloc (sizeof *me); 474 me->me_devname = xstrdup (fsd.fd_req.devname); 475 me->me_mountdir = xstrdup (fsd.fd_req.path); 476 me->me_type = gt_names[fsd.fd_req.fstype]; 477 me->me_type_malloced = 0; 478 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); 479 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 480 me->me_dev = fsd.fd_req.dev; 481 482 /* Add to the linked list. */ 483 *mtail = me; 484 mtail = &me->me_next; 485 } 486 if (val < 0) 487 goto free_then_fail; 488 } 489#endif /* MOUNTED_GETMNT. */ 490 491#if defined MOUNTED_FS_STAT_DEV /* BeOS */ 492 { 493 /* The next_dev() and fs_stat_dev() system calls give the list of 494 all file systems, including the information returned by statvfs() 495 (fs type, total blocks, free blocks etc.), but without the mount 496 point. But on BeOS all file systems except / are mounted in the 497 rootfs, directly under /. 498 The directory name of the mount point is often, but not always, 499 identical to the volume name of the device. 500 We therefore get the list of subdirectories of /, and the list 501 of all file systems, and match the two lists. */ 502 503 DIR *dirp; 504 struct rootdir_entry 505 { 506 char *name; 507 dev_t dev; 508 ino_t ino; 509 struct rootdir_entry *next; 510 }; 511 struct rootdir_entry *rootdir_list; 512 struct rootdir_entry **rootdir_tail; 513 int32 pos; 514 dev_t dev; 515 fs_info fi; 516 517 /* All volumes are mounted in the rootfs, directly under /. */ 518 rootdir_list = NULL; 519 rootdir_tail = &rootdir_list; 520 dirp = opendir ("/"); 521 if (dirp) 522 { 523 struct dirent *d; 524 525 while ((d = readdir (dirp)) != NULL) 526 { 527 char *name; 528 struct stat statbuf; 529 530 if (strcmp (d->d_name, "..") == 0) 531 continue; 532 533 if (strcmp (d->d_name, ".") == 0) 534 name = xstrdup ("/"); 535 else 536 { 537 name = xmalloc (1 + strlen (d->d_name) + 1); 538 name[0] = '/'; 539 strcpy (name + 1, d->d_name); 540 } 541 542 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) 543 { 544 struct rootdir_entry *re = xmalloc (sizeof *re); 545 re->name = name; 546 re->dev = statbuf.st_dev; 547 re->ino = statbuf.st_ino; 548 549 /* Add to the linked list. */ 550 *rootdir_tail = re; 551 rootdir_tail = &re->next; 552 } 553 else 554 free (name); 555 } 556 closedir (dirp); 557 } 558 *rootdir_tail = NULL; 559 560 for (pos = 0; (dev = next_dev (&pos)) >= 0; ) 561 if (fs_stat_dev (dev, &fi) >= 0) 562 { 563 /* Note: fi.dev == dev. */ 564 struct rootdir_entry *re; 565 566 for (re = rootdir_list; re; re = re->next) 567 if (re->dev == fi.dev && re->ino == fi.root) 568 break; 569 570 me = xmalloc (sizeof *me); 571 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name); 572 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name); 573 me->me_type = xstrdup (fi.fsh_name); 574 me->me_type_malloced = 1; 575 me->me_dev = fi.dev; 576 me->me_dummy = 0; 577 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; 578 579 /* Add to the linked list. */ 580 *mtail = me; 581 mtail = &me->me_next; 582 } 583 *mtail = NULL; 584 585 while (rootdir_list != NULL) 586 { 587 struct rootdir_entry *re = rootdir_list; 588 rootdir_list = re->next; 589 free (re->name); 590 free (re); 591 } 592 } 593#endif /* MOUNTED_FS_STAT_DEV */ 594 595#if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */ 596 { 597 int numsys, counter; 598 size_t bufsize; 599 struct statfs *stats; 600 601 numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT); 602 if (numsys < 0) 603 return (NULL); 604 if (SIZE_MAX / sizeof *stats <= numsys) 605 xalloc_die (); 606 607 bufsize = (1 + numsys) * sizeof *stats; 608 stats = xmalloc (bufsize); 609 numsys = getfsstat (stats, bufsize, MNT_NOWAIT); 610 611 if (numsys < 0) 612 { 613 free (stats); 614 return (NULL); 615 } 616 617 for (counter = 0; counter < numsys; counter++) 618 { 619 me = xmalloc (sizeof *me); 620 me->me_devname = xstrdup (stats[counter].f_mntfromname); 621 me->me_mountdir = xstrdup (stats[counter].f_mntonname); 622 me->me_type = xstrdup (FS_TYPE (stats[counter])); 623 me->me_type_malloced = 1; 624 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); 625 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 626 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ 627 628 /* Add to the linked list. */ 629 *mtail = me; 630 mtail = &me->me_next; 631 } 632 633 free (stats); 634 } 635#endif /* MOUNTED_GETFSSTAT */ 636 637#if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */ 638 { 639 struct mnttab mnt; 640 char *table = "/etc/mnttab"; 641 FILE *fp; 642 643 fp = fopen (table, "r"); 644 if (fp == NULL) 645 return NULL; 646 647 while (fread (&mnt, sizeof mnt, 1, fp) > 0) 648 { 649 me = xmalloc (sizeof *me); 650# ifdef GETFSTYP /* SVR3. */ 651 me->me_devname = xstrdup (mnt.mt_dev); 652# else 653 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6); 654 strcpy (me->me_devname, "/dev/"); 655 strcpy (me->me_devname + 5, mnt.mt_dev); 656# endif 657 me->me_mountdir = xstrdup (mnt.mt_filsys); 658 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ 659 me->me_type = ""; 660 me->me_type_malloced = 0; 661# ifdef GETFSTYP /* SVR3. */ 662 if (need_fs_type) 663 { 664 struct statfs fsd; 665 char typebuf[FSTYPSZ]; 666 667 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1 668 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1) 669 { 670 me->me_type = xstrdup (typebuf); 671 me->me_type_malloced = 1; 672 } 673 } 674# endif 675 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); 676 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 677 678 /* Add to the linked list. */ 679 *mtail = me; 680 mtail = &me->me_next; 681 } 682 683 if (ferror (fp)) 684 { 685 /* The last fread() call must have failed. */ 686 int saved_errno = errno; 687 fclose (fp); 688 errno = saved_errno; 689 goto free_then_fail; 690 } 691 692 if (fclose (fp) == EOF) 693 goto free_then_fail; 694 } 695#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */ 696 697#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */ 698 { 699 struct mntent **mnttbl = getmnttbl (), **ent; 700 for (ent=mnttbl;*ent;ent++) 701 { 702 me = xmalloc (sizeof *me); 703 me->me_devname = xstrdup ( (*ent)->mt_resource); 704 me->me_mountdir = xstrdup ( (*ent)->mt_directory); 705 me->me_type = xstrdup ((*ent)->mt_fstype); 706 me->me_type_malloced = 1; 707 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); 708 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 709 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ 710 711 /* Add to the linked list. */ 712 *mtail = me; 713 mtail = &me->me_next; 714 } 715 endmnttbl (); 716 } 717#endif 718 719#ifdef MOUNTED_GETMNTENT2 /* SVR4. */ 720 { 721 struct mnttab mnt; 722 char *table = MNTTAB; 723 FILE *fp; 724 int ret; 725 int lockfd = -1; 726 727# if defined F_RDLCK && defined F_SETLKW 728 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in 729 e.g. Solaris 2.6. If the SVR4 folks ever define a macro 730 for this file name, we should use their macro name instead. 731 (Why not just lock MNTTAB directly? We don't know.) */ 732# ifndef MNTTAB_LOCK 733# define MNTTAB_LOCK "/etc/.mnttab.lock" 734# endif 735 lockfd = open (MNTTAB_LOCK, O_RDONLY); 736 if (0 <= lockfd) 737 { 738 struct flock flock; 739 flock.l_type = F_RDLCK; 740 flock.l_whence = SEEK_SET; 741 flock.l_start = 0; 742 flock.l_len = 0; 743 while (fcntl (lockfd, F_SETLKW, &flock) == -1) 744 if (errno != EINTR) 745 { 746 int saved_errno = errno; 747 close (lockfd); 748 errno = saved_errno; 749 return NULL; 750 } 751 } 752 else if (errno != ENOENT) 753 return NULL; 754# endif 755 756 errno = 0; 757 fp = fopen (table, "r"); 758 if (fp == NULL) 759 ret = errno; 760 else 761 { 762 while ((ret = getmntent (fp, &mnt)) == 0) 763 { 764 me = xmalloc (sizeof *me); 765 me->me_devname = xstrdup (mnt.mnt_special); 766 me->me_mountdir = xstrdup (mnt.mnt_mountp); 767 me->me_type = xstrdup (mnt.mnt_fstype); 768 me->me_type_malloced = 1; 769 me->me_dummy = MNT_IGNORE (&mnt) != 0; 770 me->me_remote = ME_REMOTE (me->me_devname, me->me_type); 771 me->me_dev = dev_from_mount_options (mnt.mnt_mntopts); 772 773 /* Add to the linked list. */ 774 *mtail = me; 775 mtail = &me->me_next; 776 } 777 778 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1; 779 } 780 781 if (0 <= lockfd && close (lockfd) != 0) 782 ret = errno; 783 784 if (0 <= ret) 785 { 786 errno = ret; 787 goto free_then_fail; 788 } 789 } 790#endif /* MOUNTED_GETMNTENT2. */ 791 792#ifdef MOUNTED_VMOUNT /* AIX. */ 793 { 794 int bufsize; 795 char *entries, *thisent; 796 struct vmount *vmp; 797 int n_entries; 798 int i; 799 800 /* Ask how many bytes to allocate for the mounted file system info. */ 801 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0) 802 return NULL; 803 entries = xmalloc (bufsize); 804 805 /* Get the list of mounted file systems. */ 806 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries); 807 if (n_entries < 0) 808 { 809 int saved_errno = errno; 810 free (entries); 811 errno = saved_errno; 812 return NULL; 813 } 814 815 for (i = 0, thisent = entries; 816 i < n_entries; 817 i++, thisent += vmp->vmt_length) 818 { 819 char *options, *ignore; 820 821 vmp = (struct vmount *) thisent; 822 me = xmalloc (sizeof *me); 823 if (vmp->vmt_flags & MNT_REMOTE) 824 { 825 char *host, *dir; 826 827 me->me_remote = 1; 828 /* Prepend the remote dirname. */ 829 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off; 830 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off; 831 me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2); 832 strcpy (me->me_devname, host); 833 strcat (me->me_devname, ":"); 834 strcat (me->me_devname, dir); 835 } 836 else 837 { 838 me->me_remote = 0; 839 me->me_devname = xstrdup (thisent + 840 vmp->vmt_data[VMT_OBJECT].vmt_off); 841 } 842 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off); 843 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); 844 me->me_type_malloced = 1; 845 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; 846 ignore = strstr (options, "ignore"); 847 me->me_dummy = (ignore 848 && (ignore == options || ignore[-1] == ',') 849 && (ignore[sizeof "ignore" - 1] == ',' 850 || ignore[sizeof "ignore" - 1] == '\0')); 851 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */ 852 853 /* Add to the linked list. */ 854 *mtail = me; 855 mtail = &me->me_next; 856 } 857 free (entries); 858 } 859#endif /* MOUNTED_VMOUNT. */ 860 861 *mtail = NULL; 862 return mount_list; 863 864 865 free_then_fail: 866 { 867 int saved_errno = errno; 868 *mtail = NULL; 869 870 while (mount_list) 871 { 872 me = mount_list->me_next; 873 free (mount_list->me_devname); 874 free (mount_list->me_mountdir); 875 if (mount_list->me_type_malloced) 876 free (mount_list->me_type); 877 free (mount_list); 878 mount_list = me; 879 } 880 881 errno = saved_errno; 882 return NULL; 883 } 884} 885