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/mount.c | |
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/mount.c')
-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 | } |