📄 mount.c
字号:
return (stat(s, &statbuf) == 0);}/* * Return 0 for success (either mounted sth or -a and NOAUTO was given) */static intmount_one (const char *spec, const char *node, const char *types, const char *opts, char *cmdlineopts, int freq, int pass) { int status, status2; const char *nspec; /* Substitute values in opts, if required */ opts = usersubst(opts); /* Merge the fstab and command line options. */ if (opts == NULL) opts = cmdlineopts; else if (cmdlineopts != NULL) opts = xstrconcat3(opts, ",", cmdlineopts); /* Handle possible LABEL= and UUID= forms of spec */ nspec = mount_get_devname_for_mounting(spec); if (nspec) spec = nspec; if (types == NULL && !mounttype && !is_existing_file(spec)) { if (strchr (spec, ':') != NULL) { types = "nfs"; if (verbose) printf(_("mount: no type was given - " "I'll assume nfs because of " "the colon\n")); } else if(!strncmp(spec, "//", 2)) { types = "smbfs"; if (verbose) printf(_("mount: no type was given - " "I'll assume smbfs because of " "the // prefix\n")); } } /* * 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, types, opts, freq, pass, 0, 0); if (status != EX_BG) return status; /* * Retry in the background. */ printf (_("mount: backgrounding \"%s\"\n"), spec); fflush( stdout ); /* prevent duplicate output */ if (fork() > 0) return 0; /* parent returns "success" */ spec = xstrdup(spec); /* arguments will be destroyed */ node = xstrdup(node); /* by set_proc_name() */ types = xstrdup(types); opts = xstrdup(opts); set_proc_name (spec); /* make a nice "ps" listing */ 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 */}/* Check if an fsname/dir pair was already in the old mtab. */static intmounted (const char *spec0, const char *node0) { struct mntentchn *mc, *mc0; char *spec, *node; int ret = 0; /* Handle possible UUID= and LABEL= in spec */ spec0 = mount_get_devname(spec0); if (!spec0) return ret; spec = canonicalize(spec0); node = canonicalize(node0); mc0 = mtab_head(); for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) if (streq (spec, mc->m.mnt_fsname) && streq (node, mc->m.mnt_dir)) { ret = 1; break; } my_free(spec); my_free(node); return ret;}/* avoid using stat() on things we are not going to mount anyway.. */static inthas_noauto (const char *opts) { char *s; if (!opts) return 0; s = strstr(opts, "noauto"); if (!s) return 0; return (s == opts || s[-1] == ',') && (s[6] == 0 || s[6] == ',');}/* Mount all filesystems of the specified types except swap and root. *//* With the --fork option: fork and let different incarnations of mount handle different filesystems. However, try to avoid several simultaneous mounts on the same physical disk, since that is very slow. */#define DISKMAJOR(m) (((int) m) & ~0xf)static intdo_mount_all (char *types, char *options, char *test_opts) { struct mntentchn *mc, *mc0, *mtmp; int status = 0; struct stat statbuf; struct child { pid_t pid; char *group; struct mntentchn *mec; struct mntentchn *meclast; struct child *nxt; } childhead, *childtail, *cp; char major[22]; char *g, *colon; /* build a chain of what we have to do, or maybe several chains, one for each major or NFS host */ childhead.nxt = 0; childtail = &childhead; mc0 = fstab_head(); for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) { if (has_noauto (mc->m.mnt_opts)) continue; if (matching_type (mc->m.mnt_type, types) && matching_opts (mc->m.mnt_opts, test_opts) && !streq (mc->m.mnt_dir, "/") && !streq (mc->m.mnt_dir, "root")) { if (mounted (mc->m.mnt_fsname, mc->m.mnt_dir)) { if (verbose) printf(_("mount: %s already mounted " "on %s\n"), mc->m.mnt_fsname, mc->m.mnt_dir); continue; } mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp)); *mtmp = *mc; mtmp->nxt = 0; g = NULL; if (optfork) { if (stat(mc->m.mnt_fsname, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { sprintf(major, "#%x", DISKMAJOR(statbuf.st_rdev)); g = major; }#ifdef HAVE_NFS if (strcmp(mc->m.mnt_type, "nfs") == 0) { g = xstrdup(mc->m.mnt_fsname); colon = strchr(g, ':'); if (colon) *colon = '\0'; }#endif } if (g) { for (cp = childhead.nxt; cp; cp = cp->nxt) if (cp->group && strcmp(cp->group, g) == 0) { cp->meclast->nxt = mtmp; cp->meclast = mtmp; goto fnd; } } cp = (struct child *) xmalloc(sizeof *cp); cp->nxt = 0; cp->mec = cp->meclast = mtmp; cp->group = xstrdup(g); cp->pid = 0; childtail->nxt = cp; childtail = cp; fnd:; } } /* now do everything */ for (cp = childhead.nxt; cp; cp = cp->nxt) { pid_t p = -1; if (optfork) { p = fork(); if (p == -1) { int errsv = errno; error(_("mount: cannot fork: %s"), strerror (errsv)); } else if (p != 0) cp->pid = p; } /* if child, or not forked, do the mounting */ if (p == 0 || p == -1) { for (mc = cp->mec; mc; mc = mc->nxt) { status |= mount_one (mc->m.mnt_fsname, mc->m.mnt_dir, mc->m.mnt_type, mc->m.mnt_opts, options, 0, 0); } if (mountcount) status |= EX_SOMEOK; if (p == 0) exit(status); } } /* wait for children, if any */ while ((cp = childhead.nxt) != NULL) { childhead.nxt = cp->nxt; if (cp->pid) { int ret; keep_waiting: if(waitpid(cp->pid, &ret, 0) == -1) { if (errno == EINTR) goto keep_waiting; perror("waitpid"); } else if (WIFEXITED(ret)) status |= WEXITSTATUS(ret); else status |= EX_SYSERR; } } if (mountcount) status |= EX_SOMEOK; return status;}extern char version[];static struct option longopts[] = { { "all", 0, 0, 'a' }, { "fake", 0, 0, 'f' }, { "fork", 0, 0, 'F' }, { "help", 0, 0, 'h' }, { "no-mtab", 0, 0, 'n' }, { "read-only", 0, 0, 'r' }, { "ro", 0, 0, 'r' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { "read-write", 0, 0, 'w' }, { "rw", 0, 0, 'w' }, { "options", 1, 0, 'o' }, { "test-opts", 1, 0, 'O' }, { "pass-fd", 1, 0, 'p' }, { "types", 1, 0, 't' }, { "bind", 0, 0, 128 }, { "replace", 0, 0, 129 }, { "after", 0, 0, 130 }, { "before", 0, 0, 131 }, { "over", 0, 0, 132 }, { "move", 0, 0, 133 }, { "guess-fstype", 1, 0, 134 }, { "rbind", 0, 0, 135 }, { "internal-only", 0, 0, 'i' }, { NULL, 0, 0, 0 }};/* Keep the usage message at max 22 lines, each at most 70 chars long. The user should not need a pager to read it. */static voidusage (FILE *fp, int n) { fprintf(fp, _( "Usage: mount -V : print version\n" " mount -h : print this help\n" " mount : list mounted filesystems\n" " mount -l : idem, including volume labels\n" "So far the informational part. Next the mounting.\n" "The command is `mount [-t fstype] something somewhere'.\n" "Details found in /etc/fstab may be omitted.\n" " mount -a [-t|-O] ... : mount all stuff from /etc/fstab\n" " mount device : mount device at the known place\n" " mount directory : mount known device here\n" " mount -t type dev dir : ordinary mount command\n" "Note that one does not really mount a device, one mounts\n" "a filesystem (of the given type) found on the device.\n" "One can also mount an already visible directory tree elsewhere:\n" " mount --bind olddir newdir\n" "or move a subtree:\n" " mount --move olddir newdir\n" "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n" "or by label, using -L label or by uuid, using -U uuid .\n" "Other options: [-nfFrsvw] [-o options] [-p passwdfd].\n" "For many more details, say man 8 mount .\n" ));/* "Union or stack mounts are specified using one of\n" " --replace, --after, --before, --over\n"*/ unlock_mtab(); exit (n);}char *progname;intmain(int argc, char *argv[]) { int c, result = 0, specseen; char *options = NULL, *test_opts = NULL, *node; const char *spec; char *volumelabel = NULL; char *uuid = NULL; char *types = NULL; char *p; struct mntentchn *mc; int fd; sanitize_env(); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); progname = argv[0]; if ((p = strrchr(progname, '/')) != NULL) progname = p+1; umask(033); /* People report that a mount called from init without console writes error messages to /etc/mtab Let us try to avoid getting fd's 0,1,2 */ while((fd = open("/dev/null", O_RDWR)) == 0 || fd == 1 || fd == 2) ; if (fd > 2) close(fd); mount_blkid_get_cache();#ifdef DO_PS_FIDDLING initproctitle(argc, argv);#endif while ((c = getopt_long (argc, argv, "afFhilL:no:O:p:rsU:vVwt:", longopts, NULL)) != -1) { switch (c) { case 'a': /* mount everything in fstab */ ++mount_all; break; case 'f': /* fake: don't actually call mount(2) */ ++fake; break; case 'F': ++optfork; break; case 'h': /* help */ usage (stdout, 0); break; case 'i': external_allowed = 0; break; case 'l': list_with_volumelabel = 1; break; case 'L': volumelabel = optarg; break; case 'n': /* do not write /etc/mtab */ ++nomtab; break; case 'o': /* specify mount options */ if (options) options = xstrconcat3(options, ",", optarg); else options = xstrdup(optarg); break; case 'O': /* with -t: mount only if (not) opt */ if (test_opts) test_opts = xstrconcat3(test_opts, ",", optarg); else test_opts = xstrdup(optarg); break; case 'p': /* fd on which to read passwd */ set_pfd(optarg); break; case 'r': /* mount readonly */ readonly = 1; readwrite = 0; break; case 's': /* allow sloppy mount options */ sloppy = 1; break; case 't': /* specify file system types */ types = optarg; break; case 'U': uuid = optarg; break; case 'v': /* be chatty - more so if repeated */ ++verbose; break; case 'V': /* version */ printf ("mount: %s\n", version); exit (0); case 'w': /* mount read/write */ readwrite = 1; readonly = 0; break; case 0: break; case 128: /* bind */ mounttype = MS_BIND; break; case 129: /* replace */ mounttype = MS_REPLACE; break; case 130: /* after */ mounttype = MS_AFTER; break; case 131: /* before */ mounttype = MS_BEFORE; break; case 132: /* over */ mounttype = MS_OVER; break; case 133: /* move */ mounttype = MS_MOVE; break; case 134: /* undocumented, may go away again: call: mount --guess-fstype device use only for testing purposes - the guessing is not reliable at all */ { char *fstype; fstype = do_guess_fstype(optarg); printf("%s\n", fstype ? fstype : "unknown"); exit(fstype ? 0 : EX_FAIL); } case 135: mounttype = (MS_BIND | MS_REC); break; case '?': default: usage (stderr, EX_USAGE); } } argc -= optind; argv += optind; specseen = (uuid || volumelabel) ? 1 : 0; /* yes, .. i know */ if (argc+specseen == 0 && !mount_all) { if (options || mounttype) usage (stderr, EX_USAGE); return print_all (types); } if (getuid () != geteuid ()) { suid = 1; if (types || options || readwrite || nomtab || mount_all || fake || mounttype || (argc + specseen) != 1) die (EX_USAGE, _("mount: only root can do that")); } if (!nomtab && mtab_does_not_exist()) { if (verbose > 1) printf(_("mount: no %s found - creating it..\n"), MOUNTED); create_mtab (); } if (specseen) { if (uuid) spec = mount_get_devname_by_uuid(uuid); else spec = mount_get_devname_by_label(volumelabel); if (!spec) die (EX_USAGE, _("mount: no such partition found")); if (verbose) printf(_("mount: mounting %s\n"), spec); } else spec = NULL; /* just for gcc */ switch (argc+specseen) { case 0: /* mount -a */ result = do_mount_all (types, options, test_opts); if (result == 0 && verbose) error(_("nothing was mounted")); break; case 1: /* mount [-nfrvw] [-o options] special | node */ if (types != NULL) usage (stderr, EX_USAGE); if (specseen) { /* We know the device. Where shall we mount it? */ mc = (uuid ? getfsuuidspec (uuid) : getfsvolspec (volumelabel)); if (mc == NULL) mc = getfsspec (spec); if (mc == NULL) die (EX_USAGE, _("mount: cannot find %s in %s"), spec, _PATH_FSTAB); mc->m.mnt_fsname = spec; } else { /* Try to find the other pathname in fstab. */ spec = canonicalize (*argv); if ((mc = getfsspec (spec)) == NULL && (mc = getfsfile (spec)) == NULL && /* Try noncanonical name in fstab perhaps /dev/cdrom or /dos is a symlink */ (mc = getfsspec (*argv)) == NULL && (mc = getfsfile (*argv)) == NULL && /* Try mtab - maybe this was a remount */ (mc = getmntfile (spec)) == NULL) die (EX_USAGE, _("mount: can't find %s in %s or %s"), spec, _PATH_FSTAB, MOUNTED); /* Earlier mtab was tried first, but this would sometimes try the wrong mount in case mtab had the root device entry wrong. */ my_free(spec); } result = mount_one (xstrdup (mc->m.mnt_fsname), xstrdup (mc->m.mnt_dir), xstrdup (mc->m.mnt_type), mc->m.mnt_opts, options, 0, 0); break; case 2: /* mount [-nfrvw] [-t vfstype] [-o options] special node */ if (specseen) { /* we have spec already */ node = argv[0]; } else { spec = argv[0]; node = argv[1]; } result = mount_one (spec, node, types, NULL, options, 0, 0); break; default: usage (stderr, EX_USAGE); } if (result == EX_SOMEOK) result = 0; mount_blkid_put_cache(); exit (result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -