Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/util-linux/mount.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 8  Line 8 
8   *   *
9   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10   */   */
11    // Design notes: There is no spec for mount.  Remind me to write one.
12  /* Design notes: There is no spec for mount.  Remind me to write one.  //
13    // mount_main() calls singlemount() which calls mount_it_now().
14     mount_main() calls singlemount() which calls mount_it_now().  //
15    // mount_main() can loop through /etc/fstab for mount -a
16     mount_main() can loop through /etc/fstab for mount -a  // singlemount() can loop through /etc/filesystems for fstype detection.
17     singlemount() can loop through /etc/filesystems for fstype detection.  // mount_it_now() does the actual mount.
18     mount_it_now() does the actual mount.  //
 */  
   
19  #include <mntent.h>  #include <mntent.h>
20  #include <syslog.h>  #include <syslog.h>
21  #include "libbb.h"  #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
57    
58    #include "libbb.h"
59  #if ENABLE_FEATURE_MOUNT_LABEL  #if ENABLE_FEATURE_MOUNT_LABEL
60  #include "volume_id.h"  # include "volume_id.h"
61    #else
62    # define resolve_mount_spec(fsname) ((void)0)
63  #endif  #endif
64    
65  /* Needed for nfs support only */  // Needed for nfs support only
66  #include <sys/utsname.h>  #include <sys/utsname.h>
67  #undef TRUE  #undef TRUE
68  #undef FALSE  #undef FALSE
69  #include <rpc/rpc.h>  #if ENABLE_FEATURE_MOUNT_NFS
70  #include <rpc/pmap_prot.h>  /* This is just a warning of a common mistake.  Possibly this should be a
71  #include <rpc/pmap_clnt.h>   * uclibc faq entry rather than in busybox... */
72    # if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
73  #ifndef MS_SILENT  #  error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
74  #define MS_SILENT (1 << 15)  # endif
75  #endif  # include <rpc/rpc.h>
76  /* Grab more as needed from util-linux's mount/mount_constants.h */  # include <rpc/pmap_prot.h>
77  #ifndef MS_DIRSYNC  # include <rpc/pmap_clnt.h>
 #define MS_DIRSYNC      128     /* Directory modifications are synchronous */  
78  #endif  #endif
79    
80    
81  #if defined(__dietlibc__)  #if defined(__dietlibc__)
82  /* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)  // 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
83   * dietlibc-0.30 does not have implementation of getmntent_r() */  // dietlibc-0.30 does not have implementation of getmntent_r()
84  static struct mntent *getmntent_r(FILE* stream, struct mntent* result,  static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
85   char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)   char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
86  {  {
# Line 63  enum { Line 98  enum {
98  };  };
99    
100    
101  #define OPTION_STR "o:t:rwanfvsi"  #define OPTION_STR "o:t:rwanfvsiO:"
102  enum {  enum {
103   OPT_o = (1 << 0),   OPT_o = (1 << 0),
104   OPT_t = (1 << 1),   OPT_t = (1 << 1),
# Line 75  enum { Line 110  enum {
110   OPT_v = (1 << 7),   OPT_v = (1 << 7),
111   OPT_s = (1 << 8),   OPT_s = (1 << 8),
112   OPT_i = (1 << 9),   OPT_i = (1 << 9),
113     OPT_O = (1 << 10),
114  };  };
115    
116  #if ENABLE_FEATURE_MTAB_SUPPORT  #if ENABLE_FEATURE_MTAB_SUPPORT
117  #define useMtab (!(option_mask32 & OPT_n))  #define USE_MTAB (!(option_mask32 & OPT_n))
118  #else  #else
119  #define useMtab 0  #define USE_MTAB 0
120  #endif  #endif
121    
122  #if ENABLE_FEATURE_MOUNT_FAKE  #if ENABLE_FEATURE_MOUNT_FAKE
123  #define fakeIt (option_mask32 & OPT_f)  #define FAKE_IT (option_mask32 & OPT_f)
124  #else  #else
125  #define fakeIt 0  #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  #endif
133    
134    
# Line 99  enum { Line 141  enum {
141  // This may be useful e.g. for /dev/fd if a login script makes  // This may be useful e.g. for /dev/fd if a login script makes
142  // the console user owner of this device.  // the console user owner of this device.
143    
144  /* Standard mount options (from -o options or --options), with corresponding  // Standard mount options (from -o options or --options),
145   * flags */  // with corresponding flags
   
146  static const int32_t mount_options[] = {  static const int32_t mount_options[] = {
147   // MS_FLAGS set a bit.  ~MS_FLAGS disable that bit.  0 flags are NOPs.   // MS_FLAGS set a bit.  ~MS_FLAGS disable that bit.  0 flags are NOPs.
148    
149   USE_FEATURE_MOUNT_LOOP(   IF_FEATURE_MOUNT_LOOP(
150   /* "loop" */ 0,   /* "loop" */ 0,
151   )   )
152    
153   USE_FEATURE_MOUNT_FSTAB(   IF_FEATURE_MOUNT_FSTAB(
154   /* "defaults" */ 0,   /* "defaults" */ 0,
155   /* "quiet" 0 - do not filter out, vfat wants to see it */   /* "quiet" 0 - do not filter out, vfat wants to see it */
156   /* "noauto" */ MOUNT_NOAUTO,   /* "noauto" */ MOUNT_NOAUTO,
157   /* "sw"     */ MOUNT_SWAP,   /* "sw"     */ MOUNT_SWAP,
158   /* "swap"   */ MOUNT_SWAP,   /* "swap"   */ MOUNT_SWAP,
159   USE_DESKTOP(/* "user"  */ MOUNT_USERS,)   IF_DESKTOP(/* "user"  */ MOUNT_USERS,)
160   USE_DESKTOP(/* "users" */ MOUNT_USERS,)   IF_DESKTOP(/* "users" */ MOUNT_USERS,)
161   /* "_netdev" */ 0,   /* "_netdev" */ 0,
162   )   )
163    
164   USE_FEATURE_MOUNT_FLAGS(   IF_FEATURE_MOUNT_FLAGS(
165   // vfs flags   // vfs flags
166   /* "nosuid"      */ MS_NOSUID,   /* "nosuid"      */ MS_NOSUID,
167   /* "suid"        */ ~MS_NOSUID,   /* "suid"        */ ~MS_NOSUID,
# Line 142  static const int32_t mount_options[] = { Line 183  static const int32_t mount_options[] = {
183   /* "loud"        */ ~MS_SILENT,   /* "loud"        */ ~MS_SILENT,
184    
185   // action flags   // action flags
186     /* "union"       */ MS_UNION,
187   /* "bind"        */ MS_BIND,   /* "bind"        */ MS_BIND,
188   /* "move"        */ MS_MOVE,   /* "move"        */ MS_MOVE,
189   /* "shared"      */ MS_SHARED,   /* "shared"      */ MS_SHARED,
# Line 161  static const int32_t mount_options[] = { Line 203  static const int32_t mount_options[] = {
203  };  };
204    
205  static const char mount_option_str[] =  static const char mount_option_str[] =
206   USE_FEATURE_MOUNT_LOOP(   IF_FEATURE_MOUNT_LOOP(
207   "loop" "\0"   "loop\0"
208   )   )
209   USE_FEATURE_MOUNT_FSTAB(   IF_FEATURE_MOUNT_FSTAB(
210   "defaults" "\0"   "defaults\0"
211   /* "quiet" "\0" - do not filter out, vfat wants to see it */   // "quiet\0" - do not filter out, vfat wants to see it
212   "noauto" "\0"   "noauto\0"
213   "sw" "\0"   "sw\0"
214   "swap" "\0"   "swap\0"
215   USE_DESKTOP("user" "\0")   IF_DESKTOP("user\0")
216   USE_DESKTOP("users" "\0")   IF_DESKTOP("users\0")
217   "_netdev" "\0"   "_netdev\0"
218   )   )
219   USE_FEATURE_MOUNT_FLAGS(   IF_FEATURE_MOUNT_FLAGS(
220   // vfs flags   // vfs flags
221   "nosuid" "\0"   "nosuid\0"
222   "suid" "\0"   "suid\0"
223   "dev" "\0"   "dev\0"
224   "nodev" "\0"   "nodev\0"
225   "exec" "\0"   "exec\0"
226   "noexec" "\0"   "noexec\0"
227   "sync" "\0"   "sync\0"
228   "dirsync" "\0"   "dirsync\0"
229   "async" "\0"   "async\0"
230   "atime" "\0"   "atime\0"
231   "noatime" "\0"   "noatime\0"
232   "diratime" "\0"   "diratime\0"
233   "nodiratime" "\0"   "nodiratime\0"
234   "mand" "\0"   "mand\0"
235   "nomand" "\0"   "nomand\0"
236   "relatime" "\0"   "relatime\0"
237   "norelatime" "\0"   "norelatime\0"
238   "loud" "\0"   "loud\0"
239    
240   // action flags   // action flags
241   "bind" "\0"   "union\0"
242   "move" "\0"   "bind\0"
243   "shared" "\0"   "move\0"
244   "slave" "\0"   "shared\0"
245   "private" "\0"   "slave\0"
246   "unbindable" "\0"   "private\0"
247   "rshared" "\0"   "unbindable\0"
248   "rslave" "\0"   "rshared\0"
249   "rprivate" "\0"   "rslave\0"
250   "runbindable" "\0"   "rprivate\0"
251     "runbindable\0"
252   )   )
253    
254   // Always understood.   // Always understood.
255   "ro" "\0"        // vfs flag   "ro\0"        // vfs flag
256   "rw" "\0"        // vfs flag   "rw\0"        // vfs flag
257   "remount" "\0"   // action flag   "remount\0"   // action flag
258  ;  ;
259    
260    
# Line 257  static int verbose_mount(const char *sou Line 300  static int verbose_mount(const char *sou
300  #define verbose_mount(...) mount(__VA_ARGS__)  #define verbose_mount(...) mount(__VA_ARGS__)
301  #endif  #endif
302    
303  static int resolve_mount_spec(char **fsname)  // Append mount options to string
 {  
  char *tmp = NULL;  
   
 #if ENABLE_FEATURE_MOUNT_LABEL  
  if (!strncmp(*fsname, "UUID=", 5))  
  tmp = get_devname_from_uuid(*fsname + 5);  
  else if (!strncmp(*fsname, "LABEL=", 6))  
  tmp = get_devname_from_label(*fsname + 6);  
 #endif  
   
  if (tmp) {  
  *fsname = tmp;  
  return 1;  
  }  
  return 0;  
 }  
   
 /* Append mount options to string */  
304  static void append_mount_options(char **oldopts, const char *newopts)  static void append_mount_options(char **oldopts, const char *newopts)
305  {  {
306   if (*oldopts && **oldopts) {   if (*oldopts && **oldopts) {
307   /* do not insert options which are already there */   // Do not insert options which are already there
308   while (newopts[0]) {   while (newopts[0]) {
309   char *p;   char *p;
310   int len = strlen(newopts);   int len = strlen(newopts);
# Line 307  static void append_mount_options(char ** Line 332  static void append_mount_options(char **
332   }   }
333  }  }
334    
335  /* Use the mount_options list to parse options into flags.  // Use the mount_options list to parse options into flags.
336   * Also return list of unrecognized options if unrecognized!=NULL */  // Also return list of unrecognized options if unrecognized != NULL
337  static long parse_mount_options(char *options, char **unrecognized)  static long parse_mount_options(char *options, char **unrecognized)
338  {  {
339   long flags = MS_SILENT;   long flags = MS_SILENT;
# Line 321  static long parse_mount_options(char *op Line 346  static long parse_mount_options(char *op
346    
347   if (comma) *comma = '\0';   if (comma) *comma = '\0';
348    
349  /* FIXME: use hasmntopt() */  // FIXME: use hasmntopt()
350   // Find this option in mount_options   // Find this option in mount_options
351   for (i = 0; i < ARRAY_SIZE(mount_options); i++) {   for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
352   if (!strcasecmp(option_str, options)) {   if (!strcasecmp(option_str, options)) {
# Line 332  static long parse_mount_options(char *op Line 357  static long parse_mount_options(char *op
357   }   }
358   option_str += strlen(option_str) + 1;   option_str += strlen(option_str) + 1;
359   }   }
360   // If unrecognized not NULL, append unrecognized mount options */   // If unrecognized not NULL, append unrecognized mount options
361   if (unrecognized && i == ARRAY_SIZE(mount_options)) {   if (unrecognized && i == ARRAY_SIZE(mount_options)) {
362   // Add it to strflags, to pass on to kernel   // Add it to strflags, to pass on to kernel
363   i = *unrecognized ? strlen(*unrecognized) : 0;   i = *unrecognized ? strlen(*unrecognized) : 0;
# Line 354  static long parse_mount_options(char *op Line 379  static long parse_mount_options(char *op
379  }  }
380    
381  // Return a list of all block device backed filesystems  // Return a list of all block device backed filesystems
   
382  static llist_t *get_block_backed_filesystems(void)  static llist_t *get_block_backed_filesystems(void)
383  {  {
384   static const char filesystems[2][sizeof("/proc/filesystems")] = {   static const char filesystems[2][sizeof("/proc/filesystems")] = {
# Line 362  static llist_t *get_block_backed_filesys Line 386  static llist_t *get_block_backed_filesys
386   "/proc/filesystems",   "/proc/filesystems",
387   };   };
388   char *fs, *buf;   char *fs, *buf;
389   llist_t *list = 0;   llist_t *list = NULL;
390   int i;   int i;
391   FILE *f;   FILE *f;
392    
# Line 371  static llist_t *get_block_backed_filesys Line 395  static llist_t *get_block_backed_filesys
395   if (!f) continue;   if (!f) continue;
396    
397   while ((buf = xmalloc_fgetline(f)) != NULL) {   while ((buf = xmalloc_fgetline(f)) != NULL) {
398   if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))   if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
399   continue;   continue;
400   fs = skip_whitespace(buf);   fs = skip_whitespace(buf);
401   if (*fs=='#' || *fs=='*' || !*fs) continue;   if (*fs == '#' || *fs == '*' || !*fs)
402     continue;
403    
404   llist_add_to_end(&list, xstrdup(fs));   llist_add_to_end(&list, xstrdup(fs));
405   free(buf);   free(buf);
# Line 400  static int mount_it_now(struct mntent *m Line 425  static int mount_it_now(struct mntent *m
425  {  {
426   int rc = 0;   int rc = 0;
427    
428   if (fakeIt) {   if (FAKE_IT) {
429   if (verbose >= 2)   if (verbose >= 2)
430   bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",   bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
431   mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,   mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
# Line 416  static int mount_it_now(struct mntent *m Line 441  static int mount_it_now(struct mntent *m
441    
442   // If mount failed, try   // If mount failed, try
443   // helper program mount.<mnt_type>   // helper program mount.<mnt_type>
444   if (ENABLE_FEATURE_MOUNT_HELPERS && rc) {   if (HELPERS_ALLOWED && rc && mp->mnt_type) {
445   char *args[6];   char *args[8];
446   int errno_save = errno;   int errno_save = errno;
447   args[0] = xasprintf("mount.%s", mp->mnt_type);   args[0] = xasprintf("mount.%s", mp->mnt_type);
448   rc = 1;   rc = 1;
449     if (FAKE_IT)
450     args[rc++] = (char *)"-f";
451     if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
452     args[rc++] = (char *)"-n";
453     args[rc++] = mp->mnt_fsname;
454     args[rc++] = mp->mnt_dir;
455   if (filteropts) {   if (filteropts) {
456   args[rc++] = (char *)"-o";   args[rc++] = (char *)"-o";
457   args[rc++] = filteropts;   args[rc++] = filteropts;
458   }   }
  args[rc++] = mp->mnt_fsname;  
  args[rc++] = mp->mnt_dir;  
459   args[rc] = NULL;   args[rc] = NULL;
460   rc = wait4pid(spawn(args));   rc = wait4pid(spawn(args));
461   free(args[0]);   free(args[0]);
# Line 448  static int mount_it_now(struct mntent *m Line 477  static int mount_it_now(struct mntent *m
477   if (rc && errno == EPERM)   if (rc && errno == EPERM)
478   bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);   bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
479    
480   /* If the mount was successful, and we're maintaining an old-style   // If the mount was successful, and we're maintaining an old-style
481   * mtab file by hand, add the new entry to it now. */   // mtab file by hand, add the new entry to it now.
482   mtab:   mtab:
483   if (useMtab && !rc && !(vfsflags & MS_REMOUNT)) {   if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
484   char *fsname;   char *fsname;
485   FILE *mountTable = setmntent(bb_path_mtab_file, "a+");   FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
486   const char *option_str = mount_option_str;   const char *option_str = mount_option_str;
# Line 479  static int mount_it_now(struct mntent *m Line 508  static int mount_it_now(struct mntent *m
508    
509   mp->mnt_dir = bb_simplify_path(mp->mnt_dir);   mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
510   fsname = 0;   fsname = 0;
511   if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */   if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
512   mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);   mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
513   mp->mnt_type = (char*)"bind";   mp->mnt_type = (char*)"bind";
514   }   }
# Line 522  static int mount_it_now(struct mntent *m Line 551  static int mount_it_now(struct mntent *m
551   * plus NFSv3 stuff.   * plus NFSv3 stuff.
552   */   */
553    
 /* This is just a warning of a common mistake.  Possibly this should be a  
  * uclibc faq entry rather than in busybox... */  
 #if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)  
 #error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."  
 #endif  
   
554  #define MOUNTPORT 635  #define MOUNTPORT 635
555  #define MNTPATHLEN 1024  #define MNTPATHLEN 1024
556  #define MNTNAMLEN 255  #define MNTNAMLEN 255
# Line 718  enum { Line 741  enum {
741   * "after #include <errno.h> the symbol errno is reserved for any use,   * "after #include <errno.h> the symbol errno is reserved for any use,
742   *  it cannot even be used as a struct tag or field name".   *  it cannot even be used as a struct tag or field name".
743   */   */
   
744  #ifndef EDQUOT  #ifndef EDQUOT
745  #define EDQUOT ENOSPC  # define EDQUOT ENOSPC
746  #endif  #endif
747    /* Convert each NFSERR_BLAH into EBLAH */
748  // Convert each NFSERR_BLAH into EBLAH  static const uint8_t nfs_err_stat[] = {
749     1,  2,  5,  6, 13, 17,
750  static const struct {   19, 20, 21, 22, 27, 28,
751   short stat;   30, 63, 66, 69, 70, 71
752   short errnum;  };
753  } nfs_errtbl[] = {  static const uint8_t nfs_err_errnum[] = {
754   {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},   EPERM , ENOENT      , EIO      , ENXIO , EACCES, EEXIST,
755   {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},   ENODEV, ENOTDIR     , EISDIR   , EINVAL, EFBIG , ENOSPC,
756   {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},   EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
  {70,ESTALE}, {71,EREMOTE}, {-1,EIO}  
757  };  };
   
758  static char *nfs_strerror(int status)  static char *nfs_strerror(int status)
759  {  {
760   int i;   int i;
761    
762   for (i = 0; nfs_errtbl[i].stat != -1; i++) {   for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
763   if (nfs_errtbl[i].stat == status)   if (nfs_err_stat[i] == status)
764   return strerror(nfs_errtbl[i].errnum);   return strerror(nfs_err_errnum[i]);
765   }   }
766   return xasprintf("unknown nfs status return value: %d", status);   return xasprintf("unknown nfs status return value: %d", status);
767  }  }
# Line 777  static bool_t xdr_dirpath(XDR *xdrs, dir Line 797  static bool_t xdr_dirpath(XDR *xdrs, dir
797    
798  static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)  static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
799  {  {
800   if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))   if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
801     (unsigned int *) &objp->fhandle3_len,
802     FHSIZE3)
803     ) {
804   return FALSE;   return FALSE;
805     }
806   return TRUE;   return TRUE;
807  }  }
808    
# Line 786  static bool_t xdr_mountres3_ok(XDR *xdrs Line 810  static bool_t xdr_mountres3_ok(XDR *xdrs
810  {  {
811   if (!xdr_fhandle3(xdrs, &objp->fhandle))   if (!xdr_fhandle3(xdrs, &objp->fhandle))
812   return FALSE;   return FALSE;
813   if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,   if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
814   sizeof (int), (xdrproc_t) xdr_int))   &(objp->auth_flavours.auth_flavours_len),
815     ~0,
816     sizeof(int),
817     (xdrproc_t) xdr_int)
818     ) {
819   return FALSE;   return FALSE;
820     }
821   return TRUE;   return TRUE;
822  }  }
823    
# Line 839  find_kernel_nfs_mount_version(void) Line 868  find_kernel_nfs_mount_version(void)
868    
869   kernel_version = get_linux_version_code();   kernel_version = get_linux_version_code();
870   if (kernel_version) {   if (kernel_version) {
871   if (kernel_version < KERNEL_VERSION(2,1,32))   if (kernel_version < KERNEL_VERSION(2,2,18))
  nfs_mount_version = 1;  
  else if (kernel_version < KERNEL_VERSION(2,2,18) ||  
  (kernel_version >= KERNEL_VERSION(2,3,0) &&  
  kernel_version < KERNEL_VERSION(2,3,99)))  
872   nfs_mount_version = 3;   nfs_mount_version = 3;
873   /* else v4 since 2.3.99pre4 */   /* else v4 since 2.3.99pre4 */
874   }   }
# Line 920  static int daemonize(void) Line 945  static int daemonize(void)
945  static inline int daemonize(void) { return -ENOSYS; }  static inline int daemonize(void) { return -ENOSYS; }
946  #endif  #endif
947    
948  // TODO  /* TODO */
949  static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)  static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
950  {  {
951   return 0;   return 0;
# Line 939  static void error_msg_rpc(const char *ms Line 964  static void error_msg_rpc(const char *ms
964   bb_error_msg("%.*s", len, msg);   bb_error_msg("%.*s", len, msg);
965  }  }
966    
967  // NB: mp->xxx fields may be trashed on exit  /* NB: mp->xxx fields may be trashed on exit */
968  static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)  static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
969  {  {
970   CLIENT *mclient;   CLIENT *mclient;
971   char *hostname;   char *hostname;
972   char *pathname;   char *pathname;
973   char *mounthost;   char *mounthost;
974     /* prior to 2.6.23, kernel took NFS options in a form of this struct
975     * only. 2.6.23+ looks at data->version, and if it's not 1..6,
976     * then data pointer is interpreted as a string. */
977   struct nfs_mount_data data;   struct nfs_mount_data data;
978   char *opt;   char *opt;
979   struct hostent *hp;   struct hostent *hp;
# Line 972  static int nfsmount(struct mntent *mp, l Line 1000  static int nfsmount(struct mntent *mp, l
1000   int nfsprog;   int nfsprog;
1001   int nfsvers;   int nfsvers;
1002   int retval;   int retval;
1003   /* these all are one-bit really. 4.3.1 likes this combination: */   /* these all are one-bit really. gcc 4.3.1 likes this combination: */
1004   smallint tcp;   smallint tcp;
1005   smallint soft;   smallint soft;
1006   int intr;   int intr;
# Line 1290  static int nfsmount(struct mntent *mp, l Line 1318  static int nfsmount(struct mntent *mp, l
1318   }   }
1319   }   }
1320    
1321   /* create mount daemon client */   /* Create mount daemon client */
1322   /* See if the nfs host = mount host. */   /* See if the nfs host = mount host. */
1323   if (mounthost) {   if (mounthost) {
1324   if (mounthost[0] >= '0' && mounthost[0] <= '9') {   if (mounthost[0] >= '0' && mounthost[0] <= '9') {
# Line 1336  static int nfsmount(struct mntent *mp, l Line 1364  static int nfsmount(struct mntent *mp, l
1364   retry_timeout.tv_usec = 0;   retry_timeout.tv_usec = 0;
1365   total_timeout.tv_sec = 20;   total_timeout.tv_sec = 20;
1366   total_timeout.tv_usec = 0;   total_timeout.tv_usec = 0;
1367  //FIXME: use monotonic()?  /* FIXME: use monotonic()? */
1368   timeout = time(NULL) + 60 * retry;   timeout = time(NULL) + 60 * retry;
1369   prevt = 0;   prevt = 0;
1370   t = 30;   t = 30;
1371   retry:   retry:
1372   /* be careful not to use too many CPU cycles */   /* Be careful not to use too many CPU cycles */
1373   if (t - prevt < 30)   if (t - prevt < 30)
1374   sleep(30);   sleep(30);
1375    
# Line 1381  static int nfsmount(struct mntent *mp, l Line 1409  static int nfsmount(struct mntent *mp, l
1409   error_msg_rpc(clnt_spcreateerror(" "));   error_msg_rpc(clnt_spcreateerror(" "));
1410   } else {   } else {
1411   enum clnt_stat clnt_stat;   enum clnt_stat clnt_stat;
1412   /* try to mount hostname:pathname */  
1413     /* Try to mount hostname:pathname */
1414   mclient->cl_auth = authunix_create_default();   mclient->cl_auth = authunix_create_default();
1415    
1416   /* make pointers in xdr_mountres3 NULL so   /* Make pointers in xdr_mountres3 NULL so
1417   * that xdr_array allocates memory for us   * that xdr_array allocates memory for us
1418   */   */
1419   memset(&status, 0, sizeof(status));   memset(&status, 0, sizeof(status));
# Line 1421  static int nfsmount(struct mntent *mp, l Line 1450  static int nfsmount(struct mntent *mp, l
1450   }   }
1451    
1452   /* Timeout. We are going to retry... maybe */   /* Timeout. We are going to retry... maybe */
   
1453   if (!bg)   if (!bg)
1454   goto fail;   goto fail;
1455   if (!daemonized) {   if (!daemonized) {
# Line 1475  static int nfsmount(struct mntent *mp, l Line 1503  static int nfsmount(struct mntent *mp, l
1503   data.flags |= NFS_MOUNT_VER3;   data.flags |= NFS_MOUNT_VER3;
1504   }   }
1505    
1506   /* create nfs socket for kernel */   /* Create nfs socket for kernel */
   
1507   if (tcp) {   if (tcp) {
1508   if (nfs_mount_version < 3) {   if (nfs_mount_version < 3) {
1509   bb_error_msg("NFS over TCP is not supported");   bb_error_msg("NFS over TCP is not supported");
# Line 1502  static int nfsmount(struct mntent *mp, l Line 1529  static int nfsmount(struct mntent *mp, l
1529   }   }
1530   server_addr.sin_port = htons(port);   server_addr.sin_port = htons(port);
1531    
1532   /* prepare data structure for kernel */   /* Prepare data structure for kernel */
   
1533   data.fd = fsock;   data.fd = fsock;
1534   memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));   memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1535   strncpy(data.hostname, hostname, sizeof(data.hostname));   strncpy(data.hostname, hostname, sizeof(data.hostname));
1536    
1537   /* clean up */   /* Clean up */
   
1538   auth_destroy(mclient->cl_auth);   auth_destroy(mclient->cl_auth);
1539   clnt_destroy(mclient);   clnt_destroy(mclient);
1540   close(msock);   close(msock);
# Line 1523  static int nfsmount(struct mntent *mp, l Line 1548  static int nfsmount(struct mntent *mp, l
1548   if (!daemonized) {   if (!daemonized) {
1549   daemonized = daemonize();   daemonized = daemonize();
1550   if (daemonized <= 0) { /* parent or error */   if (daemonized <= 0) { /* parent or error */
1551  // FIXME: parent doesn't close fsock - ??!  /* FIXME: parent doesn't close fsock - ??! */
1552   retval = -daemonized;   retval = -daemonized;
1553   goto ret;   goto ret;
1554   }   }
# Line 1535  static int nfsmount(struct mntent *mp, l Line 1560  static int nfsmount(struct mntent *mp, l
1560   }   }
1561   }   }
1562    
1563   do_mount: /* perform actual mount */   /* Perform actual mount */
1564     do_mount:
1565   mp->mnt_type = (char*)"nfs";   mp->mnt_type = (char*)"nfs";
1566   retval = mount_it_now(mp, vfsflags, (char*)&data);   retval = mount_it_now(mp, vfsflags, (char*)&data);
1567   goto ret;   goto ret;
1568    
1569   fail: /* abort */   /* Abort */
1570     fail:
1571   if (msock >= 0) {   if (msock >= 0) {
1572   if (mclient) {   if (mclient) {
1573   auth_destroy(mclient->cl_auth);   auth_destroy(mclient->cl_auth);
# Line 1560  static int nfsmount(struct mntent *mp, l Line 1585  static int nfsmount(struct mntent *mp, l
1585   return retval;   return retval;
1586  }  }
1587    
1588  #else /* !ENABLE_FEATURE_MOUNT_NFS */  #else // !ENABLE_FEATURE_MOUNT_NFS
1589    
1590  /* Never called. Call should be optimized out. */  // Never called. Call should be optimized out.
1591  int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);  int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
1592    
1593  #endif /* !ENABLE_FEATURE_MOUNT_NFS */  #endif // !ENABLE_FEATURE_MOUNT_NFS
1594    
1595  // Mount one directory.  Handles CIFS, NFS, loopback, autobind, and filesystem  // Mount one directory.  Handles CIFS, NFS, loopback, autobind, and filesystem
1596  // type detection.  Returns 0 for success, nonzero for failure.  // type detection.  Returns 0 for success, nonzero for failure.
# Line 1574  static int singlemount(struct mntent *mp Line 1599  static int singlemount(struct mntent *mp
1599  {  {
1600   int rc = -1;   int rc = -1;
1601   long vfsflags;   long vfsflags;
1602   char *loopFile = 0, *filteropts = 0;   char *loopFile = NULL, *filteropts = NULL;
1603   llist_t *fl = 0;   llist_t *fl = NULL;
1604   struct stat st;   struct stat st;
1605    
1606   vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);   errno = 0;
1607    
1608   // Treat fstype "auto" as unspecified.   vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1609    
1610     // Treat fstype "auto" as unspecified
1611   if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)   if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1612   mp->mnt_type = NULL;   mp->mnt_type = NULL;
1613    
1614   // Might this be a virtual filesystem?   // Might this be a virtual filesystem?
1615     if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
1616   if (ENABLE_FEATURE_MOUNT_HELPERS   char *args[35];
1617   && (strchr(mp->mnt_fsname, '#'))   char *s;
1618   ) {   int n;
1619   char *s, *p, *args[35];   // fsname: "cmd#arg1#arg2..."
1620   int n = 0;   // WARNING: allows execution of arbitrary commands!
1621  // FIXME: does it allow execution of arbitrary commands?!   // Try "mount 'sh#-c#sh' bogus_dir".
1622  // What args[0] can end up with?   // It is safe ONLY because non-root
1623   for (s = p = mp->mnt_fsname; *s && n < 35-3; ++s) {   // cannot use two-argument mount command
1624   if (s[0] == '#' && s[1] != '#') {   // and using one-argument "mount 'sh#-c#sh'" doesn't work:
1625   *s = '\0';   // "mount: can't find sh#-c#sh in /etc/fstab"
1626   args[n++] = p;   // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
1627   p = s + 1;  
1628     s = mp->mnt_fsname;
1629     n = 0;
1630     args[n++] = s;
1631     while (*s && n < 35 - 2) {
1632     if (*s++ == '#' && *s != '#') {
1633     s[-1] = '\0';
1634     args[n++] = s;
1635   }   }
1636   }   }
  args[n++] = p;  
1637   args[n++] = mp->mnt_dir;   args[n++] = mp->mnt_dir;
1638   args[n] = NULL;   args[n] = NULL;
1639   rc = wait4pid(xspawn(args));   rc = wait4pid(xspawn(args));
# Line 1609  static int singlemount(struct mntent *mp Line 1641  static int singlemount(struct mntent *mp
1641   }   }
1642    
1643   // Might this be an CIFS filesystem?   // Might this be an CIFS filesystem?
   
1644   if (ENABLE_FEATURE_MOUNT_CIFS   if (ENABLE_FEATURE_MOUNT_CIFS
1645   && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)   && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1646   && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')   && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1647   && mp->mnt_fsname[0] == mp->mnt_fsname[1]   && mp->mnt_fsname[0] == mp->mnt_fsname[1]
1648   ) {   ) {
1649     int len;
1650     char c;
1651   len_and_sockaddr *lsa;   len_and_sockaddr *lsa;
1652   char *ip, *dotted;   char *hostname, *dotted, *ip;
  char *s;  
   
  rc = 1;  
  // Replace '/' with '\' and verify that unc points to "//server/share".  
   
  for (s = mp->mnt_fsname; *s; ++s)  
  if (*s == '/') *s = '\\';  
1653    
1654   // get server IP   hostname = mp->mnt_fsname + 2;
1655     len = strcspn(hostname, "/\\");
1656   s = strrchr(mp->mnt_fsname, '\\');   if (len == 0 || hostname[len] == '\0')
1657   if (s <= mp->mnt_fsname+1) goto report_error;   goto report_error;
1658   *s = '\0';   c = hostname[len];
1659   lsa = host2sockaddr(mp->mnt_fsname+2, 0);   hostname[len] = '\0';
1660   *s = '\\';   lsa = host2sockaddr(hostname, 0);
1661   if (!lsa) goto report_error;   hostname[len] = c;
1662     if (!lsa)
1663   // insert ip=... option into string flags.   goto report_error;
1664    
1665     // Insert "ip=..." option into options
1666   dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);   dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1667     if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1668   ip = xasprintf("ip=%s", dotted);   ip = xasprintf("ip=%s", dotted);
1669     if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
1670   parse_mount_options(ip, &filteropts);   parse_mount_options(ip, &filteropts);
1671     if (ENABLE_FEATURE_CLEAN_UP) free(ip);
1672    
1673   // compose new unc '\\server-ip\share'   // "-o mand" is required [why?]
  // (s => slash after hostname)  
   
  mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);  
   
  // lock is required  
1674   vfsflags |= MS_MANDLOCK;   vfsflags |= MS_MANDLOCK;
   
1675   mp->mnt_type = (char*)"cifs";   mp->mnt_type = (char*)"cifs";
1676   rc = mount_it_now(mp, vfsflags, filteropts);   rc = mount_it_now(mp, vfsflags, filteropts);
1677   if (ENABLE_FEATURE_CLEAN_UP) {  
  free(mp->mnt_fsname);  
  free(ip);  
  free(dotted);  
  free(lsa);  
  }  
1678   goto report_error;   goto report_error;
1679   }   }
1680    
1681   // Might this be an NFS filesystem?   // Might this be an NFS filesystem?
   
1682   if (ENABLE_FEATURE_MOUNT_NFS   if (ENABLE_FEATURE_MOUNT_NFS
1683   && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))   && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
1684   && strchr(mp->mnt_fsname, ':') != NULL   && strchr(mp->mnt_fsname, ':') != NULL
1685   ) {   ) {
1686   rc = nfsmount(mp, vfsflags, filteropts);   rc = nfsmount(mp, vfsflags, filteropts);
# Line 1673  static int singlemount(struct mntent *mp Line 1691  static int singlemount(struct mntent *mp
1691   // a synthetic filesystem like proc or sysfs.)   // a synthetic filesystem like proc or sysfs.)
1692   // (We use stat, not lstat, in order to allow   // (We use stat, not lstat, in order to allow
1693   // mount symlink_to_file_or_blkdev dir)   // mount symlink_to_file_or_blkdev dir)
   
1694   if (!stat(mp->mnt_fsname, &st)   if (!stat(mp->mnt_fsname, &st)
1695   && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))   && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1696   ) {   ) {
1697   // Do we need to allocate a loopback device for it?   // Do we need to allocate a loopback device for it?
   
1698   if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {   if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1699   loopFile = bb_simplify_path(mp->mnt_fsname);   loopFile = bb_simplify_path(mp->mnt_fsname);
1700   mp->mnt_fsname = NULL; /* will receive malloced loop dev name */   mp->mnt_fsname = NULL; // will receive malloced loop dev name
1701   if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {   if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
1702   if (errno == EPERM || errno == EACCES)   if (errno == EPERM || errno == EACCES)
1703   bb_error_msg(bb_msg_perm_denied_are_you_root);   bb_error_msg(bb_msg_perm_denied_are_you_root);
1704   else   else
1705   bb_perror_msg("cannot setup loop device");   bb_perror_msg("can't setup loop device");
1706   return errno;   return errno;
1707   }   }
1708    
1709   // Autodetect bind mounts   // Autodetect bind mounts
   
1710   } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)   } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1711   vfsflags |= MS_BIND;   vfsflags |= MS_BIND;
1712   }   }
1713    
1714   /* If we know the fstype (or don't need to), jump straight   // If we know the fstype (or don't need to), jump straight
1715   * to the actual mount. */   // to the actual mount.
   
1716   if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))   if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1717   rc = mount_it_now(mp, vfsflags, filteropts);   rc = mount_it_now(mp, vfsflags, filteropts);
1718   else {   else {
1719   // Loop through filesystem types until mount succeeds   // Loop through filesystem types until mount succeeds
1720   // or we run out   // or we run out
1721    
1722   /* Initialize list of block backed filesystems.  This has to be   // Initialize list of block backed filesystems.
1723   * done here so that during "mount -a", mounts after /proc shows up   // This has to be done here so that during "mount -a",
1724   * can autodetect. */   // mounts after /proc shows up can autodetect.
   
1725   if (!fslist) {   if (!fslist) {
1726   fslist = get_block_backed_filesystems();   fslist = get_block_backed_filesystems();
1727   if (ENABLE_FEATURE_CLEAN_UP && fslist)   if (ENABLE_FEATURE_CLEAN_UP && fslist)
# Line 1718  static int singlemount(struct mntent *mp Line 1731  static int singlemount(struct mntent *mp
1731   for (fl = fslist; fl; fl = fl->link) {   for (fl = fslist; fl; fl = fl->link) {
1732   mp->mnt_type = fl->data;   mp->mnt_type = fl->data;
1733   rc = mount_it_now(mp, vfsflags, filteropts);   rc = mount_it_now(mp, vfsflags, filteropts);
1734   if (!rc) break;   if (!rc)
1735     break;
1736   }   }
1737   }   }
1738    
1739   // If mount failed, clean up loop file (if any).   // If mount failed, clean up loop file (if any).
   
1740   if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {   if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1741   del_loop(mp->mnt_fsname);   del_loop(mp->mnt_fsname);
1742   if (ENABLE_FEATURE_CLEAN_UP) {   if (ENABLE_FEATURE_CLEAN_UP) {
# Line 1743  static int singlemount(struct mntent *mp Line 1756  static int singlemount(struct mntent *mp
1756   return rc;   return rc;
1757  }  }
1758    
1759  // Parse options, if necessary parse fstab/mtab, and call singlemount for  // -O support
1760  // each directory to be mounted.  //    -O interprets a list of filter options which select whether a mount
1761    // point will be mounted: only mounts with options matching *all* filtering
1762    // options will be selected.
1763    //    By default each -O filter option must be present in the list of mount
1764    // options, but if it is prefixed by "no" then it must be absent.
1765    // For example,
1766    //  -O a,nob,c  matches  -o a,c  but fails to match  -o a,b,c
1767    //              (and also fails to match  -o a  because  -o c  is absent).
1768    //
1769    // It is different from -t in that each option is matched exactly; a leading
1770    // "no" at the beginning of one option does not negate the rest.
1771    static int match_opt(const char *fs_opt_in, const char *O_opt)
1772    {
1773     if (!O_opt)
1774     return 1;
1775    
1776  static const char must_be_root[] ALIGN1 = "you must be root";   while (*O_opt) {
1777     const char *fs_opt = fs_opt_in;
1778     int O_len;
1779     int match;
1780    
1781     // If option begins with "no" then treat as an inverted match:
1782     // matching is a failure
1783     match = 0;
1784     if (O_opt[0] == 'n' && O_opt[1] == 'o') {
1785     match = 1;
1786     O_opt += 2;
1787     }
1788     // Isolate the current O option
1789     O_len = strchrnul(O_opt, ',') - O_opt;
1790     // Check for a match against existing options
1791     while (1) {
1792     if (strncmp(fs_opt, O_opt, O_len) == 0
1793     && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
1794     ) {
1795     if (match)
1796     return 0;  // "no" prefix, but option found
1797     match = 1;  // current O option found, go check next one
1798     break;
1799     }
1800     fs_opt = strchr(fs_opt, ',');
1801     if (!fs_opt)
1802     break;
1803     fs_opt++;
1804     }
1805     if (match == 0)
1806     return 0;     // match wanted but not found
1807     if (O_opt[O_len] == '\0') // end?
1808     break;
1809     // Step to the next O option
1810     O_opt += O_len + 1;
1811     }
1812     // If we get here then everything matched
1813     return 1;
1814    }
1815    
1816    // Parse options, if necessary parse fstab/mtab, and call singlemount for
1817    // each directory to be mounted.
1818  int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;  int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1819  int mount_main(int argc UNUSED_PARAM, char **argv)  int mount_main(int argc UNUSED_PARAM, char **argv)
1820  {  {
1821   char *cmdopts = xstrdup("");   char *cmdopts = xzalloc(1);
1822   char *fstype = NULL;   char *fstype = NULL;
1823     char *O_optmatch = NULL;
1824   char *storage_path;   char *storage_path;
1825   llist_t *lst_o = NULL;   llist_t *lst_o = NULL;
1826   const char *fstabname;   const char *fstabname;
1827   FILE *fstab;   FILE *fstab;
1828   int i, j, rc = 0;   int i, j;
1829     int rc = EXIT_SUCCESS;
1830   unsigned opt;   unsigned opt;
1831   struct mntent mtpair[2], *mtcur = mtpair;   struct mntent mtpair[2], *mtcur = mtpair;
1832   SKIP_DESKTOP(const int nonroot = 0;)   IF_NOT_DESKTOP(const int nonroot = 0;)
1833    
1834   USE_DESKTOP(int nonroot = ) sanitize_env_if_suid();   IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
1835    
1836   // Parse long options, like --bind and --move.  Note that -o option   // Parse long options, like --bind and --move.  Note that -o option
1837   // and --option are synonymous.  Yes, this means --remount,rw works.   // and --option are synonymous.  Yes, this means --remount,rw works.
# Line 1775  int mount_main(int argc UNUSED_PARAM, ch Line 1844  int mount_main(int argc UNUSED_PARAM, ch
1844   argv[j] = NULL;   argv[j] = NULL;
1845    
1846   // Parse remaining options   // Parse remaining options
1847   // Max 2 params; -v is a counter   // Max 2 params; -o is a list, -v is a counter
1848   opt_complementary = "?2o::" USE_FEATURE_MOUNT_VERBOSE(":vv");   opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
1849   opt = getopt32(argv, OPTION_STR, &lst_o, &fstype   opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
1850   USE_FEATURE_MOUNT_VERBOSE(, &verbose));   IF_FEATURE_MOUNT_VERBOSE(, &verbose));
1851   while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o   while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
1852   if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r   if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1853   if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w   if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
# Line 1797  int mount_main(int argc UNUSED_PARAM, ch Line 1866  int mount_main(int argc UNUSED_PARAM, ch
1866   {   {
1867   // Don't show rootfs. FIXME: why??   // Don't show rootfs. FIXME: why??
1868   // util-linux 2.12a happily shows rootfs...   // util-linux 2.12a happily shows rootfs...
1869   //if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;   //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
1870    
1871   if (!fstype || !strcmp(mtpair->mnt_type, fstype))   if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
1872   printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,   printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1873   mtpair->mnt_dir, mtpair->mnt_type,   mtpair->mnt_dir, mtpair->mnt_type,
1874   mtpair->mnt_opts);   mtpair->mnt_opts);
# Line 1815  int mount_main(int argc UNUSED_PARAM, ch Line 1884  int mount_main(int argc UNUSED_PARAM, ch
1884   // argument when we get it.   // argument when we get it.
1885   if (argv[1]) {   if (argv[1]) {
1886   if (nonroot)   if (nonroot)
1887   bb_error_msg_and_die(must_be_root);   bb_error_msg_and_die(bb_msg_you_must_be_root);
1888   mtpair->mnt_fsname = argv[0];   mtpair->mnt_fsname = argv[0];
1889   mtpair->mnt_dir = argv[1];   mtpair->mnt_dir = argv[1];
1890   mtpair->mnt_type = fstype;   mtpair->mnt_type = fstype;
1891   mtpair->mnt_opts = cmdopts;   mtpair->mnt_opts = cmdopts;
1892   if (ENABLE_FEATURE_MOUNT_LABEL) {   resolve_mount_spec(&mtpair->mnt_fsname);
1893   resolve_mount_spec(&mtpair->mnt_fsname);   rc = singlemount(mtpair, /*ignore_busy:*/ 0);
  }  
  rc = singlemount(mtpair, 0);  
1894   return rc;   return rc;
1895   }   }
1896   storage_path = bb_simplify_path(argv[0]); // malloced   storage_path = bb_simplify_path(argv[0]); // malloced
# Line 1832  int mount_main(int argc UNUSED_PARAM, ch Line 1899  int mount_main(int argc UNUSED_PARAM, ch
1899   // Past this point, we are handling either "mount -a [opts]"   // Past this point, we are handling either "mount -a [opts]"
1900   // or "mount [opts] single_param"   // or "mount [opts] single_param"
1901    
1902   i = parse_mount_options(cmdopts, 0); // FIXME: should be "long", not "int"   i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
1903   if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags   if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
1904   bb_error_msg_and_die(must_be_root);   bb_error_msg_and_die(bb_msg_you_must_be_root);
1905    
1906   // If we have a shared subtree flag, don't worry about fstab or mtab.   // If we have a shared subtree flag, don't worry about fstab or mtab.
1907   if (ENABLE_FEATURE_MOUNT_FLAGS   if (ENABLE_FEATURE_MOUNT_FLAGS
1908   && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))   && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1909   ) {   ) {
1910   rc = verbose_mount(/*source:*/ "", /*target:*/ argv[0],   // verbose_mount(source, target, type, flags, data)
1911   /*type:*/ "", /*flags:*/ i, /*data:*/ "");   rc = verbose_mount("", argv[0], "", i, "");
1912   if (rc)   if (rc)
1913   bb_simple_perror_msg_and_die(argv[0]);   bb_simple_perror_msg_and_die(argv[0]);
1914   return rc;   return rc;
# Line 1857  int mount_main(int argc UNUSED_PARAM, ch Line 1924  int mount_main(int argc UNUSED_PARAM, ch
1924   }   }
1925   fstab = setmntent(fstabname, "r");   fstab = setmntent(fstabname, "r");
1926   if (!fstab)   if (!fstab)
1927   bb_perror_msg_and_die("cannot read %s", fstabname);   bb_perror_msg_and_die("can't read %s", fstabname);
1928    
1929   // Loop through entries until we find what we're looking for   // Loop through entries until we find what we're looking for
1930   memset(mtpair, 0, sizeof(mtpair));   memset(mtpair, 0, sizeof(mtpair));
# Line 1879  int mount_main(int argc UNUSED_PARAM, ch Line 1946  int mount_main(int argc UNUSED_PARAM, ch
1946   if (argv[0]) {   if (argv[0]) {
1947    
1948   // Is this what we're looking for?   // Is this what we're looking for?
1949   if (strcmp(argv[0], mtcur->mnt_fsname) &&   if (strcmp(argv[0], mtcur->mnt_fsname) != 0
1950     strcmp(storage_path, mtcur->mnt_fsname) &&   && strcmp(storage_path, mtcur->mnt_fsname) != 0
1951     strcmp(argv[0], mtcur->mnt_dir) &&   && strcmp(argv[0], mtcur->mnt_dir) != 0
1952     strcmp(storage_path, mtcur->mnt_dir)) continue;   && strcmp(storage_path, mtcur->mnt_dir) != 0
1953     ) {
1954     continue; // no
1955     }
1956    
1957   // Remember this entry.  Something later may have   // Remember this entry.  Something later may have
1958   // overmounted it, and we want the _last_ match.   // overmounted it, and we want the _last_ match.
# Line 1890  int mount_main(int argc UNUSED_PARAM, ch Line 1960  int mount_main(int argc UNUSED_PARAM, ch
1960    
1961   // If we're mounting all   // If we're mounting all
1962   } else {   } else {
1963   // Do we need to match a filesystem type?   struct mntent *mp;
1964   if (fstype && match_fstype(mtcur, fstype))   // No, mount -a won't mount anything,
1965     // even user mounts, for mere humans
1966     if (nonroot)
1967     bb_error_msg_and_die(bb_msg_you_must_be_root);
1968    
1969     // Does type match? (NULL matches always)
1970     if (!match_fstype(mtcur, fstype))
1971   continue;   continue;
1972    
1973   // Skip noauto and swap anyway.   // Skip noauto and swap anyway
1974   if (parse_mount_options(mtcur->mnt_opts, 0) & (MOUNT_NOAUTO | MOUNT_SWAP))   if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
1975     // swap is bogus "fstype", parse_mount_options can't check fstypes
1976     || strcasecmp(mtcur->mnt_type, "swap") == 0
1977     ) {
1978   continue;   continue;
1979     }
1980    
1981   // No, mount -a won't mount anything,   // Does (at least one) option match?
1982   // even user mounts, for mere humans   // (NULL matches always)
1983   if (nonroot)   if (!match_opt(mtcur->mnt_opts, O_optmatch))
1984   bb_error_msg_and_die(must_be_root);   continue;
1985    
1986   // Mount this thing   resolve_mount_spec(&mtcur->mnt_fsname);
  if (ENABLE_FEATURE_MOUNT_LABEL)  
  resolve_mount_spec(&mtpair->mnt_fsname);  
1987    
1988   // NFS mounts want this to be xrealloc-able   // NFS mounts want this to be xrealloc-able
1989   mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);   mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
1990   if (singlemount(mtcur, 1)) {  
1991   // Count number of failed mounts   // If nothing is mounted on this directory...
1992   rc++;   // (otherwise repeated "mount -a" mounts everything again)
1993     mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
1994     // We do not check fsname match of found mount point -
1995     // "/" may have fsname of "/dev/root" while fstab
1996     // says "/dev/something_else".
1997     if (mp) {
1998     if (verbose) {
1999     bb_error_msg("according to %s, "
2000     "%s is already mounted on %s",
2001     bb_path_mtab_file,
2002     mp->mnt_fsname, mp->mnt_dir);
2003     }
2004     } else {
2005     // ...mount this thing
2006     if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
2007     // Count number of failed mounts
2008     rc++;
2009     }
2010   }   }
2011   free(mtcur->mnt_opts);   free(mtcur->mnt_opts);
2012   }   }
# Line 1919  int mount_main(int argc UNUSED_PARAM, ch Line 2014  int mount_main(int argc UNUSED_PARAM, ch
2014    
2015   // End of fstab/mtab is reached.   // End of fstab/mtab is reached.
2016   // Were we looking for something specific?   // Were we looking for something specific?
2017   if (argv[0]) {   if (argv[0]) { // yes
2018     long l;
2019    
2020   // If we didn't find anything, complain   // If we didn't find anything, complain
2021   if (!mtcur->mnt_fsname)   if (!mtcur->mnt_fsname)
2022   bb_error_msg_and_die("can't find %s in %s",   bb_error_msg_and_die("can't find %s in %s",
2023   argv[0], fstabname);   argv[0], fstabname);
2024    
2025     // What happens when we try to "mount swap_partition"?
2026     // (fstab containts "swap_partition swap swap defaults 0 0")
2027     // util-linux-ng 2.13.1 does this:
2028     // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
2029     // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
2030     // lstat("swap", 0x7fff62a3a640)           = -1 ENOENT (No such file or directory)
2031     // write(2, "mount: mount point swap does not exist\n", 39) = 39
2032     // exit_group(32)                          = ?
2033    #if 0
2034     // In case we want to simply skip swap partitions:
2035     l = parse_mount_options(mtcur->mnt_opts, NULL);
2036     if ((l & MOUNT_SWAP)
2037     // swap is bogus "fstype", parse_mount_options can't check fstypes
2038     || strcasecmp(mtcur->mnt_type, "swap") == 0
2039     ) {
2040     goto ret;
2041     }
2042    #endif
2043   if (nonroot) {   if (nonroot) {
2044   // fstab must have "users" or "user"   // fstab must have "users" or "user"
2045   if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))   l = parse_mount_options(mtcur->mnt_opts, NULL);
2046   bb_error_msg_and_die(must_be_root);   if (!(l & MOUNT_USERS))
2047   }   bb_error_msg_and_die(bb_msg_you_must_be_root);
2048     }
2049   // Mount the last thing we found  
2050   mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);   //util-linux-2.12 does not do this check.
2051   append_mount_options(&(mtcur->mnt_opts), cmdopts);   //// If nothing is mounted on this directory...
2052   if (ENABLE_FEATURE_MOUNT_LABEL) {   //// (otherwise repeated "mount FOO" mounts FOO again)
2053     //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
2054     //if (mp) {
2055     // bb_error_msg("according to %s, "
2056     // "%s is already mounted on %s",
2057     // bb_path_mtab_file,
2058     // mp->mnt_fsname, mp->mnt_dir);
2059     //} else {
2060     // ...mount the last thing we found
2061     mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
2062     append_mount_options(&(mtcur->mnt_opts), cmdopts);
2063   resolve_mount_spec(&mtpair->mnt_fsname);   resolve_mount_spec(&mtpair->mnt_fsname);
2064   }   rc = singlemount(mtcur, /*ignore_busy:*/ 0);
2065   rc = singlemount(mtcur, 0);   if (ENABLE_FEATURE_CLEAN_UP)
2066   if (ENABLE_FEATURE_CLEAN_UP)   free(mtcur->mnt_opts);
2067   free(mtcur->mnt_opts);   //}
2068   }   }
2069    
2070     //ret:
2071   if (ENABLE_FEATURE_CLEAN_UP)   if (ENABLE_FEATURE_CLEAN_UP)
2072   endmntent(fstab);   endmntent(fstab);
2073   if (ENABLE_FEATURE_CLEAN_UP) {   if (ENABLE_FEATURE_CLEAN_UP) {
2074   free(storage_path);   free(storage_path);
2075   free(cmdopts);   free(cmdopts);
2076   }   }
2077    
2078    //TODO: exitcode should be ORed mask of (from "man mount"):
2079    // 0 success
2080    // 1 incorrect invocation or permissions
2081    // 2 system error (out of memory, cannot fork, no more loop devices)
2082    // 4 internal mount bug or missing nfs support in mount
2083    // 8 user interrupt
2084    //16 problems writing or locking /etc/mtab
2085    //32 mount failure
2086    //64 some mount succeeded
2087   return rc;   return rc;
2088  }  }

Legend:
Removed from v.983  
changed lines
  Added in v.984