making note of my changes.
[oweals/busybox.git] / mount.c
1 /*
2  * Mini mount implementation for busybox
3  *
4  * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * 3/21/1999    Charles P. Wright <cpwright@cpwright.com>
21  *              searches through fstab when -a is passed
22  *              will try mounting stuff with all fses when passed -t auto
23  *
24  * 1999-04-17   Dave Cinege...Rewrote -t auto. Fixed ro mtab.
25  *
26  * 1999-10-07   Erik Andersen <andersen@lineo.com>, <andersee@debian.org>.
27  *              Rewrote of a lot of code. Removed mtab usage (I plan on
28  *              putting it back as a compile-time option some time), 
29  *              major adjustments to option parsing, and some serious 
30  *              dieting all around.
31 */
32
33 #include "internal.h"
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <mntent.h>
40 #include <sys/mount.h>
41 #include <ctype.h>
42 #include <fstab.h>
43
44 extern const char mtab_file[]; /* Defined in utility.c */
45
46 static const char mount_usage[] = "\tmount [flags]\n"
47     "\tmount [flags] device directory [-o options,more-options]\n"
48     "\n"
49     "Flags:\n"
50     "\t-a:\tMount all file systems in fstab.\n"
51 #ifdef BB_MTAB
52     "\t-f:\t\"Fake\" mount. Add entry to mount table but don't mount it.\n"
53     "\t-n:\tDon't write a mount table entry.\n"
54 #endif
55     "\t-o option:\tOne of many filesystem options, listed below.\n"
56     "\t-r:\tMount the filesystem read-only.\n"
57     "\t-t filesystem-type:\tSpecify the filesystem type.\n"
58     "\t-w:\tMount for reading and writing (default).\n"
59     "\n"
60     "Options for use with the \"-o\" flag:\n"
61     "\tasync / sync:\tWrites are asynchronous / synchronous.\n"
62     "\tdev / nodev:\tAllow use of special device files / disallow them.\n"
63     "\texec / noexec:\tAllow use of executable files / disallow them.\n"
64     "\tsuid / nosuid:\tAllow set-user-id-root programs / disallow them.\n"
65     "\tremount: Re-mount a currently-mounted filesystem, changing its flags.\n"
66     "\tro / rw: Mount for read-only / read-write.\n"
67     "\t"
68     "There are EVEN MORE flags that are specific to each filesystem.\n"
69     "You'll have to see the written documentation for those.\n";
70
71
72 struct mount_options {
73     const char *name;
74     unsigned long and;
75     unsigned long or;
76 };
77
78 static const struct mount_options mount_options[] = {
79     {"async", ~MS_SYNCHRONOUS, 0},
80     {"defaults", ~0, 0},
81     {"dev", ~MS_NODEV, 0},
82     {"exec", ~MS_NOEXEC, 0},
83     {"nodev", ~0, MS_NODEV},
84     {"noexec", ~0, MS_NOEXEC},
85     {"nosuid", ~0, MS_NOSUID},
86     {"remount", ~0, MS_REMOUNT},
87     {"ro", ~0, MS_RDONLY},
88     {"rw", ~MS_RDONLY, 0},
89     {"suid", ~MS_NOSUID, 0},
90     {"sync", ~0, MS_SYNCHRONOUS},
91     {0, 0, 0}
92 };
93
94 #if ! defined BB_MTAB
95 #define do_mount(specialfile, dir, filesystemtype, flags, string_flags, useMtab, fakeIt, mtab_opts) \
96         mount(specialfile, dir, filesystemtype, flags, string_flags)
97 #else
98 static int
99 do_mount(char* specialfile, char* dir, char* filesystemtype, 
100         long flags, void* string_flags, int useMtab, int fakeIt, char* mtab_opts)
101 {
102     int status=0;
103
104     if (fakeIt==FALSE)
105         status=mount(specialfile, dir, filesystemtype, flags, string_flags);
106
107     if ( status == 0 ) {
108         if ( useMtab==TRUE )
109             write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
110         return 0;
111     }
112     else 
113         return( status);
114 }
115 #endif
116
117
118 #if defined BB_MTAB
119 #define whine_if_fstab_is_missing() {} 
120 #else
121 extern void whine_if_fstab_is_missing()
122 {
123     struct stat statBuf;
124     if (stat("/etc/fstab", &statBuf) < 0) 
125         fprintf(stderr, "/etc/fstab file missing -- install one to name /dev/root.\n\n");
126 }
127 #endif
128
129
130 /* Seperate standard mount options from the nonstandard string options */
131 static void
132 parse_mount_options ( char *options, unsigned long *flags, char *strflags)
133 {
134     while (options) {
135         int gotone=FALSE;
136         char *comma = strchr (options, ',');
137         const struct mount_options* f = mount_options;
138         if (comma)
139             *comma = '\0';
140
141         while (f->name != 0) {
142             if (strcasecmp (f->name, options) == 0) {
143
144                 *flags &= f->and;
145                 *flags |= f->or;
146                 gotone=TRUE;
147                 break;
148             }
149             f++;
150         }
151         if (*strflags && strflags!= '\0' && gotone==FALSE) {
152             char *temp=strflags;
153             temp += strlen (strflags);
154             *temp++ = ',';
155             *temp++ = '\0';
156         }
157         if (gotone==FALSE) {
158             strcat (strflags, options);
159             gotone=FALSE;
160         }
161         if (comma) {
162             *comma = ',';
163             options = ++comma;
164         } else {
165             break;
166         }
167     }
168 }
169
170 int
171 mount_one(char *blockDevice, char *directory, char *filesystemType,
172            unsigned long flags, char *string_flags, int useMtab, int fakeIt, char *mtab_opts)
173 {
174     int status = 0;
175
176     char buf[255];
177
178 #if defined BB_FEATURE_USE_PROCFS
179     if (strcmp(filesystemType, "auto") == 0) {
180         FILE *f = fopen ("/proc/filesystems", "r");
181
182         if (f == NULL)
183             return( FALSE);
184
185         while (fgets (buf, sizeof (buf), f) != NULL) {
186             filesystemType = buf;
187             if (*filesystemType == '\t') {      // Not a nodev filesystem
188
189                 // Add NULL termination to each line
190                 while (*filesystemType && *filesystemType != '\n')
191                     filesystemType++;
192                 *filesystemType = '\0';
193
194                 filesystemType = buf;
195                 filesystemType++;       // hop past tab
196
197                 status = do_mount (blockDevice, directory, filesystemType,
198                                 flags | MS_MGC_VAL, string_flags, useMtab, 
199                                 fakeIt, mtab_opts);
200                 if (status == 0)
201                     break;
202             }
203         }
204         fclose (f);
205     } else
206 #endif
207     {
208         status = do_mount (blockDevice, directory, filesystemType,
209                         flags | MS_MGC_VAL, string_flags, useMtab, 
210                         fakeIt, mtab_opts);
211     }
212
213     if (status) {
214         fprintf (stderr, "Mounting %s on %s failed: %s\n",
215                  blockDevice, directory, strerror(errno));
216         return (FALSE);
217     }
218     return (TRUE);
219 }
220
221 extern int mount_main (int argc, char **argv)
222 {
223     char string_flags_buf[1024]="";
224     char *string_flags = string_flags_buf;
225     char *extra_opts = string_flags_buf;
226     unsigned long flags = 0;
227     char *filesystemType = "auto";
228     char *device = NULL;
229     char *directory = NULL;
230     int all = FALSE;
231     int fakeIt = FALSE;
232     int useMtab = TRUE;
233     int i;
234
235     /* Only compiled in if BB_MTAB is not defined */
236     whine_if_fstab_is_missing();
237
238     if (argc == 1) {
239         FILE *mountTable = setmntent (mtab_file, "r");
240         if (mountTable) {
241             struct mntent *m;
242             while ((m = getmntent (mountTable)) != 0) {
243                 struct fstab* fstabItem;
244                 char *blockDevice = m->mnt_fsname;
245                 /* Note that if /etc/fstab is missing, libc can't fix up /dev/root for us */
246                 if (strcmp (blockDevice, "/dev/root") == 0) {
247                     fstabItem = getfsfile ("/");
248                     if (fstabItem != NULL)
249                         blockDevice = fstabItem->fs_spec;
250                 }
251                 printf ("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
252                         m->mnt_type, m->mnt_opts);
253             }
254             endmntent (mountTable);
255         } else {
256             perror(mtab_file);
257         }
258         exit( TRUE);
259     }
260
261
262     /* Parse options */
263     i = --argc;
264     argv++;
265     while (i > 0 && **argv) {
266         if (**argv == '-') {
267             char *opt = *argv;
268             while (i>0 && *++opt) switch (*opt) {
269             case 'o':
270                 if (--i == 0) {
271                     goto goodbye;
272                 }
273                 parse_mount_options (*(++argv), &flags, string_flags);
274                 break;
275             case 'r':
276                 flags |= MS_RDONLY;
277                 break;
278             case 't':
279                 if (--i == 0) {
280                     goto goodbye;
281                 }
282                 filesystemType = *(++argv);
283                 break;
284             case 'w':
285                 flags &= ~MS_RDONLY;
286                 break;
287             case 'a':
288                 all = TRUE;
289                 break;
290 #ifdef BB_MTAB
291             case 'f':
292                 fakeIt = TRUE;
293                 break;
294             case 'n':
295                 useMtab = FALSE;
296                 break;
297 #endif
298             case 'v':
299             case 'h':
300             case '-':
301                 goto goodbye;
302             }
303         } else {
304             if (device == NULL)
305                 device=*argv;
306             else if (directory == NULL)
307                 directory=*argv;
308             else {
309                 goto goodbye;
310             }
311         }
312         i--;
313         argv++;
314     }
315
316     if (all == TRUE) {
317         struct mntent *m;
318         FILE *f = setmntent ("/etc/fstab", "r");
319
320         if (f == NULL) {
321             perror("/etc/fstab");
322             exit( FALSE); 
323         }
324         while ((m = getmntent (f)) != NULL) {
325             // If the file system isn't noauto, and isn't mounted on /, 
326             // and isn't swap or nfs, then mount it
327             if ((!strstr (m->mnt_opts, "noauto")) &&
328                     (m->mnt_dir[1] != '\0') && 
329                     (!strstr (m->mnt_type, "swap")) && 
330                     (!strstr (m->mnt_type, "nfs"))) 
331             {
332                 flags = 0;
333                 *string_flags = '\0';
334                 parse_mount_options(m->mnt_opts, &flags, string_flags);
335                 mount_one (m->mnt_fsname, m->mnt_dir, m->mnt_type, 
336                         flags, string_flags, useMtab, fakeIt, extra_opts);
337             }
338         }
339         endmntent (f);
340     } else {
341         if (device && directory) {
342 #ifdef BB_NFSMOUNT
343             if (strcmp(filesystemType, "nfs") == 0) {
344                 if (nfsmount(device, directory, &flags, &extra_opts, &string_flags, 1) != 0)
345                 exit(FALSE);
346             }
347 #endif
348             exit (mount_one (device, directory, filesystemType, 
349                         flags, string_flags, useMtab, fakeIt, extra_opts));
350         } else {
351             goto goodbye;
352         }
353     }
354     exit( TRUE);
355
356 goodbye:
357     usage( mount_usage);
358 }