]> git.ipfire.org Git - thirdparty/util-linux.git/blob - shlibs/mount/src/tab_update.c
libmount: add and copy FS internal flags
[thirdparty/util-linux.git] / shlibs / mount / src / tab_update.c
1 /*
2 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 */
7
8 /**
9 * SECTION: update
10 * @title: mtab managment
11 * @short_description: userspace mount information management.
12 *
13 * The struct libmnt_update provides abstraction to manage mount options in userspace independently on
14 * system configuration. This low-level API works on system with and without /etc/mtab. On
15 * systems without the regular /etc/mtab file are userspace mount options (e.g. user=)
16 * stored to the /dev/.mount/utab file.
17 *
18 * It's recommended to use high-level struct libmnt_context API.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/file.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "c.h"
32 #include "mountP.h"
33 #include "mangle.h"
34 #include "pathnames.h"
35
36 struct libmnt_update {
37 char *target;
38 struct libmnt_fs *fs;
39 char *filename;
40 unsigned long mountflags;
41 int userspace_only;
42 int ready;
43 };
44
45 static int utab_new_entry(struct libmnt_fs *fs, unsigned long mountflags, struct libmnt_fs **ent);
46 static int set_fs_root(struct libmnt_fs *result, struct libmnt_fs *fs, unsigned long mountflags);
47
48 /**
49 * mnt_new_update:
50 *
51 * Returns: newly allocated update handler
52 */
53 struct libmnt_update *mnt_new_update(void)
54 {
55 struct libmnt_update *upd;
56
57 upd = calloc(1, sizeof(*upd));
58 if (!upd)
59 return NULL;
60
61 DBG(UPDATE, mnt_debug_h(upd, "allocate"));
62
63 return upd;
64 }
65
66 /**
67 * mnt_free_update:
68 * @upd: update
69 *
70 * Deallocates struct libmnt_update handler.
71 */
72 void mnt_free_update(struct libmnt_update *upd)
73 {
74 if (!upd)
75 return;
76
77 DBG(UPDATE, mnt_debug_h(upd, "free"));
78
79 mnt_free_fs(upd->fs);
80 free(upd->target);
81 free(upd->filename);
82 free(upd);
83 }
84
85 /*
86 * Returns 0 on success, 1 if not file available, -1 in case of error.
87 */
88 int mnt_update_set_filename(struct libmnt_update *upd, const char *filename, int userspace_only)
89 {
90 const char *path = NULL;
91 int rw = 0;
92
93 assert(upd);
94
95 /* filename explicitly defined */
96 if (filename) {
97 char *p = strdup(filename);
98 if (!p)
99 return -ENOMEM;
100
101 upd->userspace_only = userspace_only;
102 free(upd->filename);
103 upd->filename = p;
104 }
105
106 if (upd->filename)
107 return 0;
108
109 /* detect tab filename -- /etc/mtab or /dev/.mount/utab
110 */
111 mnt_has_regular_mtab(&path, &rw);
112 if (!rw) {
113 path = NULL;
114 mnt_has_regular_utab(&path, &rw);
115 if (!rw)
116 return 1;
117 upd->userspace_only = TRUE;
118 }
119 upd->filename = strdup(path);
120 if (!upd->filename)
121 return -ENOMEM;
122
123 return 0;
124 }
125
126 /**
127 * mnt_update_get_filename:
128 * @upd: update
129 *
130 * This function returns file name (e.g. /etc/mtab) if the update
131 * should be covered by mnt_lock, otherwise returne NULL.
132 *
133 * Returns: pointer to filename that will be updated or NULL in case of error.
134 */
135 const char *mnt_update_get_filename(struct libmnt_update *upd)
136 {
137 return upd && !upd->userspace_only ? upd->filename : NULL;
138 }
139
140 /**
141 * mnt_update_is_ready:
142 * @upd: update handler
143 *
144 * Returns: 1 if entry described by @upd is successfully prepared and will be
145 * written to mtab/utab file.
146 */
147 int mnt_update_is_ready(struct libmnt_update *upd)
148 {
149 return upd ? upd->ready : FALSE;
150 }
151
152 /**
153 * mnt_update_set_fs:
154 * @upd: update handler
155 * @mountflags: MS_* flags
156 * @target: umount target, must be num for mount
157 * @fs: mount filesystem description, must be NULL for umount
158 *
159 * Returns: -1 in case on error, 0 on success, 1 if update is unnecessary.
160 */
161 int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
162 const char *target, struct libmnt_fs *fs)
163 {
164 int rc;
165
166 assert(upd);
167 assert(target || fs);
168
169 if (!upd)
170 return -EINVAL;
171 if ((mountflags & MS_MOVE) && (!fs || !mnt_fs_get_srcpath(fs)))
172 return -EINVAL;
173 if (target && fs)
174 return -EINVAL;
175
176 DBG(UPDATE, mnt_debug_h(upd,
177 "reseting FS [fs=0x%p, target=%s, flags=0x%08lx]",
178 fs, target, mountflags));
179 if (fs) {
180 DBG(UPDATE, mnt_debug_h(upd, "FS template:"));
181 DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
182 }
183
184 mnt_free_fs(upd->fs);
185 free(upd->target);
186 upd->ready = FALSE;
187 upd->fs = NULL;
188 upd->target = NULL;
189 upd->mountflags = 0;
190
191 if (mountflags & MS_PROPAGATION)
192 return 1;
193
194 upd->mountflags = mountflags;
195
196 rc = mnt_update_set_filename(upd, NULL, 0);
197 if (rc)
198 return rc; /* error or no file available (rc = 1) */
199
200 if (target) {
201 upd->target = strdup(target);
202 if (!upd->target)
203 return -ENOMEM;
204
205 } else if (fs) {
206 if (upd->userspace_only && !(mountflags & MS_MOVE)) {
207 int rc = utab_new_entry(fs, mountflags, &upd->fs);
208 if (rc)
209 return rc;
210 } else {
211 upd->fs = mnt_copy_mtab_fs(fs);
212 if (!upd->fs)
213 return -ENOMEM;
214
215 }
216 }
217
218
219 DBG(UPDATE, mnt_debug_h(upd, "ready"));
220 upd->ready = TRUE;
221 return 0;
222 }
223
224 /**
225 * mnt_update_get_fs:
226 * @upd: update
227 *
228 * Returns: update filesystem entry or NULL
229 */
230 struct libmnt_fs *mnt_update_get_fs(struct libmnt_update *upd)
231 {
232 return upd ? upd->fs : NULL;
233 }
234
235 /**
236 * mnt_update_get_mflags:
237 * @upd: update
238 *
239 * Returns: mount flags as was set by mnt_update_set_fs()
240 */
241 unsigned long mnt_update_get_mflags(struct libmnt_update *upd)
242 {
243 return upd ? upd->mountflags : 0;
244 }
245
246 /**
247 * mnt_update_force_rdonly:
248 * @upd: update
249 * @rdonly: is read-only?
250 *
251 * Returns: 0 on success and negative number in case of error.
252 */
253 int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly)
254 {
255 int rc = 0;
256
257 if (!upd || !upd->fs)
258 return -EINVAL;
259
260 if (rdonly && (upd->mountflags & MS_RDONLY))
261 return 0;
262 if (!rdonly && !(upd->mountflags & MS_RDONLY))
263 return 0;
264
265 if (!upd->userspace_only) {
266 /* /etc/mtab -- we care about VFS options there */
267 const char *o = mnt_fs_get_vfs_options(upd->fs);
268 char *n = o ? strdup(o) : NULL;
269
270 if (n)
271 mnt_optstr_remove_option(&n, rdonly ? "rw" : "ro");
272 if (!mnt_optstr_prepend_option(&n, rdonly ? "ro" : "rw", NULL))
273 rc = mnt_fs_set_vfs_options(upd->fs, n);
274
275 free(n);
276 }
277
278 if (rdonly)
279 upd->mountflags &= ~MS_RDONLY;
280 else
281 upd->mountflags |= MS_RDONLY;
282
283 return rc;
284 }
285
286 /*
287 * Allocates (but does not write) utab entry for mount/remount. This function
288 * should be called *before* mount(2) syscall.
289 *
290 * Returns: 0 on success, negative number on error, 1 if utabs update is
291 * unnecessary.
292 */
293 static int utab_new_entry(struct libmnt_fs *fs, unsigned long mountflags, struct libmnt_fs **ent)
294 {
295 int rc = 0;
296 const char *o = NULL, *a = NULL;
297 char *u = NULL;
298
299 assert(fs);
300 assert(ent);
301 assert(!(mountflags & MS_MOVE));
302
303 if (!fs || !ent)
304 return -EINVAL;
305 *ent = NULL;
306
307 DBG(UPDATE, mnt_debug("prepare utab entry"));
308
309 o = mnt_fs_get_user_options(fs);
310 a = mnt_fs_get_attributes(fs);
311
312 if (o) {
313 /* remove non-mtab options */
314 rc = mnt_optstr_get_options(o, &u,
315 mnt_get_builtin_optmap(MNT_USERSPACE_MAP),
316 MNT_NOMTAB);
317 if (rc)
318 goto err;
319 }
320
321 if (!u && !a) {
322 DBG(UPDATE, mnt_debug("utab entry unnecessary (no options)"));
323 return 1;
324 }
325
326 /* allocate the entry */
327 *ent = mnt_copy_fs(NULL, fs);
328 if (!*ent) {
329 rc = -ENOMEM;
330 goto err;
331 }
332
333 rc = mnt_fs_set_user_options(*ent, u);
334 if (rc)
335 goto err;
336 rc = mnt_fs_set_attributes(*ent, a);
337 if (rc)
338 goto err;
339
340 if (!(mountflags & MS_REMOUNT)) {
341 rc = set_fs_root(*ent, fs, mountflags);
342 if (rc)
343 goto err;
344 }
345
346 free(u);
347 DBG(UPDATE, mnt_debug("utab entry OK"));
348 return 0;
349 err:
350 mnt_free_fs(*ent);
351 free(u);
352 *ent = NULL;
353 return rc;
354 }
355
356 static int set_fs_root(struct libmnt_fs *result, struct libmnt_fs *fs, unsigned long mountflags)
357 {
358 char *root = NULL, *mnt = NULL;
359 const char *fstype;
360 struct libmnt_table *tb = NULL;
361 int rc = -ENOMEM;
362
363 assert(fs);
364 assert(result);
365
366 DBG(UPDATE, mnt_debug("setting FS root"));
367
368 fstype = mnt_fs_get_fstype(fs);
369
370 /*
371 * bind-mount -- get fs-root and source device for the source filesystem
372 */
373 if (mountflags & MS_BIND) {
374 const char *src, *src_root;
375 struct libmnt_fs *src_fs;
376
377 DBG(UPDATE, mnt_debug("setting FS root: bind"));
378
379 src = mnt_fs_get_srcpath(fs);
380 if (src) {
381 rc = mnt_fs_set_bindsrc(result, src);
382 if (rc)
383 goto err;
384 mnt = mnt_get_mountpoint(src);
385 }
386 if (!mnt) {
387 rc = -EINVAL;
388 goto err;
389 }
390 root = mnt_get_fs_root(src, mnt);
391
392 tb = __mnt_new_table_from_file(_PATH_PROC_MOUNTINFO, MNT_FMT_MOUNTINFO);
393 if (!tb) {
394 DBG(UPDATE, mnt_debug("failed to parse mountinfo -- using default"));
395 goto dflt;
396 }
397 src_fs = mnt_table_find_target(tb, mnt, MNT_ITER_BACKWARD);
398 if (!src_fs) {
399 DBG(UPDATE, mnt_debug("not found '%s' in mountinfo -- using default", mnt));
400 goto dflt;
401 }
402
403 /* set device name and fs */
404 src = mnt_fs_get_srcpath(src_fs);
405 rc = mnt_fs_set_source(result, src);
406 if (rc)
407 goto err;
408
409 mnt_fs_set_fstype(result, mnt_fs_get_fstype(src_fs));
410
411 /* on btrfs the subvolume is used as fs-root in
412 * /proc/self/mountinfo, so we have get the original subvolume
413 * name from src_fs and prepend the subvolume name to the
414 * fs-root path
415 */
416 src_root = mnt_fs_get_root(src_fs);
417 if (src_root && !startswith(root, src_root)) {
418 size_t sz = strlen(root) + strlen(src_root) + 1;
419 char *tmp = malloc(sz);
420
421 if (!tmp)
422 goto err;
423 snprintf(tmp, sz, "%s%s", src_root, root);
424 free(root);
425 root = tmp;
426 }
427 }
428
429 /*
430 * btrfs-subvolume mount -- get subvolume name and use it as a root-fs path
431 */
432 else if (fstype && !strcmp(fstype, "btrfs")) {
433 char *vol = NULL, *p;
434 size_t sz, volsz = 0;
435
436 if (mnt_fs_get_option(fs, "subvol", &vol, &volsz))
437 goto dflt;
438
439 DBG(UPDATE, mnt_debug("setting FS root: btrfs subvol"));
440
441 sz = volsz;
442 if (*vol != '/')
443 sz++;
444 root = malloc(sz + 1);
445 if (!root)
446 goto err;
447 p = root;
448 if (*vol != '/')
449 *p++ = '/';
450 memcpy(p, vol, volsz);
451 *(root + sz) = '\0';
452 }
453 dflt:
454 mnt_free_table(tb);
455 if (!root) {
456 root = strdup("/");
457 if (!root)
458 goto err;
459 }
460 result->root = root;
461
462 DBG(UPDATE, mnt_debug("FS root result: %s", root));
463
464 free(mnt);
465 return 0;
466 err:
467 free(root);
468 free(mnt);
469 return rc;
470 }
471
472 /* mtab and fstab update */
473 static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
474 {
475 char *o;
476 char *m1, *m2, *m3, *m4;
477 int rc;
478
479 assert(fs);
480 assert(f);
481
482 o = mnt_fs_strdup_options(fs);
483 if (!o)
484 return -ENOMEM;
485
486 m1 = mangle(mnt_fs_get_source(fs));
487 m2 = mangle(mnt_fs_get_target(fs));
488 m3 = mangle(mnt_fs_get_fstype(fs));
489 m4 = mangle(o);
490
491 if (m1 && m2 && m3 && m4)
492 rc = !fprintf(f, "%s %s %s %s %d %d\n",
493 m1, m2, m3, m4,
494 mnt_fs_get_freq(fs),
495 mnt_fs_get_passno(fs));
496 else
497 rc = -ENOMEM;
498
499 free(o);
500 free(m1);
501 free(m2);
502 free(m3);
503 free(m4);
504
505 return rc;
506 }
507
508 static int fprintf_utab_fs(FILE *f, struct libmnt_fs *fs)
509 {
510 char *p;
511
512 assert(fs);
513 assert(f);
514
515 if (!fs || !f)
516 return -EINVAL;
517
518 p = mangle(mnt_fs_get_source(fs));
519 if (p) {
520 fprintf(f, "SRC=%s ", p);
521 free(p);
522 }
523 p = mangle(mnt_fs_get_target(fs));
524 if (p) {
525 fprintf(f, "TARGET=%s ", p);
526 free(p);
527 }
528 p = mangle(mnt_fs_get_root(fs));
529 if (p) {
530 fprintf(f, "ROOT=%s ", p);
531 free(p);
532 }
533 p = mangle(mnt_fs_get_bindsrc(fs));
534 if (p) {
535 fprintf(f, "BINDSRC=%s ", p);
536 free(p);
537 }
538 p = mangle(mnt_fs_get_attributes(fs));
539 if (p) {
540 fprintf(f, "ATTRS=%s ", p);
541 free(p);
542 }
543 p = mangle(mnt_fs_get_user_options(fs));
544 if (p) {
545 fprintf(f, "OPTS=%s", p);
546 free(p);
547 }
548 fputc('\n', f);
549
550 return 0;
551 }
552
553 static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
554 {
555 FILE *f;
556 int rc, fd;
557 char *uq = NULL;
558
559 if (!tb || !upd->filename)
560 return -EINVAL;
561
562 DBG(UPDATE, mnt_debug_h(upd, "%s: updating", upd->filename));
563
564 fd = mnt_open_uniq_filename(upd->filename, &uq, O_WRONLY);
565 if (fd < 0)
566 return fd; /* error */
567
568 f = fdopen(fd, "w");
569 if (f) {
570 struct stat st;
571 struct libmnt_iter itr;
572 struct libmnt_fs *fs;
573 int fd;
574
575 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
576 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
577 if (upd->userspace_only)
578 fprintf_utab_fs(f, fs);
579 else
580 fprintf_mtab_fs(f, fs);
581 }
582 fd = fileno(f);
583 rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
584
585 if (!rc && stat(upd->filename, &st) == 0)
586 /* Copy uid/gid from the present file before renaming. */
587 rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
588
589 fclose(f);
590 rc = rename(uq, upd->filename) ? -errno : 0;
591 } else {
592 rc = -errno;
593 close(fd);
594 }
595
596 unlink(uq); /* be paranoid */
597 free(uq);
598 return rc;
599 }
600
601 static int utab_lock(const char *filename)
602 {
603 char *lfile;
604 int fd;
605
606 assert(filename);
607
608 if (asprintf(&lfile, "%s.lock", filename) == -1)
609 return -1;
610
611 DBG(UPDATE, mnt_debug("%s: locking", lfile));
612
613 fd = open(lfile, O_RDONLY|O_CREAT|O_CLOEXEC, S_IWUSR|
614 S_IRUSR|S_IRGRP|S_IROTH);
615 free(lfile);
616
617 if (fd < 0)
618 return -errno;
619 if (flock(fd, LOCK_EX)) {
620 int errsv = errno;
621 close(fd);
622 return -errsv;
623 }
624 return fd;
625 }
626
627 static void utab_unlock(int fd)
628 {
629 if (fd >= 0) {
630 DBG(UPDATE, mnt_debug("unlocking utab"));
631 close(fd);
632 }
633 }
634
635 static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
636 {
637 FILE *f;
638 int rc = 0, u_lc = -1;
639
640 assert(upd);
641 assert(upd->fs);
642
643 DBG(UPDATE, mnt_debug_h(upd, "%s: add entry", upd->filename));
644
645 if (lc)
646 mnt_lock_file(lc);
647 else if (upd->userspace_only)
648 u_lc = utab_lock(upd->filename);
649
650 f = fopen(upd->filename, "a+");
651 if (f) {
652 rc = upd->userspace_only ? fprintf_utab_fs(f, upd->fs) :
653 fprintf_mtab_fs(f, upd->fs);
654 DBG(UPDATE, mnt_debug_h(upd, "%s: add [rc=%d]", upd->filename, rc));
655 fclose(f);
656 } else {
657 DBG(UPDATE, mnt_debug_h(upd, "%s: failed: %m", upd->filename));
658 rc = -errno;
659 }
660 if (lc)
661 mnt_unlock_file(lc);
662 else if (u_lc != -1)
663 utab_unlock(u_lc);
664 return rc;
665 }
666
667 static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
668 {
669 struct libmnt_table *tb;
670 int rc = 0, u_lc = -1;
671
672 assert(upd);
673 assert(upd->target);
674
675 DBG(UPDATE, mnt_debug_h(upd, "%s: remove entry", upd->filename));
676
677 if (lc)
678 mnt_lock_file(lc);
679 else if (upd->userspace_only)
680 u_lc = utab_lock(upd->filename);
681
682 tb = __mnt_new_table_from_file(upd->filename,
683 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
684 if (tb) {
685 struct libmnt_fs *rem = mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD);
686 if (rem) {
687 mnt_table_remove_fs(tb, rem);
688 rc = update_table(upd, tb);
689 mnt_free_fs(rem);
690 }
691 mnt_free_table(tb);
692 }
693 if (lc)
694 mnt_unlock_file(lc);
695 else if (u_lc != -1)
696 utab_unlock(u_lc);
697 return rc;
698 }
699
700 static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *lc)
701 {
702 struct libmnt_table *tb = NULL;
703 int rc = 0, u_lc = -1;
704
705 DBG(UPDATE, mnt_debug_h(upd, "%s: modify target", upd->filename));
706
707 if (lc)
708 mnt_lock_file(lc);
709 else if (upd->userspace_only)
710 u_lc = utab_lock(upd->filename);
711
712 tb = __mnt_new_table_from_file(upd->filename,
713 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
714 if (tb) {
715 struct libmnt_fs *cur = mnt_table_find_target(tb,
716 mnt_fs_get_srcpath(upd->fs), MNT_ITER_BACKWARD);
717 if (cur) {
718 rc = mnt_fs_set_target(cur, mnt_fs_get_target(upd->fs));
719 if (!rc)
720 rc = update_table(upd, tb);
721 }
722 mnt_free_table(tb);
723 }
724 if (lc)
725 mnt_unlock_file(lc);
726 else if (u_lc != -1)
727 utab_unlock(u_lc);
728 return rc;
729 }
730
731 static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *lc)
732 {
733 struct libmnt_table *tb = NULL;
734 int rc = 0, u_lc = -1;
735 struct libmnt_fs *fs;
736
737 assert(upd);
738 assert(upd->fs);
739
740 DBG(UPDATE, mnt_debug_h(upd, "%s: modify options", upd->filename));
741
742 fs = upd->fs;
743
744 if (lc)
745 mnt_lock_file(lc);
746 else if (upd->userspace_only)
747 u_lc = utab_lock(upd->filename);
748
749 tb = __mnt_new_table_from_file(upd->filename,
750 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
751 if (tb) {
752 struct libmnt_fs *cur = mnt_table_find_target(tb,
753 mnt_fs_get_target(fs),
754 MNT_ITER_BACKWARD);
755 if (cur) {
756 if (upd->userspace_only)
757 rc = mnt_fs_set_attributes(cur, mnt_fs_get_attributes(fs));
758 if (!rc && !upd->userspace_only)
759 rc = mnt_fs_set_vfs_options(cur, mnt_fs_get_vfs_options(fs));
760 if (!rc && !upd->userspace_only)
761 rc = mnt_fs_set_fs_options(cur, mnt_fs_get_fs_options(fs));
762 if (!rc)
763 rc = mnt_fs_set_user_options(cur,
764 mnt_fs_get_user_options(fs));
765 if (!rc)
766 rc = update_table(upd, tb);
767 }
768 mnt_free_table(tb);
769 }
770
771 if (lc)
772 mnt_unlock_file(lc);
773 else if (u_lc != -1)
774 utab_unlock(u_lc);
775 return rc;
776 }
777
778 /**
779 * mnt_update_table:
780 * @upd: update
781 * @lc: lock
782 *
783 * High-level API to update /etc/mtab (or private /dev/.mount/utab file).
784 *
785 * Returns: 0 on success, negative number on error.
786 */
787 int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
788 {
789 int rc = -EINVAL;
790
791 assert(upd);
792
793 if (!upd->filename || !upd)
794 return -EINVAL;
795 if (!upd->ready)
796 return 0;
797
798 DBG(UPDATE, mnt_debug_h(upd, "%s: update tab", upd->filename));
799 if (upd->fs) {
800 DBG(UPDATE, mnt_fs_print_debug(upd->fs, stderr));
801 }
802
803 if (!upd->fs && upd->target)
804 rc = update_remove_entry(upd, lc); /* umount */
805 else if (upd->mountflags & MS_MOVE)
806 rc = update_modify_target(upd, lc); /* move */
807 else if (upd->mountflags & MS_REMOUNT)
808 rc = update_modify_options(upd, lc); /* remount */
809 else if (upd->fs)
810 rc = update_add_entry(upd, lc); /* mount */
811
812 upd->ready = FALSE;
813 DBG(UPDATE, mnt_debug_h(upd, "%s: update tab: done [rc=%d]",
814 upd->filename, rc));
815 return rc;
816 }
817
818 #ifdef TEST_PROGRAM
819
820 struct libmnt_lock *lock;
821
822 static void lock_fallback(void)
823 {
824 if (lock)
825 mnt_unlock_file(lock);
826 }
827
828 static int update(const char *target, struct libmnt_fs *fs, unsigned long mountflags)
829 {
830 int rc;
831 struct libmnt_update *upd;
832 const char *filename;
833
834 DBG(UPDATE, mnt_debug("update test"));
835
836 upd = mnt_new_update();
837 if (!upd)
838 return -ENOMEM;
839
840 rc = mnt_update_set_fs(upd, mountflags, target, fs);
841 if (rc == 1) {
842 /* update is unnecessary */
843 rc = 0;
844 goto done;
845 }
846 if (rc) {
847 fprintf(stderr, "failed to set FS\n");
848 goto done;
849 }
850
851 /* [... here should be mount(2) call ...] */
852
853 filename = mnt_update_get_filename(upd);
854 if (filename) {
855 lock = mnt_new_lock(filename, 0);
856 if (lock)
857 atexit(lock_fallback);
858 }
859 rc = mnt_update_table(upd, lock);
860 done:
861 return rc;
862 }
863
864 static int test_add(struct libmnt_test *ts, int argc, char *argv[])
865 {
866 struct libmnt_fs *fs = mnt_new_fs();
867 int rc;
868
869 if (argc < 5 || !fs)
870 return -1;
871 mnt_fs_set_source(fs, argv[1]);
872 mnt_fs_set_target(fs, argv[2]);
873 mnt_fs_set_fstype(fs, argv[3]);
874 mnt_fs_set_options(fs, argv[4]);
875
876 rc = update(NULL, fs, 0);
877 mnt_free_fs(fs);
878 return rc;
879 }
880
881 static int test_remove(struct libmnt_test *ts, int argc, char *argv[])
882 {
883 if (argc < 2)
884 return -1;
885 return update(argv[1], NULL, 0);
886 }
887
888 static int test_move(struct libmnt_test *ts, int argc, char *argv[])
889 {
890 struct libmnt_fs *fs = mnt_new_fs();
891 int rc;
892
893 if (argc < 3)
894 return -1;
895 mnt_fs_set_source(fs, argv[1]);
896 mnt_fs_set_target(fs, argv[2]);
897
898 rc = update(NULL, fs, MS_MOVE);
899
900 mnt_free_fs(fs);
901 return rc;
902 }
903
904 static int test_remount(struct libmnt_test *ts, int argc, char *argv[])
905 {
906 struct libmnt_fs *fs = mnt_new_fs();
907 int rc;
908
909 if (argc < 3)
910 return -1;
911 mnt_fs_set_target(fs, argv[1]);
912 mnt_fs_set_options(fs, argv[2]);
913
914 rc = update(NULL, fs, MS_REMOUNT);
915 mnt_free_fs(fs);
916 return rc;
917 }
918
919 int main(int argc, char *argv[])
920 {
921 struct libmnt_test tss[] = {
922 { "--add", test_add, "<src> <target> <type> <options> add line to mtab" },
923 { "--remove", test_remove, "<target> MS_REMOUNT mtab change" },
924 { "--move", test_move, "<old_target> <target> MS_MOVE mtab change" },
925 { "--remount",test_remount, "<target> <options> MS_REMOUNT mtab change" },
926 { NULL }
927 };
928
929 return mnt_run_test(tss, argc, argv);
930 }
931
932 #endif /* TEST_PROGRAM */