📄 mount.c
字号:
*user = getusername(); } *flags &= ~(MS_OWNER | MS_GROUP);}static intloop_check(const char **spec, const char **type, int *flags, int *loop, const char **loopdev, const char **loopfile) { int looptype; unsigned long long offset; /* * In the case of a loop mount, either type is of the form lo@/dev/loop5 * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or * mount just has to figure things out for itself from the fact that * spec is not a block device. We do not test for a block device * immediately: maybe later other types of mountable objects will occur. */ *loopdev = opt_loopdev; looptype = (*type && strncmp("lo@", *type, 3) == 0); if (looptype) { if (*loopdev) error(_("mount: loop device specified twice")); *loopdev = *type + 3; *type = opt_vfstype; } else if (opt_vfstype) { if (*type) error(_("mount: type specified twice")); else *type = opt_vfstype; } *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption); *loopfile = *spec; if (*loop) { *flags |= MS_LOOP; if (fake) { if (verbose) printf(_("mount: skipping the setup of a loop device\n")); } else { int loopro = (*flags & MS_RDONLY); if (!*loopdev || !**loopdev) *loopdev = find_unused_loop_device(); if (!*loopdev) return EX_SYSERR; /* no more loop devices */ if (verbose) printf(_("mount: going to use the loop device %s\n"), *loopdev); offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0; if (set_loop(*loopdev, *loopfile, offset, opt_encryption, pfd, &loopro)) { if (verbose) printf(_("mount: failed setting up loop device\n")); return EX_FAIL; } if (verbose > 1) printf(_("mount: setup loop device successfully\n")); *spec = *loopdev; if (loopro) *flags |= MS_RDONLY; } } return 0;}static voidupdate_mtab_entry(const char *spec, const char *node, const char *type, const char *opts, int flags, int freq, int pass) { struct my_mntent mnt; mnt.mnt_fsname = canonicalize (spec); mnt.mnt_dir = canonicalize (node); mnt.mnt_type = type; mnt.mnt_opts = opts; mnt.mnt_freq = freq; mnt.mnt_passno = pass; /* We get chatty now rather than after the update to mtab since the mount succeeded, even if the write to /etc/mtab should fail. */ if (verbose) print_one (&mnt); if (!nomtab && mtab_is_writable()) { if (flags & MS_REMOUNT) update_mtab (mnt.mnt_dir, &mnt); else { mntFILE *mfp; lock_mtab(); mfp = my_setmntent(MOUNTED, "a+"); if (mfp == NULL || mfp->mntent_fp == NULL) { int errsv = errno; error(_("mount: can't open %s: %s"), MOUNTED, strerror (errsv)); } else { if ((my_addmntent (mfp, &mnt)) == 1) { int errsv = errno; error(_("mount: error writing %s: %s"), MOUNTED, strerror (errsv)); } } my_endmntent(mfp); unlock_mtab(); } } my_free(mnt.mnt_fsname); my_free(mnt.mnt_dir);}static voidset_pfd(char *s) { if (!isdigit(*s)) die(EX_USAGE, _("mount: argument to -p or --pass-fd must be a number")); pfd = atoi(optarg);}static voidcdrom_setspeed(const char *spec) {#define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */ if (opt_speed) { int cdrom; int speed = atoi(opt_speed); if ((cdrom = open(spec, O_RDONLY | O_NONBLOCK)) < 0) die(EX_FAIL, _("mount: cannot open %s for setting speed"), spec); if (ioctl(cdrom, CDROM_SELECT_SPEED, speed) < 0) die(EX_FAIL, _("mount: cannot set speed: %s"), strerror(errno)); close(cdrom); }}/* * check_special_mountprog() * If there is a special mount program for this type, exec it. * returns: 0: no exec was done, 1: exec was done, status has result */static intcheck_special_mountprog(const char *spec, const char *node, const char *type, int flags, char *extra_opts, int *status) { char mountprog[120]; struct stat statbuf; int res; if (!external_allowed) return 0; if (type && strlen(type) < 100) { sprintf(mountprog, "/sbin/mount.%s", type); if (stat(mountprog, &statbuf) == 0) { res = fork(); if (res == 0) { const char *oo, *mountargs[10]; int i = 0; setuid(getuid()); setgid(getgid()); oo = fix_opts_string (flags, extra_opts, NULL); mountargs[i++] = mountprog; mountargs[i++] = spec; mountargs[i++] = node; if (nomtab) mountargs[i++] = "-n"; if (verbose) mountargs[i++] = "-v"; if (oo && *oo) { mountargs[i++] = "-o"; mountargs[i++] = oo; } mountargs[i] = NULL; execv(mountprog, (char **) mountargs); exit(1); /* exec failed */ } else if (res != -1) { int st; wait(&st); *status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR); return 1; } else { int errsv = errno; error(_("mount: cannot fork: %s"), strerror(errsv)); } } } return 0;}/* * try_mount_one() * Try to mount one file system. When "bg" is 1, this is a retry * in the background. One additional exit code EX_BG is used here. * It is used to instruct the caller to retry the mount in the * background. * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount, * return status from wait */static inttry_mount_one (const char *spec0, const char *node0, const char *types0, const char *opts0, int freq, int pass, int bg, int ro) { int res = 0, status; int mnt5_res = 0; /* only for gcc */ int mnt_err; int flags; char *extra_opts; /* written in mtab */ char *mount_opts; /* actually used on system call */ const char *opts, *spec, *node, *types; char *user = 0; int loop = 0; const char *loopdev = 0, *loopfile = 0; struct stat statbuf; int nfs_mount_version = 0; /* any version */ /* copies for freeing on exit */ const char *opts1, *spec1, *node1, *types1, *extra_opts1; spec = spec1 = xstrdup(spec0); node = node1 = xstrdup(node0); types = types1 = xstrdup(types0); opts = opts1 = xstrdup(opts0); parse_opts (opts, &flags, &extra_opts); extra_opts1 = extra_opts; /* quietly succeed for fstab entries that don't get mounted automatically */ if (mount_all && (flags & MS_NOAUTO)) goto out; suid_check(spec, node, &flags, &user); mount_opts = extra_opts; if (opt_speed) cdrom_setspeed(spec); if (!(flags & MS_REMOUNT)) { /* * Don't set up a (new) loop device if we only remount - this left * stale assignments of files to loop devices. Nasty when used for * encryption. */ res = loop_check(&spec, &types, &flags, &loop, &loopdev, &loopfile); if (res) goto out; } /* * Call mount.TYPE for types that require a separate mount program. * For the moment these types are ncpfs and smbfs. Maybe also vxfs. * All such special things must occur isolated in the types string. */ if (check_special_mountprog(spec, node, types, flags, extra_opts, &status)) { res = status; goto out; } /* * Also nfs requires a separate program, but it is built in. */ if (!fake && types && streq (types, "nfs")) {#ifdef HAVE_NFSretry_nfs: mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts, &nfs_mount_version, bg); if (mnt_err) { res = mnt_err; goto out; }#else die (EX_SOFTWARE, _("mount: this version was compiled " "without support for the type `nfs'"));#endif } block_signals (SIG_BLOCK); if (!fake) mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS, mount_opts); if (fake || mnt5_res == 0) { /* Mount succeeded, report this (if verbose) and write mtab entry. */ if (loop) opt_loopdev = loopdev; update_mtab_entry(loop ? loopfile : spec, node, types ? types : "unknown", fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user), flags, freq, pass); block_signals (SIG_UNBLOCK); res = 0; goto out; } mnt_err = errno; if (loop) del_loop(spec); block_signals (SIG_UNBLOCK);#ifdef HAVE_NFS if (mnt_err && types && streq (types, "nfs")) { if (nfs_mount_version == 4 && mnt_err != EBUSY && mnt_err != ENOENT) { if (verbose) printf(_("mount: failed with nfs mount version 4, trying 3..\n")); nfs_mount_version = 3; goto retry_nfs; } }#endif /* Mount failed, complain, but don't die. */ if (types == 0) { if (suid) error (_("mount: I could not determine the filesystem type, " "and none was specified")); else error (_("mount: you must specify the filesystem type")); } else if (mnt5_res != -1) { /* should not happen */ error (_("mount: mount failed")); } else { switch (mnt_err) { case EPERM: if (geteuid() == 0) { if (stat (node, &statbuf) || !S_ISDIR(statbuf.st_mode)) error (_("mount: mount point %s is not a directory"), node); else error (_("mount: permission denied")); } else error (_("mount: must be superuser to use mount")); break; case EBUSY: if (flags & MS_REMOUNT) { error (_("mount: %s is busy"), node); } 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 */ else if (!mount_all || verbose) /* yes, don't mention it */ error (_("mount: proc already mounted")); } else { error (_("mount: %s already mounted or %s busy"), spec, node); already (spec, node); } break; case ENOENT: if (lstat (node, &statbuf)) error (_("mount: mount point %s does not exist"), node); else if (stat (node, &statbuf)) error (_("mount: mount point %s is a symbolic link to nowhere"), node); else if (stat (spec, &statbuf)) error (_("mount: special device %s does not exist"), spec); else { errno = mnt_err; perror("mount"); } break; case ENOTDIR: if (stat (node, &statbuf) || ! S_ISDIR(statbuf.st_mode)) error (_("mount: mount point %s is not a directory"), node); else if (stat (spec, &statbuf) && errno == ENOTDIR) error (_("mount: special device %s does not exist\n" " (a path prefix is not a directory)\n"), spec); else { errno = mnt_err; perror("mount"); } break; case EINVAL: { int fd; unsigned long size; int warned=0; if (flags & MS_REMOUNT) { error (_("mount: %s not mounted already, or bad option"), node); } else { error (_("mount: wrong fs type, bad option, bad superblock on %s,\n" " missing codepage, or too many mounted file systems"), spec); if (stat(spec, &statbuf) == 0 && S_ISBLK(statbuf.st_mode) && (fd = open(spec, O_RDONLY | O_NONBLOCK)) >= 0) { if (ioctl(fd, BLKGETSIZE, &size) == 0) { if (size == 0 && !loop) { warned++; error (" (could this be the IDE device where you in fact use\n" " ide-scsi so that sr0 or sda or so is needed?)"); } if (size && size <= 2) { warned++; error (" (aren't you trying to mount an extended partition,\n" " instead of some logical partition inside?)"); } close(fd); }#if 0 /* 0xf for SCSI, 0x3f for IDE. One might check /proc/partitions to see whether this thing really is partitioned. Do not suggest partitions for /dev/fd0. */ if (!warned && (statbuf.st_rdev & 0xf) == 0) { warned++; error (" (could this be the whole disk device\n" " where you need a partition?)"); }#endif } } break; } case EMFILE: error (_("mount table full")); break; case EIO: error (_("mount: %s: can't read superblock"), spec); break; case ENODEV: { int pfs; 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: unknown filesystem type '%s'"), types); /* maybe this loser asked for FAT or ISO9660 or isofs */ lowtype = xstrdup(types); u = 0; for(p=lowtype; *p; p++) { if(tolower(*p) != *p) { *p = tolower(*p); u++; } } if (u && is_in_procfs(lowtype) == 1) error (_("mount: probably you meant %s"), lowtype); else if (!strncmp(lowtype, "iso", 3) && is_in_procfs("iso9660") == 1) error (_("mount: maybe you meant 'iso9660'?")); else if (!strncmp(lowtype, "fat", 3) && is_in_procfs("vfat") == 1) error (_("mount: maybe you meant 'vfat'?")); free(lowtype); } else error (_("mount: %s has wrong device number or fs type %s not supported"), spec, types); break; } case ENOTBLK: if (stat (spec, &statbuf)) /* strange ... */ error (_("mount: %s is not a block device, and stat fails?"), spec); else if (S_ISBLK(statbuf.st_mode)) error (_("mount: the kernel does not recognize %s as a block device\n" " (maybe `insmod driver'?)"), spec); else if (S_ISREG(statbuf.st_mode)) error (_("mount: %s is not a block device (maybe try `-o loop'?)"), spec); else error (_("mount: %s is not a block device"), spec); break; case ENXIO: error (_("mount: %s is not a valid block device"), spec); break; case EACCES: /* pre-linux 1.1.38, 1.1.41 and later */ case EROFS: /* linux 1.1.38 and later */ { char *bd = (loop ? "" : _("block device ")); if (ro || (flags & MS_RDONLY)) { error (_("mount: cannot mount %s%s read-only"), bd, spec); break; } else if (readwrite) { error (_("mount: %s%s is write-protected but explicit `-w' flag given"), bd, spec); break; } else { if (loop) { opts = opts0; types = types0; } if (opts) { char *opts2 = realloc(xstrdup(opts), strlen(opts)+4); strcat(opts2, ",ro"); my_free(opts1); opts = opts1 = opts2; } else opts = "ro"; if (types && !strcmp(types, "guess")) types = 0; error (_("mount: %s%s is write-protected, mounting read-only"), bd, spec0); res = try_mount_one (spec0, node0, types, opts, freq, pass, bg, 1); goto out; } break; } default: error ("mount: %s", strerror (mnt_err)); break; } } res = EX_FAIL; out: my_free(extra_opts1); my_free(spec1); my_free(node1); my_free(opts1); my_free(types1); return res;}/* * set_proc_name() * Update the argument vector, so that this process may be easily * identified in a "ps" listing. */static voidset_proc_name (const char *spec){#ifdef DO_PS_FIDDLING setproctitle ("mount", spec);#endif}static char *subst_string(const char *s, const char *sub, int sublen, const char *repl) { char *n; n = (char *) xmalloc(strlen(s)-sublen+strlen(repl)+1); strncpy (n, s, sub-s); strcpy (n + (sub-s), repl); strcat (n, sub+sublen); return n;}static const char *usersubst(const char *opts) { char *s, *w; char id[40]; s = "uid=useruid"; if (opts && (w = strstr(opts, s)) != NULL) { sprintf(id, "uid=%d", getuid()); opts = subst_string(opts, w, strlen(s), id); } s = "gid=usergid"; if (opts && (w = strstr(opts, s)) != NULL) { sprintf(id, "gid=%d", getgid()); opts = subst_string(opts, w, strlen(s), id); } return opts;}static intis_existing_file (const char *s) { struct stat statbuf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -