blob: 010757d1ec5dabb6b1447010ee4a0e7a0de7dbbd [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
2 3/21/1999 Charles P. Wright <cpwright@cpwright.com>
3 searches through fstab when -a is passed
4 will try mounting stuff with all fses when passed -t auto
5
6 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab.
7*/
8
9#include "internal.h"
10#include <stdlib.h>
11#include <unistd.h>
12#include <errno.h>
13#include <string.h>
14#include <stdio.h>
15#include <mntent.h>
16#include <sys/mount.h>
17#include <ctype.h>
18
19const char mount_usage[] = "mount\n"
20"\t\tmount [flags] special-device directory\n"
21"\n"
22"Flags:\n"
23"\t-a:\tMount all file systems in fstab.\n"
24"\t-f:\t\"Fake\" mount. Add entry to mount table but don't mount it.\n"
25"\t-n:\tDon't write a mount table entry.\n"
26"\t-o option:\tOne of many filesystem options, listed below.\n"
27"\t-r:\tMount the filesystem read-only.\n"
28"\t-t filesystem-type:\tSpecify the filesystem type.\n"
29"\t-w:\tMount for reading and writing (default).\n"
30"\n"
31"Options for use with the \"-o\" flag:\n"
32"\tasync / sync:\tWrites are asynchronous / synchronous.\n"
33"\tdev / nodev:\tAllow use of special device files / disallow them.\n"
34"\texec / noexec:\tAllow use of executable files / disallow them.\n"
35"\tsuid / nosuid:\tAllow set-user-id-root programs / disallow them.\n"
36"\tremount: Re-mount a currently-mounted filesystem, changing its flags.\n"
37"\tro / rw: Mount for read-only / read-write.\n"
38"\t"
39"There are EVEN MORE flags that are specific to each filesystem.\n"
40"You'll have to see the written documentation for those.\n";
41
42struct mount_options {
43 const char * name;
44 unsigned long and;
45 unsigned long or;
46};
47
48static const struct mount_options mount_options[] = {
49 { "async", ~MS_SYNCHRONOUS,0 },
50 { "defaults", ~0, 0 },
51 { "dev", ~MS_NODEV, 0 },
52 { "exec", ~MS_NOEXEC, 0 },
53 { "nodev", ~0, MS_NODEV },
54 { "noexec", ~0, MS_NOEXEC },
55 { "nosuid", ~0, MS_NOSUID },
56 { "remount", ~0, MS_REMOUNT },
57 { "ro", ~0, MS_RDONLY },
58 { "rw", ~MS_RDONLY, 0 },
59 { "suid", ~MS_NOSUID, 0 },
60 { "sync", ~0, MS_SYNCHRONOUS },
61 { 0, 0, 0 }
62};
63
64static void
65show_flags(unsigned long flags, char * buffer)
66{
67 const struct mount_options * f = mount_options;
68 while ( f->name ) {
69 if ( flags & f->and ) {
70 int length = strlen(f->name);
71 memcpy(buffer, f->name, length);
72 buffer += length;
73 *buffer++ = ',';
74 *buffer = '\0';
75 }
76 f++;
77 }
78}
79
80static void
81one_option(
82 char * option
83,unsigned long * flags
84,char * data)
85{
86 const struct mount_options * f = mount_options;
87
88 while ( f->name != 0 ) {
89 if ( strcasecmp(f->name, option) == 0 ) {
90 *flags &= f->and;
91 *flags |= f->or;
92 return;
93 }
94 f++;
95 }
96 if ( *data ) {
97 data += strlen(data);
98 *data++ = ',';
99 }
100 strcpy(data, option);
101}
102
103static void
104parse_mount_options(
105 char * options
106,unsigned long * flags
107,char * data)
108{
109 while ( *options ) {
110 char * comma = strchr(options, ',');
111 if ( comma )
112 *comma = '\0';
113 one_option(options, flags, data);
114 if ( comma ) {
115 *comma = ',';
116 options = ++comma;
117 }
118 else
119 break;
120 }
121}
122
123int
124mount_one(
125 char * blockDevice
126,char * directory
127,char * filesystemType
128,unsigned long flags
129,char * string_flags
130,int noMtab
131,int fake)
132{
133 int error = 0;
134 int status = 0;
135
136 char buf[255];
137
138 if (!fake) {
139 if (*filesystemType == 'a') { //Will fail on real FS starting with 'a'
140
141 FILE *f = fopen("/proc/filesystems", "r");
142
143 if (f == NULL) return 1;
144
145 while (fgets(buf, sizeof(buf), f) != NULL) {
146 filesystemType = buf;
147 if (*filesystemType == '\t') { // Not a nodev filesystem
148
149 while (*filesystemType && *filesystemType != '\n') 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 error = errno;
158
159 if (status == 0) break;
160 }
161 }
162 fclose(f);
163 } else {
164
165 status = mount( blockDevice, directory, filesystemType,
166 flags|MS_MGC_VAL ,string_flags);
167 error = errno;
168 }
169 }
170
171 if ( status == 0 ) {
172 char * s = &string_flags[strlen(string_flags)];
173 FILE * mountTable;
174 if ( s != string_flags ) {
175 *s++ = ',';
176 show_flags(flags, s);
177 }
178 if ( !noMtab && (mountTable = setmntent("/etc/mtab", "a+")) ) {
179 int length = strlen(directory);
180 struct mntent m;
181
182 if ( length > 1 && directory[length - 1] == '/' )
183 directory[length - 1] = '\0';
184
185 if ( filesystemType == 0 ) {
186 struct mntent * p
187 = findMountPoint(blockDevice, "/proc/mounts");
188
189 if ( p && p->mnt_type )
190 filesystemType = p->mnt_type;
191 }
192 m.mnt_fsname = blockDevice;
193 m.mnt_dir = directory;
194 m.mnt_type = filesystemType ? filesystemType : "default";
195
196 if (*string_flags) {
197 m.mnt_opts = string_flags;
198 } else {
199 if ( (flags | MS_RDONLY) == flags )
200 m.mnt_opts = "ro";
201 else
202 m.mnt_opts = "rw";
203 }
204
205 m.mnt_freq = 0;
206 m.mnt_passno = 0;
207 addmntent(mountTable, &m);
208 endmntent(mountTable);
209 }
210 return 0;
211 } else {
212 fprintf(stderr, "Mount %s", blockDevice);
213 if ( filesystemType && *filesystemType )
214 fprintf(stderr, " (type %s)", filesystemType);
215
216 fprintf(
217 stderr
218 ," on %s: "
219 ,directory);
220
221 switch ( error ) {
222 case EPERM:
223 if (geteuid() == 0)
224 fprintf(
225 stderr
226 ,"mount point %s is not a directory"
227 ,blockDevice);
228 else
229 fprintf(
230 stderr
231 ,"must be superuser to use mount");
232 break;
233 case EBUSY:
234 fprintf(
235 stderr
236 ,"%s already mounted or %s busy"
237 ,blockDevice
238 ,directory);
239 break;
240 case ENOENT:
241 {
242 struct stat statbuf;
243 if ( stat(directory, &statbuf) != 0 )
244 fprintf(
245 stderr
246 ,"directory %s does not exist"
247 ,directory);
248 else if ( stat(blockDevice, &statbuf) != 0 )
249 fprintf(
250 stderr
251 ,"block device %s does not exist"
252 ,blockDevice);
253 else
254 fprintf(
255 stderr
256 ,"%s is not mounted on %s, but the mount table says it is."
257 ,blockDevice
258 ,directory);
259 break;
260 }
261 case ENOTDIR:
262 fprintf(
263 stderr
264 ,"%s is not a directory"
265 ,directory);
266 break;
267 case EINVAL:
268 fprintf(
269 stderr
270 ,"wrong filesystem type, or bad superblock on %s"
271 ,blockDevice);
272 break;
273 case EMFILE:
274 fprintf(stderr, "mount table full");
275 break;
276 case EIO:
277 fprintf(
278 stderr
279 ,"I/O error reading %s"
280 ,blockDevice);
281 break;
282 case ENODEV:
283 {
284 FILE * f = fopen("/proc/filesystems", "r");
285
286 fprintf(
287 stderr
288 ,"filesystem type %s not in kernel.\n"
289 ,filesystemType);
290 fprintf(stderr, "Do you need to load a module?\n");
291 if ( f ) {
292 char buf[100];
293
294 fprintf(
295 stderr
296 ,"Here are the filesystem types the kernel"
297 " can mount:\n");
298 while ( fgets(buf, sizeof(buf), f) != 0 )
299 fprintf(stderr, "\t%s", buf);
300 fclose(f);
301 }
302 break;
303 }
304 case ENOTBLK:
305 fprintf(
306 stderr
307 ,"%s is not a block device"
308 ,blockDevice);
309 break;
310 case ENXIO:
311 fprintf(
312 stderr
313 ,"%s is not a valid block device"
314 ,blockDevice);
315 break;
316 default:
317 fputs(strerror(errno), stderr);
318 }
319 putc('\n', stderr);
320 return -1;
321 }
322}
323
324extern int
325mount_main(struct FileInfo * i, int argc, char * * argv)
326{
327 char string_flags[1024];
328 unsigned long flags = 0;
329 char * filesystemType = "auto";
330 int fake = 0;
331 int noMtab = 0;
332 int all = 0;
333
334 *string_flags = '\0';
335
336 if ( argc == 1 ) {
337 FILE * mountTable;
338 if ( (mountTable = setmntent("/etc/mtab", "r")) ) {
339 struct mntent * m;
340 while ( (m = getmntent(mountTable)) != 0 ) {
341 printf(
342 "%s on %s type %s (%s)\n"
343 ,m->mnt_fsname
344 ,m->mnt_dir
345 ,m->mnt_type
346 ,m->mnt_opts);
347 }
348 endmntent(mountTable);
349 }
350 return 0;
351 }
352
353 while ( argc >= 2 && argv[1][0] == '-' ) {
354 switch ( argv[1][1] ) {
355 case 'f':
356 fake = 1;
357 break;
358 case 'n':
359 noMtab = 1;
360 break;
361 case 'o':
362 if ( argc < 3 ) {
363 usage(mount_usage);
364 return 1;
365 }
366 parse_mount_options(argv[2], &flags, string_flags);
367 argc--;
368 argv++;
369 break;
370 case 'r':
371 flags |= MS_RDONLY;
372 break;
373 case 't':
374 if ( argc < 3 ) {
375 usage(mount_usage);
376 return 1;
377 }
378 filesystemType = argv[2];
379 argc--;
380 argv++;
381 break;
382 case 'v':
383 break;
384 case 'w':
385 flags &= ~MS_RDONLY;
386 break;
387 case 'a':
388 all = 1;
389 break;
390 default:
391 usage(mount_usage);
392 return 1;
393 }
394 argc--;
395 argv++;
396 }
397
398 if (all == 1) {
399 struct mntent *m;
400 FILE *f = setmntent("/etc/fstab", "r");
401
402 if (f == NULL) {
403 return 1;
404 }
405
406 // FIXME: Combine read routine (make new function) with unmount_all to save space.
407
408 while ((m = getmntent(f)) != NULL) {
409 // If the file system isn't noauto, and isn't mounted on /, mount it
410 if ((!strstr(m->mnt_opts, "noauto")) && (m->mnt_dir[1] != '\0')
411 && !((m->mnt_type[0] == 's') && (m->mnt_type[1] == 'w'))
412 && !((m->mnt_type[0] == 'n') && (m->mnt_type[1] == 'f'))) {
413 mount_one(m->mnt_fsname, m->mnt_dir, m->mnt_type, flags, m->mnt_opts, noMtab, fake);
414 }
415 }
416
417 endmntent(f);
418 } else {
419 if ( argc >= 3 ) {
420 if ( mount_one( argv[1], argv[2], filesystemType, flags, string_flags, noMtab, fake) == 0 )
421 return 0;
422 else
423 return 1;
424 } else {
425 usage(mount_usage);
426 return 1;
427 }
428 }
429 return 0;
430}