]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/fstab.c
3ee1f36a10818400fd55300c45cd6084b703dae4
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
));
111 if (ferror (mfp
->mntent_fp
)) {
113 error(_("warning: error reading %s: %s"),
114 fnam
, strerror (errsv
));
115 mc0
->nxt
= mc0
->prev
= NULL
;
121 * Read /etc/mtab. If that fails, try /proc/mounts.
122 * This produces a linked list. The list head mounttable is a dummy.
123 * Return 0 on success.
129 struct mntentchn
*mc
= &mounttable
;
132 mc
->nxt
= mc
->prev
= NULL
;
135 mfp
= my_setmntent (fnam
, "r");
136 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
139 mfp
= my_setmntent (fnam
, "r");
140 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
141 error(_("warning: can't open %s: %s"), MOUNTED
, strerror (errsv
));
145 printf (_("mount: could not open %s - using %s instead\n"),
146 MOUNTED
, PROC_MOUNTS
);
148 read_mntentchn(mfp
, fnam
, mc
);
155 struct mntentchn
*mc
= &fstab
;
158 mc
->nxt
= mc
->prev
= NULL
;
161 mfp
= my_setmntent (fnam
, "r");
162 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
164 error(_("warning: can't open %s: %s"),
165 _PATH_FSTAB
, strerror (errsv
));
168 read_mntentchn(mfp
, fnam
, mc
);
172 /* Given the name NAME, try to find it in mtab. */
174 getmntfile (const char *name
) {
175 struct mntentchn
*mc
, *mc0
;
178 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
179 if (streq (mc
->m
.mnt_dir
, name
) ||
180 streq (mc
->m
.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
, *mc0
;
196 for (mc
= mcprev
->prev
; mc
&& mc
!= mc0
; mc
= mc
->prev
)
197 if (streq (mc
->m
.mnt_dir
, name
) ||
198 streq (mc
->m
.mnt_fsname
, name
))
203 /* Given the name FILE, try to find the option "loop=FILE" in mtab. */
205 getmntoptfile (const char *file
) {
206 struct mntentchn
*mc
, *mc0
;
216 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
217 if ((opts
= mc
->m
.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] == ','))
226 /* Find the entry (SPEC,FILE) in fstab */
228 getfsspecfile (const char *spec
, const char *file
) {
229 struct mntentchn
*mc
, *mc0
;
232 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
233 if (streq (mc
->m
.mnt_dir
, file
) &&
234 streq (mc
->m
.mnt_fsname
, spec
))
236 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
237 if ((streq (mc
->m
.mnt_dir
, file
) ||
238 streq (canonicalize(mc
->m
.mnt_dir
), file
))
239 && (streq (mc
->m
.mnt_fsname
, spec
) ||
240 streq (canonicalize(mc
->m
.mnt_fsname
), spec
)))
245 /* Find the dir FILE in fstab. */
247 getfsfile (const char *file
) {
248 struct mntentchn
*mc
, *mc0
;
251 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
252 if (streq (mc
->m
.mnt_dir
, file
))
257 /* Find the device SPEC in fstab. */
259 getfsspec (const char *spec
) {
260 struct mntentchn
*mc
, *mc0
;
263 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
264 if (streq (mc
->m
.mnt_fsname
, spec
))
269 /* Find the uuid UUID in fstab. */
271 getfsuuidspec (const char *uuid
) {
272 struct mntentchn
*mc
, *mc0
;
275 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
276 if (strncmp (mc
->m
.mnt_fsname
, "UUID=", 5) == 0
277 && streq(mc
->m
.mnt_fsname
+ 5, uuid
))
282 /* Find the label LABEL in fstab. */
284 getfsvolspec (const char *label
) {
285 struct mntentchn
*mc
, *mc0
;
288 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
289 if (strncmp (mc
->m
.mnt_fsname
, "LABEL=", 6) == 0
290 && streq(mc
->m
.mnt_fsname
+ 6, label
))
295 /* Updating mtab ----------------------------------------------*/
297 /* Flag for already existing lock file. */
298 static int we_created_lockfile
= 0;
300 /* Flag to indicate that signals have been set up. */
301 static int signals_have_been_setup
= 0;
303 /* Ensure that the lock is released if we are interrupted. */
306 die (EX_USER
, "%s", sys_siglist
[sig
]);
310 setlkw_timeout (int sig
) {
311 /* nothing, fcntl will fail anyway */
314 /* Create the lock file.
315 The lock file will be removed if we catch a signal or when we exit. */
316 /* The old code here used flock on a lock file /etc/mtab~ and deleted
317 this lock file afterwards. However, as rgooch remarks, that has a
318 race: a second mount may be waiting on the lock and proceed as
319 soon as the lock file is deleted by the first mount, and immediately
320 afterwards a third mount comes, creates a new /etc/mtab~, applies
321 flock to that, and also proceeds, so that the second and third mount
322 now both are scribbling in /etc/mtab.
323 The new code uses a link() instead of a creat(), where we proceed
324 only if it was us that created the lock, and hence we always have
325 to delete the lock afterwards. Now the use of flock() is in principle
326 superfluous, but avoids an arbitrary sleep(). */
328 /* Where does the link point to? Obvious choices are mtab and mtab~~.
329 HJLu points out that the latter leads to races. Right now we use
330 mtab~.<pid> instead. */
331 #define MOUNTLOCK_LINKTARGET MOUNTED_LOCK "%d"
336 char *linktargetfile
;
338 if (!signals_have_been_setup
) {
342 sa
.sa_handler
= handler
;
344 sigfillset (&sa
.sa_mask
);
346 while (sigismember (&sa
.sa_mask
, ++sig
) != -1
349 sa
.sa_handler
= setlkw_timeout
;
351 sa
.sa_handler
= handler
;
352 sigaction (sig
, &sa
, (struct sigaction
*) 0);
354 signals_have_been_setup
= 1;
357 /* somewhat clumsy, but some ancient systems do not have snprintf() */
358 /* use 20 as upper bound for the length of %d output */
359 linktargetfile
= xmalloc(strlen(MOUNTLOCK_LINKTARGET
) + 20);
360 sprintf(linktargetfile
, MOUNTLOCK_LINKTARGET
, getpid ());
362 /* Repeat until it was us who made the link */
363 while (!we_created_lockfile
) {
367 i
= open (linktargetfile
, O_WRONLY
|O_CREAT
, 0);
370 /* linktargetfile does not exist (as a file)
371 and we cannot create it. Read-only filesystem?
372 Too many files open in the system?
374 die (EX_FILEIO
, _("can't create lock file %s: %s "
375 "(use -n flag to override)"),
376 linktargetfile
, strerror (errsv
));
380 j
= link(linktargetfile
, MOUNTED_LOCK
);
383 (void) unlink(linktargetfile
);
385 if (j
< 0 && errsv
!= EEXIST
) {
386 die (EX_FILEIO
, _("can't link lock file %s: %s "
387 "(use -n flag to override)"),
388 MOUNTED_LOCK
, strerror (errsv
));
391 fd
= open (MOUNTED_LOCK
, O_WRONLY
);
395 /* Strange... Maybe the file was just deleted? */
396 if (errno
== ENOENT
&& tries
-- > 0)
398 die (EX_FILEIO
, _("can't open lock file %s: %s "
399 "(use -n flag to override)"),
400 MOUNTED_LOCK
, strerror (errsv
));
403 flock
.l_type
= F_WRLCK
;
404 flock
.l_whence
= SEEK_SET
;
409 /* We made the link. Now claim the lock. */
410 if (fcntl (fd
, F_SETLK
, &flock
) == -1) {
413 printf(_("Can't lock lock file %s: %s\n"),
414 MOUNTED_LOCK
, strerror (errsv
));
418 we_created_lockfile
= 1;
420 static int tries
= 0;
422 /* Someone else made the link. Wait. */
424 if (fcntl (fd
, F_SETLKW
, &flock
) == -1) {
426 die (EX_FILEIO
, _("can't lock lock file %s: %s"),
427 MOUNTED_LOCK
, (errno
== EINTR
) ?
428 _("timed out") : strerror (errsv
));
431 /* Limit the number of iterations - maybe there
432 still is some old /etc/mtab~ */
435 die (EX_FILEIO
, _("Cannot create link %s\n"
436 "Perhaps there is a stale lock file?\n"),
446 /* Remove lock file. */
449 if (we_created_lockfile
) {
450 unlink (MOUNTED_LOCK
);
451 we_created_lockfile
= 0;
457 * Used by umount with null INSTEAD: remove the last DIR entry.
458 * Used by mount upon a remount: update option part,
459 * and complain if a wrong device or type was given.
460 * [Note that often a remount will be a rw remount of /
461 * where there was no entry before, and we'll have to believe
462 * the values given in INSTEAD.]
466 update_mtab (const char *dir
, struct mntent
*instead
) {
467 mntFILE
*mfp
, *mftmp
;
468 const char *fnam
= MOUNTED
;
469 struct mntentchn mtabhead
; /* dummy */
470 struct mntentchn
*mc
, *mc0
, absent
;
472 if (mtab_does_not_exist() || mtab_is_a_symlink())
477 /* having locked mtab, read it again */
478 mc0
= mc
= &mtabhead
;
479 mc
->nxt
= mc
->prev
= NULL
;
481 mfp
= my_setmntent(fnam
, "r");
482 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
484 error (_("cannot open %s (%s) - mtab not updated"),
485 fnam
, strerror (errsv
));
489 read_mntentchn(mfp
, fnam
, mc
);
491 /* find last occurrence of dir */
492 for (mc
= mc0
->prev
; mc
&& mc
!= mc0
; mc
= mc
->prev
)
493 if (streq (mc
->m
.mnt_dir
, dir
))
495 if (mc
&& mc
!= mc0
) {
496 if (instead
== NULL
) {
497 /* An umount - remove entry */
498 if (mc
&& mc
!= mc0
) {
499 mc
->prev
->nxt
= mc
->nxt
;
500 mc
->nxt
->prev
= mc
->prev
;
504 mc
->m
.mnt_opts
= instead
->mnt_opts
;
506 } else if (instead
) {
507 /* not found, add a new entry */
510 absent
.prev
= mc0
->prev
;
512 if (mc0
->nxt
== NULL
)
516 /* write chain to mtemp */
517 mftmp
= my_setmntent (MOUNTED_TEMP
, "w");
518 if (mftmp
== NULL
|| mfp
->mntent_fp
== NULL
) {
520 error (_("cannot open %s (%s) - mtab not updated"),
521 MOUNTED_TEMP
, strerror (errsv
));
525 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
) {
526 if (my_addmntent(mftmp
, &(mc
->m
)) == 1) {
528 die (EX_FILEIO
, _("error writing %s: %s"),
529 MOUNTED_TEMP
, strerror (errsv
));
533 if (fchmod (fileno (mftmp
->mntent_fp
),
534 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
) < 0) {
536 fprintf(stderr
, _("error changing mode of %s: %s\n"),
537 MOUNTED_TEMP
, strerror (errsv
));
539 my_endmntent (mftmp
);
541 /* rename mtemp to mtab */
542 if (rename (MOUNTED_TEMP
, MOUNTED
) < 0) {
544 fprintf(stderr
, _("can't rename %s to %s: %s\n"),
545 MOUNTED_TEMP
, MOUNTED
, strerror(errsv
));