]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/mount.cc
* mount.cc (longopts): Fix typo which disallows --options option.
[newlib-cygwin.git] / winsup / utils / mount.cc
1 /* mount.cc
2
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include <stdio.h>
12 #include <sys/mount.h>
13 #include <sys/stat.h>
14 #include <mntent.h>
15 #include <windows.h>
16 #include <sys/cygwin.h>
17 #include <stdlib.h>
18 #include <getopt.h>
19 #include <dirent.h>
20
21 #ifdef errno
22 #undef errno
23 #endif
24 #include <errno.h>
25
26 #define EXEC_FLAGS (MOUNT_EXEC | MOUNT_NOTEXEC | MOUNT_CYGWIN_EXEC)
27
28 static void mount_commands (void);
29 static void show_mounts (void);
30 static void show_cygdrive_info (void);
31 static void change_cygdrive_prefix (const char *new_prefix, int flags);
32 static int mount_already_exists (const char *posix_path, int flags);
33
34 // static short create_missing_dirs = FALSE;
35 static short force = FALSE;
36
37 static const char version[] = "$Revision$";
38 static const char *progname;
39
40 static void
41 error (const char *path)
42 {
43 fprintf (stderr, "%s: %s: %s\n", progname, path,
44 (errno == EMFILE) ? "Too many mount entries" : strerror (errno));
45 exit (1);
46 }
47
48 /* FIXME: do_mount should also print a warning message if the dev arg
49 is a non-existent Win32 path. */
50
51 static void
52 do_mount (const char *dev, const char *where, int flags)
53 {
54 struct stat statbuf;
55 char win32_path[MAX_PATH];
56 int statres;
57
58 cygwin_conv_to_win32_path (where, win32_path);
59
60 statres = stat (win32_path, &statbuf);
61
62 #if 0
63 if (statres == -1)
64 {
65 /* FIXME: this'll fail if mount dir is missing any parent dirs */
66 if (create_missing_dirs == TRUE)
67 {
68 if (mkdir (where, 0755) == -1)
69 fprintf (stderr, "Warning: unable to create %s!\n", where);
70 else
71 statres = 0; /* Pretend stat succeeded if we could mkdir. */
72 }
73 }
74 #endif
75
76 if (statres == -1)
77 {
78 if (!force)
79 fprintf (stderr, "%s: warning - %s does not exist.\n", progname, where);
80 }
81 else if (!(statbuf.st_mode & S_IFDIR))
82 {
83 if (!force)
84 fprintf (stderr, "%s: warning: %s is not a directory.\n", progname, where);
85 }
86
87 if (!force && !(flags & EXEC_FLAGS) && strlen (dev))
88 {
89 char devtmp[1 + 2 * strlen (dev)];
90 strcpy (devtmp, dev);
91 char c = strchr (devtmp, '\0')[-1];
92 if (c == '/' || c == '\\')
93 strcat (devtmp, ".");
94 /* Use a curious property of Windows which allows the use of \.. even
95 on non-directory paths. */
96 for (const char *p = dev; (p = strpbrk (p, "/\\")); p++)
97 strcat (devtmp, "\\..");
98 strcat (devtmp, "\\");
99 if (GetDriveType (devtmp) == DRIVE_REMOTE)
100 {
101 fprintf (stderr, "%s: defaulting to '--no-executable' flag for speed since native path\n"
102 "%*creferences a remote share. Use '-f' option to override.\n", progname,
103 strlen(progname) + 2, ' ');
104 flags |= MOUNT_NOTEXEC;
105 }
106 }
107
108 if (!force && flags & MOUNT_ENC)
109 {
110 DIR *dd = opendir (dev);
111 if (dd)
112 {
113 struct dirent *d;
114 while ((d = readdir (dd)))
115 {
116 if (d->d_name[0] != '.')
117 /* fall through */;
118 else if (d->d_name[1] == '\0'
119 || (d->d_name[1] == '.' && d->d_name[2] == '\0'))
120 continue;
121 fprintf (stderr, "%s: error: don't use \"-o managed\" on non-empty directories\n", progname);
122 exit (1);
123 }
124 }
125 }
126
127 if (mount (dev, where, flags))
128 error (where);
129
130 exit (0);
131 }
132
133 static struct option longopts[] =
134 {
135 {"binary", no_argument, NULL, 'b'},
136 {"change-cygdrive-prefix", no_argument, NULL, 'c'},
137 {"cygwin-executable", no_argument, NULL, 'X'},
138 {"executable", no_argument, NULL, 'x'},
139 {"force", no_argument, NULL, 'f'},
140 {"help", no_argument, NULL, 'h' },
141 {"mount-commands", no_argument, NULL, 'm'},
142 {"no-executable", no_argument, NULL, 'E'},
143 {"options", required_argument, NULL, 'o'},
144 {"show-cygdrive-prefix", no_argument, NULL, 'p'},
145 {"system", no_argument, NULL, 's'},
146 {"text", no_argument, NULL, 't'},
147 {"user", no_argument, NULL, 'u'},
148 {"version", no_argument, NULL, 'v'},
149 {NULL, 0, NULL, 0}
150 };
151
152 static char opts[] = "bcfhmpstuvxEXo:";
153
154 static void
155 usage (FILE *where = stderr)
156 {
157 fprintf (where, "Usage: %s [OPTION] [<win32path> <posixpath>]\n\
158 Display information about mounted filesystems, or mount a filesystem\n\
159 \n\
160 -b, --binary (default) text files are equivalent to binary files\n\
161 (newline = \\n)\n\
162 -c, --change-cygdrive-prefix change the cygdrive path prefix to <posixpath>\n\
163 -f, --force force mount, don't warn about missing mount\n\
164 point directories\n\
165 -h, --help output usage information and exit\n\
166 -m, --mount-commands write mount commands to replicate user and\n\
167 system mount points and cygdrive prefixes\n\
168 -o, --options X[,X...] specify mount options\n\
169 -p, --show-cygdrive-prefix show user and/or system cygdrive path prefix\n\
170 -s, --system (default) add system-wide mount point\n\
171 -t, --text text files get \\r\\n line endings\n\
172 -u, --user add user-only mount point\n\
173 -v, --version output version information and exit\n\
174 -x, --executable treat all files under mount point as executables\n\
175 -E, --no-executable treat all files under mount point as \n\
176 non-executables\n\
177 -X, --cygwin-executable treat all files under mount point as cygwin\n\
178 executables\n\
179 ", progname);
180 exit (where == stderr ? 1 : 0);
181 }
182
183 struct opt
184 {
185 const char *name;
186 unsigned val;
187 bool clear;
188 } oopts[] =
189 {
190 {"user", MOUNT_SYSTEM, 1},
191 {"system", MOUNT_SYSTEM, 0},
192 {"binary", MOUNT_BINARY, 0},
193 {"text", MOUNT_BINARY, 1},
194 {"exec", MOUNT_EXEC, 0},
195 {"notexec", MOUNT_NOTEXEC, 0},
196 {"cygexec", MOUNT_CYGWIN_EXEC, 0},
197 {"nosuid", 0, 0},
198 {"managed", MOUNT_ENC, 0}
199 };
200
201 static void
202 print_version ()
203 {
204 const char *v = strchr (version, ':');
205 int len;
206 if (!v)
207 {
208 v = "?";
209 len = 1;
210 }
211 else
212 {
213 v += 2;
214 len = strchr (v, ' ') - v;
215 }
216 printf ("\
217 %s (cygwin) %.*s\n\
218 Filesystem Utility\n\
219 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.\n\
220 Compiled on %s\n\
221 ", progname, len, v, __DATE__);
222 }
223
224 static char *
225 concat3 (char *a, const char *b, const char *c)
226 {
227 size_t totlen = strlen (a) + strlen (b) + strlen (c) + 1;
228 a = (char *) realloc (a, totlen);
229 return strcat (strcat (a, b), c);
230 }
231
232 int
233 main (int argc, char **argv)
234 {
235 int i;
236 int flags = MOUNT_BINARY;
237 int default_flag = MOUNT_SYSTEM;
238 char *options = strdup ("");
239 enum do_what
240 {
241 nada,
242 saw_change_cygdrive_prefix,
243 saw_show_cygdrive_prefix,
244 saw_mount_commands
245 } do_what = nada;
246
247 progname = strrchr (argv[0], '/');
248 if (progname == NULL)
249 progname = strrchr (argv[0], '\\');
250 if (progname == NULL)
251 progname = argv[0];
252 else
253 progname++;
254
255 if (argc == 1)
256 {
257 show_mounts ();
258 exit (0);
259 }
260
261 while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
262 switch (i)
263 {
264 case 'b':
265 flags |= MOUNT_BINARY;
266 break;
267 case 'c':
268 if (do_what == nada)
269 do_what = saw_change_cygdrive_prefix;
270 else
271 usage ();
272 break;
273 case 'f':
274 force = TRUE;
275 break;
276 case 'h':
277 usage (stdout);
278 break;
279 case 'm':
280 if (do_what == nada)
281 do_what = saw_mount_commands;
282 else
283 usage ();
284 break;
285 case 'o':
286 if (*options)
287 options = concat3 (options, ",", optarg);
288 else
289 options = strdup (optarg);
290 break;
291 case 'p':
292 if (do_what == nada)
293 do_what = saw_show_cygdrive_prefix;
294 else
295 usage ();
296 break;
297 case 's':
298 flags |= MOUNT_SYSTEM;
299 break;
300 case 't':
301 flags &= ~MOUNT_BINARY;
302 break;
303 case 'u':
304 flags &= ~MOUNT_SYSTEM;
305 default_flag = 0;
306 break;
307 case 'v':
308 print_version ();
309 return 0;
310 break;
311 case 'x':
312 flags |= MOUNT_EXEC;
313 break;
314 case 'E':
315 flags |= MOUNT_NOTEXEC;
316 break;
317 case 'X':
318 flags |= MOUNT_CYGWIN_EXEC;
319 break;
320 default:
321 usage ();
322 }
323
324 while (*options)
325 {
326 char *p = strchr (options, ',');
327 if (p)
328 *p++ = '\0';
329 else
330 p = strchr (options, '\0');
331
332 for (opt *o = oopts; o < (oopts + (sizeof (oopts) / sizeof (oopts[0]))); o++)
333 if (strcmp (options, o->name) == 0)
334 {
335 if (o->clear)
336 flags &= ~o->val;
337 else
338 flags |= o->val;
339 goto gotit;
340 }
341 fprintf (stderr, "%s: invalid option - '%s'\n", progname, options);
342 exit (1);
343
344 gotit:
345 options = p;
346 }
347
348 if (flags & MOUNT_NOTEXEC && flags & (MOUNT_EXEC | MOUNT_CYGWIN_EXEC))
349 {
350 fprintf (stderr, "%s: invalid combination of executable options\n", progname);
351 exit (1);
352 }
353
354 argc--;
355 switch (do_what)
356 {
357 case saw_change_cygdrive_prefix:
358 if (optind != argc)
359 usage ();
360 change_cygdrive_prefix (argv[optind], flags | default_flag);
361 break;
362 case saw_show_cygdrive_prefix:
363 if (optind <= argc)
364 usage ();
365 show_cygdrive_info ();
366 break;
367 case saw_mount_commands:
368 if (optind <= argc)
369 usage ();
370 mount_commands ();
371 break;
372 default:
373 if (optind != (argc - 1))
374 {
375 if (optind >= argc)
376 fprintf (stderr, "%s: not enough arguments\n", progname);
377 else
378 fprintf (stderr, "%s: too many arguments\n", progname);
379 usage ();
380 }
381 if (force || !mount_already_exists (argv[optind + 1], flags | default_flag))
382 do_mount (argv[optind], argv[optind + 1], flags | default_flag);
383 else
384 {
385 errno = EBUSY;
386 error (argv[optind + 1]);
387 }
388 }
389
390 /* NOTREACHED */
391 return 0;
392 }
393
394 static void
395 mount_commands (void)
396 {
397 FILE *m = setmntent ("/-not-used-", "r");
398 struct mntent *p;
399 char *c;
400 const char *format_mnt = "mount%s \"%s\" \"%s\"\n";
401 const char *format_cyg = "mount%s --change-cygdrive-prefix \"%s\"\n";
402 char opts[MAX_PATH];
403 char user[MAX_PATH];
404 char system[MAX_PATH];
405 char user_flags[MAX_PATH];
406 char system_flags[MAX_PATH];
407
408 // write mount commands for user and system mount points
409 while ((p = getmntent (m)) != NULL)
410 // Only list non-cygdrives
411 if (!strstr (p->mnt_opts, ",noumount"))
412 {
413 strcpy(opts, " -f");
414 if (p->mnt_type[0] == 'u')
415 strcat (opts, " -u");
416 else if (p->mnt_type[0] == 's')
417 strcat (opts, " -s");
418 if (p->mnt_opts[0] == 'b')
419 strcat (opts, " -b");
420 else if (p->mnt_opts[0] == 't')
421 strcat (opts, " -t");
422 if (strstr (p->mnt_opts, ",exec"))
423 strcat (opts, " -x");
424 if (strstr (p->mnt_opts, ",noexec"))
425 strcat (opts, " -E");
426 if (strstr (p->mnt_opts, ",cygexec"))
427 strcat (opts, " -X");
428 if (strstr (p->mnt_opts, ",managed"))
429 strcat (opts, " -o managed");
430 while ((c = strchr (p->mnt_fsname, '\\')) != NULL)
431 *c = '/';
432 printf (format_mnt, opts, p->mnt_fsname, p->mnt_dir);
433 }
434 endmntent (m);
435
436 // write mount commands for cygdrive prefixes
437 cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags,
438 system_flags);
439
440 if (strlen (user) > 0)
441 {
442 strcpy (opts, " -u");
443 if (user_flags[0] == 'b')
444 strcat (opts, " -b");
445 else if (user_flags[0] == 't')
446 strcat (opts, " -t");
447 printf (format_cyg, opts, user);
448 }
449
450 if (strlen (system) > 0)
451 {
452 strcpy (opts, " -s");
453 if (system_flags[0] == 'b')
454 strcat (opts, " -b");
455 else if (system_flags[0] == 't')
456 strcat (opts, " -t");
457 printf (format_cyg, opts, system);
458 }
459
460 exit(0);
461 }
462
463 static void
464 show_mounts (void)
465 {
466 FILE *m = setmntent ("/-not-used-", "r");
467 struct mntent *p;
468 const char *format = "%s on %s type %s (%s)\n";
469
470 // printf (format, "Device", "Directory", "Type", "Flags");
471 while ((p = getmntent (m)) != NULL)
472 printf (format, p->mnt_fsname, p->mnt_dir, p->mnt_type, p->mnt_opts);
473 endmntent (m);
474 }
475
476 /* Return 1 if mountpoint from the same registry area is already in
477 mount table. Otherwise return 0. */
478 static int
479 mount_already_exists (const char *posix_path, int flags)
480 {
481 int found_matching = 0;
482
483 FILE *m = setmntent ("/-not-used-", "r");
484 struct mntent *p;
485
486 while ((p = getmntent (m)) != NULL)
487 {
488 /* if the paths match, and they're both the same type of mount. */
489 if (strcmp (p->mnt_dir, posix_path) == 0)
490 {
491 if (p->mnt_type[0] == 'u')
492 {
493 if (!(flags & MOUNT_SYSTEM)) /* both current_user */
494 found_matching = 1;
495 else
496 fprintf (stderr,
497 "%s: warning: system mount point of '%s' "
498 "will always be masked by user mount.\n",
499 progname, posix_path);
500 break;
501 }
502 else if (p->mnt_type[0] == 's')
503 {
504 if (flags & MOUNT_SYSTEM) /* both system */
505 found_matching = 1;
506 else
507 fprintf (stderr,
508 "%s: warning: user mount point of '%s' "
509 "masks system mount.\n",
510 progname, posix_path);
511 break;
512 }
513 else
514 {
515 fprintf (stderr, "%s: warning: couldn't determine mount type.\n", progname);
516 break;
517 }
518 }
519 }
520 endmntent (m);
521
522 return found_matching;
523 }
524
525 /* change_cygdrive_prefix: Change the cygdrive prefix */
526 static void
527 change_cygdrive_prefix (const char *new_prefix, int flags)
528 {
529 flags |= MOUNT_CYGDRIVE;
530
531 if (mount (NULL, new_prefix, flags))
532 error (new_prefix);
533
534 exit (0);
535 }
536
537 /* show_cygdrive_info: Show the user and/or cygdrive info, i.e., prefix and
538 flags.*/
539 static void
540 show_cygdrive_info ()
541 {
542 /* Get the cygdrive info */
543 char user[MAX_PATH];
544 char system[MAX_PATH];
545 char user_flags[MAX_PATH];
546 char system_flags[MAX_PATH];
547 cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags,
548 system_flags);
549
550 /* Display the user and system cygdrive path prefix, if necessary
551 (ie, not empty) */
552 const char *format = "%-18s %-11s %s\n";
553 printf (format, "Prefix", "Type", "Flags");
554 if (strlen (user) > 0)
555 printf (format, user, "user", user_flags);
556 if (strlen (system) > 0)
557 printf (format, system, "system", system_flags);
558
559 exit (0);
560 }
This page took 0.057215 seconds and 6 git commands to generate.