Magellan Linux

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

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

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 18  Line 18 
18     mount_it_now() does the actual mount.     mount_it_now() does the actual mount.
19  */  */
20    
 #include "busybox.h"  
21  #include <mntent.h>  #include <mntent.h>
   
 /* Needed for nfs support only... */  
22  #include <syslog.h>  #include <syslog.h>
23    #include "libbb.h"
24    
25    #if ENABLE_FEATURE_MOUNT_LABEL
26    #include "volume_id.h"
27    #endif
28    
29    /* Needed for nfs support only */
30  #include <sys/utsname.h>  #include <sys/utsname.h>
31  #undef TRUE  #undef TRUE
32  #undef FALSE  #undef FALSE
# Line 30  Line 34 
34  #include <rpc/pmap_prot.h>  #include <rpc/pmap_prot.h>
35  #include <rpc/pmap_clnt.h>  #include <rpc/pmap_clnt.h>
36    
37    #ifndef MS_SILENT
38    #define MS_SILENT (1 << 15)
39    #endif
40    /* Grab more as needed from util-linux's mount/mount_constants.h */
41    #ifndef MS_DIRSYNC
42    #define MS_DIRSYNC      128     /* Directory modifications are synchronous */
43    #endif
44    
45    
46  #if defined(__dietlibc__)  #if defined(__dietlibc__)
47  /* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)  /* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
48   * dietlibc-0.30 does not have implementation of getmntent_r() */   * dietlibc-0.30 does not have implementation of getmntent_r() */
49  /* OTOH: why we use getmntent_r instead of getmntent? TODO... */  static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
50  struct mntent *getmntent_r(FILE* stream, struct mntent* result, char* buffer, int bufsize)   char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
51  {  {
  /* *** XXX FIXME WARNING: This hack is NOT thread safe. --Sampo */  
52   struct mntent* ment = getmntent(stream);   struct mntent* ment = getmntent(stream);
53   memcpy(result, ment, sizeof(struct mntent));   return memcpy(result, ment, sizeof(*ment));
  return result;  
54  }  }
55  #endif  #endif
56    
57    
58  // Not real flags, but we want to be able to check for this.  // Not real flags, but we want to be able to check for this.
59  enum {  enum {
60   MOUNT_USERS  = (1<<28)*ENABLE_DESKTOP,   MOUNT_USERS  = (1 << 28) * ENABLE_DESKTOP,
61   MOUNT_NOAUTO = (1<<29),   MOUNT_NOAUTO = (1 << 29),
62   MOUNT_SWAP   = (1<<30),   MOUNT_SWAP   = (1 << 30),
63  };  };
64    
65    
66    #define OPTION_STR "o:t:rwanfvsi"
67    enum {
68     OPT_o = (1 << 0),
69     OPT_t = (1 << 1),
70     OPT_r = (1 << 2),
71     OPT_w = (1 << 3),
72     OPT_a = (1 << 4),
73     OPT_n = (1 << 5),
74     OPT_f = (1 << 6),
75     OPT_v = (1 << 7),
76     OPT_s = (1 << 8),
77     OPT_i = (1 << 9),
78    };
79    
80    #if ENABLE_FEATURE_MTAB_SUPPORT
81    #define useMtab (!(option_mask32 & OPT_n))
82    #else
83    #define useMtab 0
84    #endif
85    
86    #if ENABLE_FEATURE_MOUNT_FAKE
87    #define fakeIt (option_mask32 & OPT_f)
88    #else
89    #define fakeIt 0
90    #endif
91    
92    
93  // TODO: more "user" flag compatibility.  // TODO: more "user" flag compatibility.
94  // "user" option (from mount manpage):  // "user" option (from mount manpage):
95  // Only the user that mounted a filesystem can unmount it again.  // Only the user that mounted a filesystem can unmount it again.
# Line 63  enum { Line 102  enum {
102  /* Standard mount options (from -o options or --options), with corresponding  /* Standard mount options (from -o options or --options), with corresponding
103   * flags */   * flags */
104    
105  struct {  static const int32_t mount_options[] = {
  char *name;  
  long flags;  
 } static mount_options[] = {  
106   // 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.
107    
108   USE_FEATURE_MOUNT_LOOP(   USE_FEATURE_MOUNT_LOOP(
109   {"loop", 0},   /* "loop" */ 0,
110   )   )
111    
112   USE_FEATURE_MOUNT_FSTAB(   USE_FEATURE_MOUNT_FSTAB(
113   {"defaults", 0},   /* "defaults" */ 0,
114   /* {"quiet", 0}, - do not filter out, vfat wants to see it */   /* "quiet" 0 - do not filter out, vfat wants to see it */
115   {"noauto", MOUNT_NOAUTO},   /* "noauto" */ MOUNT_NOAUTO,
116   {"swap", MOUNT_SWAP},   /* "sw"     */ MOUNT_SWAP,
117   USE_DESKTOP({"user",  MOUNT_USERS},)   /* "swap"   */ MOUNT_SWAP,
118   USE_DESKTOP({"users", MOUNT_USERS},)   USE_DESKTOP(/* "user"  */ MOUNT_USERS,)
119     USE_DESKTOP(/* "users" */ MOUNT_USERS,)
120     /* "_netdev" */ 0,
121   )   )
122    
123   USE_FEATURE_MOUNT_FLAGS(   USE_FEATURE_MOUNT_FLAGS(
124   // vfs flags   // vfs flags
125   {"nosuid", MS_NOSUID},   /* "nosuid"      */ MS_NOSUID,
126   {"suid", ~MS_NOSUID},   /* "suid"        */ ~MS_NOSUID,
127   {"dev", ~MS_NODEV},   /* "dev"         */ ~MS_NODEV,
128   {"nodev", MS_NODEV},   /* "nodev"       */ MS_NODEV,
129   {"exec", ~MS_NOEXEC},   /* "exec"        */ ~MS_NOEXEC,
130   {"noexec", MS_NOEXEC},   /* "noexec"      */ MS_NOEXEC,
131   {"sync", MS_SYNCHRONOUS},   /* "sync"        */ MS_SYNCHRONOUS,
132   {"async", ~MS_SYNCHRONOUS},   /* "dirsync"     */ MS_DIRSYNC,
133   {"atime", ~MS_NOATIME},   /* "async"       */ ~MS_SYNCHRONOUS,
134   {"noatime", MS_NOATIME},   /* "atime"       */ ~MS_NOATIME,
135   {"diratime", ~MS_NODIRATIME},   /* "noatime"     */ MS_NOATIME,
136   {"nodiratime", MS_NODIRATIME},   /* "diratime"    */ ~MS_NODIRATIME,
137   {"loud", ~MS_SILENT},   /* "nodiratime"  */ MS_NODIRATIME,
138     /* "mand"        */ MS_MANDLOCK,
139     /* "nomand"      */ ~MS_MANDLOCK,
140     /* "relatime"    */ MS_RELATIME,
141     /* "norelatime"  */ ~MS_RELATIME,
142     /* "loud"        */ ~MS_SILENT,
143    
144   // action flags   // action flags
145     /* "bind"        */ MS_BIND,
146     /* "move"        */ MS_MOVE,
147     /* "shared"      */ MS_SHARED,
148     /* "slave"       */ MS_SLAVE,
149     /* "private"     */ MS_PRIVATE,
150     /* "unbindable"  */ MS_UNBINDABLE,
151     /* "rshared"     */ MS_SHARED|MS_RECURSIVE,
152     /* "rslave"      */ MS_SLAVE|MS_RECURSIVE,
153     /* "rprivate"    */ MS_SLAVE|MS_RECURSIVE,
154     /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
155     )
156    
157     // Always understood.
158     /* "ro"      */ MS_RDONLY,  // vfs flag
159     /* "rw"      */ ~MS_RDONLY, // vfs flag
160     /* "remount" */ MS_REMOUNT  // action flag
161    };
162    
163    static const char mount_option_str[] =
164     USE_FEATURE_MOUNT_LOOP(
165     "loop" "\0"
166     )
167     USE_FEATURE_MOUNT_FSTAB(
168     "defaults" "\0"
169     /* "quiet" "\0" - do not filter out, vfat wants to see it */
170     "noauto" "\0"
171     "sw" "\0"
172     "swap" "\0"
173     USE_DESKTOP("user" "\0")
174     USE_DESKTOP("users" "\0")
175     "_netdev" "\0"
176     )
177     USE_FEATURE_MOUNT_FLAGS(
178     // vfs flags
179     "nosuid" "\0"
180     "suid" "\0"
181     "dev" "\0"
182     "nodev" "\0"
183     "exec" "\0"
184     "noexec" "\0"
185     "sync" "\0"
186     "dirsync" "\0"
187     "async" "\0"
188     "atime" "\0"
189     "noatime" "\0"
190     "diratime" "\0"
191     "nodiratime" "\0"
192     "mand" "\0"
193     "nomand" "\0"
194     "relatime" "\0"
195     "norelatime" "\0"
196     "loud" "\0"
197    
198   {"bind", MS_BIND},   // action flags
199   {"move", MS_MOVE},   "bind" "\0"
200   {"shared", MS_SHARED},   "move" "\0"
201   {"slave", MS_SLAVE},   "shared" "\0"
202   {"private", MS_PRIVATE},   "slave" "\0"
203   {"unbindable", MS_UNBINDABLE},   "private" "\0"
204   {"rshared", MS_SHARED|MS_RECURSIVE},   "unbindable" "\0"
205   {"rslave", MS_SLAVE|MS_RECURSIVE},   "rshared" "\0"
206   {"rprivate", MS_SLAVE|MS_RECURSIVE},   "rslave" "\0"
207   {"runbindable", MS_UNBINDABLE|MS_RECURSIVE},   "rprivate" "\0"
208     "runbindable" "\0"
209   )   )
210    
211   // Always understood.   // Always understood.
212     "ro" "\0"        // vfs flag
213     "rw" "\0"        // vfs flag
214     "remount" "\0"   // action flag
215    ;
216    
217    
218    struct globals {
219    #if ENABLE_FEATURE_MOUNT_NFS
220     smalluint nfs_mount_version;
221    #endif
222    #if ENABLE_FEATURE_MOUNT_VERBOSE
223     unsigned verbose;
224    #endif
225     llist_t *fslist;
226     char getmntent_buf[1];
227    
  {"ro", MS_RDONLY},        // vfs flag  
  {"rw", ~MS_RDONLY},       // vfs flag  
  {"remount", MS_REMOUNT},  // action flag  
228  };  };
229    enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
230    #define G (*(struct globals*)&bb_common_bufsiz1)
231    #define nfs_mount_version (G.nfs_mount_version)
232    #if ENABLE_FEATURE_MOUNT_VERBOSE
233    #define verbose           (G.verbose          )
234    #else
235    #define verbose           0
236    #endif
237    #define fslist            (G.fslist           )
238    #define getmntent_buf     (G.getmntent_buf    )
239    
240  #define VECTOR_SIZE(v) (sizeof(v) / sizeof((v)[0]))  
241    #if ENABLE_FEATURE_MOUNT_VERBOSE
242    static int verbose_mount(const char *source, const char *target,
243     const char *filesystemtype,
244     unsigned long mountflags, const void *data)
245    {
246     int rc;
247    
248     errno = 0;
249     rc = mount(source, target, filesystemtype, mountflags, data);
250     if (verbose >= 2)
251     bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
252     source, target, filesystemtype,
253     mountflags, (char*)data, rc);
254     return rc;
255    }
256    #else
257    #define verbose_mount(...) mount(__VA_ARGS__)
258    #endif
259    
260    static int resolve_mount_spec(char **fsname)
261    {
262     char *tmp = NULL;
263    
264    #if ENABLE_FEATURE_MOUNT_LABEL
265     if (!strncmp(*fsname, "UUID=", 5))
266     tmp = get_devname_from_uuid(*fsname + 5);
267     else if (!strncmp(*fsname, "LABEL=", 6))
268     tmp = get_devname_from_label(*fsname + 6);
269    #endif
270    
271     if (tmp) {
272     *fsname = tmp;
273     return 1;
274     }
275     return 0;
276    }
277    
278  /* Append mount options to string */  /* Append mount options to string */
279  static void append_mount_options(char **oldopts, char *newopts)  static void append_mount_options(char **oldopts, const char *newopts)
280  {  {
281   if (*oldopts && **oldopts) {   if (*oldopts && **oldopts) {
282   /* do not insert options which are already there */   /* do not insert options which are already there */
# Line 134  static void append_mount_options(char ** Line 288  static void append_mount_options(char **
288   p = *oldopts;   p = *oldopts;
289   while (1) {   while (1) {
290   if (!strncmp(p, newopts, len)   if (!strncmp(p, newopts, len)
291   && (p[len]==',' || p[len]==0))   && (p[len] == ',' || p[len] == '\0'))
292   goto skip;   goto skip;
293   p = strchr(p,',');   p = strchr(p,',');
294   if(!p) break;   if (!p) break;
295   p++;   p++;
296   }   }
297   p = xasprintf("%s,%.*s", *oldopts, len, newopts);   p = xasprintf("%s,%.*s", *oldopts, len, newopts);
298   free(*oldopts);   free(*oldopts);
299   *oldopts = p;   *oldopts = p;
300  skip:   skip:
301   newopts += len;   newopts += len;
302   while (newopts[0] == ',') newopts++;   while (newopts[0] == ',') newopts++;
303   }   }
# Line 155  skip: Line 309  skip:
309    
310  /* Use the mount_options list to parse options into flags.  /* Use the mount_options list to parse options into flags.
311   * Also return list of unrecognized options if unrecognized!=NULL */   * Also return list of unrecognized options if unrecognized!=NULL */
312  static int parse_mount_options(char *options, char **unrecognized)  static long parse_mount_options(char *options, char **unrecognized)
313  {  {
314   int flags = MS_SILENT;   long flags = MS_SILENT;
315    
316   // Loop through options   // Loop through options
317   for (;;) {   for (;;) {
318   int i;   unsigned i;
319   char *comma = strchr(options, ',');   char *comma = strchr(options, ',');
320     const char *option_str = mount_option_str;
321    
322   if (comma) *comma = 0;   if (comma) *comma = '\0';
323    
324    /* FIXME: use hasmntopt() */
325   // Find this option in mount_options   // Find this option in mount_options
326   for (i = 0; i < VECTOR_SIZE(mount_options); i++) {   for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
327   if (!strcasecmp(mount_options[i].name, options)) {   if (!strcasecmp(option_str, options)) {
328   long fl = mount_options[i].flags;   long fl = mount_options[i];
329   if (fl < 0) flags &= fl;   if (fl < 0) flags &= fl;
330   else flags |= fl;   else flags |= fl;
331   break;   break;
332   }   }
333     option_str += strlen(option_str) + 1;
334   }   }
335   // If unrecognized not NULL, append unrecognized mount options */   // If unrecognized not NULL, append unrecognized mount options */
336   if (unrecognized && i == VECTOR_SIZE(mount_options)) {   if (unrecognized && i == ARRAY_SIZE(mount_options)) {
337   // Add it to strflags, to pass on to kernel   // Add it to strflags, to pass on to kernel
338   i = *unrecognized ? strlen(*unrecognized) : 0;   i = *unrecognized ? strlen(*unrecognized) : 0;
339   *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);   *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
340    
341   // Comma separated if it's not the first one   // Comma separated if it's not the first one
342   if (i) (*unrecognized)[i++] = ',';   if (i) (*unrecognized)[i++] = ',';
343   strcpy((*unrecognized)+i, options);   strcpy((*unrecognized)+i, options);
344   }   }
345    
346   // Advance to next option, or finish   if (!comma)
347   if (comma) {   break;
348   *comma = ',';   // Advance to next option
349   options = ++comma;   *comma = ',';
350   } else break;   options = ++comma;
351   }   }
352    
353   return flags;   return flags;
# Line 200  static int parse_mount_options(char *opt Line 357  static int parse_mount_options(char *opt
357    
358  static llist_t *get_block_backed_filesystems(void)  static llist_t *get_block_backed_filesystems(void)
359  {  {
360   static const char *const filesystems[] = {   static const char filesystems[2][sizeof("/proc/filesystems")] = {
361   "/etc/filesystems",   "/etc/filesystems",
362   "/proc/filesystems",   "/proc/filesystems",
  0  
363   };   };
364   char *fs, *buf;   char *fs, *buf;
365   llist_t *list = 0;   llist_t *list = 0;
366   int i;   int i;
367   FILE *f;   FILE *f;
368    
369   for (i = 0; filesystems[i]; i++) {   for (i = 0; i < 2; i++) {
370   f = fopen(filesystems[i], "r");   f = fopen_for_read(filesystems[i]);
371   if (!f) continue;   if (!f) continue;
372    
373   while ((buf = xmalloc_getline(f)) != 0) {   while ((buf = xmalloc_fgetline(f)) != NULL) {
374   if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))   if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
375   continue;   continue;
376   fs = skip_whitespace(buf);   fs = skip_whitespace(buf);
# Line 229  static llist_t *get_block_backed_filesys Line 385  static llist_t *get_block_backed_filesys
385   return list;   return list;
386  }  }
387    
 llist_t *fslist = 0;  
   
388  #if ENABLE_FEATURE_CLEAN_UP  #if ENABLE_FEATURE_CLEAN_UP
389  static void delete_block_backed_filesystems(void)  static void delete_block_backed_filesystems(void)
390  {  {
# Line 240  static void delete_block_backed_filesyst Line 394  static void delete_block_backed_filesyst
394  void delete_block_backed_filesystems(void);  void delete_block_backed_filesystems(void);
395  #endif  #endif
396    
 #if ENABLE_FEATURE_MTAB_SUPPORT  
 static int useMtab = 1;  
 static int fakeIt;  
 #else  
 #define useMtab 0  
 #define fakeIt 0  
 #endif  
   
397  // Perform actual mount of specific filesystem at specific location.  // Perform actual mount of specific filesystem at specific location.
398  // NB: mp->xxx fields may be trashed on exit  // NB: mp->xxx fields may be trashed on exit
399  static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)  static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
400  {  {
401   int rc = 0;   int rc = 0;
402    
403   if (fakeIt) goto mtab;   if (fakeIt) {
404     if (verbose >= 2)
405     bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
406     mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
407     vfsflags, filteropts);
408     goto mtab;
409     }
410    
411   // Mount, with fallback to read-only if necessary.   // Mount, with fallback to read-only if necessary.
   
412   for (;;) {   for (;;) {
413   rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,   errno = 0;
414     rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
415   vfsflags, filteropts);   vfsflags, filteropts);
416   if (!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))  
417     // If mount failed, try
418     // helper program mount.<mnt_type>
419     if (ENABLE_FEATURE_MOUNT_HELPERS && rc) {
420     char *args[6];
421     int errno_save = errno;
422     args[0] = xasprintf("mount.%s", mp->mnt_type);
423     rc = 1;
424     if (filteropts) {
425     args[rc++] = (char *)"-o";
426     args[rc++] = filteropts;
427     }
428     args[rc++] = mp->mnt_fsname;
429     args[rc++] = mp->mnt_dir;
430     args[rc] = NULL;
431     rc = wait4pid(spawn(args));
432     free(args[0]);
433     if (!rc)
434     break;
435     errno = errno_save;
436     }
437    
438     if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
439   break;   break;
440   bb_error_msg("%s is write-protected, mounting read-only",   if (!(vfsflags & MS_SILENT))
441   mp->mnt_fsname);   bb_error_msg("%s is write-protected, mounting read-only",
442     mp->mnt_fsname);
443   vfsflags |= MS_RDONLY;   vfsflags |= MS_RDONLY;
444   }   }
445    
# Line 276  static int mount_it_now(struct mntent *m Line 451  static int mount_it_now(struct mntent *m
451   /* If the mount was successful, and we're maintaining an old-style   /* If the mount was successful, and we're maintaining an old-style
452   * mtab file by hand, add the new entry to it now. */   * mtab file by hand, add the new entry to it now. */
453   mtab:   mtab:
454   if (ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc && !(vfsflags & MS_REMOUNT)) {   if (useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
455   char *fsname;   char *fsname;
456   FILE *mountTable = setmntent(bb_path_mtab_file, "a+");   FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
457     const char *option_str = mount_option_str;
458   int i;   int i;
459    
460   if (!mountTable) {   if (!mountTable) {
461   bb_error_msg("no %s",bb_path_mtab_file);   bb_error_msg("no %s", bb_path_mtab_file);
462   goto ret;   goto ret;
463   }   }
464    
465   // Add vfs string flags   // Add vfs string flags
466    
467   for (i=0; mount_options[i].flags != MS_REMOUNT; i++)   for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
468   if (mount_options[i].flags > 0 && (mount_options[i].flags & vfsflags))   if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
469   append_mount_options(&(mp->mnt_opts), mount_options[i].name);   append_mount_options(&(mp->mnt_opts), option_str);
470     option_str += strlen(option_str) + 1;
471     }
472    
473   // Remove trailing / (if any) from directory we mounted on   // Remove trailing / (if any) from directory we mounted on
474    
475   i = strlen(mp->mnt_dir) - 1;   i = strlen(mp->mnt_dir) - 1;
476   if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = 0;   if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
477    
478   // Convert to canonical pathnames as needed   // Convert to canonical pathnames as needed
479    
# Line 303  static int mount_it_now(struct mntent *m Line 481  static int mount_it_now(struct mntent *m
481   fsname = 0;   fsname = 0;
482   if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */   if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */
483   mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);   mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
484   mp->mnt_type = "bind";   mp->mnt_type = (char*)"bind";
485   }   }
486   mp->mnt_freq = mp->mnt_passno = 0;   mp->mnt_freq = mp->mnt_passno = 0;
487    
# Line 337  static int mount_it_now(struct mntent *m Line 515  static int mount_it_now(struct mntent *m
515   * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>   * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
516   * Implemented the "bg", "fg" and "retry" mount options for NFS.   * Implemented the "bg", "fg" and "retry" mount options for NFS.
517   *   *
518   * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>   * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
519   * - added Native Language Support   * - added Native Language Support
520   *   *
521   * Modified by Olaf Kirch and Trond Myklebust for new NFS code,   * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
# Line 527  enum { Line 705  enum {
705   NFS_MOUNT_TCP = 0x0040, /* 2 */   NFS_MOUNT_TCP = 0x0040, /* 2 */
706   NFS_MOUNT_VER3 = 0x0080, /* 3 */   NFS_MOUNT_VER3 = 0x0080, /* 3 */
707   NFS_MOUNT_KERBEROS = 0x0100, /* 3 */   NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
708   NFS_MOUNT_NONLM = 0x0200 /* 3 */   NFS_MOUNT_NONLM = 0x0200, /* 3 */
709     NFS_MOUNT_NORDIRPLUS = 0x4000
710  };  };
711    
712    
# Line 547  enum { Line 726  enum {
726  // Convert each NFSERR_BLAH into EBLAH  // Convert each NFSERR_BLAH into EBLAH
727    
728  static const struct {  static const struct {
729   int stat;   short stat;
730   int errnum;   short errnum;
731  } nfs_errtbl[] = {  } nfs_errtbl[] = {
732   {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},   {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
733   {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},   {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
# Line 559  static const struct { Line 738  static const struct {
738  static char *nfs_strerror(int status)  static char *nfs_strerror(int status)
739  {  {
740   int i;   int i;
  static char buf[sizeof("unknown nfs status return value: ") + sizeof(int)*3];  
741    
742   for (i = 0; nfs_errtbl[i].stat != -1; i++) {   for (i = 0; nfs_errtbl[i].stat != -1; i++) {
743   if (nfs_errtbl[i].stat == status)   if (nfs_errtbl[i].stat == status)
744   return strerror(nfs_errtbl[i].errnum);   return strerror(nfs_errtbl[i].errnum);
745   }   }
746   sprintf(buf, "unknown nfs status return value: %d", status);   return xasprintf("unknown nfs status return value: %d", status);
  return buf;  
747  }  }
748    
749  static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)  static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
# Line 640  static bool_t xdr_mountres3(XDR *xdrs, m Line 817  static bool_t xdr_mountres3(XDR *xdrs, m
817  #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)  #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
818    
819  /*  /*
  * nfs_mount_version according to the sources seen at compile time.  
  */  
 static int nfs_mount_version;  
 static int kernel_version;  
   
 /*  
820   * Unfortunately, the kernel prints annoying console messages   * Unfortunately, the kernel prints annoying console messages
821   * in case of an unexpected nfs mount version (instead of   * in case of an unexpected nfs mount version (instead of
822   * just returning some error).  Therefore we'll have to try   * just returning some error).  Therefore we'll have to try
# Line 659  static int kernel_version; Line 830  static int kernel_version;
830  static void  static void
831  find_kernel_nfs_mount_version(void)  find_kernel_nfs_mount_version(void)
832  {  {
833   if (kernel_version)   int kernel_version;
834    
835     if (nfs_mount_version)
836   return;   return;
837    
838   nfs_mount_version = 4; /* default */   nfs_mount_version = 4; /* default */
# Line 676  find_kernel_nfs_mount_version(void) Line 849  find_kernel_nfs_mount_version(void)
849   }   }
850  }  }
851    
852  static struct pmap *  static void
853  get_mountport(struct sockaddr_in *server_addr,  get_mountport(struct pmap *pm_mnt,
854     struct sockaddr_in *server_addr,
855   long unsigned prog,   long unsigned prog,
856   long unsigned version,   long unsigned version,
857   long unsigned proto,   long unsigned proto,
858   long unsigned port)   long unsigned port)
859  {  {
860   struct pmaplist *pmap;   struct pmaplist *pmap;
  static struct pmap p = {0, 0, 0, 0};  
861    
862   server_addr->sin_port = PMAPPORT;   server_addr->sin_port = PMAPPORT;
863    /* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
864     * I understand it like "IPv6 for this is not 100% ready" */
865   pmap = pmap_getmaps(server_addr);   pmap = pmap_getmaps(server_addr);
866    
867   if (version > MAX_NFSPROT)   if (version > MAX_NFSPROT)
868   version = MAX_NFSPROT;   version = MAX_NFSPROT;
869   if (!prog)   if (!prog)
870   prog = MOUNTPROG;   prog = MOUNTPROG;
871   p.pm_prog = prog;   pm_mnt->pm_prog = prog;
872   p.pm_vers = version;   pm_mnt->pm_vers = version;
873   p.pm_prot = proto;   pm_mnt->pm_prot = proto;
874   p.pm_port = port;   pm_mnt->pm_port = port;
875    
876   while (pmap) {   while (pmap) {
877   if (pmap->pml_map.pm_prog != prog)   if (pmap->pml_map.pm_prog != prog)
878   goto next;   goto next;
879   if (!version && p.pm_vers > pmap->pml_map.pm_vers)   if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
880   goto next;   goto next;
881   if (version > 2 && pmap->pml_map.pm_vers != version)   if (version > 2 && pmap->pml_map.pm_vers != version)
882   goto next;   goto next;
883   if (version && version <= 2 && pmap->pml_map.pm_vers > 2)   if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
884   goto next;   goto next;
885   if (pmap->pml_map.pm_vers > MAX_NFSPROT ||   if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
886      (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||      (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
887      (port && pmap->pml_map.pm_port != port))      (port && pmap->pml_map.pm_port != port))
888   goto next;   goto next;
889   memcpy(&p, &pmap->pml_map, sizeof(p));   memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
890  next:   next:
891   pmap = pmap->pml_next;   pmap = pmap->pml_next;
892   }   }
893   if (!p.pm_vers)   if (!pm_mnt->pm_vers)
894   p.pm_vers = MOUNTVERS;   pm_mnt->pm_vers = MOUNTVERS;
895   if (!p.pm_port)   if (!pm_mnt->pm_port)
896   p.pm_port = MOUNTPORT;   pm_mnt->pm_port = MOUNTPORT;
897   if (!p.pm_prot)   if (!pm_mnt->pm_prot)
898   p.pm_prot = IPPROTO_TCP;   pm_mnt->pm_prot = IPPROTO_TCP;
  return &p;  
899  }  }
900    
901    #if BB_MMU
902  static int daemonize(void)  static int daemonize(void)
903  {  {
  int fd;  
904   int pid = fork();   int pid = fork();
905   if (pid < 0) /* error */   if (pid < 0) /* error */
906   return -errno;   return -errno;
907   if (pid > 0) /* parent */   if (pid > 0) /* parent */
908   return 0;   return 0;
909   /* child */   /* child */
910   fd = xopen(bb_dev_null, O_RDWR);   close(0);
911   dup2(fd, 0);   xopen(bb_dev_null, O_RDWR);
912   dup2(fd, 1);   xdup2(0, 1);
913   dup2(fd, 2);   xdup2(0, 2);
  while (fd > 2) close(fd--);  
914   setsid();   setsid();
915   openlog(applet_name, LOG_PID, LOG_DAEMON);   openlog(applet_name, LOG_PID, LOG_DAEMON);
916   logmode = LOGMODE_SYSLOG;   logmode = LOGMODE_SYSLOG;
917   return 1;   return 1;
918  }  }
919    #else
920    static inline int daemonize(void) { return -ENOSYS; }
921    #endif
922    
923  // TODO  // TODO
924  static inline int we_saw_this_host_before(const char *hostname)  static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
925  {  {
926   return 0;   return 0;
927  }  }
# Line 764  static void error_msg_rpc(const char *ms Line 940  static void error_msg_rpc(const char *ms
940  }  }
941    
942  // NB: mp->xxx fields may be trashed on exit  // NB: mp->xxx fields may be trashed on exit
943  static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)  static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
944  {  {
945   CLIENT *mclient;   CLIENT *mclient;
946   char *hostname;   char *hostname;
# Line 785  static int nfsmount(struct mntent *mp, i Line 961  static int nfsmount(struct mntent *mp, i
961   int port;   int port;
962   int mountport;   int mountport;
963   int proto;   int proto;
964   int bg;  #if BB_MMU
965   int soft;   smallint bg = 0;
966   int intr;  #else
967   int posix;   enum { bg = 0 };
968   int nocto;  #endif
  int noac;  
  int nolock;  
969   int retry;   int retry;
  int tcp;  
970   int mountprog;   int mountprog;
971   int mountvers;   int mountvers;
972   int nfsprog;   int nfsprog;
973   int nfsvers;   int nfsvers;
974   int retval;   int retval;
975     /* these all are one-bit really. 4.3.1 likes this combination: */
976     smallint tcp;
977     smallint soft;
978     int intr;
979     int posix;
980     int nocto;
981     int noac;
982     int nordirplus;
983     int nolock;
984    
985   find_kernel_nfs_mount_version();   find_kernel_nfs_mount_version();
986    
# Line 832  static int nfsmount(struct mntent *mp, i Line 1014  static int nfsmount(struct mntent *mp, i
1014   bb_herror_msg("%s", hostname);   bb_herror_msg("%s", hostname);
1015   goto fail;   goto fail;
1016   }   }
1017   if (hp->h_length > sizeof(struct in_addr)) {   if ((size_t)hp->h_length > sizeof(struct in_addr)) {
1018   bb_error_msg("got bad hp->h_length");   bb_error_msg("got bad hp->h_length");
1019   hp->h_length = sizeof(struct in_addr);   hp->h_length = sizeof(struct in_addr);
1020   }   }
# Line 859  static int nfsmount(struct mntent *mp, i Line 1041  static int nfsmount(struct mntent *mp, i
1041   * let the kernel decide.   * let the kernel decide.
1042   * timeo is filled in after we know whether it'll be TCP or UDP. */   * timeo is filled in after we know whether it'll be TCP or UDP. */
1043   memset(&data, 0, sizeof(data));   memset(&data, 0, sizeof(data));
1044   data.retrans = 3;   data.retrans  = 3;
1045   data.acregmin = 3;   data.acregmin = 3;
1046   data.acregmax = 60;   data.acregmax = 60;
1047   data.acdirmin = 30;   data.acdirmin = 30;
1048   data.acdirmax = 60;   data.acdirmax = 60;
1049   data.namlen = NAME_MAX;   data.namlen   = NAME_MAX;
1050    
  bg = 0;  
1051   soft = 0;   soft = 0;
1052   intr = 0;   intr = 0;
1053   posix = 0;   posix = 0;
1054   nocto = 0;   nocto = 0;
1055   nolock = 0;   nolock = 0;
1056   noac = 0;   noac = 0;
1057     nordirplus = 0;
1058   retry = 10000; /* 10000 minutes ~ 1 week */   retry = 10000; /* 10000 minutes ~ 1 week */
1059   tcp = 0;   tcp = 0;
1060    
# Line 884  static int nfsmount(struct mntent *mp, i Line 1066  static int nfsmount(struct mntent *mp, i
1066   nfsvers = 0;   nfsvers = 0;
1067    
1068   /* parse options */   /* parse options */
1069     if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
  for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {  
1070   char *opteq = strchr(opt, '=');   char *opteq = strchr(opt, '=');
1071   if (opteq) {   if (opteq) {
1072   const char *const options[] = {   int val, idx;
1073   /* 0 */ "rsize",   static const char options[] ALIGN1 =
1074   /* 1 */ "wsize",   /* 0 */ "rsize\0"
1075   /* 2 */ "timeo",   /* 1 */ "wsize\0"
1076   /* 3 */ "retrans",   /* 2 */ "timeo\0"
1077   /* 4 */ "acregmin",   /* 3 */ "retrans\0"
1078   /* 5 */ "acregmax",   /* 4 */ "acregmin\0"
1079   /* 6 */ "acdirmin",   /* 5 */ "acregmax\0"
1080   /* 7 */ "acdirmax",   /* 6 */ "acdirmin\0"
1081   /* 8 */ "actimeo",   /* 7 */ "acdirmax\0"
1082   /* 9 */ "retry",   /* 8 */ "actimeo\0"
1083   /* 10 */ "port",   /* 9 */ "retry\0"
1084   /* 11 */ "mountport",   /* 10 */ "port\0"
1085   /* 12 */ "mounthost",   /* 11 */ "mountport\0"
1086   /* 13 */ "mountprog",   /* 12 */ "mounthost\0"
1087   /* 14 */ "mountvers",   /* 13 */ "mountprog\0"
1088   /* 15 */ "nfsprog",   /* 14 */ "mountvers\0"
1089   /* 16 */ "nfsvers",   /* 15 */ "nfsprog\0"
1090   /* 17 */ "vers",   /* 16 */ "nfsvers\0"
1091   /* 18 */ "proto",   /* 17 */ "vers\0"
1092   /* 19 */ "namlen",   /* 18 */ "proto\0"
1093   /* 20 */ "addr",   /* 19 */ "namlen\0"
1094   NULL   /* 20 */ "addr\0";
1095   };  
1096   int val = xatoi_u(opteq + 1);   *opteq++ = '\0';
1097   *opteq = '\0';   idx = index_in_strings(options, opt);
1098   switch (index_in_str_array(options, opt)) {   switch (idx) {
1099     case 12: // "mounthost"
1100     mounthost = xstrndup(opteq,
1101     strcspn(opteq, " \t\n\r,"));
1102     continue;
1103     case 18: // "proto"
1104     if (!strncmp(opteq, "tcp", 3))
1105     tcp = 1;
1106     else if (!strncmp(opteq, "udp", 3))
1107     tcp = 0;
1108     else
1109     bb_error_msg("warning: unrecognized proto= option");
1110     continue;
1111     case 20: // "addr" - ignore
1112     continue;
1113     }
1114    
1115     val = xatoi_u(opteq);
1116     switch (idx) {
1117   case 0: // "rsize"   case 0: // "rsize"
1118   data.rsize = val;   data.rsize = val;
1119   break;   continue;
1120   case 1: // "wsize"   case 1: // "wsize"
1121   data.wsize = val;   data.wsize = val;
1122   break;   continue;
1123   case 2: // "timeo"   case 2: // "timeo"
1124   data.timeo = val;   data.timeo = val;
1125   break;   continue;
1126   case 3: // "retrans"   case 3: // "retrans"
1127   data.retrans = val;   data.retrans = val;
1128   break;   continue;
1129   case 4: // "acregmin"   case 4: // "acregmin"
1130   data.acregmin = val;   data.acregmin = val;
1131   break;   continue;
1132   case 5: // "acregmax"   case 5: // "acregmax"
1133   data.acregmax = val;   data.acregmax = val;
1134   break;   continue;
1135   case 6: // "acdirmin"   case 6: // "acdirmin"
1136   data.acdirmin = val;   data.acdirmin = val;
1137   break;   continue;
1138   case 7: // "acdirmax"   case 7: // "acdirmax"
1139   data.acdirmax = val;   data.acdirmax = val;
1140   break;   continue;
1141   case 8: // "actimeo"   case 8: // "actimeo"
1142   data.acregmin = val;   data.acregmin = val;
1143   data.acregmax = val;   data.acregmax = val;
1144   data.acdirmin = val;   data.acdirmin = val;
1145   data.acdirmax = val;   data.acdirmax = val;
1146   break;   continue;
1147   case 9: // "retry"   case 9: // "retry"
1148   retry = val;   retry = val;
1149   break;   continue;
1150   case 10: // "port"   case 10: // "port"
1151   port = val;   port = val;
1152   break;   continue;
1153   case 11: // "mountport"   case 11: // "mountport"
1154   mountport = val;   mountport = val;
1155   break;   continue;
  case 12: // "mounthost"  
  mounthost = xstrndup(opteq+1,  
  strcspn(opteq+1," \t\n\r,"));  
  break;  
1156   case 13: // "mountprog"   case 13: // "mountprog"
1157   mountprog = val;   mountprog = val;
1158   break;   continue;
1159   case 14: // "mountvers"   case 14: // "mountvers"
1160   mountvers = val;   mountvers = val;
1161   break;   continue;
1162   case 15: // "nfsprog"   case 15: // "nfsprog"
1163   nfsprog = val;   nfsprog = val;
1164   break;   continue;
1165   case 16: // "nfsvers"   case 16: // "nfsvers"
1166   case 17: // "vers"   case 17: // "vers"
1167   nfsvers = val;   nfsvers = val;
1168   break;   continue;
  case 18: // "proto"  
  if (!strncmp(opteq+1, "tcp", 3))  
  tcp = 1;  
  else if (!strncmp(opteq+1, "udp", 3))  
  tcp = 0;  
  else  
  bb_error_msg("warning: unrecognized proto= option");  
  break;  
1169   case 19: // "namlen"   case 19: // "namlen"
1170   if (nfs_mount_version >= 2)   //if (nfs_mount_version >= 2)
1171   data.namlen = val;   data.namlen = val;
1172   else   //else
1173   bb_error_msg("warning: option namlen is not supported\n");   // bb_error_msg("warning: option namlen is not supported\n");
1174   break;   continue;
  case 20: // "addr" - ignore  
  break;  
1175   default:   default:
1176   bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);   bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
1177   goto fail;   goto fail;
1178   }   }
1179   }   }
1180   else {   else { /* not of the form opt=val */
1181   const char *const options[] = {   static const char options[] ALIGN1 =
1182   "bg",   "bg\0"
1183   "fg",   "fg\0"
1184   "soft",   "soft\0"
1185   "hard",   "hard\0"
1186   "intr",   "intr\0"
1187   "posix",   "posix\0"
1188   "cto",   "cto\0"
1189   "ac",   "ac\0"
1190   "tcp",   "tcp\0"
1191   "udp",   "udp\0"
1192   "lock",   "lock\0"
1193   NULL   "rdirplus\0";
  };  
1194   int val = 1;   int val = 1;
1195   if (!strncmp(opt, "no", 2)) {   if (!strncmp(opt, "no", 2)) {
1196   val = 0;   val = 0;
1197   opt += 2;   opt += 2;
1198   }   }
1199   switch (index_in_str_array(options, opt)) {   switch (index_in_strings(options, opt)) {
1200   case 0: // "bg"   case 0: // "bg"
1201    #if BB_MMU
1202   bg = val;   bg = val;
1203    #endif
1204   break;   break;
1205   case 1: // "fg"   case 1: // "fg"
1206    #if BB_MMU
1207   bg = !val;   bg = !val;
1208    #endif
1209   break;   break;
1210   case 2: // "soft"   case 2: // "soft"
1211   soft = val;   soft = val;
# Line 1049  static int nfsmount(struct mntent *mp, i Line 1237  static int nfsmount(struct mntent *mp, i
1237   else   else
1238   bb_error_msg("warning: option nolock is not supported");   bb_error_msg("warning: option nolock is not supported");
1239   break;   break;
1240     case 11: //rdirplus
1241     nordirplus = !val;
1242     break;
1243   default:   default:
1244   bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);   bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1245   goto fail;   goto fail;
# Line 1061  static int nfsmount(struct mntent *mp, i Line 1252  static int nfsmount(struct mntent *mp, i
1252   | (intr ? NFS_MOUNT_INTR : 0)   | (intr ? NFS_MOUNT_INTR : 0)
1253   | (posix ? NFS_MOUNT_POSIX : 0)   | (posix ? NFS_MOUNT_POSIX : 0)
1254   | (nocto ? NFS_MOUNT_NOCTO : 0)   | (nocto ? NFS_MOUNT_NOCTO : 0)
1255   | (noac ? NFS_MOUNT_NOAC : 0);   | (noac ? NFS_MOUNT_NOAC : 0)
1256     | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
1257   if (nfs_mount_version >= 2)   if (nfs_mount_version >= 2)
1258   data.flags |= (tcp ? NFS_MOUNT_TCP : 0);   data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1259   if (nfs_mount_version >= 3)   if (nfs_mount_version >= 3)
# Line 1091  static int nfsmount(struct mntent *mp, i Line 1283  static int nfsmount(struct mntent *mp, i
1283   * give up immediately, to avoid the initial timeout.   * give up immediately, to avoid the initial timeout.
1284   */   */
1285   if (bg && we_saw_this_host_before(hostname)) {   if (bg && we_saw_this_host_before(hostname)) {
1286   daemonized = daemonize(); /* parent or error */   daemonized = daemonize();
1287   if (daemonized <= 0) { /* parent or error */   if (daemonized <= 0) { /* parent or error */
1288   retval = -daemonized;   retval = -daemonized;
1289   goto ret;   goto ret;
# Line 1109  static int nfsmount(struct mntent *mp, i Line 1301  static int nfsmount(struct mntent *mp, i
1301   if (hp == NULL) {   if (hp == NULL) {
1302   bb_herror_msg("%s", mounthost);   bb_herror_msg("%s", mounthost);
1303   goto fail;   goto fail;
  } else {  
  if (hp->h_length > sizeof(struct in_addr)) {  
  bb_error_msg("got bad hp->h_length?");  
  hp->h_length = sizeof(struct in_addr);  
  }  
  mount_server_addr.sin_family = AF_INET;  
  memcpy(&mount_server_addr.sin_addr,  
  hp->h_addr, hp->h_length);  
1304   }   }
1305     if ((size_t)hp->h_length > sizeof(struct in_addr)) {
1306     bb_error_msg("got bad hp->h_length");
1307     hp->h_length = sizeof(struct in_addr);
1308     }
1309     mount_server_addr.sin_family = AF_INET;
1310     memcpy(&mount_server_addr.sin_addr,
1311     hp->h_addr, hp->h_length);
1312   }   }
1313   }   }
1314    
# Line 1136  static int nfsmount(struct mntent *mp, i Line 1327  static int nfsmount(struct mntent *mp, i
1327   {   {
1328   struct timeval total_timeout;   struct timeval total_timeout;
1329   struct timeval retry_timeout;   struct timeval retry_timeout;
1330   struct pmap* pm_mnt;   struct pmap pm_mnt;
1331   time_t t;   time_t t;
1332   time_t prevt;   time_t prevt;
1333   time_t timeout;   time_t timeout;
# Line 1145  static int nfsmount(struct mntent *mp, i Line 1336  static int nfsmount(struct mntent *mp, i
1336   retry_timeout.tv_usec = 0;   retry_timeout.tv_usec = 0;
1337   total_timeout.tv_sec = 20;   total_timeout.tv_sec = 20;
1338   total_timeout.tv_usec = 0;   total_timeout.tv_usec = 0;
1339    //FIXME: use monotonic()?
1340   timeout = time(NULL) + 60 * retry;   timeout = time(NULL) + 60 * retry;
1341   prevt = 0;   prevt = 0;
1342   t = 30;   t = 30;
1343  retry:   retry:
1344   /* be careful not to use too many CPU cycles */   /* be careful not to use too many CPU cycles */
1345   if (t - prevt < 30)   if (t - prevt < 30)
1346   sleep(30);   sleep(30);
1347    
1348   pm_mnt = get_mountport(&mount_server_addr,   get_mountport(&pm_mnt, &mount_server_addr,
1349   mountprog,   mountprog,
1350   mountvers,   mountvers,
1351   proto,   proto,
1352   mountport);   mountport);
1353   nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;   nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
1354    
1355   /* contact the mount daemon via TCP */   /* contact the mount daemon via TCP */
1356   mount_server_addr.sin_port = htons(pm_mnt->pm_port);   mount_server_addr.sin_port = htons(pm_mnt.pm_port);
1357   msock = RPC_ANYSOCK;   msock = RPC_ANYSOCK;
1358    
1359   switch (pm_mnt->pm_prot) {   switch (pm_mnt.pm_prot) {
1360   case IPPROTO_UDP:   case IPPROTO_UDP:
1361   mclient = clntudp_create(&mount_server_addr,   mclient = clntudp_create(&mount_server_addr,
1362   pm_mnt->pm_prog,   pm_mnt.pm_prog,
1363   pm_mnt->pm_vers,   pm_mnt.pm_vers,
1364   retry_timeout,   retry_timeout,
1365   &msock);   &msock);
1366   if (mclient)   if (mclient)
1367   break;   break;
1368   mount_server_addr.sin_port = htons(pm_mnt->pm_port);   mount_server_addr.sin_port = htons(pm_mnt.pm_port);
1369   msock = RPC_ANYSOCK;   msock = RPC_ANYSOCK;
1370   case IPPROTO_TCP:   case IPPROTO_TCP:
1371   mclient = clnttcp_create(&mount_server_addr,   mclient = clnttcp_create(&mount_server_addr,
1372   pm_mnt->pm_prog,   pm_mnt.pm_prog,
1373   pm_mnt->pm_vers,   pm_mnt.pm_vers,
1374   &msock, 0, 0);   &msock, 0, 0);
1375   break;   break;
1376   default:   default:
1377   mclient = 0;   mclient = NULL;
1378   }   }
1379   if (!mclient) {   if (!mclient) {
1380   if (!daemonized && prevt == 0)   if (!daemonized && prevt == 0)
# Line 1197  retry: Line 1389  retry:
1389   */   */
1390   memset(&status, 0, sizeof(status));   memset(&status, 0, sizeof(status));
1391    
1392   if (pm_mnt->pm_vers == 3)   if (pm_mnt.pm_vers == 3)
1393   clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,   clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1394        (xdrproc_t) xdr_dirpath,        (xdrproc_t) xdr_dirpath,
1395        (caddr_t) &pathname,        (caddr_t) &pathname,
# Line 1223  retry: Line 1415  retry:
1415   error_msg_rpc(clnt_sperror(mclient, " "));   error_msg_rpc(clnt_sperror(mclient, " "));
1416   auth_destroy(mclient->cl_auth);   auth_destroy(mclient->cl_auth);
1417   clnt_destroy(mclient);   clnt_destroy(mclient);
1418   mclient = 0;   mclient = NULL;
1419   close(msock);   close(msock);
1420     msock = -1;
1421   }   }
1422    
1423   /* Timeout. We are going to retry... maybe */   /* Timeout. We are going to retry... maybe */
# Line 1247  retry: Line 1440  retry:
1440   goto retry;   goto retry;
1441   }   }
1442    
1443  prepare_kernel_data:   prepare_kernel_data:
1444    
1445   if (nfsvers == 2) {   if (nfsvers == 2) {
1446   if (status.nfsv2.fhs_status != 0) {   if (status.nfsv2.fhs_status != 0) {
# Line 1320  prepare_kernel_data: Line 1513  prepare_kernel_data:
1513   auth_destroy(mclient->cl_auth);   auth_destroy(mclient->cl_auth);
1514   clnt_destroy(mclient);   clnt_destroy(mclient);
1515   close(msock);   close(msock);
1516     msock = -1;
1517    
1518   if (bg) {   if (bg) {
1519   /* We must wait until mount directory is available */   /* We must wait until mount directory is available */
# Line 1329  prepare_kernel_data: Line 1523  prepare_kernel_data:
1523   if (!daemonized) {   if (!daemonized) {
1524   daemonized = daemonize();   daemonized = daemonize();
1525   if (daemonized <= 0) { /* parent or error */   if (daemonized <= 0) { /* parent or error */
1526    // FIXME: parent doesn't close fsock - ??!
1527   retval = -daemonized;   retval = -daemonized;
1528   goto ret;   goto ret;
1529   }   }
# Line 1340  prepare_kernel_data: Line 1535  prepare_kernel_data:
1535   }   }
1536   }   }
1537    
1538  do_mount: /* perform actual mount */   do_mount: /* perform actual mount */
1539    
1540   mp->mnt_type = "nfs";   mp->mnt_type = (char*)"nfs";
1541   retval = mount_it_now(mp, vfsflags, (char*)&data);   retval = mount_it_now(mp, vfsflags, (char*)&data);
1542   goto ret;   goto ret;
1543    
1544  fail: /* abort */   fail: /* abort */
1545    
1546   if (msock != -1) {   if (msock >= 0) {
1547   if (mclient) {   if (mclient) {
1548   auth_destroy(mclient->cl_auth);   auth_destroy(mclient->cl_auth);
1549   clnt_destroy(mclient);   clnt_destroy(mclient);
1550   }   }
1551   close(msock);   close(msock);
1552   }   }
1553   if (fsock != -1)   if (fsock >= 0)
1554   close(fsock);   close(fsock);
1555    
1556  ret:   ret:
1557   free(hostname);   free(hostname);
1558   free(mounthost);   free(mounthost);
1559   free(filteropts);   free(filteropts);
# Line 1368  ret: Line 1563  ret:
1563  #else /* !ENABLE_FEATURE_MOUNT_NFS */  #else /* !ENABLE_FEATURE_MOUNT_NFS */
1564    
1565  /* Never called. Call should be optimized out. */  /* Never called. Call should be optimized out. */
1566  int nfsmount(struct mntent *mp, int vfsflags, char *filteropts);  int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
1567    
1568  #endif /* !ENABLE_FEATURE_MOUNT_NFS */  #endif /* !ENABLE_FEATURE_MOUNT_NFS */
1569    
# Line 1377  int nfsmount(struct mntent *mp, int vfsf Line 1572  int nfsmount(struct mntent *mp, int vfsf
1572  // NB: mp->xxx fields may be trashed on exit  // NB: mp->xxx fields may be trashed on exit
1573  static int singlemount(struct mntent *mp, int ignore_busy)  static int singlemount(struct mntent *mp, int ignore_busy)
1574  {  {
1575   int rc = -1, vfsflags;   int rc = -1;
1576     long vfsflags;
1577   char *loopFile = 0, *filteropts = 0;   char *loopFile = 0, *filteropts = 0;
1578   llist_t *fl = 0;   llist_t *fl = 0;
1579   struct stat st;   struct stat st;
# Line 1386  static int singlemount(struct mntent *mp Line 1582  static int singlemount(struct mntent *mp
1582    
1583   // Treat fstype "auto" as unspecified.   // Treat fstype "auto" as unspecified.
1584    
1585   if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0;   if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
1586     mp->mnt_type = NULL;
1587    
1588     // Might this be a virtual filesystem?
1589    
1590     if (ENABLE_FEATURE_MOUNT_HELPERS
1591     && (strchr(mp->mnt_fsname, '#'))
1592     ) {
1593     char *s, *p, *args[35];
1594     int n = 0;
1595    // FIXME: does it allow execution of arbitrary commands?!
1596    // What args[0] can end up with?
1597     for (s = p = mp->mnt_fsname; *s && n < 35-3; ++s) {
1598     if (s[0] == '#' && s[1] != '#') {
1599     *s = '\0';
1600     args[n++] = p;
1601     p = s + 1;
1602     }
1603     }
1604     args[n++] = p;
1605     args[n++] = mp->mnt_dir;
1606     args[n] = NULL;
1607     rc = wait4pid(xspawn(args));
1608     goto report_error;
1609     }
1610    
1611   // Might this be an CIFS filesystem?   // Might this be an CIFS filesystem?
1612    
1613   if (ENABLE_FEATURE_MOUNT_CIFS &&   if (ENABLE_FEATURE_MOUNT_CIFS
1614   (!mp->mnt_type || !strcmp(mp->mnt_type,"cifs")) &&   && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
1615   (mp->mnt_fsname[0]==mp->mnt_fsname[1] && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\')))   && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
1616   {   && mp->mnt_fsname[0] == mp->mnt_fsname[1]
1617   struct hostent *he;   ) {
1618   char ip[32], *s;   len_and_sockaddr *lsa;
1619     char *ip, *dotted;
1620     char *s;
1621    
1622   rc = 1;   rc = 1;
1623   // Replace '/' with '\' and verify that unc points to "//server/share".   // Replace '/' with '\' and verify that unc points to "//server/share".
# Line 1406  static int singlemount(struct mntent *mp Line 1628  static int singlemount(struct mntent *mp
1628   // get server IP   // get server IP
1629    
1630   s = strrchr(mp->mnt_fsname, '\\');   s = strrchr(mp->mnt_fsname, '\\');
1631   if (s == mp->mnt_fsname+1) goto report_error;   if (s <= mp->mnt_fsname+1) goto report_error;
1632   *s = 0;   *s = '\0';
1633   he = gethostbyname(mp->mnt_fsname+2);   lsa = host2sockaddr(mp->mnt_fsname+2, 0);
1634   *s = '\\';   *s = '\\';
1635   if (!he) goto report_error;   if (!lsa) goto report_error;
1636    
1637   // Insert ip=... option into string flags.  (NOTE: Add IPv6 support.)   // insert ip=... option into string flags.
1638    
1639   sprintf(ip, "ip=%d.%d.%d.%d", he->h_addr[0], he->h_addr[1],   dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1640   he->h_addr[2], he->h_addr[3]);   ip = xasprintf("ip=%s", dotted);
1641   parse_mount_options(ip, &filteropts);   parse_mount_options(ip, &filteropts);
1642    
1643   // compose new unc '\\server-ip\share'   // compose new unc '\\server-ip\share'
1644     // (s => slash after hostname)
1645    
1646   mp->mnt_fsname = xasprintf("\\\\%s%s", ip+3,   mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);
  strchr(mp->mnt_fsname+2,'\\'));  
1647    
1648   // lock is required   // lock is required
1649   vfsflags |= MS_MANDLOCK;   vfsflags |= MS_MANDLOCK;
1650    
1651   mp->mnt_type = "cifs";   mp->mnt_type = (char*)"cifs";
1652   rc = mount_it_now(mp, vfsflags, filteropts);   rc = mount_it_now(mp, vfsflags, filteropts);
1653   if (ENABLE_FEATURE_CLEAN_UP) free(mp->mnt_fsname);   if (ENABLE_FEATURE_CLEAN_UP) {
1654     free(mp->mnt_fsname);
1655     free(ip);
1656     free(dotted);
1657     free(lsa);
1658     }
1659   goto report_error;   goto report_error;
1660   }   }
1661    
1662   // Might this be an NFS filesystem?   // Might this be an NFS filesystem?
1663    
1664   if (ENABLE_FEATURE_MOUNT_NFS &&   if (ENABLE_FEATURE_MOUNT_NFS
1665   (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&   && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))
1666   strchr(mp->mnt_fsname, ':') != NULL)   && strchr(mp->mnt_fsname, ':') != NULL
1667   {   ) {
1668   rc = nfsmount(mp, vfsflags, filteropts);   rc = nfsmount(mp, vfsflags, filteropts);
1669   goto report_error;   goto report_error;
1670   }   }
1671    
1672   // Look at the file.  (Not found isn't a failure for remount, or for   // Look at the file.  (Not found isn't a failure for remount, or for
1673   // a synthetic filesystem like proc or sysfs.)   // a synthetic filesystem like proc or sysfs.)
1674     // (We use stat, not lstat, in order to allow
1675     // mount symlink_to_file_or_blkdev dir)
1676    
1677   if (!lstat(mp->mnt_fsname, &st) && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))   if (!stat(mp->mnt_fsname, &st)
1678   {   && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
1679     ) {
1680   // Do we need to allocate a loopback device for it?   // Do we need to allocate a loopback device for it?
1681    
1682   if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {   if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1683   loopFile = bb_simplify_path(mp->mnt_fsname);   loopFile = bb_simplify_path(mp->mnt_fsname);
1684   mp->mnt_fsname = 0;   mp->mnt_fsname = NULL; /* will receive malloced loop dev name */
1685   switch (set_loop(&(mp->mnt_fsname), loopFile, 0)) {   if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {
1686   case 0:   if (errno == EPERM || errno == EACCES)
1687   case 1:   bb_error_msg(bb_msg_perm_denied_are_you_root);
1688   break;   else
1689   default:   bb_perror_msg("cannot setup loop device");
  bb_error_msg( errno == EPERM || errno == EACCES  
  ? bb_msg_perm_denied_are_you_root  
  : "cannot setup loop device");  
1690   return errno;   return errno;
1691   }   }
1692    
# Line 1474  static int singlemount(struct mntent *mp Line 1701  static int singlemount(struct mntent *mp
1701    
1702   if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))   if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1703   rc = mount_it_now(mp, vfsflags, filteropts);   rc = mount_it_now(mp, vfsflags, filteropts);
   
  // Loop through filesystem types until mount succeeds or we run out  
   
1704   else {   else {
1705     // Loop through filesystem types until mount succeeds
1706     // or we run out
1707    
1708   /* Initialize list of block backed filesystems.  This has to be   /* Initialize list of block backed filesystems.  This has to be
1709   * done here so that during "mount -a", mounts after /proc shows up   * done here so that during "mount -a", mounts after /proc shows up
# Line 1506  static int singlemount(struct mntent *mp Line 1732  static int singlemount(struct mntent *mp
1732   }   }
1733   }   }
1734    
1735  report_error:   report_error:
1736   if (ENABLE_FEATURE_CLEAN_UP) free(filteropts);   if (ENABLE_FEATURE_CLEAN_UP)
1737     free(filteropts);
1738    
1739   if (rc && errno == EBUSY && ignore_busy) rc = 0;   if (errno == EBUSY && ignore_busy)
1740     return 0;
1741   if (rc < 0)   if (rc < 0)
1742   /* perror here sometimes says "mounting ... on ... failed: Success" */   bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
  bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);  
   
1743   return rc;   return rc;
1744  }  }
1745    
1746  // Parse options, if necessary parse fstab/mtab, and call singlemount for  // Parse options, if necessary parse fstab/mtab, and call singlemount for
1747  // each directory to be mounted.  // each directory to be mounted.
1748    
1749  const char must_be_root[] = "you must be root";  static const char must_be_root[] ALIGN1 = "you must be root";
1750    
1751  int mount_main(int argc, char **argv)  int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1752    int mount_main(int argc UNUSED_PARAM, char **argv)
1753  {  {
1754   enum { OPT_ALL = 0x10 };   char *cmdopts = xstrdup("");
1755     char *fstype = NULL;
1756   char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0;   char *storage_path;
1757   char *opt_o;   llist_t *lst_o = NULL;
1758   const char *fstabname;   const char *fstabname;
1759   FILE *fstab;   FILE *fstab;
1760   int i, j, rc = 0;   int i, j, rc = 0;
1761   unsigned opt;   unsigned opt;
1762   struct mntent mtpair[2], *mtcur = mtpair;   struct mntent mtpair[2], *mtcur = mtpair;
1763   SKIP_DESKTOP(const int nonroot = 0;)   SKIP_DESKTOP(const int nonroot = 0;)
  USE_DESKTOP( int nonroot = (getuid() != 0);)  
1764    
1765   /* parse long options, like --bind and --move.  Note that -o option   USE_DESKTOP(int nonroot = ) sanitize_env_if_suid();
  * and --option are synonymous.  Yes, this means --remount,rw works. */  
1766    
1767   for (i = j = 0; i < argc; i++) {   // Parse long options, like --bind and --move.  Note that -o option
1768   if (argv[i][0] == '-' && argv[i][1] == '-') {   // and --option are synonymous.  Yes, this means --remount,rw works.
1769   append_mount_options(&cmdopts, argv[i]+2);   for (i = j = 1; argv[i]; i++) {
1770   } else argv[j++] = argv[i];   if (argv[i][0] == '-' && argv[i][1] == '-')
1771     append_mount_options(&cmdopts, argv[i] + 2);
1772     else
1773     argv[j++] = argv[i];
1774   }   }
1775   argv[j] = 0;   argv[j] = NULL;
  argc = j;  
1776    
1777   // Parse remaining options   // Parse remaining options
1778     // Max 2 params; -v is a counter
1779   opt = getopt32(argc, argv, "o:t:rwanfvs", &opt_o, &fstype);   opt_complementary = "?2o::" USE_FEATURE_MOUNT_VERBOSE(":vv");
1780   if (opt & 0x1) append_mount_options(&cmdopts, opt_o); // -o   opt = getopt32(argv, OPTION_STR, &lst_o, &fstype
1781   //if (opt & 0x2) // -t   USE_FEATURE_MOUNT_VERBOSE(, &verbose));
1782   if (opt & 0x4) append_mount_options(&cmdopts, "ro"); // -r   while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
1783   if (opt & 0x8) append_mount_options(&cmdopts, "rw"); // -w   if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
1784   //if (opt & 0x10) // -a   if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
  if (opt & 0x20) USE_FEATURE_MTAB_SUPPORT(useMtab = 0); // -n  
  if (opt & 0x40) USE_FEATURE_MTAB_SUPPORT(fakeIt = 1); // -f  
  //if (opt & 0x80) // -v: verbose (ignore)  
  //if (opt & 0x100) // -s: sloppy (ignore)  
1785   argv += optind;   argv += optind;
  argc -= optind;  
   
  // Three or more non-option arguments?  Die with a usage message.  
   
  if (argc > 2) bb_show_usage();  
1786    
1787   // If we have no arguments, show currently mounted filesystems   // If we have no arguments, show currently mounted filesystems
1788     if (!argv[0]) {
1789   if (!argc) {   if (!(opt & OPT_a)) {
  if (!(opt & OPT_ALL)) {  
1790   FILE *mountTable = setmntent(bb_path_mtab_file, "r");   FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1791    
1792   if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file);   if (!mountTable)
1793     bb_error_msg_and_die("no %s", bb_path_mtab_file);
1794    
1795   while (getmntent_r(mountTable, mtpair, bb_common_bufsiz1,   while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
1796   sizeof(bb_common_bufsiz1)))   GETMNTENT_BUFSIZE))
1797   {   {
1798   // Don't show rootfs. FIXME: why??   // Don't show rootfs. FIXME: why??
1799   // util-linux 2.12a happily shows rootfs...   // util-linux 2.12a happily shows rootfs...
# Line 1586  int mount_main(int argc, char **argv) Line 1804  int mount_main(int argc, char **argv)
1804   mtpair->mnt_dir, mtpair->mnt_type,   mtpair->mnt_dir, mtpair->mnt_type,
1805   mtpair->mnt_opts);   mtpair->mnt_opts);
1806   }   }
1807   if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);   if (ENABLE_FEATURE_CLEAN_UP)
1808     endmntent(mountTable);
1809   return EXIT_SUCCESS;   return EXIT_SUCCESS;
1810   }   }
1811   } else storage_path = bb_simplify_path(argv[0]);   storage_path = NULL;
1812     } else {
1813   // When we have two arguments, the second is the directory and we can   // When we have two arguments, the second is the directory and we can
1814   // skip looking at fstab entirely.  We can always abspath() the directory   // skip looking at fstab entirely.  We can always abspath() the directory
1815   // argument when we get it.   // argument when we get it.
1816     if (argv[1]) {
1817   if (argc == 2) {   if (nonroot)
1818   if (nonroot)   bb_error_msg_and_die(must_be_root);
1819   bb_error_msg_and_die(must_be_root);   mtpair->mnt_fsname = argv[0];
1820   mtpair->mnt_fsname = argv[0];   mtpair->mnt_dir = argv[1];
1821   mtpair->mnt_dir = argv[1];   mtpair->mnt_type = fstype;
1822   mtpair->mnt_type = fstype;   mtpair->mnt_opts = cmdopts;
1823   mtpair->mnt_opts = cmdopts;   if (ENABLE_FEATURE_MOUNT_LABEL) {
1824   rc = singlemount(mtpair, 0);   resolve_mount_spec(&mtpair->mnt_fsname);
1825   goto clean_up;   }
1826     rc = singlemount(mtpair, 0);
1827     return rc;
1828     }
1829     storage_path = bb_simplify_path(argv[0]); // malloced
1830   }   }
1831    
1832   i = parse_mount_options(cmdopts, 0);   // Past this point, we are handling either "mount -a [opts]"
1833     // or "mount [opts] single_param"
1834    
1835     i = parse_mount_options(cmdopts, 0); // FIXME: should be "long", not "int"
1836   if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags   if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
1837   bb_error_msg_and_die(must_be_root);   bb_error_msg_and_die(must_be_root);
1838    
1839   // 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.
1840     if (ENABLE_FEATURE_MOUNT_FLAGS
1841   if (ENABLE_FEATURE_MOUNT_FLAGS &&   && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
1842   (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)))   ) {
1843   {   rc = verbose_mount(/*source:*/ "", /*target:*/ argv[0],
1844   rc = mount("", argv[0], "", i, "");   /*type:*/ "", /*flags:*/ i, /*data:*/ "");
1845   if (rc) bb_perror_msg_and_die("%s", argv[0]);   if (rc)
1846   goto clean_up;   bb_simple_perror_msg_and_die(argv[0]);
1847     return rc;
1848   }   }
1849    
1850   // Open either fstab or mtab   // Open either fstab or mtab
   
1851   fstabname = "/etc/fstab";   fstabname = "/etc/fstab";
1852   if (i & MS_REMOUNT) {   if (i & MS_REMOUNT) {
1853     // WARNING. I am not sure this matches util-linux's
1854     // behavior. It's possible util-linux does not
1855     // take -o opts from mtab (takes only mount source).
1856   fstabname = bb_path_mtab_file;   fstabname = bb_path_mtab_file;
1857   }   }
1858   fstab = setmntent(fstabname, "r");   fstab = setmntent(fstabname, "r");
1859   if (!fstab)   if (!fstab)
1860   bb_perror_msg_and_die("cannot read %s", fstabname);   bb_perror_msg_and_die("cannot read %s", fstabname);
1861    
1862   // Loop through entries until we find what we're looking for.   // Loop through entries until we find what we're looking for
   
1863   memset(mtpair, 0, sizeof(mtpair));   memset(mtpair, 0, sizeof(mtpair));
1864   for (;;) {   for (;;) {
1865   struct mntent *mtnext = (mtcur==mtpair ? mtpair+1 : mtpair);   struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
1866    
1867   // Get next fstab entry   // Get next fstab entry
1868     if (!getmntent_r(fstab, mtcur, getmntent_buf
1869   if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1   + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
1870   + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0),   GETMNTENT_BUFSIZE/2)
1871   sizeof(bb_common_bufsiz1)/2))   ) { // End of fstab/mtab is reached
1872   {   mtcur = mtother; // the thing we found last time
1873   // Were we looking for something specific?   break;
   
  if (argc) {  
   
  // If we didn't find anything, complain.  
   
  if (!mtnext->mnt_fsname)  
  bb_error_msg_and_die("can't find %s in %s",  
  argv[0], fstabname);  
   
  mtcur = mtnext;  
  if (nonroot) {  
  // fstab must have "users" or "user"  
  if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))  
  bb_error_msg_and_die(must_be_root);  
  }  
   
  // Mount the last thing we found.  
   
  mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);  
  append_mount_options(&(mtcur->mnt_opts), cmdopts);  
  rc = singlemount(mtcur, 0);  
  free(mtcur->mnt_opts);  
  }  
  goto clean_up;  
1874   }   }
1875    
1876   /* If we're trying to mount something specific and this isn't it,   // If we're trying to mount something specific and this isn't it,
1877   * skip it.  Note we must match both the exact text in fstab (ala   // skip it.  Note we must match the exact text in fstab (ala
1878   * "proc") or a full path from root */   // "proc") or a full path from root
1879     if (argv[0]) {
  if (argc) {  
1880    
1881   // Is this what we're looking for?   // Is this what we're looking for?
   
1882   if (strcmp(argv[0], mtcur->mnt_fsname) &&   if (strcmp(argv[0], mtcur->mnt_fsname) &&
1883     strcmp(storage_path, mtcur->mnt_fsname) &&     strcmp(storage_path, mtcur->mnt_fsname) &&
1884     strcmp(argv[0], mtcur->mnt_dir) &&     strcmp(argv[0], mtcur->mnt_dir) &&
1885     strcmp(storage_path, mtcur->mnt_dir)) continue;     strcmp(storage_path, mtcur->mnt_dir)) continue;
1886    
1887   // Remember this entry.  Something later may have overmounted   // Remember this entry.  Something later may have
1888   // it, and we want the _last_ match.   // overmounted it, and we want the _last_ match.
1889     mtcur = mtother;
  mtcur = mtnext;  
   
  // If we're mounting all.  
1890    
1891     // If we're mounting all
1892   } else {   } else {
1893   // Do we need to match a filesystem type?   // Do we need to match a filesystem type?
1894   // TODO: support "-t type1,type2"; "-t notype1,type2"   if (fstype && match_fstype(mtcur, fstype))
1895     continue;
  if (fstype && strcmp(mtcur->mnt_type, fstype)) continue;  
1896    
1897   // Skip noauto and swap anyway.   // Skip noauto and swap anyway.
1898     if (parse_mount_options(mtcur->mnt_opts, 0) & (MOUNT_NOAUTO | MOUNT_SWAP))
1899   if (parse_mount_options(mtcur->mnt_opts, 0)   continue;
  & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;  
1900    
1901   // No, mount -a won't mount anything,   // No, mount -a won't mount anything,
1902   // even user mounts, for mere humans.   // even user mounts, for mere humans
   
1903   if (nonroot)   if (nonroot)
1904   bb_error_msg_and_die(must_be_root);   bb_error_msg_and_die(must_be_root);
1905    
1906   // Mount this thing.   // Mount this thing
1907     if (ENABLE_FEATURE_MOUNT_LABEL)
1908     resolve_mount_spec(&mtpair->mnt_fsname);
1909    
1910   // NFS mounts want this to be xrealloc-able   // NFS mounts want this to be xrealloc-able
1911   mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);   mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
1912   if (singlemount(mtcur, 1)) {   if (singlemount(mtcur, 1)) {
1913   /* Count number of failed mounts */   // Count number of failed mounts
1914   rc++;   rc++;
1915   }   }
1916   free(mtcur->mnt_opts);   free(mtcur->mnt_opts);
1917   }   }
1918   }   }
  if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);  
1919    
1920  clean_up:   // End of fstab/mtab is reached.
1921     // Were we looking for something specific?
1922     if (argv[0]) {
1923     // If we didn't find anything, complain
1924     if (!mtcur->mnt_fsname)
1925     bb_error_msg_and_die("can't find %s in %s",
1926     argv[0], fstabname);
1927     if (nonroot) {
1928     // fstab must have "users" or "user"
1929     if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
1930     bb_error_msg_and_die(must_be_root);
1931     }
1932    
1933     // Mount the last thing we found
1934     mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
1935     append_mount_options(&(mtcur->mnt_opts), cmdopts);
1936     if (ENABLE_FEATURE_MOUNT_LABEL) {
1937     resolve_mount_spec(&mtpair->mnt_fsname);
1938     }
1939     rc = singlemount(mtcur, 0);
1940     if (ENABLE_FEATURE_CLEAN_UP)
1941     free(mtcur->mnt_opts);
1942     }
1943    
1944     if (ENABLE_FEATURE_CLEAN_UP)
1945     endmntent(fstab);
1946   if (ENABLE_FEATURE_CLEAN_UP) {   if (ENABLE_FEATURE_CLEAN_UP) {
1947   free(storage_path);   free(storage_path);
1948   free(cmdopts);   free(cmdopts);
1949   }   }
   
1950   return rc;   return rc;
1951  }  }

Legend:
Removed from v.532  
changed lines
  Added in v.816