diff options
| author | Rob Landley <rob@landley.net> | 2006-03-14 18:16:25 +0000 |
|---|---|---|
| committer | Rob Landley <rob@landley.net> | 2006-03-14 18:16:25 +0000 |
| commit | dc0955b603547dad03e5a9d65f6ab50e0d935aba (patch) | |
| tree | d176f2a516f6f92aad5c8a35e082e690f29d637e /util-linux | |
| parent | 0b22c1c962ff57e68035413d7790dd2b137a2aeb (diff) | |
| download | busybox-w32-dc0955b603547dad03e5a9d65f6ab50e0d935aba.tar.gz busybox-w32-dc0955b603547dad03e5a9d65f6ab50e0d935aba.tar.bz2 busybox-w32-dc0955b603547dad03e5a9d65f6ab50e0d935aba.zip | |
The new, new mount rewrite. (Mount double prime?) Still being debugged, but
the new infrastructure is reentrant so in theory it's capable of handling
mount -a sanely. It can also re-use existing flags with remount, handle
-t auto, mount -a -t, and several smaller bugfixes.
Diffstat (limited to 'util-linux')
| -rw-r--r-- | util-linux/mount.c | 660 |
1 files changed, 408 insertions, 252 deletions
diff --git a/util-linux/mount.c b/util-linux/mount.c index 68542f9bc..c5aec74fa 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c | |||
| @@ -4,11 +4,24 @@ | |||
| 4 | * | 4 | * |
| 5 | * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. | 5 | * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. |
| 6 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | 6 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> |
| 7 | * Copyright (C) 2005 by Rob Landley <rob@landley.net> | 7 | * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net> |
| 8 | * | 8 | * |
| 9 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 9 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | /* todo: | ||
| 13 | * bb_getopt_ulflags(); | ||
| 14 | */ | ||
| 15 | |||
| 16 | /* Design notes: There is no spec for this. Remind me to write one. | ||
| 17 | |||
| 18 | mount_main() calls singlemount() which calls mount_it_now(). | ||
| 19 | |||
| 20 | mount_main() can loop through /etc/fstab for mount -a | ||
| 21 | singlemount() can loop through /etc/filesystems for fstype detection. | ||
| 22 | mount_it_now() does the actual mount. | ||
| 23 | */ | ||
| 24 | |||
| 12 | #include <limits.h> | 25 | #include <limits.h> |
| 13 | #include <stdlib.h> | 26 | #include <stdlib.h> |
| 14 | #include <unistd.h> | 27 | #include <unistd.h> |
| @@ -29,18 +42,28 @@ | |||
| 29 | #ifndef MS_MOVE | 42 | #ifndef MS_MOVE |
| 30 | #define MS_MOVE 8192 | 43 | #define MS_MOVE 8192 |
| 31 | #endif | 44 | #endif |
| 45 | #ifndef MS_SILENT | ||
| 46 | #define MS_SILENT 32768 | ||
| 47 | #endif | ||
| 32 | 48 | ||
| 33 | /* Consume standard mount options (from -o options or --options). | 49 | // Not real flags, but we want to be able to check for this. |
| 34 | * Set appropriate flags and collect unrecognized ones as a comma separated | 50 | #define MOUNT_NOAUTO (1<<29) |
| 35 | * string to pass to kernel */ | 51 | #define MOUNT_SWAP (1<<30) |
| 52 | /* Standard mount options (from -o options or --options), with corresponding | ||
| 53 | * flags */ | ||
| 36 | 54 | ||
| 37 | struct { | 55 | struct { |
| 38 | const char *name; | 56 | const char *name; |
| 39 | long flags; | 57 | long flags; |
| 40 | } static const mount_options[] = { | 58 | } static const mount_options[] = { |
| 59 | // NOP flags. | ||
| 60 | |||
| 41 | {"loop", 0}, | 61 | {"loop", 0}, |
| 42 | {"defaults", 0}, | 62 | {"defaults", 0}, |
| 43 | {"noauto", 0}, | 63 | {"quiet", 0}, |
| 64 | |||
| 65 | // vfs flags | ||
| 66 | |||
| 44 | {"ro", MS_RDONLY}, | 67 | {"ro", MS_RDONLY}, |
| 45 | {"rw", ~MS_RDONLY}, | 68 | {"rw", ~MS_RDONLY}, |
| 46 | {"nosuid", MS_NOSUID}, | 69 | {"nosuid", MS_NOSUID}, |
| @@ -51,336 +74,469 @@ struct { | |||
| 51 | {"noexec", MS_NOEXEC}, | 74 | {"noexec", MS_NOEXEC}, |
| 52 | {"sync", MS_SYNCHRONOUS}, | 75 | {"sync", MS_SYNCHRONOUS}, |
| 53 | {"async", ~MS_SYNCHRONOUS}, | 76 | {"async", ~MS_SYNCHRONOUS}, |
| 54 | {"remount", MS_REMOUNT}, | ||
| 55 | {"atime", ~MS_NOATIME}, | 77 | {"atime", ~MS_NOATIME}, |
| 56 | {"noatime", MS_NOATIME}, | 78 | {"noatime", MS_NOATIME}, |
| 57 | {"diratime", ~MS_NODIRATIME}, | 79 | {"diratime", ~MS_NODIRATIME}, |
| 58 | {"nodiratime", MS_NODIRATIME}, | 80 | {"nodiratime", MS_NODIRATIME}, |
| 81 | {"loud", ~MS_SILENT}, | ||
| 82 | |||
| 83 | // action flags | ||
| 84 | |||
| 85 | {"remount", MS_REMOUNT}, | ||
| 59 | {"bind", MS_BIND}, | 86 | {"bind", MS_BIND}, |
| 60 | {"move", MS_MOVE} | 87 | {"move", MS_MOVE}, |
| 88 | {"noauto",MOUNT_NOAUTO}, | ||
| 89 | {"swap",MOUNT_SWAP} | ||
| 61 | }; | 90 | }; |
| 62 | 91 | ||
| 63 | /* Uses the mount_options list above */ | 92 | /* Append mount options to string */ |
| 64 | static void parse_mount_options(char *options, int *flags, char **strflags) | 93 | static void append_mount_options(char **oldopts, char *newopts) |
| 94 | { | ||
| 95 | if(*oldopts && **oldopts) { | ||
| 96 | char *temp=bb_xasprintf("%s,%s",*oldopts,newopts); | ||
| 97 | free(*oldopts); | ||
| 98 | *oldopts=temp; | ||
| 99 | } else { | ||
| 100 | if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts); | ||
| 101 | *oldopts = bb_xstrdup(newopts); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | /* Use the mount_options list to parse options into flags. | ||
| 106 | * Return list of unrecognized options in *strflags if strflags!=NULL */ | ||
| 107 | static int parse_mount_options(char *options, char **unrecognized) | ||
| 65 | { | 108 | { |
| 109 | int flags = MS_SILENT; | ||
| 110 | |||
| 66 | // Loop through options | 111 | // Loop through options |
| 67 | for(;;) { | 112 | for (;;) { |
| 68 | int i; | 113 | int i; |
| 69 | char *comma = strchr(options, ','); | 114 | char *comma = strchr(options, ','); |
| 70 | 115 | ||
| 71 | if(comma) *comma = 0; | 116 | if (comma) *comma = 0; |
| 72 | 117 | ||
| 73 | // Find this option in mount_options | 118 | // Find this option in mount_options |
| 74 | for(i = 0; i < (sizeof(mount_options) / sizeof(*mount_options)); i++) { | 119 | for (i = 0; i < (sizeof(mount_options) / sizeof(*mount_options)); i++) { |
| 75 | if(!strcasecmp(mount_options[i].name, options)) { | 120 | if (!strcasecmp(mount_options[i].name, options)) { |
| 76 | long fl = mount_options[i].flags; | 121 | long fl = mount_options[i].flags; |
| 77 | if(fl < 0) *flags &= fl; | 122 | if(fl < 0) flags &= fl; |
| 78 | else *flags |= fl; | 123 | else flags |= fl; |
| 79 | break; | 124 | break; |
| 80 | } | 125 | } |
| 81 | } | 126 | } |
| 82 | // Unrecognized mount option? | 127 | // If unrecognized not NULL, append unrecognized mount options */ |
| 83 | if(i == (sizeof(mount_options) / sizeof(*mount_options))) { | 128 | if (unrecognized |
| 129 | && i == (sizeof(mount_options) / sizeof(*mount_options))) | ||
| 130 | { | ||
| 84 | // Add it to strflags, to pass on to kernel | 131 | // Add it to strflags, to pass on to kernel |
| 85 | i = *strflags ? strlen(*strflags) : 0; | 132 | i = *unrecognized ? strlen(*unrecognized) : 0; |
| 86 | *strflags = xrealloc(*strflags, i+strlen(options)+2); | 133 | *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2); |
| 134 | |||
| 87 | // Comma separated if it's not the first one | 135 | // Comma separated if it's not the first one |
| 88 | if(i) (*strflags)[i++] = ','; | 136 | if (i) (*unrecognized)[i++] = ','; |
| 89 | strcpy((*strflags)+i, options); | 137 | strcpy((*unrecognized)+i, options); |
| 90 | } | 138 | } |
| 139 | |||
| 91 | // Advance to next option, or finish | 140 | // Advance to next option, or finish |
| 92 | if(comma) { | 141 | if(comma) { |
| 93 | *comma = ','; | 142 | *comma = ','; |
| 94 | options = ++comma; | 143 | options = ++comma; |
| 95 | } else break; | 144 | } else break; |
| 96 | } | 145 | } |
| 146 | |||
| 147 | return flags; | ||
| 97 | } | 148 | } |
| 98 | 149 | ||
| 99 | /* This does the work */ | 150 | // Return a list of all block device backed filesystems |
| 100 | 151 | ||
| 101 | extern int mount_main(int argc, char **argv) | 152 | static llist_t *get_block_backed_filesystems(void) |
| 102 | { | 153 | { |
| 103 | char *string_flags = 0, *fsType = 0, *blockDevice = 0, *directory = 0, | 154 | char *fs, *buf, |
| 104 | *loopFile = 0, *buf = 0, | 155 | *filesystems[] = {"/etc/filesystems", "/proc/filesystems", 0}; |
| 105 | *files[] = {"/etc/filesystems", "/proc/filesystems", 0}; | 156 | llist_t *list = 0; |
| 106 | int i, opt, all = FALSE, fakeIt = FALSE, allowWrite = FALSE, | 157 | int i; |
| 107 | rc = 1, useMtab = ENABLE_FEATURE_MTAB_SUPPORT; | 158 | FILE *f; |
| 108 | int flags=0xc0ed0000; // Needed for linux 2.2, ignored by 2.4 and 2.6. | 159 | |
| 109 | FILE *file = 0,*f = 0; | 160 | for(i = 0; filesystems[i]; i++) { |
| 110 | char path[PATH_MAX*2]; | 161 | if(!(f = fopen(filesystems[i], "r"))) continue; |
| 111 | struct mntent m; | 162 | |
| 112 | struct stat statbuf; | 163 | for(fs = buf = 0; (fs = buf = bb_get_chomped_line_from_file(f)); |
| 164 | free(buf)) | ||
| 165 | { | ||
| 166 | if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue; | ||
| 167 | |||
| 168 | while(isspace(*fs)) fs++; | ||
| 169 | if(*fs=='#' || *fs=='*') continue; | ||
| 170 | if(!*fs) continue; | ||
| 171 | |||
| 172 | list=llist_add_to_end(list,bb_xstrdup(fs)); | ||
| 173 | } | ||
| 174 | if (ENABLE_FEATURE_CLEAN_UP) fclose(f); | ||
| 175 | } | ||
| 113 | 176 | ||
| 114 | /* parse long options, like --bind and --move. Note that -o option | 177 | return list; |
| 115 | * and --option are synonymous. Yes, this means --remount,rw works. */ | 178 | } |
| 116 | 179 | ||
| 117 | for(i = opt = 0; i < argc; i++) { | 180 | llist_t *fslist = 0; |
| 118 | if(argv[i][0] == '-' && argv[i][1] == '-') | ||
| 119 | parse_mount_options(argv[i]+2, &flags, &string_flags); | ||
| 120 | else argv[opt++] = argv[i]; | ||
| 121 | } | ||
| 122 | argc = opt; | ||
| 123 | 181 | ||
| 124 | // Parse remaining options | 182 | void delete_block_backed_filesystems(void); |
| 183 | #if ENABLE_FEATURE_CLEAN_UP | ||
| 184 | static void delete_block_backed_filesystems(void) | ||
| 185 | { | ||
| 186 | llist_free(fslist); | ||
| 187 | } | ||
| 188 | #endif | ||
| 125 | 189 | ||
| 126 | while((opt = getopt(argc, argv, "o:t:rwafnv")) > 0) { | 190 | #if ENABLE_FEATURE_MTAB_SUPPORT |
| 127 | switch (opt) { | 191 | static int useMtab; |
| 128 | case 'o': | 192 | #else |
| 129 | parse_mount_options(optarg, &flags, &string_flags); | 193 | #define useMtab 0 |
| 130 | break; | 194 | #endif |
| 131 | case 't': | 195 | |
| 132 | fsType = optarg; | 196 | // Perform actual mount of specific filesystem at specific location. |
| 133 | break; | 197 | |
| 134 | case 'r': | 198 | static int mount_it_now(struct mntent *mp, int vfsflags) |
| 135 | flags |= MS_RDONLY; | 199 | { |
| 136 | break; | 200 | int rc; |
| 137 | case 'w': | 201 | char *filteropts = 0; |
| 138 | allowWrite=TRUE; | 202 | |
| 139 | break; | 203 | parse_mount_options(mp->mnt_opts, &filteropts); |
| 140 | case 'a': | 204 | // Mount, with fallback to read-only if necessary. |
| 141 | all = TRUE; | 205 | |
| 142 | break; | 206 | for(;;) { |
| 143 | case 'f': | 207 | rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type, |
| 144 | fakeIt = TRUE; | 208 | vfsflags, filteropts); |
| 145 | break; | 209 | if(!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS)) |
| 146 | case 'n': | ||
| 147 | useMtab = FALSE; | ||
| 148 | break; | 210 | break; |
| 149 | case 'v': | 211 | bb_error_msg("%s is write-protected, mounting read-only", |
| 150 | break; // ignore -v | 212 | mp->mnt_fsname); |
| 151 | default: | 213 | vfsflags |= MS_RDONLY; |
| 152 | bb_show_usage(); | ||
| 153 | } | ||
| 154 | } | 214 | } |
| 155 | 215 | ||
| 156 | // If we have no arguments, show currently mounted filesystems | 216 | free(filteropts); |
| 157 | 217 | ||
| 158 | if(!all && (optind == argc)) { | 218 | // Abort entirely if permission denied. |
| 159 | FILE *mountTable = setmntent(bb_path_mtab_file, "r"); | ||
| 160 | 219 | ||
| 161 | if(!mountTable) bb_perror_msg_and_die(bb_path_mtab_file); | 220 | if (rc && errno == EPERM) |
| 221 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); | ||
| 162 | 222 | ||
| 163 | while (getmntent_r(mountTable,&m,path,sizeof(path))) { | 223 | /* If the mount was successful, and we're maintaining an old-style |
| 164 | blockDevice = m.mnt_fsname; | 224 | * mtab file by hand, add the new entry to it now. */ |
| 225 | |||
| 226 | if(ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc) { | ||
| 227 | FILE *mountTable = setmntent(bb_path_mtab_file, "a+"); | ||
| 228 | int i; | ||
| 165 | 229 | ||
| 166 | // Clean up display a little bit regarding root device | 230 | if(!mountTable) |
| 167 | if(!strcmp(blockDevice, "rootfs")) continue; | 231 | bb_error_msg("No %s\n",bb_path_mtab_file); |
| 168 | if(!strcmp(blockDevice, "/dev/root")) | ||
| 169 | blockDevice = find_block_device("/"); | ||
| 170 | 232 | ||
| 171 | if(!fsType || !strcmp(m.mnt_type, fsType)) | 233 | // Add vfs string flags |
| 172 | printf("%s on %s type %s (%s)\n", blockDevice, m.mnt_dir, | 234 | |
| 173 | m.mnt_type, m.mnt_opts); | 235 | for(i=0; mount_options[i].flags != MS_REMOUNT; i++) |
| 174 | if(ENABLE_FEATURE_CLEAN_UP && blockDevice != m.mnt_fsname) | 236 | if (mount_options[i].flags > 0) |
| 175 | free(blockDevice); | 237 | append_mount_options(&(mp->mnt_opts), |
| 176 | } | 238 | // Shut up about the darn const. It's not important. I don't care. |
| 239 | (char *)mount_options[i].name); | ||
| 240 | |||
| 241 | // Remove trailing / (if any) from directory we mounted on | ||
| 242 | |||
| 243 | i = strlen(mp->mnt_dir); | ||
| 244 | if(i>1 && mp->mnt_dir[i-1] == '/') mp->mnt_dir[i-1] = 0; | ||
| 245 | |||
| 246 | // Write and close. | ||
| 247 | |||
| 248 | if(!mp->mnt_type || !*mp->mnt_type) mp->mnt_type="--bind"; | ||
| 249 | addmntent(mountTable, mp); | ||
| 177 | endmntent(mountTable); | 250 | endmntent(mountTable); |
| 178 | return EXIT_SUCCESS; | 251 | if (ENABLE_FEATURE_CLEAN_UP) |
| 252 | if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0; | ||
| 179 | } | 253 | } |
| 254 | |||
| 255 | return rc; | ||
| 256 | } | ||
| 180 | 257 | ||
| 181 | /* The next argument is what to mount. if there's an argument after that | ||
| 182 | * it's where to mount it. If we're not mounting all, and we have both | ||
| 183 | * of these arguments, jump straight to the actual mount. */ | ||
| 184 | 258 | ||
| 185 | statbuf.st_mode=0; | 259 | // Mount one directory. Handles NFS, loopback, autobind, and filesystem type |
| 186 | if(optind < argc) | 260 | // detection. Returns 0 for success, nonzero for failure. |
| 187 | blockDevice = !stat(argv[optind], &statbuf) ? | ||
| 188 | bb_simplify_path(argv[optind]) : | ||
| 189 | (ENABLE_FEATURE_CLEAN_UP ? strdup(argv[optind]) : argv[optind]); | ||
| 190 | if(optind+1 < argc) directory = bb_simplify_path(argv[optind+1]); | ||
| 191 | 261 | ||
| 192 | // If we don't have to loop through fstab, skip ahead a bit. | 262 | static int singlemount(struct mntent *mp) |
| 263 | { | ||
| 264 | int rc = 0, vfsflags; | ||
| 265 | char *loopFile = 0; | ||
| 266 | llist_t *fl = 0; | ||
| 267 | struct stat st; | ||
| 268 | |||
| 269 | vfsflags = parse_mount_options(mp->mnt_opts, 0); | ||
| 270 | |||
| 271 | // Might this be an NFS filesystem? | ||
| 272 | |||
| 273 | if (ENABLE_FEATURE_MOUNT_NFS && | ||
| 274 | (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && | ||
| 275 | strchr(mp->mnt_fsname, ':') != NULL) | ||
| 276 | { | ||
| 277 | char *options=0; | ||
| 278 | parse_mount_options(mp->mnt_opts, &options); | ||
| 279 | if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &options, 1)) { | ||
| 280 | bb_perror_msg("nfsmount failed"); | ||
| 281 | return 1; | ||
| 282 | } | ||
| 283 | |||
| 284 | // Strangely enough, nfsmount() doesn't actually mount() anything. | ||
| 193 | 285 | ||
| 194 | if(!all && optind+1!=argc) goto singlemount; | 286 | else return mount_it_now(mp, vfsflags); |
| 287 | } | ||
| 195 | 288 | ||
| 196 | // Loop through /etc/fstab entries to look up this entry. | 289 | // Look at the file. (Not found isn't a failure for remount.) |
| 290 | |||
| 291 | if (lstat(mp->mnt_fsname, &st)); | ||
| 292 | |||
| 293 | if (!(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) { | ||
| 294 | // Do we need to allocate a loopback device for it? | ||
| 295 | |||
| 296 | if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { | ||
| 297 | loopFile = mp->mnt_fsname; | ||
| 298 | mp->mnt_fsname = 0; | ||
| 299 | switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) { | ||
| 300 | case 0: | ||
| 301 | case 1: | ||
| 302 | break; | ||
| 303 | default: | ||
| 304 | bb_error_msg( errno == EPERM || errno == EACCES | ||
| 305 | ? bb_msg_perm_denied_are_you_root | ||
| 306 | : "Couldn't setup loop device"); | ||
| 307 | return errno; | ||
| 308 | } | ||
| 309 | |||
| 310 | // Autodetect bind mounts | ||
| 197 | 311 | ||
| 198 | if(!(file=setmntent("/etc/fstab","r"))) | 312 | } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) vfsflags |= MS_BIND; |
| 199 | bb_perror_msg_and_die("\nCannot read /etc/fstab"); | 313 | } |
| 200 | for(;;) { | ||
| 201 | 314 | ||
| 202 | // Get next fstab entry | 315 | /* If we know the fstype (or don't need to), jump straight |
| 316 | * to the actual mount. */ | ||
| 203 | 317 | ||
| 204 | if(!getmntent_r(file,&m,path,sizeof(path))) { | 318 | if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) |
| 205 | if(!all) | 319 | rc = mount_it_now(mp, vfsflags); |
| 206 | bb_perror_msg("Can't find %s in /etc/fstab\n", blockDevice); | ||
| 207 | break; | ||
| 208 | } | ||
| 209 | 320 | ||
| 210 | // If we're mounting all and all doesn't mount this one, skip it. | 321 | // Loop through filesystem types until mount succeeds or we run out |
| 211 | 322 | ||
| 212 | if(all) { | 323 | else for (fl = fslist; fl; fl = fl->link) { |
| 213 | if(strstr(m.mnt_opts,"noauto") || strstr(m.mnt_type,"swap")) | 324 | mp->mnt_type = fl->data; |
| 214 | continue; | ||
| 215 | flags=0; | ||
| 216 | 325 | ||
| 217 | /* If we're mounting something specific and this isn't it, skip it. | 326 | if (!(rc = mount_it_now(mp,vfsflags))) break; |
| 218 | * Note we must match both the exact text in fstab (ala "proc") or | ||
| 219 | * a full path from root */ | ||
| 220 | 327 | ||
| 221 | } else if(strcmp(blockDevice,m.mnt_fsname) && | 328 | mp->mnt_type = 0; |
| 222 | strcmp(argv[optind],m.mnt_fsname) && | 329 | } |
| 223 | strcmp(blockDevice,m.mnt_dir) && | ||
| 224 | strcmp(argv[optind],m.mnt_dir)) continue; | ||
| 225 | 330 | ||
| 226 | /* Parse flags from /etc/fstab (unless this is a single mount | 331 | // Mount failed. Clean up |
| 227 | * overriding fstab -- note the "all" test above zeroed the flags, | 332 | if (rc && loopFile) { |
| 228 | * to prevent flags from previous entries affecting this one, so | 333 | del_loop(mp->mnt_fsname); |
| 229 | * the only way we could get here with nonzero flags is a single | 334 | if(ENABLE_FEATURE_CLEAN_UP) free(loopFile); |
| 230 | * mount). */ | 335 | } |
| 336 | return rc; | ||
| 337 | } | ||
| 231 | 338 | ||
| 232 | if(!flags) { | ||
| 233 | if(ENABLE_FEATURE_CLEAN_UP) free(string_flags); | ||
| 234 | string_flags=NULL; | ||
| 235 | parse_mount_options(m.mnt_opts, &flags, &string_flags); | ||
| 236 | } | ||
| 237 | 339 | ||
| 238 | /* Fill out remaining fields with info from mtab */ | 340 | // Parse options, if necessary parse fstab/mtab, and call singlemount for |
| 341 | // each directory to be mounted. | ||
| 239 | 342 | ||
| 240 | if(ENABLE_FEATURE_CLEAN_UP) { | 343 | int mount_main(int argc, char **argv) |
| 241 | free(blockDevice); | 344 | { |
| 242 | blockDevice=strdup(m.mnt_fsname); | 345 | char *cmdopts = bb_xstrdup(""), *fstabname, *fstype=0, *storage_path=0; |
| 243 | free(directory); | 346 | FILE *fstab; |
| 244 | directory=strdup(m.mnt_dir); | 347 | int i, opt, all = FALSE, rc = 1; |
| 245 | } else { | 348 | struct mntent mtpair[2], *mtcur = mtpair; |
| 246 | blockDevice=m.mnt_fsname; | 349 | |
| 247 | directory=m.mnt_dir; | 350 | /* parse long options, like --bind and --move. Note that -o option |
| 248 | } | 351 | * and --option are synonymous. Yes, this means --remount,rw works. */ |
| 249 | fsType=m.mnt_type; | ||
| 250 | 352 | ||
| 251 | /* Ok, we're ready to actually mount a specific source on a specific | 353 | for (i = opt = 0; i < argc; i++) { |
| 252 | * directory now. */ | 354 | if (argv[i][0] == '-' && argv[i][1] == '-') { |
| 355 | append_mount_options(&cmdopts,argv[i]+2); | ||
| 356 | } else argv[opt++] = argv[i]; | ||
| 357 | } | ||
| 358 | argc = opt; | ||
| 253 | 359 | ||
| 254 | singlemount: | 360 | // Parse remaining options |
| 255 | 361 | ||
| 256 | // If they said -w, override fstab | 362 | while ((opt = getopt(argc, argv, "o:t:rwavnf")) > 0) { |
| 363 | switch (opt) { | ||
| 364 | case 'o': | ||
| 365 | append_mount_options(&cmdopts, optarg); | ||
| 366 | break; | ||
| 367 | case 't': | ||
| 368 | fstype = optarg; | ||
| 369 | break; | ||
| 370 | case 'r': | ||
| 371 | append_mount_options(&cmdopts, "ro"); | ||
| 372 | break; | ||
| 373 | case 'w': | ||
| 374 | append_mount_options(&cmdopts, "rw"); | ||
| 375 | break; | ||
| 376 | case 'a': | ||
| 377 | all = TRUE; | ||
| 378 | break; | ||
| 379 | case 'n': | ||
| 380 | USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;) | ||
| 381 | break; | ||
| 382 | case 'f': | ||
| 383 | USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;) | ||
| 384 | break; | ||
| 385 | case 'v': | ||
| 386 | break; // ignore -v | ||
| 387 | default: | ||
| 388 | bb_show_usage(); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | // Ignore type "auto". | ||
| 257 | 393 | ||
| 258 | if(allowWrite) flags&=~MS_RDONLY; | 394 | if (fstype && !strcmp(fstype, "auto")) fstype = NULL; |
| 259 | 395 | ||
| 260 | // Might this be an NFS filesystem? | 396 | // Three or more non-option arguments? Die with a usage message. |
| 261 | 397 | ||
| 262 | if(ENABLE_FEATURE_MOUNT_NFS && (!fsType || !strcmp(fsType,"nfs")) && | 398 | if (optind-argc>2) bb_show_usage(); |
| 263 | strchr(blockDevice, ':') != NULL) | 399 | |
| 264 | { | 400 | // If we have no arguments, show currently mounted filesystems |
| 265 | if(nfsmount(blockDevice, directory, &flags, &string_flags, 1)) | 401 | |
| 266 | bb_perror_msg("nfsmount failed"); | 402 | if (optind == argc) { |
| 267 | else { | 403 | if (!all) { |
| 268 | rc = 0; | 404 | FILE *mountTable = setmntent(bb_path_mtab_file, "r"); |
| 269 | fsType="nfs"; | ||
| 270 | // Strangely enough, nfsmount() doesn't actually mount() | ||
| 271 | goto mount_it_now; | ||
| 272 | } | ||
| 273 | } else { | ||
| 274 | 405 | ||
| 275 | // Do we need to allocate a loopback device? | 406 | if(!mountTable) bb_error_msg_and_die("No %s",bb_path_mtab_file); |
| 276 | 407 | ||
| 277 | if(ENABLE_FEATURE_MOUNT_LOOP && !fakeIt && S_ISREG(statbuf.st_mode)) | 408 | while (getmntent_r(mountTable,mtpair,bb_common_bufsiz1, |
| 409 | sizeof(bb_common_bufsiz1))) | ||
| 278 | { | 410 | { |
| 279 | loopFile = blockDevice; | 411 | // Don't show rootfs. |
| 280 | blockDevice = 0; | 412 | if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue; |
| 281 | switch(set_loop(&blockDevice, loopFile, 0)) { | 413 | |
| 282 | case 0: | 414 | if (!fstype || !strcmp(mtpair->mnt_type, fstype)) |
| 283 | case 1: | 415 | printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname, |
| 284 | break; | 416 | mtpair->mnt_dir, mtpair->mnt_type, |
| 285 | default: | 417 | mtpair->mnt_opts); |
| 286 | bb_error_msg_and_die( | ||
| 287 | errno == EPERM || errno == EACCES ? | ||
| 288 | bb_msg_perm_denied_are_you_root : | ||
| 289 | "Couldn't setup loop device"); | ||
| 290 | break; | ||
| 291 | } | ||
| 292 | } | 418 | } |
| 419 | if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable); | ||
| 420 | return EXIT_SUCCESS; | ||
| 421 | } | ||
| 422 | } | ||
| 293 | 423 | ||
| 294 | /* If we know the fstype (or don't need to), jump straight | 424 | /* Initialize list of block backed filesystems */ |
| 295 | * to the actual mount. */ | 425 | |
| 426 | fslist = get_block_backed_filesystems(); | ||
| 427 | if (ENABLE_FEATURE_CLEAN_UP) atexit(delete_block_backed_filesystems); | ||
| 428 | |||
| 429 | // When we have two arguments, the second is the directory and we can | ||
| 430 | // skip looking at fstab entirely. We can always abspath() the directory | ||
| 431 | // argument when we get it. | ||
| 432 | |||
| 433 | if (optind+2 == argc) { | ||
| 434 | mtpair->mnt_fsname = argv[optind]; | ||
| 435 | mtpair->mnt_dir = argv[optind+1]; | ||
| 436 | mtpair->mnt_type = fstype; | ||
| 437 | mtpair->mnt_opts = cmdopts; | ||
| 438 | rc = singlemount(mtpair); | ||
| 439 | goto clean_up; | ||
| 440 | } | ||
| 296 | 441 | ||
| 297 | if(fsType || (flags & (MS_REMOUNT | MS_BIND | MS_MOVE))) | 442 | // If we have at least one argument, it's the storage location |
| 298 | goto mount_it_now; | 443 | |
| 299 | } | 444 | if (optind < argc) storage_path = bb_simplify_path(argv[optind]); |
| 445 | |||
| 446 | // Open either fstab or mtab | ||
| 447 | |||
| 448 | if (parse_mount_options(cmdopts,0) & MS_REMOUNT) | ||
| 449 | fstabname = (char *)bb_path_mtab_file; // Again with the evil const. | ||
| 450 | else fstabname="/etc/fstab"; | ||
| 451 | |||
| 452 | if (!(fstab=setmntent(fstabname,"r"))) | ||
| 453 | bb_perror_msg_and_die("Cannot read %s",fstabname); | ||
| 454 | |||
| 455 | // Loop through entries until we find what we're looking for. | ||
| 456 | |||
| 457 | memset(mtpair,0,sizeof(mtpair)); | ||
| 458 | for (;;) { | ||
| 459 | struct mntent *mtnext = mtpair + (mtcur==mtpair ? 1 : 0); | ||
| 300 | 460 | ||
| 301 | // Loop through filesystem types until mount succeeds or we run out | 461 | // Get next fstab entry |
| 302 | 462 | ||
| 303 | for(i = 0; files[i] && rc; i++) { | 463 | if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1, |
| 304 | f = fopen(files[i], "r"); | 464 | sizeof(bb_common_bufsiz1))) |
| 305 | if(!f) continue; | 465 | { |
| 306 | // Get next block device backed filesystem | 466 | // Were we looking for something specific? |
| 307 | for(buf = 0; (buf = fsType = bb_get_chomped_line_from_file(f)); | 467 | |
| 308 | free(buf)) | 468 | if (optind != argc) { |
| 309 | { | 469 | |
| 310 | // Skip funky entries in /proc | 470 | // If we didn't find anything, complain. |
| 311 | if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue; | 471 | |
| 312 | 472 | if (!mtnext->mnt_fsname) | |
| 313 | while(isspace(*fsType)) fsType++; | 473 | bb_error_msg_and_die("Can't find %s in %s", |
| 314 | if(*buf=='#' || *buf=='*') continue; | 474 | argv[optind], fstabname); |
| 315 | if(!*fsType) continue; | 475 | |
| 316 | mount_it_now: | 476 | // Mount the last thing we found. |
| 317 | // Okay, try to mount | 477 | |
| 318 | 478 | mtcur = mtnext; | |
| 319 | if (!fakeIt) { | 479 | mtcur->mnt_opts=bb_xstrdup(mtcur->mnt_opts); |
| 320 | for(;;) { | 480 | append_mount_options(&(mtcur->mnt_opts),cmdopts); |
| 321 | rc = mount(blockDevice, directory, fsType, flags, string_flags); | 481 | rc = singlemount(mtcur); |
| 322 | if(!rc || (flags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS)) | 482 | free(mtcur->mnt_opts); |
| 323 | break; | ||
| 324 | bb_error_msg("%s is write-protected, mounting read-only", blockDevice); | ||
| 325 | flags|=MS_RDONLY; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | if(!rc || !f) break; | ||
| 329 | } | 483 | } |
| 330 | if(!f) break; | 484 | break; |
| 331 | fclose(f); | ||
| 332 | // goto mount_it_now with -a can jump past the initialization | ||
| 333 | f=0; | ||
| 334 | if(!rc) break; | ||
| 335 | } | 485 | } |
| 486 | |||
| 487 | /* If we're trying to mount something specific and this isn't it, | ||
| 488 | * skip it. Note we must match both the exact text in fstab (ala | ||
| 489 | * "proc") or a full path from root */ | ||
| 490 | |||
| 491 | if (optind != argc) { | ||
| 492 | |||
| 493 | // Is this what we're looking for? | ||
| 494 | |||
| 495 | if(strcmp(argv[optind],mtcur->mnt_fsname) && | ||
| 496 | strcmp(storage_path,mtcur->mnt_fsname) && | ||
| 497 | strcmp(argv[optind],mtcur->mnt_dir) && | ||
| 498 | strcmp(storage_path,mtcur->mnt_dir)) continue; | ||
| 499 | |||
| 500 | // Remember this entry. Something later may have overmounted | ||
| 501 | // it, and we want the _last_ match. | ||
| 502 | |||
| 503 | mtcur = mtnext; | ||
| 504 | |||
| 505 | // If we're mounting all. | ||
| 336 | 506 | ||
| 337 | /* If the mount was successful, and we're maintaining an old-style | ||
| 338 | * mtab file by hand, add new entry to it now. */ | ||
| 339 | if((!rc || fakeIt) && useMtab) { | ||
| 340 | FILE *mountTable = setmntent(bb_path_mtab_file, "a+"); | ||
| 341 | |||
| 342 | if(!mountTable) bb_perror_msg(bb_path_mtab_file); | ||
| 343 | else { | ||
| 344 | // Remove trailing / (if any) from directory we mounted on | ||
| 345 | int length=strlen(directory); | ||
| 346 | if(length>1 && directory[length-1] == '/') | ||
| 347 | directory[length-1]=0; | ||
| 348 | |||
| 349 | // Fill out structure (should be ok to re-use existing one). | ||
| 350 | m.mnt_fsname=blockDevice; | ||
| 351 | m.mnt_dir=directory; | ||
| 352 | m.mnt_type=fsType ? : "--bind"; | ||
| 353 | m.mnt_opts=string_flags ? : | ||
| 354 | ((flags & MS_RDONLY) ? "ro" : "rw"); | ||
| 355 | m.mnt_freq = 0; | ||
| 356 | m.mnt_passno = 0; | ||
| 357 | |||
| 358 | // Write and close | ||
| 359 | addmntent(mountTable, &m); | ||
| 360 | endmntent(mountTable); | ||
| 361 | } | ||
| 362 | } else { | 507 | } else { |
| 363 | // Mount failed. Clean up | 508 | |
| 364 | if(loopFile) { | 509 | // Do we need to match a filesystem type? |
| 365 | del_loop(blockDevice); | 510 | if (fstype && strcmp(mtcur->mnt_type,fstype)) continue; |
| 366 | if(ENABLE_FEATURE_CLEAN_UP) free(loopFile); | 511 | |
| 512 | // Skip noauto and swap anyway. | ||
| 513 | |||
| 514 | if (parse_mount_options(mtcur->mnt_opts,0) | ||
| 515 | & (MOUNT_NOAUTO | MOUNT_SWAP)) continue; | ||
| 516 | |||
| 517 | // Mount this thing. | ||
| 518 | |||
| 519 | rc = singlemount(mtcur); | ||
| 520 | if (rc) { | ||
| 521 | // Don't whine about already mounted fs when mounting all. | ||
| 522 | if (errno == EBUSY) rc = 0; | ||
| 523 | else break; | ||
| 367 | } | 524 | } |
| 368 | // Don't whine about already mounted fs when mounting all. | ||
| 369 | if(rc<0 && errno == EBUSY && all) rc = 0; | ||
| 370 | else if (errno == EPERM) | ||
| 371 | bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); | ||
| 372 | } | 525 | } |
| 373 | // We couldn't free this earlier becase fsType could be in buf. | ||
| 374 | if(ENABLE_FEATURE_CLEAN_UP) free(buf); | ||
| 375 | if(!all) break; | ||
| 376 | } | 526 | } |
| 527 | if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab); | ||
| 528 | |||
| 529 | clean_up: | ||
| 377 | 530 | ||
| 378 | if(file) endmntent(file); | 531 | if (ENABLE_FEATURE_CLEAN_UP) { |
| 379 | if(rc) bb_perror_msg("Mounting %s on %s failed", blockDevice, directory); | 532 | free(storage_path); |
| 380 | if(ENABLE_FEATURE_CLEAN_UP) { | 533 | free(cmdopts); |
| 381 | free(blockDevice); | 534 | free(fstype); |
| 382 | free(directory); | ||
| 383 | } | 535 | } |
| 536 | |||
| 537 | if(rc) | ||
| 538 | bb_perror_msg("Mounting %s on %s failed", | ||
| 539 | mtcur->mnt_fsname, mtcur->mnt_dir); | ||
| 384 | 540 | ||
| 385 | return rc; | 541 | return rc; |
| 386 | } | 542 | } |
