]> git.ipfire.org Git - thirdparty/util-linux.git/blob - shlibs/mount/src/tab_update.c
libmount: improve parsers return codes
[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 (fstab) managment
11 * @short_description: userspace mount information management
12 *
13 * The libmount library allows to use more modes for mtab management:
14 *
15 * - /etc/mtab is regular file
16 *
17 * then libmount manages the file in classical way (all mounts are added to
18 * the file). This mode is always used for /etc/fstab updates as well.
19 *
20 * - /etc/mtab is symlink
21 *
22 * then libmount ignores mtab at all
23 *
24 * - /etc/mtab is symlink and /var/run/mount/ directory exists
25 *
26 * then libmount stores userspace specific mount options to the
27 * /var/run/mount/mountinfo file (the file format compatible to
28 * /proc/self/mountinfo)
29 *
30 *
31 * The mtab is always updated in two steps. The first step is to prepare a new
32 * update entry -- mnt_prepare_update(), this step has to be done before
33 * mount(2) syscall. The second step is to update the file --
34 * mnt_update_file(), this step should be done after mount(2) syscall.
35 *
36 * The mnt_update_file() behaviour is undefined if mnt_prepare_update() has
37 * not been used.
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include <errno.h>
47
48 #include "c.h"
49 #include "mountP.h"
50 #include "mangle.h"
51 #include "pathnames.h"
52
53
54
55 /*
56 * mtab update description
57 */
58 struct _mnt_update {
59 int action; /* MNT_ACT_{MOUNT,UMOUNT} */
60 unsigned long mountflags; /* MS_* flags */
61 char *filename; /* usually /etc/mtab or /var/run/mount/mountinfo */
62 char *old_target; /* for MS_MOVE */
63 int format; /* MNT_FMT_{MTAB,FSTAB,MOUNTINFO} */
64 int nolock; /* don't alloca private mnt_lock */
65 mnt_fs *fs; /* entry */
66 mnt_lock *lc; /* lock or NULL */
67 };
68
69 /**
70 * mnt_new_update:
71 * @action: MNT_ACT_{MOUNT,UMOUNT}
72 * @mountflags: MS_{REMOUNT,BIND,MOVE}
73 * @fs: FS description
74 *
75 * Returns: newly allocated update description
76 */
77 mnt_update *mnt_new_update(int action, unsigned long mountflags, const mnt_fs *fs)
78 {
79 mnt_update *upd;
80
81 upd = calloc(1, sizeof(struct _mnt_update));
82 if (!upd)
83 return NULL;
84
85 DBG(UPDATE, mnt_debug_h(upd, "allocate"));
86
87 if (action)
88 mnt_update_set_action(upd, action);
89 if (mountflags)
90 mnt_update_set_mountflags(upd, mountflags);
91 if (fs)
92 mnt_update_set_fs(upd, fs);
93 return upd;
94 }
95
96 /**
97 * mnt_free_update:
98 * @upd: update
99 *
100 * Deallocates mnt_update handler.
101 */
102 void mnt_free_update(mnt_update *upd)
103 {
104 if (!upd)
105 return;
106
107 DBG(UPDATE, mnt_debug_h(upd, "free"));
108
109 mnt_free_lock(upd->lc);
110 free(upd->filename);
111 free(upd->old_target);
112 free(upd);
113 }
114
115 /**
116 * mnt_update_set_filename:
117 * @upd: update
118 * @filename: path to update (default is /etc/update or /var/run/mount/mountinfo)
119 *
120 * Returns: 0 on success, -1 in case of error.
121 */
122 int mnt_update_set_filename(mnt_update *upd, const char *filename)
123 {
124 char *p = NULL;
125
126 assert(upd);
127 if (!upd)
128 return -1;
129 if (filename) {
130 p = strdup(filename);
131 if (!p)
132 return -1;
133 }
134 free(upd->filename);
135 upd->filename = p;
136 return 0;
137 }
138
139 /**
140 * mnt_update_set_action:
141 * @upd: update
142 * @action: MNT_ACT_{MOUNT,UMOUNT}
143 *
144 * Overwrites the previously defined (usually by mnt_new_update()) action.
145 *
146 * Returns: 0 on success, -1 in case of error.
147 */
148 int mnt_update_set_action(mnt_update *upd, int action)
149 {
150 assert(upd);
151 if (!upd)
152 return -1;
153 upd->action = action;
154 return 0;
155 }
156
157 /**
158 * mnt_update_set_format:
159 * @upd: update
160 * @format: MNT_FMT_{MTAB,FSTAB,MOUNTINFO}
161 *
162 * Sets update file format, default is MNT_FMT_MTAB for paths that end with
163 * "update", MNT_FMT_MOUNTINFO for paths that end with "mountinfo" and
164 * MNT_FMT_FSTAB for paths that end with "fstab".
165 *
166 * Returns: 0 on success, -1 in case of error.
167 */
168 int mnt_update_set_format(mnt_update *upd, int format)
169 {
170 assert(upd);
171 if (!upd)
172 return -1;
173 upd->format = format;
174 return 0;
175 }
176
177 /**
178 * mnt_update_set_fs:
179 * @upd: update
180 * @fs: filesystem to write to file
181 *
182 * Returns; 0 on success, -1 in case of error.
183 */
184 int mnt_update_set_fs(mnt_update *upd, const mnt_fs *fs)
185 {
186 mnt_fs *x = NULL;
187
188 assert(upd);
189 if (!upd)
190 return -1;
191 if (fs) {
192 x = mnt_copy_fs(fs);
193 if (!x)
194 return -1;
195 }
196
197 mnt_free_fs(upd->fs);
198 upd->fs = x;
199 return 0;
200 }
201
202 /**
203 * mnt_update_set_mountflags:
204 * @upd: update
205 * @flags: MS_{REMOUNT,MOVE,BIND,...}
206 *
207 * Sets mount flags for mount/umount action. The flags are also
208 * extracted from mount options by mnt_prepare_update(). The mount flags
209 * are used for mtab update to differentiate between move, remount, ...
210 *
211 * Returns: 0 on success, -1 in case of error.
212 */
213 int mnt_update_set_mountflags(mnt_update *upd, unsigned long flags)
214 {
215 assert(upd);
216 if (!upd)
217 return -1;
218 upd->mountflags = flags;
219 return 0;
220 }
221
222 /**
223 * mnt_update_get_lock:
224 * @upd: update
225 *
226 * This function should not be called before mnt_prepare_update(). The lock
227 * is initialized when mtab update is required only.
228 *
229 * Note that after mnt_update_disable_lock(mt, TRUE) or after mnt_free_update()
230 * the lock will be automatically deallocated.
231 *
232 * Returns: libmount lock handler or NULL if locking is disabled.
233 */
234 mnt_lock *mnt_update_get_lock(mnt_update *upd)
235 {
236 return upd ? upd->lc : NULL;
237 }
238
239 /**
240 * mnt_update_disable_lock:
241 * @upd: update
242 * @disable: TRUE/FALSE
243 *
244 * Enable or disable update locking, the locking is enabled by default.
245 *
246 * Returns: 0 on success, -1 in case of error.
247 */
248 int mnt_update_disable_lock(mnt_update *upd, int disable)
249 {
250 if (!upd)
251 return -1;
252 if (disable) {
253 mnt_free_lock(upd->lc);
254 upd->lc = NULL;
255 }
256 upd->nolock = disable;
257 return 0;
258 }
259
260 /**
261 * mnt_update_set_old_target:
262 * @upd: update
263 * @target: old mountpoint
264 *
265 * Sets the original target for the MS_MOVE operation.
266 *
267 * Returns: 0 on success, -1 in case of error.
268 */
269 int mnt_update_set_old_target(mnt_update *upd, const char *target)
270 {
271 char *p = NULL;
272
273 if (!upd)
274 return -1;
275 if (p) {
276 p = strdup(target);
277 if (!p)
278 return -1;
279 }
280 free(upd->old_target);
281 upd->old_target = p;
282 return 0;
283 }
284
285 /*
286 * The format is same as /proc/self/mountinfo, but it contains userspace
287 * mount options and some unnecessary fields are ignored.
288 */
289 static int fprintf_mountinfo_fs(FILE *f, mnt_fs *fs)
290 {
291 char *root = NULL, *target = NULL, *optstr = NULL,
292 *fstype = NULL, *source = NULL;
293 int rc = -1;
294 dev_t devno;
295
296 assert(fs);
297 assert(f);
298
299 if (!fs || !f)
300 return -1;
301 devno = mnt_fs_get_devno(fs);
302 source = mangle(mnt_fs_get_source(fs));
303 root = mangle(mnt_fs_get_root(fs));
304 target = mangle(mnt_fs_get_target(fs));
305 fstype = mangle(mnt_fs_get_fstype(fs));
306 optstr = mangle(mnt_fs_get_optstr(fs));
307
308 if (!root || !target || !optstr)
309 goto done;
310
311 rc = fprintf(f, "%i %i %u:%u %s %s %s - %s %s %s\n",
312 mnt_fs_get_id(fs),
313 mnt_fs_get_parent_id(fs),
314 major(devno), minor(devno),
315 root,
316 target,
317 optstr,
318 fstype ? fstype : "auto",
319 source ? source : "none",
320 "none");
321 rc = 0;
322 done:
323 free(root);
324 free(target);
325 free(optstr);
326 free(fstype);
327 free(source);
328 return rc;
329 }
330
331 /* mtab and fstab update */
332 static int fprintf_mtab_fs(FILE *f, mnt_fs *fs)
333 {
334 char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL;
335 int rc = -1;
336
337 assert(fs);
338 assert(f);
339
340 if (!fs || !f)
341 return -1;
342
343 m1 = mangle(mnt_fs_get_source(fs));
344 m2 = mangle(mnt_fs_get_target(fs));
345 m3 = mangle(mnt_fs_get_fstype(fs));
346 m4 = mangle(mnt_fs_get_optstr(fs));
347
348 if (!m1 || !m2 || !m3 || !m4)
349 goto done;
350
351 rc = fprintf(f, "%s %s %s %s %d %d\n",
352 m1, m2, m3, m4,
353 mnt_fs_get_freq(fs),
354 mnt_fs_get_passno(fs));
355 rc = 0;
356 done:
357 free(m1);
358 free(m2);
359 free(m3);
360 free(m4);
361
362 return rc;
363 }
364
365 static int update_file(const char *filename, int fmt, mnt_tab *tb)
366 {
367 mnt_iter itr;
368 mnt_fs *fs;
369 FILE *f = NULL;
370 char tmpname[PATH_MAX];
371 struct stat st;
372 int fd;
373 int (*line_fn)(FILE *, mnt_fs *) = fprintf_mountinfo_fs;
374
375 assert(tb);
376 if (!tb)
377 goto error;
378
379 DBG(UPDATE, mnt_debug("%s: update from tab %p", filename, tb));
380
381 if (snprintf(tmpname, sizeof(tmpname), "%s.tmp", filename)
382 >= sizeof(tmpname))
383 goto error;
384
385 f = fopen(tmpname, "w");
386 if (!f)
387 goto error;
388
389
390 if (fmt == MNT_FMT_MTAB || fmt == MNT_FMT_FSTAB)
391 line_fn = fprintf_mtab_fs;
392
393 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
394 while(mnt_tab_next_fs(tb, &itr, &fs) == 0)
395 line_fn(f, fs);
396
397 fd = fileno(f);
398
399 if (fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
400 goto error;
401
402 /* Copy uid/gid from the present file before renaming. */
403 if (stat(filename, &st) == 0) {
404 if (fchown(fd, st.st_uid, st.st_gid) < 0)
405 goto error;
406 }
407
408 fclose(f);
409 f = NULL;
410
411 if (rename(tmpname, filename) < 0)
412 goto error;
413
414 return 0;
415 error:
416 DBG(UPDATE, mnt_debug("%s: update from tab %p failed", filename, tb));
417 if (f)
418 fclose(f);
419 return -1;
420 }
421
422 static int set_fs_root(mnt_update *upd, mnt_fs *fs)
423 {
424 char *root = NULL, *mnt = NULL;
425 const char *fstype;
426 char *optstr;
427 mnt_tab *tb = NULL;
428
429 if (upd->mountflags & MS_REMOUNT)
430 return 0;
431
432 optstr = (char *) mnt_fs_get_optstr(fs);
433 fstype = mnt_fs_get_fstype(fs);
434
435 /*
436 * bind-mount -- get fs-root and source device for the source filesystem
437 */
438 if (upd->mountflags & MS_BIND) {
439 const char *src, *src_root;
440 mnt_fs *src_fs;
441
442 src = mnt_fs_get_srcpath(fs);
443 if (!src)
444 goto err;
445 mnt = mnt_get_mountpoint(src);
446 if (!mnt)
447 goto err;
448 root = mnt_get_fs_root(src, mnt);
449
450 tb = mnt_new_tab_from_file(_PATH_PROC_MOUNTINFO);
451 if (!tb)
452 goto dflt;
453 src_fs = mnt_tab_find_target(tb, mnt, MNT_ITER_BACKWARD);
454 if (!src_fs)
455 goto dflt;
456
457 /* set device name and fs */
458 src = mnt_fs_get_srcpath(src_fs);
459 mnt_fs_set_source(fs, src);
460
461 mnt_fs_set_fstype(fs, mnt_fs_get_fstype(src_fs));
462
463 /* on btrfs the subvolume is used as fs-root in
464 * /proc/self/mountinfo, so we have get the original subvolume
465 * name from src_fs and prepend the subvolume name to the
466 * fs-root path
467 */
468 src_root = mnt_fs_get_root(src_fs);
469 if (src_root && !startswith(root, src_root)) {
470 size_t sz = strlen(root) + strlen(src_root) + 1;
471 char *tmp = malloc(sz);
472
473 if (!tmp)
474 goto err;
475 snprintf(tmp, sz, "%s%s", src_root, root);
476 free(root);
477 root = tmp;
478 }
479 }
480
481 /*
482 * btrfs-subvolume mount -- get subvolume name and use it as a root-fs path
483 */
484 else if (fstype && !strcmp(fstype, "btrfs")) {
485 char *vol = NULL, *p;
486 size_t sz, volsz = 0;
487
488 if (mnt_optstr_get_option(optstr, "subvol", &vol, &volsz))
489 goto dflt;
490
491 sz = volsz;
492 if (*vol != '/')
493 sz++;
494 root = malloc(sz + 1);
495 if (!root)
496 goto err;
497 p = root;
498 if (*vol != '/')
499 *p++ = '/';
500 memcpy(p, vol, volsz);
501 *(root + sz) = '\0';
502 }
503
504 dflt:
505 mnt_free_tab(tb);
506 if (!root)
507 root = strdup("/");
508 if (!root)
509 goto err;
510 fs->root = root;
511 free(mnt);
512 return 0;
513 err:
514 free(root);
515 free(mnt);
516 return -1;
517 }
518
519 /**
520 * mnt_prepare_update:
521 * @upd: update
522 *
523 * Prepares internal data for mtab update:
524 * - set filename if mnt_update_set_filename() wasn't called
525 * - set file format if mnt_update_set_format() wasn't called
526 * - bitwise-OR mountflags from mount options
527 * - for /var/run/mount/mountinfo:
528 * * evaluate if the update is necessary
529 * * set fs root and devname for bind mount and btrfs subvolumes
530 * * removes unnecessary mount options
531 * - allocate update_lock if necessary
532 *
533 * This function has to be always called before mount(2). The mnt_update_file()
534 * should not be called if mnt_prepare_update() returns non-zero value.
535 *
536 * Returns: 0 on success, 1 if update is unnecessary, negative in case of error
537 */
538 int mnt_prepare_update(mnt_update *upd)
539 {
540 char *u = NULL;
541 const char *o = NULL;
542 int rc = 0;
543
544 assert(upd);
545 assert(upd->fs);
546
547 if (!upd || !upd->fs)
548 return -EINVAL;
549
550 DBG(UPDATE, mnt_debug_h(upd,
551 "prepare update (target %s, source %s, optstr %s)",
552 mnt_fs_get_target(upd->fs),
553 mnt_fs_get_source(upd->fs),
554 mnt_fs_get_optstr(upd->fs)));
555
556 if (!upd->filename) {
557 const char *p = mnt_get_writable_mtab_path();
558 if (!p) {
559 if (errno) {
560 rc = -errno;
561 goto err; /* EACCES? */
562 }
563 goto nothing; /* no mtab */
564 }
565 upd->filename = strdup(p);
566 if (!upd->filename) {
567 rc = -ENOMEM;
568 goto err;
569 }
570 }
571 if (!upd->format) {
572 if (endswith(upd->filename, "mountinfo"))
573 upd->format = MNT_FMT_MOUNTINFO;
574 else if (endswith(upd->filename, "fstab"))
575 upd->format = MNT_FMT_FSTAB;
576 else
577 upd->format = MNT_FMT_MTAB;
578 }
579
580 /* TODO: cannonicalize source and target paths on mnt->fs */
581
582 if (upd->format != MNT_FMT_FSTAB) {
583 unsigned long fl = 0;
584
585 o = mnt_fs_get_optstr(upd->fs);
586 if (o && !mnt_optstr_get_mountflags(o, &fl))
587 upd->mountflags |= fl;
588 }
589
590 /* umount */
591 if (upd->action == MNT_ACT_UMOUNT)
592 return 0;
593
594 /*
595 * A) classic /etc/mtab or /etc/fstab update
596 */
597 if (upd->format != MNT_FMT_MOUNTINFO)
598 return 0;
599
600 /*
601 * B) /var/run/mount/mountinfo
602 * - remove all non-userspace mount options
603 */
604 if (upd->mountflags & MS_REMOUNT) {
605 rc = mnt_split_optstr(o, &u, NULL, NULL, MNT_NOMTAB, 0);
606 if (rc)
607 goto err;
608 rc = __mnt_fs_set_optstr_ptr(upd->fs, u, FALSE);
609 if (rc)
610 goto err;
611 u = NULL;
612 } else {
613 if (!o)
614 goto nothing; /* no options */
615 rc = mnt_split_optstr(o, &u, NULL, NULL, MNT_NOMTAB, 0);
616 if (rc)
617 goto err;
618 if (!u)
619 goto nothing; /* no userpsace options */
620 rc = set_fs_root(upd, upd->fs);
621 if (rc)
622 goto err;
623 rc = __mnt_fs_set_optstr_ptr(upd->fs, u, FALSE);
624 if (rc)
625 goto err;
626 u = NULL;
627 }
628
629 if (!upd->nolock && !upd->lc) {
630 upd->lc = mnt_new_lock(upd->filename, 0);
631 if (!upd->lc) {
632 rc = -ENOMEM;
633 goto err;
634 }
635 }
636
637 DBG(UPDATE, mnt_debug_h(upd, "prepare update: success"));
638 return 0;
639 err:
640 free(u);
641 DBG(UPDATE, mnt_debug_h(upd, "prepare update: failed"));
642 return rc;
643 nothing:
644 return 1;
645 }
646
647 static int add_entry(mnt_update *upd)
648 {
649 FILE *f;
650 int rc = -1;
651
652 assert(upd);
653
654 DBG(UPDATE, mnt_debug_h(upd, "add entry"));
655
656 if (upd->lc)
657 mnt_lock_file(upd->lc);
658 f = fopen(upd->filename, "a+");
659 if (f) {
660 if (upd->format == MNT_FMT_MOUNTINFO)
661 rc = fprintf_mountinfo_fs(f, upd->fs);
662 else
663 rc = fprintf_mtab_fs(f, upd->fs);
664 fclose(f);
665 }
666 if (upd->lc)
667 mnt_unlock_file(upd->lc);
668 return rc;
669 }
670
671 static int remove_entry(mnt_update *upd)
672 {
673 const char *target;
674 mnt_tab *tb = NULL;
675 mnt_fs *fs = NULL;
676 int rc = -1;
677
678 assert(upd);
679 assert(upd->filename);
680
681 target = mnt_fs_get_target(upd->fs);
682 assert(target);
683
684 DBG(UPDATE, mnt_debug_h(upd, "remove entry (target %s)", target));
685
686 if (upd->lc)
687 mnt_lock_file(upd->lc);
688 tb = mnt_new_tab_from_file(upd->filename);
689 if (!tb)
690 goto done;
691 fs = mnt_tab_find_target(tb, target, MNT_ITER_BACKWARD);
692 if (!fs) {
693 rc = 0; /* no error if the file does not contain the target */
694 goto done;
695 }
696 mnt_tab_remove_fs(tb, fs);
697
698 if (!update_file(upd->filename, upd->format, tb))
699 rc = 0;
700 done:
701 if (upd->lc)
702 mnt_unlock_file(upd->lc);
703 mnt_free_tab(tb);
704 mnt_free_fs(fs);
705 return rc;
706 }
707
708 static int modify_target(mnt_update *upd)
709 {
710 mnt_tab *tb = NULL;
711 mnt_fs *fs = NULL;
712 int rc = -1;
713
714 assert(upd);
715 assert(upd->old_target);
716 assert(upd->filename);
717 assert(mnt_fs_get_target(upd->fs));
718
719 if (!upd->old_target)
720 return -1;
721
722 DBG(UPDATE, mnt_debug_h(upd, "modify target (%s->%s)",
723 upd->old_target, mnt_fs_get_target(upd->fs)));
724
725 if (upd->lc)
726 mnt_lock_file(upd->lc);
727 tb = mnt_new_tab_from_file(upd->filename);
728 if (!tb)
729 goto done;
730 fs = mnt_tab_find_target(tb, upd->old_target, MNT_ITER_BACKWARD);
731 if (!fs) {
732 rc = 0; /* no error if the file does not contain the target */
733 goto done;
734 }
735
736 mnt_fs_set_target(fs, mnt_fs_get_target(upd->fs));
737
738 if (!update_file(upd->filename, upd->format, tb))
739 rc = 0;
740 done:
741 if (upd->lc)
742 mnt_unlock_file(upd->lc);
743 mnt_free_tab(tb);
744 return rc;
745 }
746
747 static int modify_options(mnt_update *upd)
748 {
749 mnt_tab *tb = NULL;
750 mnt_fs *fs = NULL, *rem_fs = NULL;
751 int rc = -1;
752 const char *target = mnt_fs_get_target(upd->fs);
753
754 assert(target);
755 assert(upd->filename);
756
757 DBG(UPDATE, mnt_debug_h(upd, "modify options (target %s)", target));
758
759 if (upd->lc)
760 mnt_lock_file(upd->lc);
761 tb = mnt_new_tab_from_file(upd->filename);
762 if (!tb)
763 goto done;
764 fs = mnt_tab_find_target(tb, target, MNT_ITER_BACKWARD);
765 if (!fs) {
766 rc = 0; /* no error if the file does not contain the target */
767 goto done;
768 }
769 if (upd->format == MNT_FMT_MOUNTINFO && !mnt_fs_get_optstr(upd->fs)) {
770 mnt_tab_remove_fs(tb, fs);
771 rem_fs = fs;
772 } else
773 rc = __mnt_fs_set_optstr(fs, mnt_fs_get_optstr(upd->fs), FALSE);
774
775 if (!update_file(upd->filename, upd->format, tb))
776 rc = 0;
777 done:
778 if (upd->lc)
779 mnt_unlock_file(upd->lc);
780 mnt_free_tab(tb);
781 mnt_free_fs(rem_fs);
782 return rc;
783 }
784
785 /**
786 * mnt_update_file:
787 * @upd: update
788 *
789 * Updates the update file. The behavior of this function is undefined if
790 * mnt_prepare_update() has not been called.
791 *
792 * Returns: 0 on success, -1 in case of error.
793 */
794 int mnt_update_file(mnt_update *upd)
795 {
796 assert(upd);
797 assert(upd->filename);
798 assert(upd->format);
799 assert(upd->fs);
800
801 if (!upd || !upd->fs)
802 return -1;
803
804 DBG(UPDATE, mnt_debug_h(upd, "update (target %s)",
805 mnt_fs_get_target(upd->fs)));
806 /*
807 * umount
808 */
809 if (upd->action == MNT_ACT_UMOUNT)
810 return remove_entry(upd);
811 /*
812 * mount
813 */
814 if (upd->action == MNT_ACT_MOUNT) {
815 if (upd->mountflags & MS_REMOUNT)
816 return modify_options(upd);
817
818 if (upd->mountflags & MS_MOVE)
819 return modify_target(upd);
820
821 return add_entry(upd); /* mount */
822 }
823 return -1;
824 }
825
826 #ifdef TEST_PROGRAM
827
828 #include <errno.h>
829
830 mnt_lock *lock;
831
832 static void lock_fallback(void)
833 {
834 if (lock)
835 mnt_unlock_file(lock);
836 }
837
838 static int update(mnt_update *upd)
839 {
840 int rc;
841
842 /*
843 * Note that mount(2) syscal should be called *after*
844 * mnt_prepare_update() and *before* mnt_update_file()
845 */
846 rc = mnt_prepare_update(upd);
847 if (!rc) {
848 /* setup lock fallback */
849 lock = mnt_update_get_lock(upd);
850 atexit(lock_fallback);
851
852 return mnt_update_file(upd);
853 }
854 if (rc == 1) {
855 printf("update: update is not reuquired\n");
856 return 0;
857 }
858 fprintf(stderr, "update: failed to prepare update\n");
859 return -1;
860 }
861
862 int test_add(struct mtest *ts, int argc, char *argv[])
863 {
864 mnt_fs *fs = mnt_new_fs();
865 mnt_update *upd;
866 int rc = -1;
867
868 if (argc < 5 || !fs)
869 return -1;
870 mnt_fs_set_source(fs, argv[1]);
871 mnt_fs_set_target(fs, argv[2]);
872 mnt_fs_set_fstype(fs, argv[3]);
873 mnt_fs_set_optstr(fs, argv[4]);
874
875 upd = mnt_new_update(MNT_ACT_MOUNT, 0, fs);
876 if (!upd)
877 return -1;
878
879 rc = update(upd);
880
881 mnt_free_update(upd);
882 mnt_free_fs(fs);
883 return rc;
884 }
885
886 int test_add_fstab(struct mtest *ts, int argc, char *argv[])
887 {
888 mnt_fs *fs = mnt_new_fs();
889 mnt_update *upd;
890 int rc = -1;
891
892 if (argc < 7 || !fs)
893 return -1;
894 mnt_fs_set_source(fs, argv[1]);
895 mnt_fs_set_target(fs, argv[2]);
896 mnt_fs_set_fstype(fs, argv[3]);
897 mnt_fs_set_optstr(fs, argv[4]);
898 mnt_fs_set_freq(fs, atoi(argv[5]));
899 mnt_fs_set_passno(fs, atoi(argv[6]));
900
901 /* this is tricky -- to add to fstab use "MNT_ACT_MOUNT" */
902 upd = mnt_new_update(MNT_ACT_MOUNT, 0, fs);
903 if (!upd)
904 return -1;
905
906 mnt_update_disable_lock(upd, TRUE); /* lock is unnecessary */
907 mnt_update_set_filename(upd, _PATH_MNTTAB); /* fstab */
908 mnt_update_set_format(upd, MNT_FMT_FSTAB);
909
910 rc = update(upd);
911
912 mnt_free_update(upd);
913 mnt_free_fs(fs);
914 return rc;
915 }
916
917 int test_remove(struct mtest *ts, int argc, char *argv[])
918 {
919 mnt_fs *fs = mnt_new_fs();
920 mnt_update *upd;
921 int rc = -1;
922
923 if (argc < 2 || !fs)
924 return -1;
925 mnt_fs_set_target(fs, argv[1]);
926
927 upd = mnt_new_update(MNT_ACT_UMOUNT, 0, fs);
928 if (!upd)
929 return -1;
930
931 rc = update(upd);
932
933 mnt_free_update(upd);
934 mnt_free_fs(fs);
935 return rc;
936 }
937
938 int test_move(struct mtest *ts, int argc, char *argv[])
939 {
940 mnt_fs *fs = mnt_new_fs();
941 mnt_update *upd;
942 int rc = -1;
943
944 if (argc < 3 || !fs)
945 return -1;
946 mnt_fs_set_target(fs, argv[2]);
947
948 upd = mnt_new_update(MNT_ACT_MOUNT, MS_MOVE, fs);
949 if (!upd)
950 return -1;
951 mnt_update_set_old_target(upd, argv[1]);
952
953 rc = update(upd);
954
955 mnt_free_update(upd);
956 mnt_free_fs(fs);
957 return rc;
958 }
959
960 int test_remount(struct mtest *ts, int argc, char *argv[])
961 {
962 mnt_fs *fs = mnt_new_fs();
963 mnt_update *upd;
964 int rc = -1;
965
966 if (argc < 3 || !fs)
967 return -1;
968
969 mnt_fs_set_target(fs, argv[1]);
970 mnt_fs_set_optstr(fs, argv[2]);
971
972 upd = mnt_new_update(MNT_ACT_MOUNT, MS_REMOUNT, fs);
973 if (!upd)
974 return -1;
975
976 rc = update(upd);
977
978 mnt_free_update(upd);
979 mnt_free_fs(fs);
980 return rc;
981 }
982
983 int main(int argc, char *argv[])
984 {
985 struct mtest tss[] = {
986 { "--add", test_add, "<src> <target> <type> <options> add line to mtab" },
987 { "--remove", test_remove, "<target> MS_REMOUNT mtab change" },
988 { "--move", test_move, "<old_target> <target> MS_MOVE mtab change" },
989 { "--remount",test_remount, "<target> <options> MS_REMOUNT mtab change" },
990
991 { "--add-fstab", test_add_fstab, "<src> <target> <type> <options> <freq> <passno> add line to fstab" },
992
993 { NULL }
994 };
995
996 return mnt_run_test(tss, argc, argv);
997 }
998
999 #endif /* TEST_PROGRAM */