]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/mount.cc
Update copyrights
[newlib-cygwin.git] / winsup / utils / mount.cc
1 /* mount.cc
2
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
4 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include <stdio.h>
13 #include <sys/mount.h>
14 #include <sys/stat.h>
15 #include <mntent.h>
16 #include <windows.h>
17 #include <sys/cygwin.h>
18 #include <cygwin/version.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <dirent.h>
23 #include "path.h"
24
25 #ifdef errno
26 #undef errno
27 #endif
28 #include <errno.h>
29
30 #define NT_MAX_PATH 32768
31
32 #define EXEC_FLAGS (MOUNT_EXEC | MOUNT_NOTEXEC | MOUNT_CYGWIN_EXEC)
33
34 static void mount_entries (void);
35 static void show_mounts (void);
36 static void show_cygdrive_info (void);
37 static void change_cygdrive_prefix (const char *new_prefix, int flags);
38 static int mount_already_exists (const char *posix_path, int flags);
39
40 // static short create_missing_dirs = FALSE;
41 static bool force = false;
42
43 static const char *progname;
44
45 static void
46 error (const char *path)
47 {
48 fprintf (stderr, "%s: %s: %s\n", progname, path,
49 (errno == EMFILE) ? "Too many mount entries" : strerror (errno));
50 exit (1);
51 }
52
53 /* FIXME: do_mount should also print a warning message if the dev arg
54 is a non-existent Win32 path. */
55
56 static void
57 do_mount (const char *dev, const char *where, int flags)
58 {
59 struct stat statbuf;
60 int statres;
61
62 statres = stat (where, &statbuf);
63
64 #if 0
65 if (statres == -1)
66 {
67 /* FIXME: this'll fail if mount dir is missing any parent dirs */
68 if (create_missing_dirs == TRUE)
69 {
70 if (mkdir (where, 0755) == -1)
71 fprintf (stderr, "Warning: unable to create %s!\n", where);
72 else
73 statres = 0; /* Pretend stat succeeded if we could mkdir. */
74 }
75 }
76 #endif
77
78 if (statres == -1)
79 {
80 if (!force)
81 fprintf (stderr, "%s: warning - %s does not exist.\n", progname, where);
82 }
83 else if (!(statbuf.st_mode & S_IFDIR))
84 {
85 if (!force)
86 fprintf (stderr, "%s: warning: %s is not a directory.\n",
87 progname, where);
88 }
89
90 if (!force && !(flags & (EXEC_FLAGS | MOUNT_BIND)) && strlen (dev))
91 {
92 char devtmp[1 + 2 * strlen (dev)];
93 strcpy (devtmp, dev);
94 char c = strchr (devtmp, '\0')[-1];
95 if (c == '/' || c == '\\')
96 strcat (devtmp, ".");
97 /* Use a curious property of Windows which allows the use of \.. even
98 on non-directory paths. */
99 for (const char *p = dev; (p = strpbrk (p, "/\\")); p++)
100 strcat (devtmp, "\\..");
101 strcat (devtmp, "\\");
102 if (GetDriveType (devtmp) == DRIVE_REMOTE)
103 {
104 fprintf (stderr,
105 "%s: defaulting to 'notexec' mount option for speed since native path\n"
106 "%*creferences a remote share. Use '-f' option to override.\n",
107 progname, strlen(progname) + 2, ' ');
108 flags |= MOUNT_NOTEXEC;
109 }
110 }
111
112 if (mount (dev, where, flags))
113 error (where);
114 }
115
116 static void
117 from_fstab (bool user)
118 {
119 char path[PATH_MAX];
120 char buf[65536];
121 mnt_t *m = mount_table + max_mount_entry;
122
123 strcpy (path, "/etc/fstab");
124 if (user)
125 {
126 strcat (path, ".d/");
127 strcat (path, getlogin ());
128 }
129 FILE *fh = fopen (path, "rt");
130 if (!fh)
131 return;
132 while (fgets (buf, 65536, fh))
133 {
134 char *c = strrchr (buf, '\n');
135 if (c)
136 *c = '\0';
137 if (from_fstab_line (m, buf, user))
138 ++m;
139 }
140 max_mount_entry = m - mount_table;
141 fclose (fh);
142 }
143
144 static void
145 do_mount_from_fstab (const char *where)
146 {
147 force = true;
148 /* Read fstab entries. */
149 from_fstab (false);
150 from_fstab (true);
151 /* Loop through fstab entries and see if it matches `where'. If `where'
152 is NULL, all entries match. */
153 bool exists = false;
154 for (mnt_t *m = mount_table; m - mount_table < max_mount_entry; ++m)
155 if (!where || !strcmp (where, m->posix))
156 {
157 if (m->flags & MOUNT_CYGDRIVE)
158 {
159 /* Get the cygdrive info */
160 char user[MAX_PATH];
161 char system[MAX_PATH];
162 char user_flags[MAX_PATH];
163 char system_flags[MAX_PATH];
164
165 exists = true;
166 cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags,
167 system_flags);
168 if ((*user && strcmp (user, m->posix) != 0)
169 || (*system && strcmp (system, m->posix) != 0))
170 if (mount (NULL, m->posix, m->flags))
171 error (m->posix);
172 }
173 else
174 {
175 exists = true;
176 /* Compare with existing mount table. If the entry doesn't exist,
177 mount it. */
178 FILE *mt = setmntent ("/-not-used-", "r");
179 struct mntent *p;
180
181 while ((p = getmntent (mt)) != NULL)
182 if (!strcmp (m->posix, p->mnt_dir))
183 break;
184 if (!p)
185 do_mount (m->native, m->posix, m->flags);
186 endmntent (mt);
187 if (where)
188 break;
189 }
190 }
191 if (!exists && where)
192 fprintf (stderr,
193 "%s: can't find %s in /etc/fstab or in /etc/fstab.d/$USER\n",
194 progname, where);
195 }
196
197 static struct option longopts[] =
198 {
199 {"all", no_argument, NULL, 'a'},
200 {"change-cygdrive-prefix", no_argument, NULL, 'c'},
201 {"force", no_argument, NULL, 'f'},
202 {"help", no_argument, NULL, 'h' },
203 {"mount-entries", no_argument, NULL, 'm'},
204 {"options", required_argument, NULL, 'o'},
205 {"show-cygdrive-prefix", no_argument, NULL, 'p'},
206 {"version", no_argument, NULL, 'V'},
207 {NULL, 0, NULL, 0}
208 };
209
210 static char opts[] = "acfhmpVo:";
211
212 static void
213 usage (FILE *where = stderr)
214 {
215 char *options;
216
217 fprintf (where, "Usage: %1$s [OPTION] [<win32path> <posixpath>]\n\
218 %1$s -a\n\
219 %1$s <posixpath>\n\
220 \n\
221 Display information about mounted filesystems, or mount a filesystem\n\
222 \n\
223 -a, --all mount all filesystems mentioned in fstab\n\
224 -c, --change-cygdrive-prefix change the cygdrive path prefix to <posixpath>\n\
225 -f, --force force mount, don't warn about missing mount\n\
226 point directories\n\
227 -h, --help output usage information and exit\n\
228 -m, --mount-entries write fstab entries to replicate mount points\n\
229 and cygdrive prefixes\n\
230 -o, --options X[,X...] specify mount options\n\
231 -p, --show-cygdrive-prefix show user and/or system cygdrive path prefix\n\
232 -V, --version output version information and exit\n\n",
233 progname);
234 if (!cygwin_internal (CW_LST_MNT_OPTS, &options))
235 fprintf (where, "Valid options are: %s\n\n", options);
236 exit (where == stderr ? 1 : 0);
237 }
238
239 static void
240 print_version ()
241 {
242 printf ("mount (cygwin) %d.%d.%d\n"
243 "Mount filesystem utility\n"
244 "Copyright (C) 1996 - %s Red Hat, Inc.\n"
245 "This is free software; see the source for copying conditions. There is NO\n"
246 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
247 CYGWIN_VERSION_DLL_MAJOR / 1000,
248 CYGWIN_VERSION_DLL_MAJOR % 1000,
249 CYGWIN_VERSION_DLL_MINOR,
250 strrchr (__DATE__, ' ') + 1);
251 }
252
253 static char *
254 concat3 (char *a, const char *b, const char *c)
255 {
256 size_t totlen = strlen (a) + strlen (b) + strlen (c) + 1;
257 a = (char *) realloc (a, totlen);
258 return strcat (strcat (a, b), c);
259 }
260
261 int
262 main (int argc, char **argv)
263 {
264 int i;
265 int flags = MOUNT_BINARY;
266 char *options = strdup ("");
267 enum do_what
268 {
269 nada,
270 saw_change_cygdrive_prefix,
271 saw_show_cygdrive_prefix,
272 saw_mount_commands,
273 saw_mount_all,
274 } do_what = nada;
275
276 progname = program_invocation_short_name;
277
278 if (argc == 1)
279 {
280 show_mounts ();
281 exit (0);
282 }
283
284 while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
285 switch (i)
286 {
287 case 'a':
288 if (do_what == nada)
289 do_what = saw_mount_all;
290 else
291 usage ();
292 break;
293 case 'c':
294 if (do_what == nada)
295 do_what = saw_change_cygdrive_prefix;
296 else
297 usage ();
298 break;
299 case 'f':
300 force = true;
301 break;
302 case 'h':
303 usage (stdout);
304 break;
305 case 'm':
306 if (do_what == nada)
307 do_what = saw_mount_commands;
308 else
309 usage ();
310 break;
311 case 'o':
312 if (do_what == saw_mount_all)
313 usage ();
314 else if (*options)
315 options = concat3 (options, ",", optarg);
316 else
317 options = strdup (optarg);
318 break;
319 case 'p':
320 if (do_what == nada)
321 do_what = saw_show_cygdrive_prefix;
322 else
323 usage ();
324 break;
325 case 'V':
326 print_version ();
327 return 0;
328 break;
329 default:
330 fprintf (stderr, "Try `%s --help' for more information.\n", progname);
331 return 1;
332 }
333
334 if (cygwin_internal (CW_CVT_MNT_OPTS, &options, &flags))
335 {
336 fprintf (stderr, "%s: invalid option - '%s'\n", progname, options);
337 exit (1);
338 }
339
340 if (flags & MOUNT_NOTEXEC && flags & (MOUNT_EXEC | MOUNT_CYGWIN_EXEC))
341 {
342 fprintf (stderr, "%s: invalid combination of executable options\n",
343 progname);
344 exit (1);
345 }
346
347 cygwin_internal (CW_SET_DOS_FILE_WARNING, false);
348
349 argc--;
350 switch (do_what)
351 {
352 case saw_change_cygdrive_prefix:
353 if (optind != argc)
354 usage ();
355 change_cygdrive_prefix (argv[optind], flags);
356 break;
357 case saw_show_cygdrive_prefix:
358 if (optind <= argc)
359 usage ();
360 show_cygdrive_info ();
361 break;
362 case saw_mount_commands:
363 if (optind <= argc)
364 usage ();
365 mount_entries ();
366 break;
367 case saw_mount_all:
368 if (optind <= argc)
369 usage ();
370 do_mount_from_fstab (NULL);
371 break;
372 default:
373 if (optind == argc)
374 do_mount_from_fstab (argv[optind]);
375 else if (optind != (argc - 1))
376 {
377 fprintf (stderr, "%s: too many arguments\n", progname);
378 usage ();
379 }
380 else if (force || !mount_already_exists (argv[optind + 1], flags))
381 do_mount (argv[optind], argv[optind + 1], flags);
382 else
383 {
384 errno = EBUSY;
385 error (argv[optind + 1]);
386 }
387 }
388
389 /* NOTREACHED */
390 return 0;
391 }
392
393 static char *
394 convert_spaces (char *tgt, const char *src)
395 {
396 char *tp, *spacep;
397 const char *sp;
398
399 tp = tgt;
400 for (sp = src; (spacep = strchr (sp, ' ')); sp = spacep + 1)
401 {
402 tp = stpncpy (tp, sp, spacep - sp);
403 tp = stpcpy (tp, "\\040");
404 }
405 stpcpy (tp, sp);
406 return tgt;
407 }
408
409 static void
410 mount_entries (void)
411 {
412 FILE *m = setmntent ("/-not-used-", "r");
413 struct mntent *p;
414 const char *format_mnt = "%s %s %s %s 0 0\n";
415 const char *format_cyg = "none %s cygdrive %s 0 0\n";
416
417 // write fstab entries for normal mount points
418 while ((p = getmntent (m)) != NULL)
419 // Only list non-cygdrives and non-automounts
420 if (!strstr (p->mnt_opts, ",noumount") && !strstr (p->mnt_opts, ",auto"))
421 {
422 char fsname[NT_MAX_PATH], dirname[NT_MAX_PATH];
423 /* Drop the "bind" option since it can't be reverted. */
424 char *c = strstr (p->mnt_opts, ",bind");
425 if (c)
426 memmove (c, c + 5, strlen (c + 5) + 1);
427 printf (format_mnt, convert_spaces (fsname, p->mnt_fsname),
428 convert_spaces (dirname, p->mnt_dir),
429 p->mnt_type, p->mnt_opts);
430 }
431 endmntent (m);
432
433 // write fstab entry for cygdrive prefix
434 m = setmntent ("/-not-used-", "r");
435 while ((p = getmntent (m)) != NULL)
436 {
437 char *noumount;
438 if ((noumount = strstr (p->mnt_opts, ",noumount")))
439 {
440 char dirname[NT_MAX_PATH];
441 char opts[strlen (p->mnt_opts) + 1];
442
443 convert_spaces (dirname, p->mnt_dir);
444 // remove trailing slash
445 char *ls = strrchr (dirname, '/');
446 if (ls)
447 {
448 // last slash == leading slash? cygdrive prefix == "/"
449 if (ls == dirname)
450 ++ls;
451 *ls = '\0';
452 }
453 *stpncpy (opts, p->mnt_opts, noumount - p->mnt_opts) = '\0';
454 printf (format_cyg, dirname, opts);
455 break;
456 }
457 }
458 endmntent (m);
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", progname, posix_path);
510 break;
511 }
512 else
513 {
514 fprintf (stderr, "%s: warning: couldn't determine mount type.\n",
515 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, "nouser", system_flags);
558
559 exit (0);
560 }
This page took 0.05954 seconds and 6 git commands to generate.