diff options
author | Karel Zak | 2006-12-07 00:25:48 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:48 +0100 |
commit | 364cda4857f7dd5e2b4e2eb7583a2eaa279ef4ed (patch) | |
tree | c60dfad813ca42bf619fe2ac8ce893d2331e508f /mount | |
parent | Imported from util-linux-2.11b tarball. (diff) | |
download | kernel-qcow2-util-linux-364cda4857f7dd5e2b4e2eb7583a2eaa279ef4ed.tar.gz kernel-qcow2-util-linux-364cda4857f7dd5e2b4e2eb7583a2eaa279ef4ed.tar.xz kernel-qcow2-util-linux-364cda4857f7dd5e2b4e2eb7583a2eaa279ef4ed.zip |
Imported from util-linux-2.11f tarball.
Diffstat (limited to 'mount')
-rw-r--r-- | mount/Makefile | 4 | ||||
-rw-r--r-- | mount/linux_fs.h | 17 | ||||
-rw-r--r-- | mount/mount.8 | 14 | ||||
-rw-r--r-- | mount/mount.c | 124 | ||||
-rw-r--r-- | mount/mount_by_label.c | 3 | ||||
-rw-r--r-- | mount/mount_guess_fstype.c | 46 | ||||
-rw-r--r-- | mount/nfs.5 | 4 | ||||
-rw-r--r-- | mount/nfsmount.c | 94 | ||||
-rw-r--r-- | mount/realpath.c | 20 | ||||
-rw-r--r-- | mount/sundries.c | 79 | ||||
-rw-r--r-- | mount/sundries.h | 18 | ||||
-rw-r--r-- | mount/swapon.c | 15 | ||||
-rw-r--r-- | mount/umount.c | 345 |
13 files changed, 433 insertions, 350 deletions
diff --git a/mount/Makefile b/mount/Makefile index ef65601f7..453b640ae 100644 --- a/mount/Makefile +++ b/mount/Makefile @@ -44,11 +44,11 @@ install: $(PROGS) mount: mount.o fstab.o sundries.o realpath.o mntent.o version.o \ mount_guess_fstype.o mount_by_label.o getusername.o \ - $(LIB)/setproctitle.o $(NFS_OBJS) $(LO_OBJS) + $(LIB)/setproctitle.o $(LIB)/env.o $(NFS_OBJS) $(LO_OBJS) $(LINK) $^ -o $@ umount: umount.o fstab.o sundries.o realpath.o mntent.o getusername.o \ - version.o $(LO_OBJS) + version.o $(LIB)/env.o $(LO_OBJS) $(LINK) $^ -o $@ swapon: swapon.o version.o diff --git a/mount/linux_fs.h b/mount/linux_fs.h index 043ac16a7..978573892 100644 --- a/mount/linux_fs.h +++ b/mount/linux_fs.h @@ -48,12 +48,18 @@ struct ext_super_block { #define EXT2_PRE_02B_MAGIC 0xEF51 #define EXT2_SUPER_MAGIC 0xEF53 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 struct ext2_super_block { - u_char s_dummy1[56]; - u_char s_magic[2]; - u_char s_dummy2[46]; - u_char s_uuid[16]; - u_char s_volume_name[16]; + u_char s_dummy1[56]; + u_char s_magic[2]; + u_char s_dummy2[34]; + u_char s_feature_compat[4]; + u_char s_feature_incompat[4]; + u_char s_feature_ro_compat[4]; + u_char s_uuid[16]; + u_char s_volume_name[16]; + u_char s_dummy3[88]; + u_char s_journal_inum[4]; /* ext3 only */ }; #define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) @@ -102,7 +108,6 @@ struct fat_super_block { }; #define XFS_SUPER_MAGIC "XFSB" -#define XFS_SUPER_MAGIC2 "BSFX" struct xfs_super_block { u_char s_magic[4]; u_char s_dummy[28]; diff --git a/mount/mount.8 b/mount/mount.8 index 42a7a4a72..6f96457df 100644 --- a/mount/mount.8 +++ b/mount/mount.8 @@ -221,11 +221,7 @@ option below). It is possible to replace by a symbolic link to .IR /proc/mounts , but some information is lost that way, and in particular -working with the loop device will be less convenient. Also, -pathnames containing spaces are handled correctly by -.I /etc/mtab -but not (yet) by -.IR /proc/mounts . +working with the loop device will be less convenient. .SH OPTIONS The full set of options used by an invocation of @@ -442,7 +438,9 @@ flag followed by a comma separated string of options. Some of these options are only useful when they appear in the .I /etc/fstab file. The following options apply to any file system that is being -mounted: +mounted (but not every file system actually honors them - e.g., the +.B sync +option today has effect only for ext2 and ufs): .RS .TP .B async @@ -582,6 +580,8 @@ Give blocksize. Allowed values are 512, 1024, 2048, 4096. .TP .BR grpquota " / " noquota " / " quota " / " usrquota These options are accepted but ignored. +(However, quota utilities may react to such strings in +.IR /etc/fstab .) .SH "Mount options for coherent" None. @@ -1149,7 +1149,7 @@ UFS is a file system widely used in different operating systems. The problem are differences among implementations. Features of some implementations are undocumented, so its hard to recognize the type of ufs automatically. -That's why user must specify the type of ufs by mount option. +That's why the user must specify the type of ufs by mount option. Possible values are: .RS .TP diff --git a/mount/mount.c b/mount/mount.c index dc7e9823f..8d62087eb 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -66,6 +66,7 @@ #include "mount_guess_fstype.h" #include "mount_by_label.h" #include "getusername.h" +#include "env.h" #include "nls.h" #define DO_PS_FIDDLING @@ -244,7 +245,7 @@ print_one (const struct mntent *me) { /* Report on everything in mtab (of the specified types if any). */ static int -print_all (string_list types) { +print_all (char *types) { struct mntentchn *mc, *mc0; mc0 = mtab_head(); @@ -452,33 +453,51 @@ do_mount_syscall (struct mountargs *args) { * Mount a single file system. Guess the type when unknown. * returns: 0: OK, -1: error in errno, 1: other error * don't exit on non-fatal errors. + * on return types is filled with the type used. */ static int -guess_fstype_and_mount (char *spec, char *node, char **type, +guess_fstype_and_mount (char *spec, char *node, char **types, int flags, char *mount_opts) { struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts }; - if (*type && strcasecmp (*type, "auto") == 0) - *type = NULL; + if (*types && strcasecmp (*types, "auto") == 0) + *types = NULL; - if (!*type && (flags & (MS_BIND | MS_MOVE))) - *type = "none"; /* random, but not "bind" */ + if (!*types && (flags & (MS_BIND | MS_MOVE))) + *types = "none"; /* random, but not "bind" */ - if (!*type && !(flags & MS_REMOUNT)) { - *type = guess_fstype_from_superblock(spec); - if (*type && !strcmp(*type, "swap")) { + if (!*types && !(flags & MS_REMOUNT)) { + *types = guess_fstype_from_superblock(spec); + if (*types && !strcmp(*types, "swap")) { error(_("%s looks like swapspace - not mounted"), spec); - *type = NULL; + *types = NULL; return 1; } } - if (*type || (flags & MS_REMOUNT)) { - args.type = *type; + /* Accept a comma-separated list of types, and try them one by one */ + /* A list like "nonfs,.." indicates types not to use */ + if (*types && strncmp(*types, "no", 2) && index(*types,',')) { + char *t = strdup(*types); + char *p; + + while((p = index(t,',')) != NULL) { + *p = 0; + args.type = *types = t; + if(do_mount_syscall (&args) == 0) + return 0; + t = p+1; + } + /* do last type below */ + *types = t; + } + + if (*types || (flags & MS_REMOUNT)) { + args.type = *types; return do_mount_syscall (&args); } - return procfsloop(do_mount_syscall, &args, type); + return procfsloop(do_mount_syscall, &args, types); } /* @@ -715,7 +734,7 @@ check_special_mountprog(char *spec, char *node, char *type, int flags, * return status from wait */ static int -try_mount_one (const char *spec0, const char *node0, char *type0, +try_mount_one (const char *spec0, const char *node0, char *types0, const char *opts0, int freq, int pass, int bg, int ro) { int res, status; int mnt5_res = 0; /* only for gcc */ @@ -724,15 +743,16 @@ try_mount_one (const char *spec0, const char *node0, char *type0, char *extra_opts; /* written in mtab */ char *mount_opts; /* actually used on system call */ const char *opts; - char *spec, *node, *type; + char *spec, *node, *types; char *user = 0; int loop = 0; char *loopdev = 0, *loopfile = 0; struct stat statbuf; + int nfs_mount_version = 0; /* any version */ spec = xstrdup(spec0); node = xstrdup(node0); - type = xstrdup(type0); + types = xstrdup(types0); opts = xstrdup(opts0); parse_opts (xstrdup (opts), &flags, &extra_opts); @@ -753,22 +773,27 @@ try_mount_one (const char *spec0, const char *node0, char *type0, * stale assignments of files to loop devices. Nasty when used for * encryption. */ - res = loop_check (&spec, &type, &flags, &loop, &loopdev, &loopfile); + res = loop_check (&spec, &types, &flags, &loop, &loopdev, &loopfile); if (res) return res; } /* * Call mount.TYPE for types that require a separate mount program. - * For the moment these types are ncp and smb. + * For the moment these types are ncp and smb. Maybe also vxfs. + * All such special things must occur isolated in the types string. */ - if (check_special_mountprog (spec, node, type, flags, extra_opts, &status)) + if (check_special_mountprog (spec, node, types, flags, extra_opts, &status)) return status; - if (!fake && type && streq (type, "nfs")) { + /* + * Also nfs requires a separate program, but it is built in. + */ + if (!fake && types && streq (types, "nfs")) { #ifdef HAVE_NFS retry_nfs: - mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts, bg); + mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts, + &nfs_mount_version, bg); if (mnt_err) return mnt_err; #else @@ -780,7 +805,7 @@ retry_nfs: block_signals (SIG_BLOCK); if (!fake) - mnt5_res = guess_fstype_and_mount (spec, node, &type, flags & ~MS_NOSYS, + mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS, mount_opts); if (fake || mnt5_res == 0) { @@ -790,7 +815,7 @@ retry_nfs: update_mtab_entry(loop ? loopfile : spec, node, - type ? type : "unknown", + types ? types : "unknown", fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user), flags, freq, @@ -808,8 +833,7 @@ retry_nfs: block_signals (SIG_UNBLOCK); #ifdef HAVE_NFS - if (mnt_err && type && streq (type, "nfs")) { - extern int nfs_mount_version; + if (mnt_err && types && streq (types, "nfs")) { if (nfs_mount_version == 4) { if (verbose) printf(_("mount: failed with nfs mount version 4, trying 3..\n")); @@ -821,7 +845,7 @@ retry_nfs: /* Mount failed, complain, but don't die. */ - if (type == 0) { + if (types == 0) { if (suid) error (_("mount: I could not determine the filesystem type, " "and none was specified")); @@ -844,7 +868,7 @@ retry_nfs: case EBUSY: if (flags & MS_REMOUNT) { error (_("mount: %s is busy"), node); - } else if (!strcmp(type, "proc") && !strcmp(node, "/proc")) { + } else if (!strcmp(types, "proc") && !strcmp(node, "/proc")) { /* heuristic: if /proc/version exists, then probably proc is mounted */ if (stat ("/proc/version", &statbuf)) /* proc mounted? */ error (_("mount: %s is busy"), node); /* no */ @@ -926,16 +950,16 @@ retry_nfs: error (_("mount: %s: can't read superblock"), spec); break; case ENODEV: { int pfs; - if ((pfs = is_in_procfs(type)) == 1 || !strcmp(type, "guess")) + if ((pfs = is_in_procfs(types)) == 1 || !strcmp(types, "guess")) error(_("mount: %s: unknown device"), spec); else if (pfs == 0) { char *lowtype, *p; int u; - error (_("mount: fs type %s not supported by kernel"), type); + error (_("mount: fs type %s not supported by kernel"), types); /* maybe this loser asked for FAT or ISO9660 or isofs */ - lowtype = xstrdup(type); + lowtype = xstrdup(types); u = 0; for(p=lowtype; *p; p++) { if(tolower(*p) != *p) { @@ -950,7 +974,7 @@ retry_nfs: free(lowtype); } else error (_("mount: %s has wrong device number or fs type %s not supported"), - spec, type); + spec, types); break; } case ENOTBLK: @@ -981,7 +1005,7 @@ retry_nfs: } else { if (loop) { opts = opts0; - type = type0; + types = types0; } if (opts) { char *opts1 = realloc(xstrdup(opts), strlen(opts)+4); @@ -989,11 +1013,11 @@ retry_nfs: opts = opts1; } else opts = "ro"; - if (type && !strcmp(type, "guess")) - type = 0; + if (types && !strcmp(types, "guess")) + types = 0; error (_("mount: %s%s is write-protected, mounting read-only"), bd, spec0); - return try_mount_one (spec0, node0, type, opts, freq, pass, bg, 1); + return try_mount_one (spec0, node0, types, opts, freq, pass, bg, 1); } break; } @@ -1051,7 +1075,7 @@ usersubst(const char *opts) { * Return 0 for success (either mounted sth or -a and NOAUTO was given) */ static int -mount_one (const char *spec, const char *node, char *type, const char *opts, +mount_one (const char *spec, const char *node, char *types, const char *opts, char *cmdlineopts, int freq, int pass) { int status; int status2; @@ -1087,9 +1111,9 @@ mount_one (const char *spec, const char *node, char *type, const char *opts, /* if -a then we may be rescued by a noauto option */ } - if (type == NULL && !mounttype) { + if (types == NULL && !mounttype) { if (strchr (spec, ':') != NULL) { - type = "nfs"; + types = "nfs"; if (verbose) printf(_("mount: no type was given - " "I'll assume nfs because of the colon\n")); @@ -1100,7 +1124,7 @@ mount_one (const char *spec, const char *node, char *type, const char *opts, * Try to mount the file system. When the exit status is EX_BG, * we will retry in the background. Otherwise, we're done. */ - status = try_mount_one (spec, node, type, opts, freq, pass, 0, 0); + status = try_mount_one (spec, node, types, opts, freq, pass, 0, 0); if (status != EX_BG) return status; @@ -1113,10 +1137,10 @@ mount_one (const char *spec, const char *node, char *type, const char *opts, return 0; /* parent returns "success" */ spec = xstrdup(spec); /* arguments will be destroyed */ node = xstrdup(node); /* by set_proc_name() */ - type = xstrdup(type); + types = xstrdup(types); opts = xstrdup(opts); set_proc_name (spec); /* make a nice "ps" listing */ - status2 = try_mount_one (spec, node, type, opts, freq, pass, 1, 0); + status2 = try_mount_one (spec, node, types, opts, freq, pass, 1, 0); if (verbose && status2) printf (_("mount: giving up \"%s\"\n"), spec); exit (0); /* child stops here */ @@ -1153,7 +1177,7 @@ mounted (char *spec, char *node) { #define DISKMAJOR(m) (((int) m) & ~0xf) static int -mount_all (string_list types, char *options) { +mount_all (char *types, char *options) { struct mntentchn *mc, *mc0, *mtmp; int status = 0; struct stat statbuf; @@ -1330,10 +1354,11 @@ main (int argc, char *argv[]) { char *options = NULL, *spec, *node; char *volumelabel = NULL; char *uuid = NULL; - string_list types = NULL; + char *types = NULL; struct mntentchn *mc; int fd; + sanitize_env(); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); @@ -1387,7 +1412,7 @@ main (int argc, char *argv[]) { sloppy = 1; break; case 't': /* specify file system types */ - types = parse_list (optarg); + types = optarg; break; case 'U': uuid = optarg; @@ -1472,7 +1497,7 @@ main (int argc, char *argv[]) { /* mount -a */ result = mount_all (types, options); if (result == 0 && verbose) - error(_("not mounted anything")); + error(_("nothing was mounted")); break; case 1: @@ -1524,14 +1549,7 @@ main (int argc, char *argv[]) { spec = argv[0]; node = argv[1]; } - if (types == NULL) - result = mount_one (spec, node, NULL, NULL, - options, 0, 0); - else if (cdr (types) == NULL) - result = mount_one (spec, node, car (types), NULL, - options, 0, 0); - else - usage (stderr, EX_USAGE); + result = mount_one (spec, node, types, NULL, options, 0, 0); break; default: diff --git a/mount/mount_by_label.c b/mount/mount_by_label.c index ad3b5ebd2..18344e4bd 100644 --- a/mount/mount_by_label.c +++ b/mount/mount_by_label.c @@ -58,8 +58,7 @@ get_label_uuid(const char *device, char **label, char *uuid) { } else if (lseek(fd, 0, SEEK_SET) == 0 && read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb) - && (strncmp((char *) &xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0 || - strncmp((char *) &xfsb.s_magic, XFS_SUPER_MAGIC2,4) == 0)) { + && (strncmp(xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0)) { memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid)); namesize = sizeof(xfsb.s_fname); if ((*label = calloc(namesize + 1, 1)) != NULL) diff --git a/mount/mount_guess_fstype.c b/mount/mount_guess_fstype.c index a87409295..8694213d0 100644 --- a/mount/mount_guess_fstype.c +++ b/mount/mount_guess_fstype.c @@ -57,6 +57,11 @@ swapped(unsigned short a) { return (a>>8) | (a<<8); } +static inline int +assemble4le(unsigned char *p) { + return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); +} + /* char *guess_fstype_from_superblock(const char *device); @@ -74,10 +79,11 @@ swapped(unsigned short a) { Added a very weak heuristic for vfat - aeb Added xfs - 2000-03-21 Martin K. Petersen <mkp@linuxcare.com> Added cramfs, hfs, hpfs, adfs - Sepp Wijnands <mrrazz@garbage-coderz.net> + Added ext3 - Andrew Morton */ static char *magic_known[] = { - "adfs", "bfs", "cramfs", "ext", "ext2", + "adfs", "bfs", "cramfs", "ext", "ext2", "ext3", "hfs", "hpfs", "iso9660", "minix", "ntfs", "qnx4", "romfs", "swap", "udf", "ufs", "xfs", "xiafs" @@ -180,9 +186,16 @@ fstype(const char *device) { PPC ext2 systems */ if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC || ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC - || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC)) + || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC)) { type = "ext2"; + /* maybe even ext3? */ + if ((assemble4le(sb.e2s.s_feature_compat) + & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && + assemble4le(sb.e2s.s_journal_inum) != 0) + type = "ext3,ext2"; + } + else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2 || minixmagic(sb.ms) == swapped(MINIX_SUPER_MAGIC2)) @@ -200,8 +213,7 @@ fstype(const char *device) { type = "xiafs"; else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8)) type = "romfs"; - else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4) || - !strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC2, 4)) + else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4)) type = "xfs"; else if(!strncmp(xsb.qnx4fs_magic+4, "QNX4FS", 6)) type = "qnx4fs"; @@ -216,7 +228,10 @@ fstype(const char *device) { !strncmp(xsb.fatsb.s_os, "MSWIN", 5) || !strncmp(xsb.fatsb.s_os, "MTOOL", 5) || !strncmp(xsb.fatsb.s_os, "mkdosfs", 7) || - !strncmp(xsb.fatsb.s_os, "kmkdosfs", 8)) + !strncmp(xsb.fatsb.s_os, "kmkdosfs", 8) || + /* Michal Svec: created by fdformat, old msdos utility for + formatting large (1.7) floppy disks. */ + !strncmp(xsb.fatsb.s_os, "CH-FOR18", 8)) && (!strncmp(xsb.fatsb.s_fs, "FAT12 ", 8) || !strncmp(xsb.fatsb.s_fs, "FAT16 ", 8) || !strncmp(xsb.fatsb.s_fs2, "FAT32 ", 8))) @@ -363,19 +378,28 @@ is_in_procfs(const char *type) { return ret; } +/* Try all types in FILESYSTEMS, except those in *types, + in case *types starts with "no" */ /* return: 0: OK, -1: error in errno, 1: type not found */ -/* when 1 is returned, *type is NULL */ +/* when 0 or -1 is returned, *types contains the type used */ +/* when 1 is returned, *types is NULL */ int procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args, - char **type) { + char **types) { char *files[2] = { ETC_FILESYSTEMS, PROC_FILESYSTEMS }; FILE *procfs; char *fsname; + char *notypes = NULL; + int no = 0; int ret = 1; int errsv = 0; int i; - *type = NULL; + if (!strncmp(*types, "no", 2)) { + no = 1; + notypes = (*types) + 2; + } + *types = NULL; /* Use PROC_FILESYSTEMS only when ETC_FILESYSTEMS does not exist. In some cases trying a filesystem that the kernel knows about @@ -396,18 +420,20 @@ procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args, } if (tested (fsname)) continue; + if (no && matching_type(fsname, notypes)) + continue; args->type = fsname; if (verbose) { printf(_("Trying %s\n"), fsname); fflush(stdout); } if ((*mount_fn) (args) == 0) { - *type = fsname; + *types = fsname; ret = 0; break; } else if (errno != EINVAL && is_in_procfs(fsname) == 1) { - *type = "guess"; + *types = "guess"; ret = -1; errsv = errno; break; diff --git a/mount/nfs.5 b/mount/nfs.5 index 6ffce6cdf..b29a8bdb0 100644 --- a/mount/nfs.5 +++ b/mount/nfs.5 @@ -143,6 +143,10 @@ NFS daemon on the remote host. This option is useful for hosts that can run multiple NFS servers. The default value is version 2. .TP 1.5i +.I nolock +Disable NFS locking. This has to be used with some old NFS servers +that don't support locking. +.TP 1.5i .I bg If the first NFS mount attempt times out, retry the mount in the background. diff --git a/mount/nfsmount.c b/mount/nfsmount.c index 70298e0c6..d81c062e1 100644 --- a/mount/nfsmount.c +++ b/mount/nfsmount.c @@ -37,6 +37,7 @@ #include <string.h> #include <errno.h> #include <netdb.h> +#include <time.h> #include <rpc/rpc.h> #include <rpc/pmap_prot.h> #include <rpc/pmap_clnt.h> @@ -86,11 +87,6 @@ linux_version_code(void) { } /* - * nfs_mount_version according to the sources seen at compile time. - */ -int nfs_mount_version = NFS_MOUNT_VERSION; - -/* * Unfortunately, the kernel prints annoying console messages * in case of an unexpected nfs mount version (instead of * just returning some error). Therefore we'll have to try @@ -100,14 +96,13 @@ int nfs_mount_version = NFS_MOUNT_VERSION; * NFS_MOUNT_VERSION: these nfsmount sources at compile time * nfs_mount_version: version this source and running kernel can handle */ -static void +static int find_kernel_nfs_mount_version(void) { - static int kernel_version = 0; + static int kernel_version = -1; + int nfs_mount_version = NFS_MOUNT_VERSION; - if (kernel_version) - return; - - kernel_version = linux_version_code(); + if (kernel_version == -1) + kernel_version = linux_version_code(); if (kernel_version) { if (kernel_version < MAKE_VERSION(2,1,32)) @@ -123,6 +118,7 @@ find_kernel_nfs_mount_version(void) { } if (nfs_mount_version > NFS_MOUNT_VERSION) nfs_mount_version = NFS_MOUNT_VERSION; + return nfs_mount_version; } static struct pmap * @@ -130,7 +126,8 @@ get_mountport(struct sockaddr_in *server_addr, long unsigned prog, long unsigned version, long unsigned proto, - long unsigned port) + long unsigned port, + int nfs_mount_version) { struct pmaplist *pmap; static struct pmap p = {0, 0, 0, 0}; @@ -174,20 +171,19 @@ get_mountport(struct sockaddr_in *server_addr, } int nfsmount(const char *spec, const char *node, int *flags, - char **extra_opts, char **mount_opts, int running_bg) + char **extra_opts, char **mount_opts, int *nfs_mount_vers, + int running_bg) { static char *prev_bg_host; char hostdir[1024]; CLIENT *mclient; - char *hostname; - char *dirname; - char *old_opts; - char *mounthost=NULL; + char *hostname, *dirname, *old_opts, *mounthost = NULL; char new_opts[1024]; struct timeval total_timeout; enum clnt_stat clnt_stat; static struct nfs_mount_data data; char *opt, *opteq; + int nfs_mount_version; int val; struct hostent *hp; struct sockaddr_in server_addr; @@ -201,29 +197,20 @@ int nfsmount(const char *spec, const char *node, int *flags, } status; struct stat statbuf; char *s; - int port; - int mountport; - int proto; - int bg; - int soft; - int intr; - int posix; - int nocto; - int noac; - int nolock; - int broken_suid; - int retry; - int tcp; - int mountprog; - int mountvers; - int nfsprog; - int nfsvers; + int port, mountport, proto, bg, soft, intr; + int posix, nocto, noac, nolock, broken_suid; + int retry, tcp; + int mountprog, mountvers, nfsprog, nfsvers; int retval; time_t t; time_t prevt; time_t timeout; - find_kernel_nfs_mount_version(); + /* The version to try is either specified or 0 + In case it is 0 we tell the caller what we tried */ + if (!*nfs_mount_vers) + *nfs_mount_vers = find_kernel_nfs_mount_version(); + nfs_mount_version = *nfs_mount_vers; retval = EX_FAIL; msock = fsock = -1; @@ -242,12 +229,14 @@ int nfsmount(const char *spec, const char *node, int *flags, until they can be fully supported. (mack@sgi.com) */ if ((s = strchr(hostdir, ','))) { *s = '\0'; - fprintf(stderr, _("mount: warning: " - "multiple hostnames not supported\n")); + fprintf(stderr, + _("mount: warning: " + "multiple hostnames not supported\n")); } } else { - fprintf(stderr, _("mount: " - "directory to mount not in host:dir format\n")); + fprintf(stderr, + _("mount: " + "directory to mount not in host:dir format\n")); goto fail; } @@ -380,15 +369,14 @@ int nfsmount(const char *spec, const char *node, int *flags, else #endif printf(_("Warning: Option namlen is not supported.\n")); - } else if (!strcmp(opt, "addr")) + } else if (!strcmp(opt, "addr")) { /* ignore */; - else { + } else { printf(_("unknown nfs mount parameter: " "%s=%d\n"), opt, val); goto fail; } - } - else { + } else { val = 1; if (!strncmp(opt, "no", 2)) { val = 0; @@ -459,9 +447,8 @@ int nfsmount(const char *spec, const char *node, int *flags, } if (nfsvers && !mountvers) mountvers = (nfsvers < 3) ? 1 : nfsvers; - if (nfsvers && nfsvers < mountvers) { + if (nfsvers && nfsvers < mountvers) mountvers = nfsvers; - } /* Adjust options if none specified */ if (!data.timeo) @@ -515,7 +502,7 @@ int nfsmount(const char *spec, const char *node, int *flags, } else { if ((hp = gethostbyname(mounthost)) == NULL) { fprintf(stderr, _("mount: can't get address for %s\n"), - hostname); + mounthost); goto fail; } else { if (hp->h_length > sizeof(struct in_addr)) { @@ -573,7 +560,8 @@ int nfsmount(const char *spec, const char *node, int *flags, mountprog, mountvers, proto, - mountport); + mountport, + nfs_mount_version); /* contact the mount daemon via TCP */ mount_server_addr.sin_port = htons(pm_mnt->pm_port); @@ -724,6 +712,18 @@ int nfsmount(const char *spec, const char *node, int *flags, server_addr.sin_port = PMAPPORT; port = pmap_getport(&server_addr, nfsprog, nfsvers, tcp ? IPPROTO_TCP : IPPROTO_UDP); +#if 1 + /* Here we check to see if user is mounting with the + * tcp option. If so, and if the portmap returns a + * '0' for port (service unavailable), we then exit, + * notifying the user, rather than hanging up mount. + */ + if (port == 0 && tcp == 1) { + perror(_("nfs server reported service unavailable")); + goto fail; + } +#endif + if (port == 0) port = NFS_PORT; #ifdef NFS_MOUNT_DEBUG diff --git a/mount/realpath.c b/mount/realpath.c index 374f8a3a2..61832efd2 100644 --- a/mount/realpath.c +++ b/mount/realpath.c @@ -13,12 +13,17 @@ * GNU Library Public License for more details. */ +#undef resolve_symlinks + /* * This routine is part of libc. We include it nevertheless, * since the libc version has some security flaws. */ #include <limits.h> /* for PATH_MAX */ +#ifndef PATH_MAX +#define PATH_MAX 8192 +#endif #include <unistd.h> #include <string.h> #include <errno.h> @@ -30,10 +35,14 @@ /* this leaks some memory - unimportant for mount */ char * myrealpath(const char *path, char *resolved_path, int maxreslth) { - char *npath, *buf; - char link_path[PATH_MAX+1]; int readlinks = 0; - int m, n; + char *npath; + char link_path[PATH_MAX+1]; + int n; +#ifdef resolve_symlinks + char *buf; + int m; +#endif npath = resolved_path; @@ -85,7 +94,7 @@ myrealpath(const char *path, char *resolved_path, int maxreslth) { return NULL; } - /* See if latest pathname component is a symlink. */ + /* See if last pathname component is a symlink. */ *npath = '\0'; n = readlink(resolved_path, link_path, PATH_MAX); if (n < 0) { @@ -93,6 +102,7 @@ myrealpath(const char *path, char *resolved_path, int maxreslth) { if (errno != EINVAL) return NULL; } else { +#ifdef resolve_symlinks /* Richard Gooch dislikes sl resolution */ /* Note: readlink doesn't add the null byte. */ link_path[n] = '\0'; if (*link_path == '/') @@ -109,8 +119,8 @@ myrealpath(const char *path, char *resolved_path, int maxreslth) { memcpy(buf, link_path, n); memcpy(buf + n, path, m + 1); path = buf; +#endif } - *npath++ = '/'; } /* Delete trailing slash but don't whomp a lone slash. */ diff --git a/mount/sundries.c b/mount/sundries.c index 1da3b666e..59b069678 100644 --- a/mount/sundries.c +++ b/mount/sundries.c @@ -18,17 +18,6 @@ #include "nfsmount.h" #include "nls.h" -/* String list constructor. (car() and cdr() are defined in "sundries.h"). */ -string_list -cons (char *a, const string_list b) { - string_list p; - - p = xmalloc (sizeof *p); - car (p) = a; - cdr (p) = b; - return p; -} - void * xmalloc (size_t size) { void *t; @@ -157,57 +146,43 @@ die (int err, const char *fmt, ...) { exit (err); } -/* Parse a list of strings like str[,str]... into a string list. */ -string_list -parse_list (char *strings) { - string_list list; - char *s, *t; - - if (strings == NULL) - return NULL; - - /* strtok() destroys its argument, so we have to use a copy */ - s = xstrdup(strings); - - list = cons (strtok (s, ","), NULL); - - while ((t = strtok (NULL, ",")) != NULL) - list = cons (t, list); - - return list; -} - /* True if fstypes match. Null *TYPES means match anything, - except that swap types always return false. - This routine has some ugliness to deal with ``no'' types. - Fixed bug: the `no' part comes at the end - aeb, 970216 */ + except that swap types always return false. */ +/* Accept nonfs,proc,devpts and nonfs,noproc,nodevpts + with the same meaning. */ int -matching_type (const char *type, string_list types) { - char *notype; - int foundyes, foundno; - int no; /* true if a "no" type match, eg -t nominix */ +matching_type (const char *type, const char *types) { + int no; /* negated types list */ + int len; + const char *p; if (streq (type, MNTTYPE_SWAP)) return 0; if (types == NULL) return 1; - if ((notype = alloca (strlen (type) + 3)) == NULL) - die (EX_SYSERR, _("%s: Out of memory!\n"), "mount"); - sprintf (notype, "no%s", type); - - foundyes = foundno = no = 0; - while (types != NULL) { - if (cdr (types) == NULL) - no = (car (types)[0] == 'n') && (car (types)[1] == 'o'); - if (streq (type, car (types))) - foundyes = 1; - else if (streq (notype, car (types))) - foundno = 1; - types = cdr (types); + no = 0; + if (!strncmp(types, "no", 2)) { + no = 1; + types += 2; } - return (foundno ? 0 : (no ^ foundyes)); + /* Does type occur in types, separated by commas? */ + len = strlen(type); + p = types; + while(1) { + if (!strncmp(p, "no", 2) && !strncmp(p+2, type, len) && + (p[len+2] == 0 || p[len+2] == ',')) + return 0; + if (strncmp(p, type, len) == 0 && + (p[len] == 0 || p[len] == ',')) + return !no; + p = index(p,','); + if (!p) + break; + p++; + } + return no; } /* Make a canonical pathname from PATH. Returns a freshly malloced string. diff --git a/mount/sundries.h b/mount/sundries.h index 742d761f4..5b91ca1ee 100644 --- a/mount/sundries.h +++ b/mount/sundries.h @@ -19,26 +19,12 @@ extern int sloppy; #define streq(s, t) (strcmp ((s), (t)) == 0) - -/* String list data structure. */ -typedef struct string_list -{ - char *hd; - struct string_list *tl; -} *string_list; - -#define car(p) ((p) -> hd) -#define cdr(p) ((p) -> tl) - -string_list cons (char *a, const string_list); - /* Functions in sundries.c that are used in mount.c and umount.c */ void block_signals (int how); char *canonicalize (const char *path); char *realpath (const char *path, char *resolved_path); void error (const char *fmt, ...); -int matching_type (const char *type, string_list types); -string_list parse_list (char *strings); +int matching_type (const char *type, const char *types); void *xmalloc (size_t size); char *xstrdup (const char *s); char *xstrndup (const char *s, int n); @@ -50,7 +36,7 @@ void die (int errcode, const char *fmt, ...); #ifdef HAVE_NFS int nfsmount (const char *spec, const char *node, int *flags, - char **orig_opts, char **opt_args, int running_bg); + char **orig_opts, char **opt_args, int *version, int running_bg); #endif /* exit status - bits below are ORed */ diff --git a/mount/swapon.c b/mount/swapon.c index 829acadd4..b87a021ae 100644 --- a/mount/swapon.c +++ b/mount/swapon.c @@ -90,15 +90,22 @@ swap (const char *special, int prio) if (streq (program_name, "swapon")) { if (stat(special, &st) < 0) { int errsv = errno; - fprintf (stderr, _("swapon: cannot stat %s: %s\n"), special, strerror (errsv)); + fprintf (stderr, _("swapon: cannot stat %s: %s\n"), + special, strerror (errsv)); return -1; } /* people generally dislike this warning - now it is printed only when `verbose' is set */ - if (verbose && (st.st_mode & 07077) != 0) { - fprintf(stderr, _("swapon: warning: %s has insecure permissions %04o, " - "0600 suggested\n"), special, st.st_mode & 07777); + if (verbose) { + int permMask = (S_ISBLK(st.st_mode) ? 07007 : 07077); + + if ((st.st_mode & permMask) != 0) { + fprintf(stderr, + _("swapon: warning: %s has insecure permissions %04o, " + "%04o suggested\n"), + special, st.st_mode & 07777, ~permMask & 0666); + } } /* test for holes by LBT */ diff --git a/mount/umount.c b/mount/umount.c index 1843e08e5..92400875a 100644 --- a/mount/umount.c +++ b/mount/umount.c @@ -39,6 +39,7 @@ #include "lomount.h" #include "loop.h" #include "fstab.h" +#include "env.h" #include "nls.h" #ifdef HAVE_NFS @@ -52,7 +53,7 @@ #include <arpa/inet.h> #endif -#if defined(MNT_FORCE) && !defined(__sparc__) && !defined(__arm__) && !defined(__mips__) +#if defined(MNT_FORCE) && !defined(__sparc__) && !defined(__arm__) /* Interesting ... it seems libc knows about MNT_FORCE and presumably about umount2 as well -- need not do anything */ #else /* MNT_FORCE */ @@ -100,6 +101,16 @@ int verbose = 0; /* True if ruid != euid. */ int suid = 0; +#ifdef USE_SPECIAL_UMOUNTPROG +/* unimplemented so far */ +static int +check_special_umountprog() { + /* find type from command line or /etc/mtab; + stat /sbin/umount.%s + if it exists, use it */ +} +#endif + #ifdef HAVE_NFS static int xdr_dir(XDR *xdrsp, char *dirp) { @@ -236,7 +247,6 @@ umount_one (const char *spec, const char *node, const char *type, nfs_umount_rpc_call(spec, opts); #endif - umnt_err = umnt_err2 = 0; if (force) { /* completely untested; @@ -383,7 +393,7 @@ umount_one_bw (const char *file, struct mntentchn *mc) { in any case it's important to umount mtab entries in reverse order to mount, e.g. /usr/spool before /usr. */ static int -umount_all (string_list types) { +umount_all (char *types) { struct mntentchn *mc, *hd; int errors = 0; @@ -426,152 +436,195 @@ usage (FILE *fp, int n) int mount_quiet = 0; -int -main (int argc, char *argv[]) -{ - int c; - int all = 0; - string_list types = NULL; - string_list options; - struct mntentchn *mc, *fs; - char *file; - int result = 0; - - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - - while ((c = getopt_long (argc, argv, "afhnrt:vV", - longopts, NULL)) != EOF) - switch (c) { - case 'a': /* umount everything */ - ++all; - break; - /* fall through? */ - case 'd': /* do losetup -d for unmounted loop devices */ - ++delloop; - break; - case 'f': /* force umount */ - ++force; - break; - case 'h': /* help */ - usage (stdout, 0); - break; - case 'n': /* do not write in /etc/mtab */ - ++nomtab; - break; - case 'r': /* remount read-only if umount fails */ - ++remount; - break; - case 'v': /* make noise */ - ++verbose; - break; - case 'V': /* version */ - printf ("umount: %s\n", version); - exit (0); - case 't': /* specify file system type */ - types = parse_list (optarg); - break; - case 0: - break; - case '?': - default: - usage (stderr, 1); - } - - if (getuid () != geteuid ()) - { - suid = 1; - if (all || types || nomtab || force) - die (2, _("umount: only root can do that")); - } - - argc -= optind; - argv += optind; - - if (all) { - if (types == NULL) - types = parse_list("noproc"); - result = umount_all (types); - } else if (argc < 1) { - usage (stderr, 2); - } else while (argc--) { - file = canonicalize (*argv); /* mtab paths are canonicalized */ - if (verbose > 1) - printf(_("Trying to umount %s\n"), file); - - mc = getmntfilesbackward (file, NULL); - if (!mc && verbose) - printf(_("Could not find %s in mtab\n"), file); - - if (suid) { - if (!mc) - die (2, _("umount: %s is not mounted (according to mtab)"), file); - if (getmntfilesbackward (file, mc)) - die (2, _("umount: it seems %s is mounted multiple times"), file); - - /* If fstab contains the two lines - /dev/sda1 /mnt/zip auto user,noauto 0 0 - /dev/sda4 /mnt/zip auto user,noauto 0 0 - then "mount /dev/sda4" followed by "umount /mnt/zip" - used to fail. So, we must not look for file, but for - the pair (spec,file) in fstab. */ - fs = getfsspecfile(mc->m.mnt_fsname, mc->m.mnt_dir); - if (!fs) { - if (!getfsspec (file) && !getfsfile (file)) - die (2, - _("umount: %s is not in the fstab (and you are not root)"), - file); - else - die (2, _("umount: %s mount disagrees with the fstab"), file); - } +/*=======================================================================*/ +/* string list stuff - no longer used by mount - will disappear entirely */ +typedef struct string_list { + char *hd; + struct string_list *tl; +} *string_list; - /* User mounting and unmounting is allowed only - if fstab contains the option `user' or `users' */ - /* The option `users' allows arbitrary users to mount - and unmount - this may be a security risk. */ - /* The option `user' only allows unmounting by the user - that mounted. */ - /* The option `owner' only allows (un)mounting by the owner. */ - /* A convenient side effect is that the user who mounted - is visible in mtab. */ - options = parse_list (fs->m.mnt_opts); - while (options) { - if (streq (car (options), "user") || - streq (car (options), "users") || - streq (car (options), "owner")) - break; - options = cdr (options); - } - if (!options) - die (2, _("umount: only root can unmount %s from %s"), - fs->m.mnt_fsname, fs->m.mnt_dir); - if (streq (car (options), "user") || - streq (car (options), "owner")) { - char *user = getusername(); - - options = parse_list (mc->m.mnt_opts); - while (options) { - char *co = car (options); - if (!strncmp(co, "user=", 5)) { - if (!user || !streq(co+5,user)) - die(2, _("umount: only %s can unmount %s from %s"), - co+5, fs->m.mnt_fsname, fs->m.mnt_dir); - break; - } - options = cdr (options); - } - } - } +#define car(p) ((p) -> hd) +#define cdr(p) ((p) -> tl) - if (mc) - result = umount_one_bw (file, mc); - else - result = umount_one (*argv, *argv, *argv, *argv, NULL); +static string_list +cons (char *a, const string_list b) { + string_list p; - argv++; + p = xmalloc (sizeof *p); + car (p) = a; + cdr (p) = b; + return p; +} + +/* Parse a list of strings like str[,str]... into a string list. */ +static string_list +parse_list (char *strings) { + string_list list; + char *s, *t; + + if (strings == NULL) + return NULL; + + /* strtok() destroys its argument, so we have to use a copy */ + s = xstrdup(strings); + + list = cons (strtok (s, ","), NULL); + + while ((t = strtok (NULL, ",")) != NULL) + list = cons (t, list); + + return list; +} +/*=======================================================================*/ + +static int +umount_file (char *arg) { + struct mntentchn *mc, *fs; + char *file; + string_list options; + + file = canonicalize (arg); /* mtab paths are canonicalized */ + if (verbose > 1) + printf(_("Trying to umount %s\n"), file); + + mc = getmntfilesbackward (file, NULL); + if (!mc && verbose) + printf(_("Could not find %s in mtab\n"), file); + + if (suid) { + if (!mc) + die (2, _("umount: %s is not mounted (according to mtab)"), file); + if (getmntfilesbackward (file, mc)) + die (2, _("umount: it seems %s is mounted multiple times"), file); + + /* If fstab contains the two lines + /dev/sda1 /mnt/zip auto user,noauto 0 0 + /dev/sda4 /mnt/zip auto user,noauto 0 0 + then "mount /dev/sda4" followed by "umount /mnt/zip" + used to fail. So, we must not look for file, but for + the pair (spec,file) in fstab. */ + fs = getfsspecfile(mc->m.mnt_fsname, mc->m.mnt_dir); + if (!fs) { + if (!getfsspec (file) && !getfsfile (file)) + die (2, + _("umount: %s is not in the fstab (and you are not root)"), + file); + else + die (2, _("umount: %s mount disagrees with the fstab"), file); + } + + /* User mounting and unmounting is allowed only + if fstab contains the option `user' or `users' */ + /* The option `users' allows arbitrary users to mount + and unmount - this may be a security risk. */ + /* The option `user' only allows unmounting by the user + that mounted. */ + /* The option `owner' only allows (un)mounting by the owner. */ + /* A convenient side effect is that the user who mounted + is visible in mtab. */ + options = parse_list (fs->m.mnt_opts); + while (options) { + if (streq (car (options), "user") || + streq (car (options), "users") || + streq (car (options), "owner")) + break; + options = cdr (options); + } + if (!options) + die (2, _("umount: only root can unmount %s from %s"), + fs->m.mnt_fsname, fs->m.mnt_dir); + if (streq (car (options), "user") || + streq (car (options), "owner")) { + char *user = getusername(); + + options = parse_list (mc->m.mnt_opts); + while (options) { + char *co = car (options); + if (!strncmp(co, "user=", 5)) { + if (!user || !streq(co+5,user)) + die(2, _("umount: only %s can unmount %s from %s"), + co+5, fs->m.mnt_fsname, fs->m.mnt_dir); + break; + } + options = cdr (options); + } + } + } + + if (mc) + return umount_one_bw (file, mc); + else + return umount_one (arg, arg, arg, arg, NULL); - } - exit (result); } +int +main (int argc, char *argv[]) { + int c; + int all = 0; + char *types = NULL; + int result = 0; + + sanitize_env(); + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + while ((c = getopt_long (argc, argv, "adfhnrt:vV", + longopts, NULL)) != EOF) + switch (c) { + case 'a': /* umount everything */ + ++all; + break; + /* fall through? */ + case 'd': /* do losetup -d for unmounted loop devices */ + ++delloop; + break; + case 'f': /* force umount */ + ++force; + break; + case 'h': /* help */ + usage (stdout, 0); + break; + case 'n': /* do not write in /etc/mtab */ + ++nomtab; + break; + case 'r': /* remount read-only if umount fails */ + ++remount; + break; + case 'v': /* make noise */ + ++verbose; + break; + case 'V': /* version */ + printf ("umount: %s\n", version); + exit (0); + case 't': /* specify file system type */ + types = optarg; + break; + case 0: + break; + case '?': + default: + usage (stderr, 1); + } + + if (getuid () != geteuid ()) { + suid = 1; + if (all || types || nomtab || force) + die (2, _("umount: only root can do that")); + } + + argc -= optind; + argv += optind; + + if (all) { + if (types == NULL) + types = "noproc"; + result = umount_all (types); + } else if (argc < 1) { + usage (stderr, 2); + } else while (argc--) { + result += umount_file(*argv++); + } + exit (result); /* nonzero on at least one failure */ +} |