]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/fstab.c
1 /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
2 * - added Native Language Support
3 * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
4 * - fixed strerr(errno) in gettext calls
14 #include "sundries.h" /* for xmalloc() etc */
17 #define streq(s, t) (strcmp ((s), (t)) == 0)
19 #define PROC_MOUNTS "/proc/mounts"
22 /* Information about mtab. ------------------------------------*/
23 static int have_mtab_info
= 0;
24 static int var_mtab_does_not_exist
= 0;
25 static int var_mtab_is_a_symlink
= 0;
29 struct stat mtab_stat
;
31 if (!have_mtab_info
) {
32 if (lstat(MOUNTED
, &mtab_stat
))
33 var_mtab_does_not_exist
= 1;
34 else if (S_ISLNK(mtab_stat
.st_mode
))
35 var_mtab_is_a_symlink
= 1;
41 mtab_does_not_exist(void) {
43 return var_mtab_does_not_exist
;
47 mtab_is_a_symlink(void) {
49 return var_mtab_is_a_symlink
;
56 /* Should we write to /etc/mtab upon an update?
57 Probably not if it is a symlink to /proc/mounts, since that
58 would create a file /proc/mounts in case the proc filesystem
60 if (mtab_is_a_symlink())
64 int fd
= open(MOUNTED
, O_RDWR
| O_CREAT
, 0644);
74 /* Contents of mtab and fstab ---------------------------------*/
76 struct mntentchn mounttable
, fstab
;
77 static int got_mtab
= 0;
78 static int got_fstab
= 0;
80 static void read_mounttable(void), read_fstab(void);
97 read_mntentchn(mntFILE
*mfp
, const char *fnam
, struct mntentchn
*mc0
) {
98 struct mntentchn
*mc
= mc0
;
101 while ((mnt
= my_getmntent (mfp
)) != NULL
) {
102 if (!streq (mnt
->mnt_type
, MNTTYPE_IGNORE
)) {
103 mc
->nxt
= (struct mntentchn
*) xmalloc(sizeof(*mc
));
106 mc
->mnt_fsname
= mnt
->mnt_fsname
;
107 mc
->mnt_dir
= mnt
->mnt_dir
;
108 mc
->mnt_type
= mnt
->mnt_type
;
109 mc
->mnt_opts
= mnt
->mnt_opts
;
114 if (ferror (mfp
->mntent_fp
)) {
116 error(_("warning: error reading %s: %s"), fnam
, strerror (errsv
));
117 mc0
->nxt
= mc0
->prev
= NULL
;
123 * Read /etc/mtab. If that fails, try /proc/mounts.
124 * This produces a linked list. The list head mounttable is a dummy.
125 * Return 0 on success.
131 struct mntentchn
*mc
= &mounttable
;
134 mc
->nxt
= mc
->prev
= NULL
;
137 mfp
= my_setmntent (fnam
, "r");
138 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
141 mfp
= my_setmntent (fnam
, "r");
142 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
143 error(_("warning: can't open %s: %s"), MOUNTED
, strerror (errsv
));
147 printf (_("mount: could not open %s - using %s instead\n"),
148 MOUNTED
, PROC_MOUNTS
);
150 read_mntentchn(mfp
, fnam
, mc
);
157 struct mntentchn
*mc
= &fstab
;
160 mc
->nxt
= mc
->prev
= NULL
;
163 mfp
= my_setmntent (fnam
, "r");
164 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
166 error(_("warning: can't open %s: %s"), _PATH_FSTAB
, strerror (errsv
));
169 read_mntentchn(mfp
, fnam
, mc
);
173 /* Given the name NAME, try to find it in mtab. */
175 getmntfile (const char *name
) {
176 struct mntentchn
*mc
;
178 for (mc
= mtab_head()->nxt
; mc
; mc
= mc
->nxt
)
179 if (streq (mc
->mnt_dir
, name
) || (streq (mc
->mnt_fsname
, name
)))
186 * Given the name NAME, and the place MCPREV we found it last time,
187 * try to find more occurrences.
190 getmntfilesbackward (const char *name
, struct mntentchn
*mcprev
) {
191 struct mntentchn
*mc
, *mh
;
196 for (mc
= mcprev
->prev
; mc
&& mc
!= mh
; mc
= mc
->prev
)
197 if (streq (mc
->mnt_dir
, name
) || (streq (mc
->mnt_fsname
, name
)))
203 /* Given the name FILE, try to find the option "loop=FILE" in mtab. */
205 getmntoptfile (const char *file
)
207 struct mntentchn
*mc
;
216 for (mc
= mtab_head()->nxt
; mc
; mc
= mc
->nxt
)
217 if ((opts
= mc
->mnt_opts
) != NULL
218 && (s
= strstr(opts
, "loop="))
219 && !strncmp(s
+5, file
, l
)
220 && (s
== opts
|| s
[-1] == ',')
221 && (s
[l
+5] == 0 || s
[l
+5] == ','))
227 /* Find the dir FILE in fstab. */
229 getfsfile (const char *file
) {
230 struct mntentchn
*mc
;
232 for (mc
= fstab_head()->nxt
; mc
; mc
= mc
->nxt
)
233 if (streq (mc
->mnt_dir
, file
))
239 /* Find the device SPEC in fstab. */
241 getfsspec (const char *spec
)
243 struct mntentchn
*mc
;
245 for (mc
= fstab_head()->nxt
; mc
; mc
= mc
->nxt
)
246 if (streq (mc
->mnt_fsname
, spec
))
252 /* Find the uuid UUID in fstab. */
254 getfsuuidspec (const char *uuid
)
256 struct mntentchn
*mc
;
258 for (mc
= fstab_head()->nxt
; mc
; mc
= mc
->nxt
)
259 if (strncmp (mc
->mnt_fsname
, "UUID=", 5) == 0
260 && streq(mc
->mnt_fsname
+ 5, uuid
))
266 /* Find the label LABEL in fstab. */
268 getfsvolspec (const char *label
)
270 struct mntentchn
*mc
;
272 for (mc
= fstab_head()->nxt
; mc
; mc
= mc
->nxt
)
273 if (strncmp (mc
->mnt_fsname
, "LABEL=", 6) == 0
274 && streq(mc
->mnt_fsname
+ 6, label
))
280 /* Updating mtab ----------------------------------------------*/
282 /* Flag for already existing lock file. */
283 static int we_created_lockfile
= 0;
285 /* Flag to indicate that signals have been set up. */
286 static int signals_have_been_setup
= 0;
288 /* Ensure that the lock is released if we are interrupted. */
291 die (EX_USER
, "%s", sys_siglist
[sig
]);
295 setlkw_timeout (int sig
) {
296 /* nothing, fcntl will fail anyway */
299 /* Create the lock file.
300 The lock file will be removed if we catch a signal or when we exit. */
301 /* The old code here used flock on a lock file /etc/mtab~ and deleted
302 this lock file afterwards. However, as rgooch remarks, that has a
303 race: a second mount may be waiting on the lock and proceed as
304 soon as the lock file is deleted by the first mount, and immediately
305 afterwards a third mount comes, creates a new /etc/mtab~, applies
306 flock to that, and also proceeds, so that the second and third mount
307 now both are scribbling in /etc/mtab.
308 The new code uses a link() instead of a creat(), where we proceed
309 only if it was us that created the lock, and hence we always have
310 to delete the lock afterwards. Now the use of flock() is in principle
311 superfluous, but avoids an arbitrary sleep(). */
313 /* Where does the link point to? Obvious choices are mtab and mtab~~.
314 HJLu points out that the latter leads to races. Right now we use
315 mtab~.<pid> instead. */
316 #define MOUNTLOCK_LINKTARGET MOUNTED_LOCK "%d"
321 char *linktargetfile
;
323 if (!signals_have_been_setup
) {
327 sa
.sa_handler
= handler
;
329 sigfillset (&sa
.sa_mask
);
331 while (sigismember (&sa
.sa_mask
, ++sig
) != -1
334 sa
.sa_handler
= setlkw_timeout
;
336 sa
.sa_handler
= handler
;
337 sigaction (sig
, &sa
, (struct sigaction
*) 0);
339 signals_have_been_setup
= 1;
342 /* somewhat clumsy, but some ancient systems do not have snprintf() */
343 /* use 20 as upper bound for the length of %d output */
344 linktargetfile
= xmalloc(strlen(MOUNTLOCK_LINKTARGET
) + 20);
345 sprintf(linktargetfile
, MOUNTLOCK_LINKTARGET
, getpid ());
347 /* Repeat until it was us who made the link */
348 while (!we_created_lockfile
) {
352 i
= open (linktargetfile
, O_WRONLY
|O_CREAT
, 0);
355 /* linktargetfile does not exist (as a file)
356 and we cannot create it. Read-only filesystem?
357 Too many files open in the system? Filesystem full? */
358 die (EX_FILEIO
, _("can't create lock file %s: %s "
359 "(use -n flag to override)"),
360 linktargetfile
, strerror (errsv
));
364 j
= link(linktargetfile
, MOUNTED_LOCK
);
367 (void) unlink(linktargetfile
);
369 if (j
< 0 && errsv
!= EEXIST
) {
370 die (EX_FILEIO
, _("can't link lock file %s: %s "
371 "(use -n flag to override)"),
372 MOUNTED_LOCK
, strerror (errsv
));
375 fd
= open (MOUNTED_LOCK
, O_WRONLY
);
379 /* Strange... Maybe the file was just deleted? */
380 if (errno
== ENOENT
&& tries
-- > 0)
382 die (EX_FILEIO
, _("can't open lock file %s: %s "
383 "(use -n flag to override)"),
384 MOUNTED_LOCK
, strerror (errsv
));
387 flock
.l_type
= F_WRLCK
;
388 flock
.l_whence
= SEEK_SET
;
393 /* We made the link. Now claim the lock. */
394 if (fcntl (fd
, F_SETLK
, &flock
) == -1) {
397 printf(_("Can't lock lock file %s: %s\n"),
398 MOUNTED_LOCK
, strerror (errsv
));
402 we_created_lockfile
= 1;
404 /* Someone else made the link. Wait. */
406 if (fcntl (fd
, F_SETLKW
, &flock
) == -1) {
408 die (EX_FILEIO
, _("can't lock lock file %s: %s"),
409 MOUNTED_LOCK
, (errno
== EINTR
) ?
410 _("timed out") : strerror (errsv
));
413 /* Maybe limit the number of iterations? */
420 /* Remove lock file. */
423 if (we_created_lockfile
) {
424 unlink (MOUNTED_LOCK
);
425 we_created_lockfile
= 0;
431 * Used by umount with null INSTEAD: remove any DIR entries.
432 * Used by mount upon a remount: update option part,
433 * and complain if a wrong device or type was given.
434 * [Note that often a remount will be a rw remount of /
435 * where there was no entry before, and we'll have to believe
436 * the values given in INSTEAD.]
440 update_mtab (const char *dir
, struct mntent
*instead
) {
445 mntFILE
*mfp
, *mftmp
;
447 if (mtab_does_not_exist() || mtab_is_a_symlink())
452 mfp
= my_setmntent(MOUNTED
, "r");
453 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
455 error (_("cannot open %s (%s) - mtab not updated"),
456 MOUNTED
, strerror (errsv
));
460 mftmp
= my_setmntent (MOUNTED_TEMP
, "w");
461 if (mftmp
== NULL
|| mfp
->mntent_fp
== NULL
) {
463 error (_("cannot open %s (%s) - mtab not updated"),
464 MOUNTED_TEMP
, strerror (errsv
));
468 while ((mnt
= my_getmntent (mfp
))) {
469 if (streq (mnt
->mnt_dir
, dir
)
471 /* Matthew Wilcox <willy@odie.barnet.ac.uk> */
472 /* This is meant for Patch 212 on Jitterbug,
473 still in incoming, to allow remounting
474 on a different directory. */
475 || (instead
&& instead
->mnt_fsname
&&
476 (!streq (instead
->mnt_fsname
, "none")) &&
477 (streq (mnt
->mnt_fsname
, instead
->mnt_fsname
)))
481 if (instead
) { /* a remount */
484 remnt
.mnt_fsname
= mnt
->mnt_fsname
;
485 remnt
.mnt_type
= mnt
->mnt_type
;
486 if (instead
->mnt_fsname
487 && !streq(mnt
->mnt_fsname
, instead
->mnt_fsname
))
488 printf(_("mount: warning: cannot change "
489 "mounted device with a remount\n"));
490 else if (instead
->mnt_type
491 && !streq(instead
->mnt_type
, "unknown")
492 && !streq(mnt
->mnt_type
, instead
->mnt_type
))
493 printf(_("mount: warning: cannot change "
494 "filesystem type with a remount\n"));
499 if (next
&& my_addmntent(mftmp
, next
) == 1) {
501 die (EX_FILEIO
, _("error writing %s: %s"),
502 MOUNTED_TEMP
, strerror (errsv
));
505 if (instead
&& !added
&& my_addmntent(mftmp
, instead
) == 1) {
507 die (EX_FILEIO
, _("error writing %s: %s"),
508 MOUNTED_TEMP
, strerror (errsv
));
512 if (fchmod (fileno (mftmp
->mntent_fp
), S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
) < 0) {
514 fprintf(stderr
, _("error changing mode of %s: %s\n"), MOUNTED_TEMP
,
517 my_endmntent (mftmp
);
519 if (rename (MOUNTED_TEMP
, MOUNTED
) < 0) {
521 fprintf(stderr
, _("can't rename %s to %s: %s\n"), MOUNTED_TEMP
, MOUNTED
,