Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/util-linux/mount.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/util-linux/mount.c
r1765 r2725 7 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 source tree. 10 10 */ 11 12 /* Design notes: There is no spec for mount. Remind me to write one. 13 14 mount_main() calls singlemount() which calls mount_it_now(). 15 16 mount_main() can loop through /etc/fstab for mount -a 17 singlemount() can loop through /etc/filesystems for fstype detection. 18 mount_it_now() does the actual mount. 19 */ 11 // Design notes: There is no spec for mount. Remind me to write one. 12 // 13 // mount_main() calls singlemount() which calls mount_it_now(). 14 // 15 // mount_main() can loop through /etc/fstab for mount -a 16 // singlemount() can loop through /etc/filesystems for fstype detection. 17 // mount_it_now() does the actual mount. 18 // 19 #include <mntent.h> 20 #include <syslog.h> 21 #include <sys/mount.h> 22 // Grab more as needed from util-linux's mount/mount_constants.h 23 #ifndef MS_DIRSYNC 24 # define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous 25 #endif 26 #ifndef MS_UNION 27 # define MS_UNION (1 << 8) 28 #endif 29 #ifndef MS_BIND 30 # define MS_BIND (1 << 12) 31 #endif 32 #ifndef MS_MOVE 33 # define MS_MOVE (1 << 13) 34 #endif 35 #ifndef MS_RECURSIVE 36 # define MS_RECURSIVE (1 << 14) 37 #endif 38 #ifndef MS_SILENT 39 # define MS_SILENT (1 << 15) 40 #endif 41 // The shared subtree stuff, which went in around 2.6.15 42 #ifndef MS_UNBINDABLE 43 # define MS_UNBINDABLE (1 << 17) 44 #endif 45 #ifndef MS_PRIVATE 46 # define MS_PRIVATE (1 << 18) 47 #endif 48 #ifndef MS_SLAVE 49 # define MS_SLAVE (1 << 19) 50 #endif 51 #ifndef MS_SHARED 52 # define MS_SHARED (1 << 20) 53 #endif 54 #ifndef MS_RELATIME 55 # define MS_RELATIME (1 << 21) 56 #endif 20 57 21 58 #include "libbb.h" 22 #include <mntent.h> 23 24 /* Needed for nfs support only... */ 25 #include <syslog.h> 59 #if ENABLE_FEATURE_MOUNT_LABEL 60 # include "volume_id.h" 61 #else 62 # define resolve_mount_spec(fsname) ((void)0) 63 #endif 64 65 // Needed for nfs support only 26 66 #include <sys/utsname.h> 27 67 #undef TRUE 28 68 #undef FALSE 29 #include <rpc/rpc.h> 30 #include <rpc/pmap_prot.h> 31 #include <rpc/pmap_clnt.h> 69 #if ENABLE_FEATURE_MOUNT_NFS 70 /* This is just a warning of a common mistake. Possibly this should be a 71 * uclibc faq entry rather than in busybox... */ 72 # if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) 73 # error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support" 74 # endif 75 # include <rpc/rpc.h> 76 # include <rpc/pmap_prot.h> 77 # include <rpc/pmap_clnt.h> 78 #endif 32 79 33 80 34 81 #if defined(__dietlibc__) 35 /* 16.12.2006, Sampo Kellomaki (sampo@iki.fi) 36 * dietlibc-0.30 does not have implementation of getmntent_r() */ 37 /* OTOH: why we use getmntent_r instead of getmntent? TODO... */ 38 struct mntent *getmntent_r(FILE* stream, struct mntent* result, char* buffer, int bufsize) 39 { 40 /* *** XXX FIXME WARNING: This hack is NOT thread safe. --Sampo */ 82 // 16.12.2006, Sampo Kellomaki (sampo@iki.fi) 83 // dietlibc-0.30 does not have implementation of getmntent_r() 84 static struct mntent *getmntent_r(FILE* stream, struct mntent* result, 85 char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM) 86 { 41 87 struct mntent* ment = getmntent(stream); 42 memcpy(result, ment, sizeof(struct mntent)); 43 return result; 88 return memcpy(result, ment, sizeof(*ment)); 44 89 } 45 90 #endif … … 48 93 // Not real flags, but we want to be able to check for this. 49 94 enum { 50 MOUNT_USERS = (1 <<28)*ENABLE_DESKTOP,51 MOUNT_NOAUTO = (1 <<29),52 MOUNT_SWAP = (1 <<30),95 MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP, 96 MOUNT_NOAUTO = (1 << 29), 97 MOUNT_SWAP = (1 << 30), 53 98 }; 99 100 101 #define OPTION_STR "o:t:rwanfvsiO:" 102 enum { 103 OPT_o = (1 << 0), 104 OPT_t = (1 << 1), 105 OPT_r = (1 << 2), 106 OPT_w = (1 << 3), 107 OPT_a = (1 << 4), 108 OPT_n = (1 << 5), 109 OPT_f = (1 << 6), 110 OPT_v = (1 << 7), 111 OPT_s = (1 << 8), 112 OPT_i = (1 << 9), 113 OPT_O = (1 << 10), 114 }; 115 116 #if ENABLE_FEATURE_MTAB_SUPPORT 117 #define USE_MTAB (!(option_mask32 & OPT_n)) 118 #else 119 #define USE_MTAB 0 120 #endif 121 122 #if ENABLE_FEATURE_MOUNT_FAKE 123 #define FAKE_IT (option_mask32 & OPT_f) 124 #else 125 #define FAKE_IT 0 126 #endif 127 128 #if ENABLE_FEATURE_MOUNT_HELPERS 129 #define HELPERS_ALLOWED (!(option_mask32 & OPT_i)) 130 #else 131 #define HELPERS_ALLOWED 0 132 #endif 133 134 54 135 // TODO: more "user" flag compatibility. 55 136 // "user" option (from mount manpage): … … 61 142 // the console user owner of this device. 62 143 63 /* Standard mount options (from -o options or --options), with corresponding 64 * flags */ 65 66 struct { 67 const char *name; 68 long flags; 69 } static mount_options[] = { 144 // Standard mount options (from -o options or --options), 145 // with corresponding flags 146 static const int32_t mount_options[] = { 70 147 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs. 71 148 72 USE_FEATURE_MOUNT_LOOP(73 {"loop", 0},149 IF_FEATURE_MOUNT_LOOP( 150 /* "loop" */ 0, 74 151 ) 75 152 76 USE_FEATURE_MOUNT_FSTAB( 77 {"defaults", 0}, 78 /* {"quiet", 0}, - do not filter out, vfat wants to see it */ 79 {"noauto", MOUNT_NOAUTO}, 80 {"sw", MOUNT_SWAP}, 81 {"swap", MOUNT_SWAP}, 82 USE_DESKTOP({"user", MOUNT_USERS},) 83 USE_DESKTOP({"users", MOUNT_USERS},) 153 IF_FEATURE_MOUNT_FSTAB( 154 /* "defaults" */ 0, 155 /* "quiet" 0 - do not filter out, vfat wants to see it */ 156 /* "noauto" */ MOUNT_NOAUTO, 157 /* "sw" */ MOUNT_SWAP, 158 /* "swap" */ MOUNT_SWAP, 159 IF_DESKTOP(/* "user" */ MOUNT_USERS,) 160 IF_DESKTOP(/* "users" */ MOUNT_USERS,) 161 /* "_netdev" */ 0, 84 162 ) 85 163 86 USE_FEATURE_MOUNT_FLAGS(164 IF_FEATURE_MOUNT_FLAGS( 87 165 // vfs flags 88 {"nosuid", MS_NOSUID}, 89 {"suid", ~MS_NOSUID}, 90 {"dev", ~MS_NODEV}, 91 {"nodev", MS_NODEV}, 92 {"exec", ~MS_NOEXEC}, 93 {"noexec", MS_NOEXEC}, 94 {"sync", MS_SYNCHRONOUS}, 95 {"async", ~MS_SYNCHRONOUS}, 96 {"atime", ~MS_NOATIME}, 97 {"noatime", MS_NOATIME}, 98 {"diratime", ~MS_NODIRATIME}, 99 {"nodiratime", MS_NODIRATIME}, 100 {"loud", ~MS_SILENT}, 166 /* "nosuid" */ MS_NOSUID, 167 /* "suid" */ ~MS_NOSUID, 168 /* "dev" */ ~MS_NODEV, 169 /* "nodev" */ MS_NODEV, 170 /* "exec" */ ~MS_NOEXEC, 171 /* "noexec" */ MS_NOEXEC, 172 /* "sync" */ MS_SYNCHRONOUS, 173 /* "dirsync" */ MS_DIRSYNC, 174 /* "async" */ ~MS_SYNCHRONOUS, 175 /* "atime" */ ~MS_NOATIME, 176 /* "noatime" */ MS_NOATIME, 177 /* "diratime" */ ~MS_NODIRATIME, 178 /* "nodiratime" */ MS_NODIRATIME, 179 /* "mand" */ MS_MANDLOCK, 180 /* "nomand" */ ~MS_MANDLOCK, 181 /* "relatime" */ MS_RELATIME, 182 /* "norelatime" */ ~MS_RELATIME, 183 /* "loud" */ ~MS_SILENT, 101 184 102 185 // action flags 103 104 {"bind", MS_BIND},105 {"move", MS_MOVE},106 {"shared", MS_SHARED},107 {"slave", MS_SLAVE},108 {"private", MS_PRIVATE},109 {"unbindable", MS_UNBINDABLE},110 {"rshared", MS_SHARED|MS_RECURSIVE},111 {"rslave", MS_SLAVE|MS_RECURSIVE},112 {"rprivate", MS_SLAVE|MS_RECURSIVE},113 {"runbindable", MS_UNBINDABLE|MS_RECURSIVE},186 /* "union" */ MS_UNION, 187 /* "bind" */ MS_BIND, 188 /* "move" */ MS_MOVE, 189 /* "shared" */ MS_SHARED, 190 /* "slave" */ MS_SLAVE, 191 /* "private" */ MS_PRIVATE, 192 /* "unbindable" */ MS_UNBINDABLE, 193 /* "rshared" */ MS_SHARED|MS_RECURSIVE, 194 /* "rslave" */ MS_SLAVE|MS_RECURSIVE, 195 /* "rprivate" */ MS_SLAVE|MS_RECURSIVE, 196 /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE, 114 197 ) 115 198 116 199 // Always understood. 117 118 {"ro", MS_RDONLY}, // vfs flag 119 {"rw", ~MS_RDONLY}, // vfs flag 120 {"remount", MS_REMOUNT}, // action flag 200 /* "ro" */ MS_RDONLY, // vfs flag 201 /* "rw" */ ~MS_RDONLY, // vfs flag 202 /* "remount" */ MS_REMOUNT // action flag 121 203 }; 122 204 123 124 /* Append mount options to string */ 205 static const char mount_option_str[] = 206 IF_FEATURE_MOUNT_LOOP( 207 "loop\0" 208 ) 209 IF_FEATURE_MOUNT_FSTAB( 210 "defaults\0" 211 // "quiet\0" - do not filter out, vfat wants to see it 212 "noauto\0" 213 "sw\0" 214 "swap\0" 215 IF_DESKTOP("user\0") 216 IF_DESKTOP("users\0") 217 "_netdev\0" 218 ) 219 IF_FEATURE_MOUNT_FLAGS( 220 // vfs flags 221 "nosuid\0" 222 "suid\0" 223 "dev\0" 224 "nodev\0" 225 "exec\0" 226 "noexec\0" 227 "sync\0" 228 "dirsync\0" 229 "async\0" 230 "atime\0" 231 "noatime\0" 232 "diratime\0" 233 "nodiratime\0" 234 "mand\0" 235 "nomand\0" 236 "relatime\0" 237 "norelatime\0" 238 "loud\0" 239 240 // action flags 241 "union\0" 242 "bind\0" 243 "move\0" 244 "shared\0" 245 "slave\0" 246 "private\0" 247 "unbindable\0" 248 "rshared\0" 249 "rslave\0" 250 "rprivate\0" 251 "runbindable\0" 252 ) 253 254 // Always understood. 255 "ro\0" // vfs flag 256 "rw\0" // vfs flag 257 "remount\0" // action flag 258 ; 259 260 261 struct globals { 262 #if ENABLE_FEATURE_MOUNT_NFS 263 smalluint nfs_mount_version; 264 #endif 265 #if ENABLE_FEATURE_MOUNT_VERBOSE 266 unsigned verbose; 267 #endif 268 llist_t *fslist; 269 char getmntent_buf[1]; 270 } FIX_ALIASING; 271 enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) }; 272 #define G (*(struct globals*)&bb_common_bufsiz1) 273 #define nfs_mount_version (G.nfs_mount_version) 274 #if ENABLE_FEATURE_MOUNT_VERBOSE 275 #define verbose (G.verbose ) 276 #else 277 #define verbose 0 278 #endif 279 #define fslist (G.fslist ) 280 #define getmntent_buf (G.getmntent_buf ) 281 282 283 #if ENABLE_FEATURE_MOUNT_VERBOSE 284 static int verbose_mount(const char *source, const char *target, 285 const char *filesystemtype, 286 unsigned long mountflags, const void *data) 287 { 288 int rc; 289 290 errno = 0; 291 rc = mount(source, target, filesystemtype, mountflags, data); 292 if (verbose >= 2) 293 bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d", 294 source, target, filesystemtype, 295 mountflags, (char*)data, rc); 296 return rc; 297 } 298 #else 299 #define verbose_mount(...) mount(__VA_ARGS__) 300 #endif 301 302 // Append mount options to string 125 303 static void append_mount_options(char **oldopts, const char *newopts) 126 304 { 127 305 if (*oldopts && **oldopts) { 128 / * do not insert options which are already there */306 // Do not insert options which are already there 129 307 while (newopts[0]) { 130 308 char *p; … … 135 313 while (1) { 136 314 if (!strncmp(p, newopts, len) 137 && (p[len] ==',' || p[len]==0))315 && (p[len] == ',' || p[len] == '\0')) 138 316 goto skip; 139 317 p = strchr(p,','); … … 144 322 free(*oldopts); 145 323 *oldopts = p; 146 skip:324 skip: 147 325 newopts += len; 148 326 while (newopts[0] == ',') newopts++; … … 154 332 } 155 333 156 / *Use the mount_options list to parse options into flags.157 * Also return list of unrecognized options if unrecognized!=NULL */ 158 static intparse_mount_options(char *options, char **unrecognized)159 { 160 intflags = MS_SILENT;334 // Use the mount_options list to parse options into flags. 335 // Also update list of unrecognized options if unrecognized != NULL 336 static long parse_mount_options(char *options, char **unrecognized) 337 { 338 long flags = MS_SILENT; 161 339 162 340 // Loop through options 163 341 for (;;) { 164 inti;342 unsigned i; 165 343 char *comma = strchr(options, ','); 166 167 if (comma) *comma = 0; 168 344 const char *option_str = mount_option_str; 345 346 if (comma) *comma = '\0'; 347 348 // FIXME: use hasmntopt() 169 349 // Find this option in mount_options 170 350 for (i = 0; i < ARRAY_SIZE(mount_options); i++) { 171 if (!strcasecmp(mount_options[i].name, options)) { 172 long fl = mount_options[i].flags; 173 if (fl < 0) flags &= fl; 174 else flags |= fl; 175 break; 351 if (strcasecmp(option_str, options) == 0) { 352 long fl = mount_options[i]; 353 if (fl < 0) 354 flags &= fl; 355 else 356 flags |= fl; 357 goto found; 176 358 } 177 } 178 // If unrecognized not NULL, append unrecognized mount options */ 179 if (unrecognized && i == ARRAY_SIZE(mount_options)) { 359 option_str += strlen(option_str) + 1; 360 } 361 // We did not recognize this option. 362 // If "unrecognized" is not NULL, append option there. 363 // Note that we should not append *empty* option - 364 // in this case we want to pass NULL, not "", to "data" 365 // parameter of mount(2) syscall. 366 // This is crucial for filesystems that don't accept 367 // any arbitrary mount options, like cgroup fs: 368 // "mount -t cgroup none /mnt" 369 if (options[0] && unrecognized) { 180 370 // Add it to strflags, to pass on to kernel 181 i = *unrecognized ? strlen(*unrecognized) : 0; 182 *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2); 371 char *p = *unrecognized; 372 unsigned len = p ? strlen(p) : 0; 373 *unrecognized = p = xrealloc(p, len + strlen(options) + 2); 183 374 184 375 // Comma separated if it's not the first one 185 if ( i) (*unrecognized)[i++] = ',';186 strcpy( (*unrecognized)+i, options);187 } 188 189 // Advance to next option, or finish190 if (comma) {191 *comma = ',';192 options = ++comma;193 } else break;376 if (len) p[len++] = ','; 377 strcpy(p + len, options); 378 } 379 found: 380 if (!comma) 381 break; 382 // Advance to next option 383 *comma = ','; 384 options = ++comma; 194 385 } 195 386 … … 198 389 199 390 // Return a list of all block device backed filesystems 200 201 391 static llist_t *get_block_backed_filesystems(void) 202 392 { … … 206 396 }; 207 397 char *fs, *buf; 208 llist_t *list = 0;398 llist_t *list = NULL; 209 399 int i; 210 400 FILE *f; 211 401 212 402 for (i = 0; i < 2; i++) { 213 f = fopen (filesystems[i], "r");403 f = fopen_for_read(filesystems[i]); 214 404 if (!f) continue; 215 405 216 while ((buf = xmalloc_ getline(f)) != 0) {217 if ( !strncmp(buf, "nodev", 5)&& isspace(buf[5]))406 while ((buf = xmalloc_fgetline(f)) != NULL) { 407 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5])) 218 408 continue; 219 409 fs = skip_whitespace(buf); 220 if (*fs=='#' || *fs=='*' || !*fs) continue; 410 if (*fs == '#' || *fs == '*' || !*fs) 411 continue; 221 412 222 413 llist_add_to_end(&list, xstrdup(fs)); … … 229 420 } 230 421 231 llist_t *fslist = 0;232 233 422 #if ENABLE_FEATURE_CLEAN_UP 234 423 static void delete_block_backed_filesystems(void) … … 240 429 #endif 241 430 242 #if ENABLE_FEATURE_MTAB_SUPPORT243 static int useMtab = 1;244 static int fakeIt;245 #else246 #define useMtab 0247 #define fakeIt 0248 #endif249 250 431 // Perform actual mount of specific filesystem at specific location. 251 432 // NB: mp->xxx fields may be trashed on exit 252 static int mount_it_now(struct mntent *mp, intvfsflags, char *filteropts)433 static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts) 253 434 { 254 435 int rc = 0; 255 436 256 if (fakeIt) goto mtab; 437 if (FAKE_IT) { 438 if (verbose >= 2) 439 bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')", 440 mp->mnt_fsname, mp->mnt_dir, mp->mnt_type, 441 vfsflags, filteropts); 442 goto mtab; 443 } 257 444 258 445 // Mount, with fallback to read-only if necessary. 259 260 446 for (;;) { 261 rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type, 447 errno = 0; 448 rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type, 262 449 vfsflags, filteropts); 263 if (!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS)) 450 451 // If mount failed, try 452 // helper program mount.<mnt_type> 453 if (HELPERS_ALLOWED && rc && mp->mnt_type) { 454 char *args[8]; 455 int errno_save = errno; 456 args[0] = xasprintf("mount.%s", mp->mnt_type); 457 rc = 1; 458 if (FAKE_IT) 459 args[rc++] = (char *)"-f"; 460 if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB) 461 args[rc++] = (char *)"-n"; 462 args[rc++] = mp->mnt_fsname; 463 args[rc++] = mp->mnt_dir; 464 if (filteropts) { 465 args[rc++] = (char *)"-o"; 466 args[rc++] = filteropts; 467 } 468 args[rc] = NULL; 469 rc = spawn_and_wait(args); 470 free(args[0]); 471 if (!rc) 472 break; 473 errno = errno_save; 474 } 475 476 if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS)) 264 477 break; 265 bb_error_msg("%s is write-protected, mounting read-only", 266 mp->mnt_fsname); 478 if (!(vfsflags & MS_SILENT)) 479 bb_error_msg("%s is write-protected, mounting read-only", 480 mp->mnt_fsname); 267 481 vfsflags |= MS_RDONLY; 268 482 } … … 273 487 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 274 488 275 / *If the mount was successful, and we're maintaining an old-style276 * mtab file by hand, add the new entry to it now. */489 // If the mount was successful, and we're maintaining an old-style 490 // mtab file by hand, add the new entry to it now. 277 491 mtab: 278 if ( ENABLE_FEATURE_MTAB_SUPPORT && useMtab&& !rc && !(vfsflags & MS_REMOUNT)) {492 if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) { 279 493 char *fsname; 280 494 FILE *mountTable = setmntent(bb_path_mtab_file, "a+"); 495 const char *option_str = mount_option_str; 281 496 int i; 282 497 283 498 if (!mountTable) { 284 bb_error_msg("no %s", bb_path_mtab_file);499 bb_error_msg("no %s", bb_path_mtab_file); 285 500 goto ret; 286 501 } … … 288 503 // Add vfs string flags 289 504 290 for (i=0; mount_options[i].flags != MS_REMOUNT; i++) 291 if (mount_options[i].flags > 0 && (mount_options[i].flags & vfsflags)) 292 append_mount_options(&(mp->mnt_opts), mount_options[i].name); 505 for (i = 0; mount_options[i] != MS_REMOUNT; i++) { 506 if (mount_options[i] > 0 && (mount_options[i] & vfsflags)) 507 append_mount_options(&(mp->mnt_opts), option_str); 508 option_str += strlen(option_str) + 1; 509 } 293 510 294 511 // Remove trailing / (if any) from directory we mounted on 295 512 296 513 i = strlen(mp->mnt_dir) - 1; 297 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = 0;514 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0'; 298 515 299 516 // Convert to canonical pathnames as needed … … 301 518 mp->mnt_dir = bb_simplify_path(mp->mnt_dir); 302 519 fsname = 0; 303 if (!mp->mnt_type || !*mp->mnt_type) { / * bind mount */520 if (!mp->mnt_type || !*mp->mnt_type) { // bind mount 304 521 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname); 305 522 mp->mnt_type = (char*)"bind"; … … 326 543 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> 327 544 * 328 * Licensed under GPLv2, see file LICENSE in this tarball for details.545 * Licensed under GPLv2, see file LICENSE in this source tree. 329 546 * 330 547 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port … … 337 554 * Implemented the "bg", "fg" and "retry" mount options for NFS. 338 555 * 339 * 1999-02-22 Arkadiusz Mi ¶kiewicz <misiek@misiek.eu.org>556 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org> 340 557 * - added Native Language Support 341 558 * … … 343 560 * plus NFSv3 stuff. 344 561 */ 345 346 /* This is just a warning of a common mistake. Possibly this should be a347 * uclibc faq entry rather than in busybox... */348 #if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)349 #error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."350 #endif351 562 352 563 #define MOUNTPORT 635 … … 527 738 NFS_MOUNT_VER3 = 0x0080, /* 3 */ 528 739 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */ 529 NFS_MOUNT_NONLM = 0x0200 /* 3 */ 740 NFS_MOUNT_NONLM = 0x0200, /* 3 */ 741 NFS_MOUNT_NORDIRPLUS = 0x4000 530 742 }; 531 743 … … 539 751 * it cannot even be used as a struct tag or field name". 540 752 */ 541 542 753 #ifndef EDQUOT 543 #define EDQUOT ENOSPC 544 #endif 545 546 // Convert each NFSERR_BLAH into EBLAH 547 548 static const struct { 549 int stat; 550 int errnum; 551 } nfs_errtbl[] = { 552 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST}, 553 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG}, 554 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT}, 555 {70,ESTALE}, {71,EREMOTE}, {-1,EIO} 754 # define EDQUOT ENOSPC 755 #endif 756 /* Convert each NFSERR_BLAH into EBLAH */ 757 static const uint8_t nfs_err_stat[] = { 758 1, 2, 5, 6, 13, 17, 759 19, 20, 21, 22, 27, 28, 760 30, 63, 66, 69, 70, 71 556 761 }; 557 762 #if ( \ 763 EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \ 764 ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \ 765 EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256 766 typedef uint8_t nfs_err_type; 767 #else 768 typedef uint16_t nfs_err_type; 769 #endif 770 static const nfs_err_type nfs_err_errnum[] = { 771 EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST, 772 ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC, 773 EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE 774 }; 558 775 static char *nfs_strerror(int status) 559 776 { 560 777 int i; 561 static char buf[sizeof("unknown nfs status return value: ") + sizeof(int)*3]; 562 563 for (i = 0; nfs_errtbl[i].stat != -1; i++) { 564 if (nfs_errtbl[i].stat == status) 565 return strerror(nfs_errtbl[i].errnum); 566 } 567 sprintf(buf, "unknown nfs status return value: %d", status); 568 return buf; 778 779 for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) { 780 if (nfs_err_stat[i] == status) 781 return strerror(nfs_err_errnum[i]); 782 } 783 return xasprintf("unknown nfs status return value: %d", status); 569 784 } 570 785 571 786 static bool_t xdr_fhandle(XDR *xdrs, fhandle objp) 572 787 { 573 if (!xdr_opaque(xdrs, objp, FHSIZE)) 574 return FALSE; 575 return TRUE; 788 return xdr_opaque(xdrs, objp, FHSIZE); 576 789 } 577 790 … … 580 793 if (!xdr_u_int(xdrs, &objp->fhs_status)) 581 794 return FALSE; 582 switch (objp->fhs_status) { 583 case 0: 584 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) 585 return FALSE; 586 break; 587 default: 588 break; 589 } 795 if (objp->fhs_status == 0) 796 return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle); 590 797 return TRUE; 591 798 } … … 593 800 static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp) 594 801 { 595 if (!xdr_string(xdrs, objp, MNTPATHLEN)) 596 return FALSE; 597 return TRUE; 802 return xdr_string(xdrs, objp, MNTPATHLEN); 598 803 } 599 804 600 805 static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp) 601 806 { 602 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))603 return FALSE;604 return TRUE;807 return xdr_bytes(xdrs, (char **)&objp->fhandle3_val, 808 (unsigned int *) &objp->fhandle3_len, 809 FHSIZE3); 605 810 } 606 811 … … 609 814 if (!xdr_fhandle3(xdrs, &objp->fhandle)) 610 815 return FALSE; 611 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0, 612 sizeof (int), (xdrproc_t) xdr_int)) 613 return FALSE; 614 return TRUE; 816 return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), 817 &(objp->auth_flavours.auth_flavours_len), 818 ~0, 819 sizeof(int), 820 (xdrproc_t) xdr_int); 615 821 } 616 822 617 823 static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp) 618 824 { 619 if (!xdr_enum(xdrs, (enum_t *) objp)) 620 return FALSE; 621 return TRUE; 825 return xdr_enum(xdrs, (enum_t *) objp); 622 826 } 623 827 … … 626 830 if (!xdr_mountstat3(xdrs, &objp->fhs_status)) 627 831 return FALSE; 628 switch (objp->fhs_status) { 629 case MNT_OK: 630 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo)) 631 return FALSE; 632 break; 633 default: 634 break; 635 } 832 if (objp->fhs_status == MNT_OK) 833 return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo); 636 834 return TRUE; 637 835 } 638 836 639 837 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) 640 641 /*642 * nfs_mount_version according to the sources seen at compile time.643 */644 static int nfs_mount_version;645 static int kernel_version;646 838 647 839 /* … … 659 851 find_kernel_nfs_mount_version(void) 660 852 { 661 if (kernel_version) 853 int kernel_version; 854 855 if (nfs_mount_version) 662 856 return; 663 857 … … 666 860 kernel_version = get_linux_version_code(); 667 861 if (kernel_version) { 668 if (kernel_version < KERNEL_VERSION(2,1,32)) 669 nfs_mount_version = 1; 670 else if (kernel_version < KERNEL_VERSION(2,2,18) || 671 (kernel_version >= KERNEL_VERSION(2,3,0) && 672 kernel_version < KERNEL_VERSION(2,3,99))) 862 if (kernel_version < KERNEL_VERSION(2,2,18)) 673 863 nfs_mount_version = 3; 674 864 /* else v4 since 2.3.99pre4 */ … … 676 866 } 677 867 678 static struct pmap * 679 get_mountport(struct sockaddr_in *server_addr, 868 static void 869 get_mountport(struct pmap *pm_mnt, 870 struct sockaddr_in *server_addr, 680 871 long unsigned prog, 681 872 long unsigned version, … … 684 875 { 685 876 struct pmaplist *pmap; 686 static struct pmap p = {0, 0, 0, 0};687 877 688 878 server_addr->sin_port = PMAPPORT; … … 695 885 if (!prog) 696 886 prog = MOUNTPROG; 697 p .pm_prog = prog;698 p .pm_vers = version;699 p .pm_prot = proto;700 p .pm_port = port;887 pm_mnt->pm_prog = prog; 888 pm_mnt->pm_vers = version; 889 pm_mnt->pm_prot = proto; 890 pm_mnt->pm_port = port; 701 891 702 892 while (pmap) { 703 893 if (pmap->pml_map.pm_prog != prog) 704 894 goto next; 705 if (!version && p .pm_vers > pmap->pml_map.pm_vers)895 if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers) 706 896 goto next; 707 897 if (version > 2 && pmap->pml_map.pm_vers != version) … … 709 899 if (version && version <= 2 && pmap->pml_map.pm_vers > 2) 710 900 goto next; 711 if (pmap->pml_map.pm_vers > MAX_NFSPROT || 712 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || 713 (port && pmap->pml_map.pm_port != port)) 901 if (pmap->pml_map.pm_vers > MAX_NFSPROT 902 || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) 903 || (port && pmap->pml_map.pm_port != port) 904 ) { 714 905 goto next; 715 memcpy(&p, &pmap->pml_map, sizeof(p)); 716 next: 906 } 907 memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt)); 908 next: 717 909 pmap = pmap->pml_next; 718 910 } 719 if (!p .pm_vers)720 p .pm_vers = MOUNTVERS;721 if (!p .pm_port)722 p .pm_port = MOUNTPORT;723 if (!p .pm_prot)724 p .pm_prot = IPPROTO_TCP;725 return &p; 726 } 727 911 if (!pm_mnt->pm_vers) 912 pm_mnt->pm_vers = MOUNTVERS; 913 if (!pm_mnt->pm_port) 914 pm_mnt->pm_port = MOUNTPORT; 915 if (!pm_mnt->pm_prot) 916 pm_mnt->pm_prot = IPPROTO_TCP; 917 } 918 919 #if BB_MMU 728 920 static int daemonize(void) 729 921 { 730 int fd;731 922 int pid = fork(); 732 923 if (pid < 0) /* error */ … … 735 926 return 0; 736 927 /* child */ 737 fd = xopen(bb_dev_null, O_RDWR); 738 dup2(fd, 0); 739 dup2(fd, 1); 740 dup2(fd, 2); 741 while (fd > 2) close(fd--); 928 close(0); 929 xopen(bb_dev_null, O_RDWR); 930 xdup2(0, 1); 931 xdup2(0, 2); 742 932 setsid(); 743 933 openlog(applet_name, LOG_PID, LOG_DAEMON); … … 745 935 return 1; 746 936 } 747 748 // TODO 749 static inline int we_saw_this_host_before(const char *hostname) 937 #else 938 static inline int daemonize(void) { return -ENOSYS; } 939 #endif 940 941 /* TODO */ 942 static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM) 750 943 { 751 944 return 0; … … 765 958 } 766 959 767 / / NB: mp->xxx fields may be trashed on exit768 static int nfsmount(struct mntent *mp, intvfsflags, char *filteropts)960 /* NB: mp->xxx fields may be trashed on exit */ 961 static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) 769 962 { 770 963 CLIENT *mclient; … … 772 965 char *pathname; 773 966 char *mounthost; 967 /* prior to 2.6.23, kernel took NFS options in a form of this struct 968 * only. 2.6.23+ looks at data->version, and if it's not 1..6, 969 * then data pointer is interpreted as a string. */ 774 970 struct nfs_mount_data data; 775 971 char *opt; … … 787 983 int mountport; 788 984 int proto; 789 int bg; 790 int soft; 791 int intr; 792 int posix; 793 int nocto; 794 int noac; 795 int nolock; 985 #if BB_MMU 986 smallint bg = 0; 987 #else 988 enum { bg = 0 }; 989 #endif 796 990 int retry; 797 int tcp;798 991 int mountprog; 799 992 int mountvers; … … 801 994 int nfsvers; 802 995 int retval; 996 /* these all are one-bit really. gcc 4.3.1 likes this combination: */ 997 smallint tcp; 998 smallint soft; 999 int intr; 1000 int posix; 1001 int nocto; 1002 int noac; 1003 int nordirplus; 1004 int nolock; 803 1005 804 1006 find_kernel_nfs_mount_version(); … … 834 1036 goto fail; 835 1037 } 836 if (hp->h_length > sizeof(struct in_addr)) { 837 bb_error_msg("got bad hp->h_length"); 838 hp->h_length = sizeof(struct in_addr); 839 } 840 memcpy(&server_addr.sin_addr, 841 hp->h_addr, hp->h_length); 1038 if (hp->h_length != (int)sizeof(struct in_addr)) { 1039 bb_error_msg_and_die("only IPv4 is supported"); 1040 } 1041 memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); 842 1042 } 843 1043 … … 861 1061 * timeo is filled in after we know whether it'll be TCP or UDP. */ 862 1062 memset(&data, 0, sizeof(data)); 863 data.retrans = 3; 864 data.acregmin = 3; 865 data.acregmax = 60; 866 data.acdirmin = 30; 867 data.acdirmax = 60; 868 data.namlen = NAME_MAX; 869 870 bg = 0; 1063 data.retrans = 3; 1064 data.acregmin = 3; 1065 data.acregmax = 60; 1066 data.acdirmin = 30; 1067 data.acdirmax = 60; 1068 data.namlen = NAME_MAX; 1069 871 1070 soft = 0; 872 1071 intr = 0; … … 875 1074 nolock = 0; 876 1075 noac = 0; 1076 nordirplus = 0; 877 1077 retry = 10000; /* 10000 minutes ~ 1 week */ 878 1078 tcp = 0; … … 889 1089 char *opteq = strchr(opt, '='); 890 1090 if (opteq) { 1091 int val, idx; 891 1092 static const char options[] ALIGN1 = 892 1093 /* 0 */ "rsize\0" … … 911 1112 /* 19 */ "namlen\0" 912 1113 /* 20 */ "addr\0"; 913 int val = xatoi_u(opteq + 1); 914 *opteq = '\0'; 915 switch (index_in_strings(options, opt)) { 1114 1115 *opteq++ = '\0'; 1116 idx = index_in_strings(options, opt); 1117 switch (idx) { 1118 case 12: // "mounthost" 1119 mounthost = xstrndup(opteq, 1120 strcspn(opteq, " \t\n\r,")); 1121 continue; 1122 case 18: // "proto" 1123 if (!strncmp(opteq, "tcp", 3)) 1124 tcp = 1; 1125 else if (!strncmp(opteq, "udp", 3)) 1126 tcp = 0; 1127 else 1128 bb_error_msg("warning: unrecognized proto= option"); 1129 continue; 1130 case 20: // "addr" - ignore 1131 continue; 1132 } 1133 1134 val = xatoi_positive(opteq); 1135 switch (idx) { 916 1136 case 0: // "rsize" 917 1137 data.rsize = val; 918 break;1138 continue; 919 1139 case 1: // "wsize" 920 1140 data.wsize = val; 921 break;1141 continue; 922 1142 case 2: // "timeo" 923 1143 data.timeo = val; 924 break;1144 continue; 925 1145 case 3: // "retrans" 926 1146 data.retrans = val; 927 break;1147 continue; 928 1148 case 4: // "acregmin" 929 1149 data.acregmin = val; 930 break;1150 continue; 931 1151 case 5: // "acregmax" 932 1152 data.acregmax = val; 933 break;1153 continue; 934 1154 case 6: // "acdirmin" 935 1155 data.acdirmin = val; 936 break;1156 continue; 937 1157 case 7: // "acdirmax" 938 1158 data.acdirmax = val; 939 break;1159 continue; 940 1160 case 8: // "actimeo" 941 1161 data.acregmin = val; … … 943 1163 data.acdirmin = val; 944 1164 data.acdirmax = val; 945 break;1165 continue; 946 1166 case 9: // "retry" 947 1167 retry = val; 948 break;1168 continue; 949 1169 case 10: // "port" 950 1170 port = val; 951 break;1171 continue; 952 1172 case 11: // "mountport" 953 1173 mountport = val; 954 break; 955 case 12: // "mounthost" 956 mounthost = xstrndup(opteq+1, 957 strcspn(opteq+1," \t\n\r,")); 958 break; 1174 continue; 959 1175 case 13: // "mountprog" 960 1176 mountprog = val; 961 break;1177 continue; 962 1178 case 14: // "mountvers" 963 1179 mountvers = val; 964 break;1180 continue; 965 1181 case 15: // "nfsprog" 966 1182 nfsprog = val; 967 break;1183 continue; 968 1184 case 16: // "nfsvers" 969 1185 case 17: // "vers" 970 1186 nfsvers = val; 971 break; 972 case 18: // "proto" 973 if (!strncmp(opteq+1, "tcp", 3)) 974 tcp = 1; 975 else if (!strncmp(opteq+1, "udp", 3)) 976 tcp = 0; 977 else 978 bb_error_msg("warning: unrecognized proto= option"); 979 break; 1187 continue; 980 1188 case 19: // "namlen" 981 if (nfs_mount_version >= 2)1189 //if (nfs_mount_version >= 2) 982 1190 data.namlen = val; 983 else 984 bb_error_msg("warning: option namlen is not supported\n"); 985 break; 986 case 20: // "addr" - ignore 987 break; 1191 //else 1192 // bb_error_msg("warning: option namlen is not supported\n"); 1193 continue; 988 1194 default: 989 1195 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val); … … 991 1197 } 992 1198 } 993 else { 1199 else { /* not of the form opt=val */ 994 1200 static const char options[] ALIGN1 = 995 1201 "bg\0" … … 1003 1209 "tcp\0" 1004 1210 "udp\0" 1005 "lock\0"; 1211 "lock\0" 1212 "rdirplus\0"; 1006 1213 int val = 1; 1007 1214 if (!strncmp(opt, "no", 2)) { … … 1011 1218 switch (index_in_strings(options, opt)) { 1012 1219 case 0: // "bg" 1220 #if BB_MMU 1013 1221 bg = val; 1222 #endif 1014 1223 break; 1015 1224 case 1: // "fg" 1225 #if BB_MMU 1016 1226 bg = !val; 1227 #endif 1017 1228 break; 1018 1229 case 2: // "soft" … … 1046 1257 bb_error_msg("warning: option nolock is not supported"); 1047 1258 break; 1259 case 11: //rdirplus 1260 nordirplus = !val; 1261 break; 1048 1262 default: 1049 1263 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt); … … 1058 1272 | (posix ? NFS_MOUNT_POSIX : 0) 1059 1273 | (nocto ? NFS_MOUNT_NOCTO : 0) 1060 | (noac ? NFS_MOUNT_NOAC : 0); 1274 | (noac ? NFS_MOUNT_NOAC : 0) 1275 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0); 1061 1276 if (nfs_mount_version >= 2) 1062 1277 data.flags |= (tcp ? NFS_MOUNT_TCP : 0); … … 1088 1303 */ 1089 1304 if (bg && we_saw_this_host_before(hostname)) { 1090 daemonized = daemonize(); /* parent or error */1305 daemonized = daemonize(); 1091 1306 if (daemonized <= 0) { /* parent or error */ 1092 1307 retval = -daemonized; … … 1095 1310 } 1096 1311 1097 /* create mount daemon client */1312 /* Create mount daemon client */ 1098 1313 /* See if the nfs host = mount host. */ 1099 1314 if (mounthost) { … … 1106 1321 bb_herror_msg("%s", mounthost); 1107 1322 goto fail; 1108 } else {1109 if (hp->h_length > sizeof(struct in_addr)) {1110 bb_error_msg("got bad hp->h_length?");1111 hp->h_length = sizeof(struct in_addr);1112 }1113 mount_server_addr.sin_family = AF_INET;1114 memcpy(&mount_server_addr.sin_addr,1115 hp->h_addr, hp->h_length);1116 1323 } 1324 if (hp->h_length != (int)sizeof(struct in_addr)) { 1325 bb_error_msg_and_die("only IPv4 is supported"); 1326 } 1327 mount_server_addr.sin_family = AF_INET; 1328 memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); 1117 1329 } 1118 1330 } … … 1133 1345 struct timeval total_timeout; 1134 1346 struct timeval retry_timeout; 1135 struct pmap *pm_mnt;1347 struct pmap pm_mnt; 1136 1348 time_t t; 1137 1349 time_t prevt; … … 1142 1354 total_timeout.tv_sec = 20; 1143 1355 total_timeout.tv_usec = 0; 1356 /* FIXME: use monotonic()? */ 1144 1357 timeout = time(NULL) + 60 * retry; 1145 1358 prevt = 0; 1146 1359 t = 30; 1147 retry:1148 /* be careful not to use too many CPU cycles */1360 retry: 1361 /* Be careful not to use too many CPU cycles */ 1149 1362 if (t - prevt < 30) 1150 1363 sleep(30); 1151 1364 1152 pm_mnt = get_mountport(&mount_server_addr,1365 get_mountport(&pm_mnt, &mount_server_addr, 1153 1366 mountprog, 1154 1367 mountvers, 1155 1368 proto, 1156 1369 mountport); 1157 nfsvers = (pm_mnt ->pm_vers < 2) ? 2 : pm_mnt->pm_vers;1370 nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers; 1158 1371 1159 1372 /* contact the mount daemon via TCP */ 1160 mount_server_addr.sin_port = htons(pm_mnt ->pm_port);1373 mount_server_addr.sin_port = htons(pm_mnt.pm_port); 1161 1374 msock = RPC_ANYSOCK; 1162 1375 1163 switch (pm_mnt ->pm_prot) {1376 switch (pm_mnt.pm_prot) { 1164 1377 case IPPROTO_UDP: 1165 1378 mclient = clntudp_create(&mount_server_addr, 1166 pm_mnt ->pm_prog,1167 pm_mnt ->pm_vers,1379 pm_mnt.pm_prog, 1380 pm_mnt.pm_vers, 1168 1381 retry_timeout, 1169 1382 &msock); 1170 1383 if (mclient) 1171 1384 break; 1172 mount_server_addr.sin_port = htons(pm_mnt ->pm_port);1385 mount_server_addr.sin_port = htons(pm_mnt.pm_port); 1173 1386 msock = RPC_ANYSOCK; 1174 1387 case IPPROTO_TCP: 1175 1388 mclient = clnttcp_create(&mount_server_addr, 1176 pm_mnt ->pm_prog,1177 pm_mnt ->pm_vers,1389 pm_mnt.pm_prog, 1390 pm_mnt.pm_vers, 1178 1391 &msock, 0, 0); 1179 1392 break; 1180 1393 default: 1181 mclient = 0;1394 mclient = NULL; 1182 1395 } 1183 1396 if (!mclient) { … … 1186 1399 } else { 1187 1400 enum clnt_stat clnt_stat; 1188 /* try to mount hostname:pathname */ 1401 1402 /* Try to mount hostname:pathname */ 1189 1403 mclient->cl_auth = authunix_create_default(); 1190 1404 1191 /* make pointers in xdr_mountres3 NULL so1405 /* Make pointers in xdr_mountres3 NULL so 1192 1406 * that xdr_array allocates memory for us 1193 1407 */ 1194 1408 memset(&status, 0, sizeof(status)); 1195 1409 1196 if (pm_mnt ->pm_vers == 3)1410 if (pm_mnt.pm_vers == 3) 1197 1411 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, 1198 1412 (xdrproc_t) xdr_dirpath, … … 1220 1434 auth_destroy(mclient->cl_auth); 1221 1435 clnt_destroy(mclient); 1222 mclient = 0;1436 mclient = NULL; 1223 1437 close(msock); 1438 msock = -1; 1224 1439 } 1225 1440 1226 1441 /* Timeout. We are going to retry... maybe */ 1227 1228 1442 if (!bg) 1229 1443 goto fail; … … 1244 1458 } 1245 1459 1246 prepare_kernel_data:1460 prepare_kernel_data: 1247 1461 1248 1462 if (nfsvers == 2) { … … 1279 1493 } 1280 1494 1281 /* create nfs socket for kernel */ 1282 1495 /* Create nfs socket for kernel */ 1283 1496 if (tcp) { 1284 1497 if (nfs_mount_version < 3) { … … 1306 1519 server_addr.sin_port = htons(port); 1307 1520 1308 /* prepare data structure for kernel */ 1309 1521 /* Prepare data structure for kernel */ 1310 1522 data.fd = fsock; 1311 1523 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); 1312 1524 strncpy(data.hostname, hostname, sizeof(data.hostname)); 1313 1525 1314 /* clean up */ 1315 1526 /* Clean up */ 1316 1527 auth_destroy(mclient->cl_auth); 1317 1528 clnt_destroy(mclient); 1318 1529 close(msock); 1530 msock = -1; 1319 1531 1320 1532 if (bg) { … … 1326 1538 daemonized = daemonize(); 1327 1539 if (daemonized <= 0) { /* parent or error */ 1540 /* FIXME: parent doesn't close fsock - ??! */ 1328 1541 retval = -daemonized; 1329 1542 goto ret; … … 1337 1550 } 1338 1551 1339 do_mount: /* perform actual mount */1340 1552 /* Perform actual mount */ 1553 do_mount: 1341 1554 mp->mnt_type = (char*)"nfs"; 1342 1555 retval = mount_it_now(mp, vfsflags, (char*)&data); 1343 1556 goto ret; 1344 1557 1345 fail: /* abort */1346 1347 if (msock != -1) {1558 /* Abort */ 1559 fail: 1560 if (msock >= 0) { 1348 1561 if (mclient) { 1349 1562 auth_destroy(mclient->cl_auth); … … 1352 1565 close(msock); 1353 1566 } 1354 if (fsock != -1)1567 if (fsock >= 0) 1355 1568 close(fsock); 1356 1569 1357 ret:1570 ret: 1358 1571 free(hostname); 1359 1572 free(mounthost); … … 1362 1575 } 1363 1576 1364 #else / * !ENABLE_FEATURE_MOUNT_NFS */1365 1366 / * Never called. Call should be optimized out. */1367 int nfsmount(struct mntent *mp, intvfsflags, char *filteropts);1368 1369 #endif / * !ENABLE_FEATURE_MOUNT_NFS */1577 #else // !ENABLE_FEATURE_MOUNT_NFS 1578 1579 // Never called. Call should be optimized out. 1580 int nfsmount(struct mntent *mp, long vfsflags, char *filteropts); 1581 1582 #endif // !ENABLE_FEATURE_MOUNT_NFS 1370 1583 1371 1584 // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem … … 1374 1587 static int singlemount(struct mntent *mp, int ignore_busy) 1375 1588 { 1376 int rc = -1, vfsflags; 1377 char *loopFile = 0, *filteropts = 0; 1378 llist_t *fl = 0; 1589 int rc = -1; 1590 long vfsflags; 1591 char *loopFile = NULL, *filteropts = NULL; 1592 llist_t *fl = NULL; 1379 1593 struct stat st; 1380 1594 1595 errno = 0; 1596 1381 1597 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts); 1382 1598 1383 // Treat fstype "auto" as unspecified. 1384 1385 if (mp->mnt_type && strcmp(mp->mnt_type,"auto") == 0) 1386 mp->mnt_type = 0; 1599 // Treat fstype "auto" as unspecified 1600 if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0) 1601 mp->mnt_type = NULL; 1602 1603 // Might this be a virtual filesystem? 1604 if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) { 1605 char *args[35]; 1606 char *s; 1607 int n; 1608 // fsname: "cmd#arg1#arg2..." 1609 // WARNING: allows execution of arbitrary commands! 1610 // Try "mount 'sh#-c#sh' bogus_dir". 1611 // It is safe ONLY because non-root 1612 // cannot use two-argument mount command 1613 // and using one-argument "mount 'sh#-c#sh'" doesn't work: 1614 // "mount: can't find sh#-c#sh in /etc/fstab" 1615 // (if /etc/fstab has it, it's ok: root sets up /etc/fstab). 1616 1617 s = mp->mnt_fsname; 1618 n = 0; 1619 args[n++] = s; 1620 while (*s && n < 35 - 2) { 1621 if (*s++ == '#' && *s != '#') { 1622 s[-1] = '\0'; 1623 args[n++] = s; 1624 } 1625 } 1626 args[n++] = mp->mnt_dir; 1627 args[n] = NULL; 1628 rc = spawn_and_wait(args); 1629 goto report_error; 1630 } 1387 1631 1388 1632 // Might this be an CIFS filesystem? 1389 1390 1633 if (ENABLE_FEATURE_MOUNT_CIFS 1391 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)1392 && (mp->mnt_fsname[0] =='/' || mp->mnt_fsname[0]=='\\')1393 && mp->mnt_fsname[0] ==mp->mnt_fsname[1]1634 && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0) 1635 && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\') 1636 && mp->mnt_fsname[0] == mp->mnt_fsname[1] 1394 1637 ) { 1638 int len; 1639 char c; 1395 1640 len_and_sockaddr *lsa; 1396 char *ip, *dotted; 1397 char *s; 1398 1399 rc = 1; 1400 // Replace '/' with '\' and verify that unc points to "//server/share". 1401 1402 for (s = mp->mnt_fsname; *s; ++s) 1403 if (*s == '/') *s = '\\'; 1404 1405 // get server IP 1406 1407 s = strrchr(mp->mnt_fsname, '\\'); 1408 if (s <= mp->mnt_fsname+1) goto report_error; 1409 *s = '\0'; 1410 lsa = host2sockaddr(mp->mnt_fsname+2, 0); 1411 *s = '\\'; 1412 if (!lsa) goto report_error; 1413 1414 // insert ip=... option into string flags. 1415 1416 dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa); 1641 char *hostname, *dotted, *ip; 1642 1643 hostname = mp->mnt_fsname + 2; 1644 len = strcspn(hostname, "/\\"); 1645 if (len == 0 || hostname[len] == '\0') 1646 goto report_error; 1647 c = hostname[len]; 1648 hostname[len] = '\0'; 1649 lsa = host2sockaddr(hostname, 0); 1650 hostname[len] = c; 1651 if (!lsa) 1652 goto report_error; 1653 1654 // Insert "ip=..." option into options 1655 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); 1656 if (ENABLE_FEATURE_CLEAN_UP) free(lsa); 1417 1657 ip = xasprintf("ip=%s", dotted); 1658 if (ENABLE_FEATURE_CLEAN_UP) free(dotted); 1418 1659 parse_mount_options(ip, &filteropts); 1419 1420 // compose new unc '\\server-ip\share' 1421 // (s => slash after hostname) 1422 1423 mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s); 1424 1425 // lock is required 1660 if (ENABLE_FEATURE_CLEAN_UP) free(ip); 1661 1662 // "-o mand" is required [why?] 1426 1663 vfsflags |= MS_MANDLOCK; 1427 1428 1664 mp->mnt_type = (char*)"cifs"; 1429 1665 rc = mount_it_now(mp, vfsflags, filteropts); 1430 if (ENABLE_FEATURE_CLEAN_UP) { 1431 free(mp->mnt_fsname); 1432 free(ip); 1433 free(dotted); 1434 free(lsa); 1435 } 1666 1436 1667 goto report_error; 1437 1668 } 1438 1669 1439 1670 // Might this be an NFS filesystem? 1440 1441 1671 if (ENABLE_FEATURE_MOUNT_NFS 1442 && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))1672 && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0) 1443 1673 && strchr(mp->mnt_fsname, ':') != NULL 1444 1674 ) { … … 1451 1681 // (We use stat, not lstat, in order to allow 1452 1682 // mount symlink_to_file_or_blkdev dir) 1453 1454 1683 if (!stat(mp->mnt_fsname, &st) 1455 1684 && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)) 1456 1685 ) { 1457 1686 // Do we need to allocate a loopback device for it? 1458 1459 1687 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { 1460 1688 loopFile = bb_simplify_path(mp->mnt_fsname); 1461 mp->mnt_fsname = NULL; / * will receive malloced loop dev name */1462 if (set_loop(& (mp->mnt_fsname), loopFile, 0) < 0) {1689 mp->mnt_fsname = NULL; // will receive malloced loop dev name 1690 if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) { 1463 1691 if (errno == EPERM || errno == EACCES) 1464 1692 bb_error_msg(bb_msg_perm_denied_are_you_root); 1465 1693 else 1466 bb_perror_msg("can not setup loop device");1694 bb_perror_msg("can't setup loop device"); 1467 1695 return errno; 1468 1696 } 1469 1697 1470 1698 // Autodetect bind mounts 1471 1472 1699 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) 1473 1700 vfsflags |= MS_BIND; 1474 1701 } 1475 1702 1476 /* If we know the fstype (or don't need to), jump straight 1477 * to the actual mount. */ 1478 1479 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) 1703 // If we know the fstype (or don't need to), jump straight 1704 // to the actual mount. 1705 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) { 1480 1706 rc = mount_it_now(mp, vfsflags, filteropts); 1481 else {1707 } else { 1482 1708 // Loop through filesystem types until mount succeeds 1483 1709 // or we run out 1484 1710 1485 /* Initialize list of block backed filesystems. This has to be 1486 * done here so that during "mount -a", mounts after /proc shows up 1487 * can autodetect. */ 1488 1711 // Initialize list of block backed filesystems. 1712 // This has to be done here so that during "mount -a", 1713 // mounts after /proc shows up can autodetect. 1489 1714 if (!fslist) { 1490 1715 fslist = get_block_backed_filesystems(); … … 1496 1721 mp->mnt_type = fl->data; 1497 1722 rc = mount_it_now(mp, vfsflags, filteropts); 1498 if (!rc) break; 1723 if (!rc) 1724 break; 1499 1725 } 1500 1726 } 1501 1727 1502 1728 // If mount failed, clean up loop file (if any). 1503 1504 1729 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) { 1505 1730 del_loop(mp->mnt_fsname); … … 1514 1739 free(filteropts); 1515 1740 1516 if ( rc &&errno == EBUSY && ignore_busy)1517 r c =0;1518 if (rc <0)1741 if (errno == EBUSY && ignore_busy) 1742 return 0; 1743 if (rc != 0) 1519 1744 bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); 1520 1521 1745 return rc; 1746 } 1747 1748 // -O support 1749 // -O interprets a list of filter options which select whether a mount 1750 // point will be mounted: only mounts with options matching *all* filtering 1751 // options will be selected. 1752 // By default each -O filter option must be present in the list of mount 1753 // options, but if it is prefixed by "no" then it must be absent. 1754 // For example, 1755 // -O a,nob,c matches -o a,c but fails to match -o a,b,c 1756 // (and also fails to match -o a because -o c is absent). 1757 // 1758 // It is different from -t in that each option is matched exactly; a leading 1759 // "no" at the beginning of one option does not negate the rest. 1760 static int match_opt(const char *fs_opt_in, const char *O_opt) 1761 { 1762 if (!O_opt) 1763 return 1; 1764 1765 while (*O_opt) { 1766 const char *fs_opt = fs_opt_in; 1767 int O_len; 1768 int match; 1769 1770 // If option begins with "no" then treat as an inverted match: 1771 // matching is a failure 1772 match = 0; 1773 if (O_opt[0] == 'n' && O_opt[1] == 'o') { 1774 match = 1; 1775 O_opt += 2; 1776 } 1777 // Isolate the current O option 1778 O_len = strchrnul(O_opt, ',') - O_opt; 1779 // Check for a match against existing options 1780 while (1) { 1781 if (strncmp(fs_opt, O_opt, O_len) == 0 1782 && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',') 1783 ) { 1784 if (match) 1785 return 0; // "no" prefix, but option found 1786 match = 1; // current O option found, go check next one 1787 break; 1788 } 1789 fs_opt = strchr(fs_opt, ','); 1790 if (!fs_opt) 1791 break; 1792 fs_opt++; 1793 } 1794 if (match == 0) 1795 return 0; // match wanted but not found 1796 if (O_opt[O_len] == '\0') // end? 1797 break; 1798 // Step to the next O option 1799 O_opt += O_len + 1; 1800 } 1801 // If we get here then everything matched 1802 return 1; 1522 1803 } 1523 1804 1524 1805 // Parse options, if necessary parse fstab/mtab, and call singlemount for 1525 1806 // each directory to be mounted. 1526 1527 static const char must_be_root[] ALIGN1 = "you must be root"; 1528 1529 int mount_main(int argc, char **argv); 1530 int mount_main(int argc, char **argv) 1531 { 1532 enum { OPT_ALL = 0x10 }; 1533 1534 char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0; 1535 char *opt_o; 1807 int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1808 int mount_main(int argc UNUSED_PARAM, char **argv) 1809 { 1810 char *cmdopts = xzalloc(1); 1811 char *fstype = NULL; 1812 char *O_optmatch = NULL; 1813 char *storage_path; 1814 llist_t *lst_o = NULL; 1536 1815 const char *fstabname; 1537 1816 FILE *fstab; 1538 int i, j, rc = 0; 1817 int i, j; 1818 int rc = EXIT_SUCCESS; 1539 1819 unsigned opt; 1540 1820 struct mntent mtpair[2], *mtcur = mtpair; 1541 SKIP_DESKTOP(const int nonroot = 0;)1542 USE_DESKTOP( int nonroot = (getuid() != 0);) 1543 1544 /* parse long options, like --bind and --move. Note that -o option 1545 * and --option are synonymous. Yes, this means --remount,rw works. */1546 1547 for (i = j = 0; i < argc; i++) {1548 if (argv[i][0] == '-' && argv[i][1] == '-') {1549 append_mount_options(&cmdopts, argv[i] +2);1550 } else argv[j++] = argv[i];1551 }1552 argv[j] = 0;1553 arg c = j;1821 IF_NOT_DESKTOP(const int nonroot = 0;) 1822 1823 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid(); 1824 1825 // Parse long options, like --bind and --move. Note that -o option 1826 // and --option are synonymous. Yes, this means --remount,rw works. 1827 for (i = j = 1; argv[i]; i++) { 1828 if (argv[i][0] == '-' && argv[i][1] == '-') 1829 append_mount_options(&cmdopts, argv[i] + 2); 1830 else 1831 argv[j++] = argv[i]; 1832 } 1833 argv[j] = NULL; 1554 1834 1555 1835 // Parse remaining options 1556 1557 opt = getopt32(argv, "o:t:rwanfvs", &opt_o, &fstype); 1558 if (opt & 0x1) append_mount_options(&cmdopts, opt_o); // -o 1559 //if (opt & 0x2) // -t 1560 if (opt & 0x4) append_mount_options(&cmdopts, "ro"); // -r 1561 if (opt & 0x8) append_mount_options(&cmdopts, "rw"); // -w 1562 //if (opt & 0x10) // -a 1563 if (opt & 0x20) USE_FEATURE_MTAB_SUPPORT(useMtab = 0); // -n 1564 if (opt & 0x40) USE_FEATURE_MTAB_SUPPORT(fakeIt = 1); // -f 1565 //if (opt & 0x80) // -v: verbose (ignore) 1566 //if (opt & 0x100) // -s: sloppy (ignore) 1836 // Max 2 params; -o is a list, -v is a counter 1837 opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv"); 1838 opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch 1839 IF_FEATURE_MOUNT_VERBOSE(, &verbose)); 1840 while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o 1841 if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r 1842 if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w 1567 1843 argv += optind; 1568 argc -= optind;1569 1570 // Three or more non-option arguments? Die with a usage message.1571 1572 if (argc > 2) bb_show_usage();1573 1844 1574 1845 // If we have no arguments, show currently mounted filesystems 1575 1576 if (!argc) { 1577 if (!(opt & OPT_ALL)) { 1846 if (!argv[0]) { 1847 if (!(opt & OPT_a)) { 1578 1848 FILE *mountTable = setmntent(bb_path_mtab_file, "r"); 1579 1849 1580 if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file); 1581 1582 while (getmntent_r(mountTable, mtpair, bb_common_bufsiz1, 1583 sizeof(bb_common_bufsiz1))) 1850 if (!mountTable) 1851 bb_error_msg_and_die("no %s", bb_path_mtab_file); 1852 1853 while (getmntent_r(mountTable, &mtpair[0], getmntent_buf, 1854 GETMNTENT_BUFSIZE)) 1584 1855 { 1585 1856 // Don't show rootfs. FIXME: why?? 1586 1857 // util-linux 2.12a happily shows rootfs... 1587 //if ( !strcmp(mtpair->mnt_fsname, "rootfs")) continue;1588 1589 if (!fstype || !strcmp(mtpair->mnt_type, fstype))1858 //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue; 1859 1860 if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0) 1590 1861 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname, 1591 1862 mtpair->mnt_dir, mtpair->mnt_type, 1592 1863 mtpair->mnt_opts); 1593 1864 } 1594 if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable); 1865 if (ENABLE_FEATURE_CLEAN_UP) 1866 endmntent(mountTable); 1595 1867 return EXIT_SUCCESS; 1596 1868 } 1597 } else storage_path = bb_simplify_path(argv[0]); 1598 1599 // When we have two arguments, the second is the directory and we can 1600 // skip looking at fstab entirely. We can always abspath() the directory 1601 // argument when we get it. 1602 1603 if (argc == 2) { 1604 if (nonroot) 1605 bb_error_msg_and_die(must_be_root); 1606 mtpair->mnt_fsname = argv[0]; 1607 mtpair->mnt_dir = argv[1]; 1608 mtpair->mnt_type = fstype; 1609 mtpair->mnt_opts = cmdopts; 1610 rc = singlemount(mtpair, 0); 1611 goto clean_up; 1612 } 1613 1614 i = parse_mount_options(cmdopts, 0); 1869 storage_path = NULL; 1870 } else { 1871 // When we have two arguments, the second is the directory and we can 1872 // skip looking at fstab entirely. We can always abspath() the directory 1873 // argument when we get it. 1874 if (argv[1]) { 1875 if (nonroot) 1876 bb_error_msg_and_die(bb_msg_you_must_be_root); 1877 mtpair->mnt_fsname = argv[0]; 1878 mtpair->mnt_dir = argv[1]; 1879 mtpair->mnt_type = fstype; 1880 mtpair->mnt_opts = cmdopts; 1881 resolve_mount_spec(&mtpair->mnt_fsname); 1882 rc = singlemount(mtpair, /*ignore_busy:*/ 0); 1883 return rc; 1884 } 1885 storage_path = bb_simplify_path(argv[0]); // malloced 1886 } 1887 1888 // Past this point, we are handling either "mount -a [opts]" 1889 // or "mount [opts] single_param" 1890 1891 i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int" 1615 1892 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags 1616 bb_error_msg_and_die( must_be_root);1893 bb_error_msg_and_die(bb_msg_you_must_be_root); 1617 1894 1618 1895 // If we have a shared subtree flag, don't worry about fstab or mtab. 1619 1620 1896 if (ENABLE_FEATURE_MOUNT_FLAGS 1621 1897 && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) 1622 1898 ) { 1623 rc = mount("", argv[0], "", i, ""); 1624 if (rc) bb_perror_msg_and_die("%s", argv[0]); 1625 goto clean_up; 1899 // verbose_mount(source, target, type, flags, data) 1900 rc = verbose_mount("", argv[0], "", i, ""); 1901 if (rc) 1902 bb_simple_perror_msg_and_die(argv[0]); 1903 return rc; 1626 1904 } 1627 1905 1628 1906 // Open either fstab or mtab 1629 1630 1907 fstabname = "/etc/fstab"; 1631 1908 if (i & MS_REMOUNT) { 1909 // WARNING. I am not sure this matches util-linux's 1910 // behavior. It's possible util-linux does not 1911 // take -o opts from mtab (takes only mount source). 1632 1912 fstabname = bb_path_mtab_file; 1633 1913 } 1634 1914 fstab = setmntent(fstabname, "r"); 1635 1915 if (!fstab) 1636 bb_perror_msg_and_die("cannot read %s", fstabname); 1637 1638 // Loop through entries until we find what we're looking for. 1639 1916 bb_perror_msg_and_die("can't read '%s'", fstabname); 1917 1918 // Loop through entries until we find what we're looking for 1640 1919 memset(mtpair, 0, sizeof(mtpair)); 1641 1920 for (;;) { 1642 struct mntent *mt next= (mtcur==mtpair ? mtpair+1 : mtpair);1921 struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair); 1643 1922 1644 1923 // Get next fstab entry 1645 1646 if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1 1647 + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0), 1648 sizeof(bb_common_bufsiz1)/2)) 1649 { 1650 // Were we looking for something specific? 1651 1652 if (argc) { 1653 1654 // If we didn't find anything, complain. 1655 1656 if (!mtnext->mnt_fsname) 1657 bb_error_msg_and_die("can't find %s in %s", 1658 argv[0], fstabname); 1659 1660 mtcur = mtnext; 1661 if (nonroot) { 1662 // fstab must have "users" or "user" 1663 if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS)) 1664 bb_error_msg_and_die(must_be_root); 1665 } 1666 1667 // Mount the last thing we found. 1668 1669 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); 1670 append_mount_options(&(mtcur->mnt_opts), cmdopts); 1671 rc = singlemount(mtcur, 0); 1672 free(mtcur->mnt_opts); 1924 if (!getmntent_r(fstab, mtcur, getmntent_buf 1925 + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0), 1926 GETMNTENT_BUFSIZE/2) 1927 ) { // End of fstab/mtab is reached 1928 mtcur = mtother; // the thing we found last time 1929 break; 1930 } 1931 1932 // If we're trying to mount something specific and this isn't it, 1933 // skip it. Note we must match the exact text in fstab (ala 1934 // "proc") or a full path from root 1935 if (argv[0]) { 1936 1937 // Is this what we're looking for? 1938 if (strcmp(argv[0], mtcur->mnt_fsname) != 0 1939 && strcmp(storage_path, mtcur->mnt_fsname) != 0 1940 && strcmp(argv[0], mtcur->mnt_dir) != 0 1941 && strcmp(storage_path, mtcur->mnt_dir) != 0 1942 ) { 1943 continue; // no 1673 1944 } 1674 goto clean_up; 1675 } 1676 1677 /* If we're trying to mount something specific and this isn't it, 1678 * skip it. Note we must match both the exact text in fstab (ala 1679 * "proc") or a full path from root */ 1680 1681 if (argc) { 1682 1683 // Is this what we're looking for? 1684 1685 if (strcmp(argv[0], mtcur->mnt_fsname) && 1686 strcmp(storage_path, mtcur->mnt_fsname) && 1687 strcmp(argv[0], mtcur->mnt_dir) && 1688 strcmp(storage_path, mtcur->mnt_dir)) continue; 1689 1690 // Remember this entry. Something later may have overmounted 1691 // it, and we want the _last_ match. 1692 1693 mtcur = mtnext; 1694 1695 // If we're mounting all. 1696 1945 1946 // Remember this entry. Something later may have 1947 // overmounted it, and we want the _last_ match. 1948 mtcur = mtother; 1949 1950 // If we're mounting all 1697 1951 } else { 1698 // Do we need to match a filesystem type? 1699 if (fstype && match_fstype(mtcur, fstype)) continue; 1700 1701 // Skip noauto and swap anyway. 1702 1703 if (parse_mount_options(mtcur->mnt_opts, 0) 1704 & (MOUNT_NOAUTO | MOUNT_SWAP)) continue; 1705 1952 struct mntent *mp; 1706 1953 // No, mount -a won't mount anything, 1707 // even user mounts, for mere humans. 1708 1954 // even user mounts, for mere humans 1709 1955 if (nonroot) 1710 bb_error_msg_and_die(must_be_root); 1711 1712 // Mount this thing. 1956 bb_error_msg_and_die(bb_msg_you_must_be_root); 1957 1958 // Does type match? (NULL matches always) 1959 if (!match_fstype(mtcur, fstype)) 1960 continue; 1961 1962 // Skip noauto and swap anyway 1963 if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP)) 1964 // swap is bogus "fstype", parse_mount_options can't check fstypes 1965 || strcasecmp(mtcur->mnt_type, "swap") == 0 1966 ) { 1967 continue; 1968 } 1969 1970 // Does (at least one) option match? 1971 // (NULL matches always) 1972 if (!match_opt(mtcur->mnt_opts, O_optmatch)) 1973 continue; 1974 1975 resolve_mount_spec(&mtcur->mnt_fsname); 1713 1976 1714 1977 // NFS mounts want this to be xrealloc-able 1715 1978 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); 1716 if (singlemount(mtcur, 1)) { 1717 /* Count number of failed mounts */ 1718 rc++; 1979 1980 // If nothing is mounted on this directory... 1981 // (otherwise repeated "mount -a" mounts everything again) 1982 mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0); 1983 // We do not check fsname match of found mount point - 1984 // "/" may have fsname of "/dev/root" while fstab 1985 // says "/dev/something_else". 1986 if (mp) { 1987 if (verbose) { 1988 bb_error_msg("according to %s, " 1989 "%s is already mounted on %s", 1990 bb_path_mtab_file, 1991 mp->mnt_fsname, mp->mnt_dir); 1992 } 1993 } else { 1994 // ...mount this thing 1995 if (singlemount(mtcur, /*ignore_busy:*/ 1)) { 1996 // Count number of failed mounts 1997 rc++; 1998 } 1719 1999 } 1720 2000 free(mtcur->mnt_opts); 1721 2001 } 1722 2002 } 1723 if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab); 1724 1725 clean_up: 1726 2003 2004 // End of fstab/mtab is reached. 2005 // Were we looking for something specific? 2006 if (argv[0]) { // yes 2007 long l; 2008 2009 // If we didn't find anything, complain 2010 if (!mtcur->mnt_fsname) 2011 bb_error_msg_and_die("can't find %s in %s", 2012 argv[0], fstabname); 2013 2014 // What happens when we try to "mount swap_partition"? 2015 // (fstab containts "swap_partition swap swap defaults 0 0") 2016 // util-linux-ng 2.13.1 does this: 2017 // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory) 2018 // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory) 2019 // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory) 2020 // write(2, "mount: mount point swap does not exist\n", 39) = 39 2021 // exit_group(32) = ? 2022 #if 0 2023 // In case we want to simply skip swap partitions: 2024 l = parse_mount_options(mtcur->mnt_opts, NULL); 2025 if ((l & MOUNT_SWAP) 2026 // swap is bogus "fstype", parse_mount_options can't check fstypes 2027 || strcasecmp(mtcur->mnt_type, "swap") == 0 2028 ) { 2029 goto ret; 2030 } 2031 #endif 2032 if (nonroot) { 2033 // fstab must have "users" or "user" 2034 l = parse_mount_options(mtcur->mnt_opts, NULL); 2035 if (!(l & MOUNT_USERS)) 2036 bb_error_msg_and_die(bb_msg_you_must_be_root); 2037 } 2038 2039 //util-linux-2.12 does not do this check. 2040 //// If nothing is mounted on this directory... 2041 //// (otherwise repeated "mount FOO" mounts FOO again) 2042 //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0); 2043 //if (mp) { 2044 // bb_error_msg("according to %s, " 2045 // "%s is already mounted on %s", 2046 // bb_path_mtab_file, 2047 // mp->mnt_fsname, mp->mnt_dir); 2048 //} else { 2049 // ...mount the last thing we found 2050 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts); 2051 append_mount_options(&(mtcur->mnt_opts), cmdopts); 2052 resolve_mount_spec(&mtpair->mnt_fsname); 2053 rc = singlemount(mtcur, /*ignore_busy:*/ 0); 2054 if (ENABLE_FEATURE_CLEAN_UP) 2055 free(mtcur->mnt_opts); 2056 //} 2057 } 2058 2059 //ret: 2060 if (ENABLE_FEATURE_CLEAN_UP) 2061 endmntent(fstab); 1727 2062 if (ENABLE_FEATURE_CLEAN_UP) { 1728 2063 free(storage_path); … … 1730 2065 } 1731 2066 2067 //TODO: exitcode should be ORed mask of (from "man mount"): 2068 // 0 success 2069 // 1 incorrect invocation or permissions 2070 // 2 system error (out of memory, cannot fork, no more loop devices) 2071 // 4 internal mount bug or missing nfs support in mount 2072 // 8 user interrupt 2073 //16 problems writing or locking /etc/mtab 2074 //32 mount failure 2075 //64 some mount succeeded 1732 2076 return rc; 1733 2077 }
Note:
See TracChangeset
for help on using the changeset viewer.