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