Added sfdisk. Ststic-ified a bunch of stuff.
[platform/upstream/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.  Rewrote of a lot of code. Removed mtab 
26  *              usage, major adjustments, 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 static 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 /* Seperate standard mount options from the nonstandard string options */
85 static void
86 parse_mount_options ( char *options, unsigned long *flags, char *strflags)
87 {
88     while (options) {
89         int gotone=FALSE;
90         char *comma = strchr (options, ',');
91         const struct mount_options* f = mount_options;
92         if (comma)
93             *comma = '\0';
94
95         while (f->name != 0) {
96             if (strcasecmp (f->name, options) == 0) {
97                 *flags &= f->and;
98                 *flags |= f->or;
99                 gotone=TRUE;
100                 break;
101             }
102             f++;
103         }
104         if (*strflags && strflags!= '\0' && gotone==FALSE) {
105             char *temp=strflags;
106             temp += strlen (strflags);
107             *temp++ = ',';
108             *temp++ = '\0';
109         }
110         if (gotone==FALSE) {
111             strcat (strflags, options);
112             gotone=FALSE;
113         }
114         if (comma) {
115             *comma = ',';
116             options = ++comma;
117         } else {
118             break;
119         }
120     }
121 }
122
123 int
124 mount_one (
125            char *blockDevice, char *directory, char *filesystemType,
126            unsigned long flags, char *string_flags)
127 {
128     int status = 0;
129
130     char buf[255];
131
132     if (strcmp(filesystemType, "auto") == 0) {
133         FILE *f = fopen ("/proc/filesystems", "r");
134
135         if (f == NULL)
136             return( FALSE);
137
138         while (fgets (buf, sizeof (buf), f) != NULL) {
139             filesystemType = buf;
140             if (*filesystemType == '\t') {      // Not a nodev filesystem
141
142                 // Add NULL termination to each line
143                 while (*filesystemType && *filesystemType != '\n')
144                     filesystemType++;
145                 *filesystemType = '\0';
146
147                 filesystemType = buf;
148                 filesystemType++;       // hop past tab
149
150                 status = mount (blockDevice, directory, filesystemType,
151                                 flags | MS_MGC_VAL, string_flags);
152                 if (status == 0)
153                     break;
154             }
155         }
156         fclose (f);
157     } else {
158         status = mount (blockDevice, directory, filesystemType,
159                         flags | MS_MGC_VAL, string_flags);
160     }
161
162     if (status) {
163         fprintf (stderr, "Mounting %s on %s failed: %s\n",
164                  blockDevice, directory, strerror(errno));
165         return (FALSE);
166     }
167     return (TRUE);
168 }
169
170 extern int mount_main (int argc, char **argv)
171 {
172     char string_flags[1024]="";
173     unsigned long flags = 0;
174     char *filesystemType = "auto";
175     char *device = NULL;
176     char *directory = NULL;
177     struct stat statBuf;
178     int all = 0;
179     int i;
180
181     if (stat("/etc/fstab", &statBuf) < 0) 
182         fprintf(stderr, "/etc/fstab file missing -- Please install one.\n\n");
183
184     if (argc == 1) {
185         FILE *mountTable;
186         if ((mountTable = setmntent ("/proc/mounts", "r"))) {
187             struct mntent *m;
188             while ((m = getmntent (mountTable)) != 0) {
189                 struct fstab* fstabItem;
190                 char *blockDevice = m->mnt_fsname;
191                 /* Note that if /etc/fstab is missing, libc can't fix up /dev/root for us */
192                 if (strcmp (blockDevice, "/dev/root") == 0) {
193                     fstabItem = getfsfile ("/");
194                     if (fstabItem != NULL)
195                         blockDevice = fstabItem->fs_spec;
196                 }
197                 printf ("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
198                         m->mnt_type, m->mnt_opts);
199             }
200             endmntent (mountTable);
201         }
202         exit( TRUE);
203     }
204
205
206     /* Parse options */
207     i = --argc;
208     argv++;
209     while (i > 0 && **argv) {
210         if (**argv == '-') {
211             while (i>0 && *++(*argv)) switch (**argv) {
212             case 'o':
213                 if (--i == 0) {
214                     fprintf (stderr, "%s\n", mount_usage);
215                     exit( FALSE);
216                 }
217                 parse_mount_options (*(++argv), &flags, string_flags);
218                 --i;
219                 ++argv;
220                 break;
221             case 'r':
222                 flags |= MS_RDONLY;
223                 break;
224             case 't':
225                 if (--i == 0) {
226                     fprintf (stderr, "%s\n", mount_usage);
227                     exit( FALSE);
228                 }
229                 filesystemType = *(++argv);
230                 --i;
231                 ++argv;
232                 break;
233             case 'w':
234                 flags &= ~MS_RDONLY;
235                 break;
236             case 'a':
237                 all = 1;
238                 break;
239             case 'v':
240             case 'h':
241             case '-':
242                 fprintf (stderr, "%s\n", mount_usage);
243                 exit( TRUE);
244                 break;
245             }
246         } else {
247             if (device == NULL)
248                 device=*argv;
249             else if (directory == NULL)
250                 directory=*argv;
251             else {
252                 fprintf (stderr, "%s\n", mount_usage);
253                 exit( TRUE);
254             }
255         }
256         i--;
257         argv++;
258     }
259
260     if (all == 1) {
261         struct mntent *m;
262         FILE *f = setmntent ("/etc/fstab", "r");
263
264         if (f == NULL) {
265             perror("/etc/fstab");
266             exit( FALSE); 
267         }
268         while ((m = getmntent (f)) != NULL) {
269             // If the file system isn't noauto, and isn't mounted on /, mount 
270             // it
271             if ((!strstr (m->mnt_opts, "noauto"))
272                 && (m->mnt_dir[1] != '\0') && !((m->mnt_type[0] == 's')
273                                                 && (m->mnt_type[1] == 'w'))
274                 && !((m->mnt_type[0] == 'n') && (m->mnt_type[1] == 'f'))) {
275                 mount_one (m->mnt_fsname, m->mnt_dir, m->mnt_type, flags,
276                            m->mnt_opts);
277             }
278         }
279         endmntent (f);
280     } else {
281         if (device && directory) {
282             exit (mount_one (device, directory, filesystemType, 
283                         flags, string_flags));
284         } else {
285             fprintf (stderr, "%s\n", mount_usage);
286             exit( FALSE);
287         }
288     }
289     exit( TRUE);
290 }