9a1accc88acbf8a6462ac67b13b98a3a3ec75a65
[oweals/busybox.git] / mount.c
1 /*
2  * Mini mount implementation for busybox
3  *
4  * Copyright (C) 1999 by Erik Andersen <andersee@debian.org>
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  * 1999-10-07   Erik Andersen.  Removed mtab usage, major adjustments,
26  *              and some serious dieting all around.
27 */
28
29 #include "internal.h"
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <mntent.h>
36 #include <sys/mount.h>
37 #include <ctype.h>
38 #include <fstab.h>
39
40 const char mount_usage[] = "Usage:\tmount [flags]\n"
41     "\tmount [flags] device directory [-o options,more-options]\n"
42     "\n"
43     "Flags:\n"
44     "\t-a:\tMount all file systems in fstab.\n"
45     "\t-o option:\tOne of many filesystem options, listed below.\n"
46     "\t-r:\tMount the filesystem read-only.\n"
47     "\t-t filesystem-type:\tSpecify the filesystem type.\n"
48     "\t-w:\tMount for reading and writing (default).\n"
49     "\n"
50     "Options for use with the \"-o\" flag:\n"
51     "\tasync / sync:\tWrites are asynchronous / synchronous.\n"
52     "\tdev / nodev:\tAllow use of special device files / disallow them.\n"
53     "\texec / noexec:\tAllow use of executable files / disallow them.\n"
54     "\tsuid / nosuid:\tAllow set-user-id-root programs / disallow them.\n"
55     "\tremount: Re-mount a currently-mounted filesystem, changing its flags.\n"
56     "\tro / rw: Mount for read-only / read-write.\n"
57     "\t"
58     "There are EVEN MORE flags that are specific to each filesystem.\n"
59     "You'll have to see the written documentation for those.\n";
60
61 struct mount_options {
62     const char *name;
63     unsigned long and;
64     unsigned long or;
65 };
66
67 static const struct mount_options mount_options[] = {
68     {"async", ~MS_SYNCHRONOUS, 0},
69     {"defaults", ~0, 0},
70     {"dev", ~MS_NODEV, 0},
71     {"exec", ~MS_NOEXEC, 0},
72     {"nodev", ~0, MS_NODEV},
73     {"noexec", ~0, MS_NOEXEC},
74     {"nosuid", ~0, MS_NOSUID},
75     {"remount", ~0, MS_REMOUNT},
76     {"ro", ~0, MS_RDONLY},
77     {"rw", ~MS_RDONLY, 0},
78     {"suid", ~MS_NOSUID, 0},
79     {"sync", ~0, MS_SYNCHRONOUS},
80     {0, 0, 0}
81 };
82
83
84 static void
85 parse_mount_options ( char *options, unsigned long *flags, char *data)
86 {
87     printf("option=%s\n", options);
88     while (*options) {
89         char *comma = strchr (options, ',');
90         const struct mount_options* f = mount_options;
91         if (comma)
92             *comma = '\0';
93
94         printf("checking option=%s vs %s\n", options, f->name);
95         while (f->name != 0) {
96             printf("checking option=%s vs %s\n", options, f->name);
97             if (strcasecmp (f->name, options) == 0) {
98                 *flags &= f->and;
99                 *flags |= f->or;
100                 return;
101             }
102             f++;
103         }
104         if (*data) {
105             data += strlen (data);
106             *data++ = ',';
107         }
108         strcpy (data, options);
109         if (comma) {
110             *comma = ',';
111             options = ++comma;
112         } else
113             break;
114     }
115 }
116
117 int
118 mount_one (
119            char *blockDevice, char *directory, char *filesystemType,
120            unsigned long flags, char *string_flags)
121 {
122     int status = 0;
123
124     char buf[255];
125
126     if (strcmp(filesystemType, "auto") == 0) {
127         FILE *f = fopen ("/proc/filesystems", "r");
128
129         if (f == NULL)
130             return( FALSE);
131
132         while (fgets (buf, sizeof (buf), f) != NULL) {
133             filesystemType = buf;
134             if (*filesystemType == '\t') {      // Not a nodev filesystem
135
136                 // Add NULL termination to each line
137                 while (*filesystemType && *filesystemType != '\n')
138                     filesystemType++;
139                 *filesystemType = '\0';
140
141                 filesystemType = buf;
142                 filesystemType++;       // hop past tab
143
144                 status = mount (blockDevice, directory, filesystemType,
145                                 flags | MS_MGC_VAL, string_flags);
146                 if (status == 0)
147                     break;
148             }
149         }
150         fclose (f);
151     } else {
152         status = mount (blockDevice, directory, filesystemType,
153                         flags | MS_MGC_VAL, string_flags);
154     }
155
156     if (status) {
157         fprintf (stderr, "Mounting %s on %s failed: %s\n",
158                  blockDevice, directory, strerror(errno));
159         return (FALSE);
160     }
161     return (TRUE);
162 }
163
164 extern int mount_main (int argc, char **argv)
165 {
166     char string_flags[1024]="\0";
167     unsigned long flags = 0;
168     char *filesystemType = "auto";
169     int all = 0;
170     int i = argc;
171
172     if (argc == 1) {
173         FILE *mountTable;
174         if ((mountTable = setmntent ("/proc/mounts", "r"))) {
175             struct mntent *m;
176             while ((m = getmntent (mountTable)) != 0) {
177                 char *blockDevice = m->mnt_fsname;
178                 if (strcmp (blockDevice, "/dev/root") == 0)
179                     blockDevice = (getfsfile ("/"))->fs_spec;
180                 printf ("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
181                         m->mnt_type, m->mnt_opts);
182             }
183             endmntent (mountTable);
184         }
185         return( TRUE);
186     }
187
188
189     /* Parse options */
190     while (**argv) {
191         if (**argv == '-') {
192             switch (**argv) {
193             case 'o':
194                 if (++argv == 0) {
195                     fprintf (stderr, "%s\n", mount_usage);
196                     return( FALSE);
197                 }
198                 parse_mount_options (*argv, &flags, string_flags);
199                 argc--;
200                 argv++;
201                 break;
202             case 'r':
203                 flags |= MS_RDONLY;
204                 break;
205             case 't':
206                 if (++argv == 0) {
207                     fprintf (stderr, "%s\n", mount_usage);
208                     return( FALSE);
209                 }
210                 filesystemType = *argv;
211                 argc--;
212                 argv++;
213                 break;
214             case 'w':
215                 flags &= ~MS_RDONLY;
216                 break;
217             case 'a':
218                 all = 1;
219                 break;
220             case 'v':
221             case 'h':
222             case '-':
223                 fprintf (stderr, "%s\n", mount_usage);
224                 return( TRUE);
225             }
226         }
227         i--;
228         argv++;
229     }
230
231     if (all == 1) {
232         struct mntent *m;
233         FILE *f = setmntent ("/etc/fstab", "r");
234
235         if (f == NULL) {
236             perror("/etc/fstab");
237             return( FALSE); 
238         }
239         // FIXME: Combine read routine (make new function) with unmount_all
240         // to save space.
241
242         while ((m = getmntent (f)) != NULL) {
243             // If the file system isn't noauto, and isn't mounted on /, mount 
244             // it
245             if ((!strstr (m->mnt_opts, "noauto"))
246                 && (m->mnt_dir[1] != '\0') && !((m->mnt_type[0] == 's')
247                                                 && (m->mnt_type[1] == 'w'))
248                 && !((m->mnt_type[0] == 'n') && (m->mnt_type[1] == 'f'))) {
249                 mount_one (m->mnt_fsname, m->mnt_dir, m->mnt_type, flags,
250                            m->mnt_opts);
251             }
252         }
253
254         endmntent (f);
255     } else {
256         if (argc >= 3) {
257             while (i < argc)
258                 argv--;
259             while (**argv == '-')
260                 argv++;
261             if (mount_one
262                 (*argv, *(argv+1), filesystemType, flags,
263                  string_flags) == 0) return 0;
264             else
265                 return( FALSE);
266         } else {
267             fprintf (stderr, "%s\n", mount_usage);
268             return( FALSE);
269         }
270     }
271     return( TRUE);
272 }