1efbdf4079a0060a4bf2b9fe730915756f19cfcf
[oweals/busybox.git] / util-linux / 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 static const char mount_usage[] = "Usage:\tmount [flags]\n"
45     "\tmount [flags] device directory [-o options,more-options]\n"
46     "\n"
47     "Flags:\n"
48     "\t-a:\tMount all file systems in fstab.\n"
49     "\t-o option:\tOne of many filesystem options, listed below.\n"
50     "\t-r:\tMount the filesystem read-only.\n"
51     "\t-t filesystem-type:\tSpecify the filesystem type.\n"
52     "\t-w:\tMount for reading and writing (default).\n"
53     "\n"
54     "Options for use with the \"-o\" flag:\n"
55     "\tasync / sync:\tWrites are asynchronous / synchronous.\n"
56     "\tdev / nodev:\tAllow use of special device files / disallow them.\n"
57     "\texec / noexec:\tAllow use of executable files / disallow them.\n"
58     "\tsuid / nosuid:\tAllow set-user-id-root programs / disallow them.\n"
59     "\tremount: Re-mount a currently-mounted filesystem, changing its flags.\n"
60     "\tro / rw: Mount for read-only / read-write.\n"
61     "\t"
62     "There are EVEN MORE flags that are specific to each filesystem.\n"
63     "You'll have to see the written documentation for those.\n";
64
65 struct mount_options {
66     const char *name;
67     unsigned long and;
68     unsigned long or;
69 };
70
71 static const struct mount_options mount_options[] = {
72     {"async", ~MS_SYNCHRONOUS, 0},
73     {"defaults", ~0, 0},
74     {"dev", ~MS_NODEV, 0},
75     {"exec", ~MS_NOEXEC, 0},
76     {"nodev", ~0, MS_NODEV},
77     {"noexec", ~0, MS_NOEXEC},
78     {"nosuid", ~0, MS_NOSUID},
79     {"remount", ~0, MS_REMOUNT},
80     {"ro", ~0, MS_RDONLY},
81     {"rw", ~MS_RDONLY, 0},
82     {"suid", ~MS_NOSUID, 0},
83     {"sync", ~0, MS_SYNCHRONOUS},
84     {0, 0, 0}
85 };
86
87
88 /* Seperate standard mount options from the nonstandard string options */
89 static void
90 parse_mount_options ( char *options, unsigned long *flags, char *strflags)
91 {
92     while (options) {
93         int gotone=FALSE;
94         char *comma = strchr (options, ',');
95         const struct mount_options* f = mount_options;
96         if (comma)
97             *comma = '\0';
98
99         while (f->name != 0) {
100             if (strcasecmp (f->name, options) == 0) {
101
102                 *flags &= f->and;
103                 *flags |= f->or;
104                 gotone=TRUE;
105                 break;
106             }
107             f++;
108         }
109         if (*strflags && strflags!= '\0' && gotone==FALSE) {
110             char *temp=strflags;
111             temp += strlen (strflags);
112             *temp++ = ',';
113             *temp++ = '\0';
114         }
115         if (gotone==FALSE) {
116             strcat (strflags, options);
117             gotone=FALSE;
118         }
119         if (comma) {
120             *comma = ',';
121             options = ++comma;
122         } else {
123             break;
124         }
125     }
126 }
127
128 int
129 mount_one (
130            char *blockDevice, char *directory, char *filesystemType,
131            unsigned long flags, char *string_flags)
132 {
133     int status = 0;
134
135     char buf[255];
136
137     if (strcmp(filesystemType, "auto") == 0) {
138         FILE *f = fopen ("/proc/filesystems", "r");
139
140         if (f == NULL)
141             return( FALSE);
142
143         while (fgets (buf, sizeof (buf), f) != NULL) {
144             filesystemType = buf;
145             if (*filesystemType == '\t') {      // Not a nodev filesystem
146
147                 // Add NULL termination to each line
148                 while (*filesystemType && *filesystemType != '\n')
149                     filesystemType++;
150                 *filesystemType = '\0';
151
152                 filesystemType = buf;
153                 filesystemType++;       // hop past tab
154
155                 status = mount (blockDevice, directory, filesystemType,
156                                 flags | MS_MGC_VAL, string_flags);
157                 if (status == 0)
158                     break;
159             }
160         }
161         fclose (f);
162     } else {
163         status = mount (blockDevice, directory, filesystemType,
164                         flags | MS_MGC_VAL, string_flags);
165     }
166
167     if (status) {
168         fprintf (stderr, "Mounting %s on %s failed: %s\n",
169                  blockDevice, directory, strerror(errno));
170         return (FALSE);
171     }
172     return (TRUE);
173 }
174
175 extern int mount_main (int argc, char **argv)
176 {
177     char string_flags[1024]="";
178     unsigned long flags = 0;
179     char *filesystemType = "auto";
180     char *device = NULL;
181     char *directory = NULL;
182     struct stat statBuf;
183     int all = 0;
184     int i;
185
186     if (stat("/etc/fstab", &statBuf) < 0) 
187         fprintf(stderr, "/etc/fstab file missing -- Please install one.\n\n");
188
189     if (argc == 1) {
190         FILE *mountTable;
191         if ((mountTable = setmntent ("/proc/mounts", "r"))) {
192             struct mntent *m;
193             while ((m = getmntent (mountTable)) != 0) {
194                 struct fstab* fstabItem;
195                 char *blockDevice = m->mnt_fsname;
196                 /* Note that if /etc/fstab is missing, libc can't fix up /dev/root for us */
197                 if (strcmp (blockDevice, "/dev/root") == 0) {
198                     fstabItem = getfsfile ("/");
199                     if (fstabItem != NULL)
200                         blockDevice = fstabItem->fs_spec;
201                 }
202                 printf ("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
203                         m->mnt_type, m->mnt_opts);
204             }
205             endmntent (mountTable);
206         }
207         exit( TRUE);
208     }
209
210
211     /* Parse options */
212     i = --argc;
213     argv++;
214     while (i > 0 && **argv) {
215         if (**argv == '-') {
216             while (i>0 && *++(*argv)) switch (**argv) {
217             case 'o':
218                 if (--i == 0) {
219                     fprintf (stderr, "%s\n", mount_usage);
220                     exit( FALSE);
221                 }
222                 parse_mount_options (*(++argv), &flags, string_flags);
223                 --i;
224                 ++argv;
225                 break;
226             case 'r':
227                 flags |= MS_RDONLY;
228                 break;
229             case 't':
230                 if (--i == 0) {
231                     fprintf (stderr, "%s\n", mount_usage);
232                     exit( FALSE);
233                 }
234                 filesystemType = *(++argv);
235                 --i;
236                 ++argv;
237                 break;
238             case 'w':
239                 flags &= ~MS_RDONLY;
240                 break;
241             case 'a':
242                 all = TRUE;
243                 break;
244             case 'v':
245             case 'h':
246             case '-':
247                 fprintf (stderr, "%s\n", mount_usage);
248                 exit( TRUE);
249                 break;
250             }
251         } else {
252             if (device == NULL)
253                 device=*argv;
254             else if (directory == NULL)
255                 directory=*argv;
256             else {
257                 fprintf (stderr, "%s\n", mount_usage);
258                 exit( TRUE);
259             }
260         }
261         i--;
262         argv++;
263     }
264
265     if (all == TRUE) {
266         long newFlags;
267         struct mntent *m;
268         FILE *f = setmntent ("/etc/fstab", "r");
269
270         if (f == NULL) {
271             perror("/etc/fstab");
272             exit( FALSE); 
273         }
274         while ((m = getmntent (f)) != NULL) {
275             // If the file system isn't noauto, and isn't mounted on /, 
276             // and isn't swap or nfs, then mount it
277             if ((!strstr (m->mnt_opts, "noauto")) &&
278                     (m->mnt_dir[1] != '\0') && 
279                     (!strstr (m->mnt_type, "swap")) && 
280                     (!strstr (m->mnt_type, "nfs"))) 
281             {
282                 newFlags = flags;
283                 *string_flags = '\0';
284                 parse_mount_options(m->mnt_opts, &newFlags, string_flags);
285                 mount_one (m->mnt_fsname, m->mnt_dir, m->mnt_type, newFlags, string_flags);
286             }
287         }
288         endmntent (f);
289     } else {
290         if (device && directory) {
291             exit (mount_one (device, directory, filesystemType, 
292                         flags, string_flags));
293         } else {
294             fprintf (stderr, "%s\n", mount_usage);
295             exit( FALSE);
296         }
297     }
298     exit( TRUE);
299 }