]> git.ipfire.org Git - thirdparty/util-linux.git/blame - shlibs/mount/src/tab_update.c
libmount: cleanup API, remove typedef
[thirdparty/util-linux.git] / shlibs / mount / src / tab_update.c
CommitLineData
6c40a53d
KZ
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/**
30493710 9 * SECTION: update
0f32f1e2
KZ
10 * @title: mtab managment
11 * @short_description: userspace mount information management.
12 *
68164f6c 13 * The struct libmnt_update provides abstraction to manage mount options in userspace independently on
0f32f1e2
KZ
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 *
68164f6c 18 * It's recommended to use high-level struct libmnt_context API.
6c40a53d
KZ
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <sys/types.h>
24#include <sys/stat.h>
1d0cd73f
KZ
25#include <sys/file.h>
26#include <fcntl.h>
6c40a53d
KZ
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
68164f6c 36struct libmnt_update {
1d0cd73f 37 char *target;
68164f6c 38 struct libmnt_fs *fs;
77417bc0 39 char *filename;
1d0cd73f
KZ
40 unsigned long mountflags;
41 int userspace_only;
42 int ready;
6c40a53d
KZ
43};
44
68164f6c
KZ
45static int utab_new_entry(struct libmnt_fs *fs, unsigned long mountflags, struct libmnt_fs **ent);
46static int set_fs_root(struct libmnt_fs *result, struct libmnt_fs *fs, unsigned long mountflags);
1d0cd73f 47
6c40a53d 48/**
30493710 49 * mnt_new_update:
6c40a53d 50 *
1d0cd73f 51 * Returns: newly allocated update handler
6c40a53d 52 */
68164f6c 53struct libmnt_update *mnt_new_update(void)
6c40a53d 54{
68164f6c 55 struct libmnt_update *upd;
6c40a53d 56
68164f6c 57 upd = calloc(1, sizeof(*upd));
30493710 58 if (!upd)
6c40a53d
KZ
59 return NULL;
60
4e92d2b0 61 DBG(UPDATE, mnt_debug_h(upd, "allocate"));
6c40a53d 62
30493710 63 return upd;
6c40a53d
KZ
64}
65
66/**
30493710
KZ
67 * mnt_free_update:
68 * @upd: update
6c40a53d 69 *
68164f6c 70 * Deallocates struct libmnt_update handler.
6c40a53d 71 */
68164f6c 72void mnt_free_update(struct libmnt_update *upd)
6c40a53d 73{
30493710 74 if (!upd)
6c40a53d
KZ
75 return;
76
4e92d2b0 77 DBG(UPDATE, mnt_debug_h(upd, "free"));
6c40a53d 78
1d0cd73f
KZ
79 mnt_free_fs(upd->fs);
80 free(upd->target);
77417bc0 81 free(upd->filename);
30493710 82 free(upd);
6c40a53d
KZ
83}
84
77417bc0
KZ
85/*
86 * Returns 0 on success, 1 if not file available, -1 in case of error.
87 */
68164f6c 88int mnt_update_set_filename(struct libmnt_update *upd, const char *filename, int userspace_only)
77417bc0
KZ
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
36bda5cb
KZ
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 */
68164f6c 135const char *mnt_update_get_filename(struct libmnt_update *upd)
36bda5cb
KZ
136{
137 return upd && !upd->userspace_only ? upd->filename : NULL;
138}
139
6c40a53d 140/**
1d0cd73f
KZ
141 * mnt_update_is_ready:
142 * @upd: update handler
d300992d 143 *
1d0cd73f
KZ
144 * Returns: 1 if entry described by @upd is successfully prepared and will be
145 * written to mtab/utab file.
d300992d 146 */
68164f6c 147int mnt_update_is_ready(struct libmnt_update *upd)
d300992d 148{
1d0cd73f 149 return upd ? upd->ready : FALSE;
6c40a53d
KZ
150}
151
6c40a53d 152/**
30493710 153 * mnt_update_set_fs:
1d0cd73f
KZ
154 * @upd: update handler
155 * @mountflags: MS_* flags
2915bdc0
KZ
156 * @target: umount target, must be num for mount
157 * @fs: mount filesystem description, must be NULL for umount
d300992d 158 *
1d0cd73f 159 * Returns: -1 in case on error, 0 on success, 1 if update is unnecessary.
6c40a53d 160 */
68164f6c
KZ
161int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
162 const char *target, struct libmnt_fs *fs)
6c40a53d 163{
77417bc0
KZ
164 int rc;
165
30493710 166 assert(upd);
1d0cd73f 167 assert(target || fs);
7714c689 168
30493710 169 if (!upd)
3a5b1b1d 170 return -EINVAL;
2915bdc0
KZ
171 if ((mountflags & MS_MOVE) && (!fs || !mnt_fs_get_srcpath(fs)))
172 return -EINVAL;
173 if (target && fs)
174 return -EINVAL;
6c40a53d 175
1d0cd73f 176 DBG(UPDATE, mnt_debug_h(upd,
36bda5cb 177 "reseting FS [fs=0x%p, target=%s, flags=0x%08lx]",
1d0cd73f 178 fs, target, mountflags));
87a07a4c
KZ
179 if (fs) {
180 DBG(UPDATE, mnt_debug_h(upd, "FS template:"));
181 DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
182 }
6c40a53d 183
1d0cd73f
KZ
184 mnt_free_fs(upd->fs);
185 free(upd->target);
186 upd->ready = FALSE;
187 upd->fs = NULL;
188 upd->target = NULL;
36bda5cb
KZ
189 upd->mountflags = 0;
190
191 if (mountflags & MS_PROPAGATION)
192 return 1;
193
1d0cd73f 194 upd->mountflags = mountflags;
6c40a53d 195
77417bc0
KZ
196 rc = mnt_update_set_filename(upd, NULL, 0);
197 if (rc)
198 return rc; /* error or no file available (rc = 1) */
199
2915bdc0
KZ
200 if (target) {
201 upd->target = strdup(target);
202 if (!upd->target)
203 return -ENOMEM;
204
205 } else if (fs) {
1d0cd73f
KZ
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 {
f84fa6f7 211 upd->fs = mnt_copy_mtab_fs(fs);
1d0cd73f
KZ
212 if (!upd->fs)
213 return -ENOMEM;
f84fa6f7 214
1d0cd73f
KZ
215 }
216 }
6c40a53d 217
1d0cd73f
KZ
218
219 DBG(UPDATE, mnt_debug_h(upd, "ready"));
220 upd->ready = TRUE;
7714c689 221 return 0;
6c40a53d
KZ
222}
223
36bda5cb 224/**
f84fa6f7
KZ
225 * mnt_update_get_fs:
226 * @upd: update
227 *
228 * Returns: update filesystem entry or NULL
97e23b5e 229 */
68164f6c 230struct libmnt_fs *mnt_update_get_fs(struct libmnt_update *upd)
97e23b5e
KZ
231{
232 return upd ? upd->fs : NULL;
233}
1d0cd73f 234
36bda5cb 235/**
68164f6c 236 * mnt_update_get_mflags:
36bda5cb
KZ
237 * @upd: update
238 *
239 * Returns: mount flags as was set by mnt_update_set_fs()
240 */
68164f6c 241unsigned long mnt_update_get_mflags(struct libmnt_update *upd)
36bda5cb
KZ
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 */
68164f6c 253int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly)
36bda5cb
KZ
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
6c40a53d 286/*
1d0cd73f
KZ
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.
6c40a53d 292 */
68164f6c 293static int utab_new_entry(struct libmnt_fs *fs, unsigned long mountflags, struct libmnt_fs **ent)
6c40a53d 294{
1d0cd73f 295 int rc = 0;
76a06ca4 296 const char *o = NULL, *a = NULL;
f84fa6f7 297 char *u = NULL;
6c40a53d
KZ
298
299 assert(fs);
1d0cd73f
KZ
300 assert(ent);
301 assert(!(mountflags & MS_MOVE));
6c40a53d 302
1d0cd73f 303 if (!fs || !ent)
3a5b1b1d 304 return -EINVAL;
1d0cd73f 305 *ent = NULL;
6c40a53d 306
1d0cd73f 307 DBG(UPDATE, mnt_debug("prepare utab entry"));
6c40a53d 308
68164f6c 309 o = mnt_fs_get_user_options(fs);
76a06ca4
KZ
310 a = mnt_fs_get_attributes(fs);
311
f84fa6f7
KZ
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 }
1d0cd73f
KZ
325
326 /* allocate the entry */
327 *ent = mnt_copy_fs(fs);
328 if (!*ent) {
329 rc = -ENOMEM;
330 goto err;
6c40a53d
KZ
331 }
332
68164f6c 333 rc = mnt_fs_set_user_options(*ent, u);
76a06ca4
KZ
334 if (rc)
335 goto err;
336 rc = mnt_fs_set_attributes(*ent, a);
1d0cd73f
KZ
337 if (rc)
338 goto err;
6c40a53d 339
1d0cd73f 340 if (!(mountflags & MS_REMOUNT)) {
766af80b 341 rc = set_fs_root(*ent, fs, mountflags);
1d0cd73f
KZ
342 if (rc)
343 goto err;
344 }
6c40a53d 345
f84fa6f7 346 free(u);
1d0cd73f 347 DBG(UPDATE, mnt_debug("utab entry OK"));
6c40a53d 348 return 0;
1d0cd73f 349err:
1d0cd73f 350 mnt_free_fs(*ent);
f84fa6f7 351 free(u);
76a06ca4 352 *ent = NULL;
1d0cd73f 353 return rc;
6c40a53d
KZ
354}
355
68164f6c 356static int set_fs_root(struct libmnt_fs *result, struct libmnt_fs *fs, unsigned long mountflags)
6c40a53d
KZ
357{
358 char *root = NULL, *mnt = NULL;
76a06ca4 359 const char *fstype;
68164f6c 360 struct libmnt_table *tb = NULL;
1d0cd73f 361 int rc = -ENOMEM;
6c40a53d 362
1d0cd73f 363 assert(fs);
766af80b 364 assert(result);
1d0cd73f
KZ
365
366 DBG(UPDATE, mnt_debug("setting FS root"));
6c40a53d 367
6c40a53d
KZ
368 fstype = mnt_fs_get_fstype(fs);
369
370 /*
371 * bind-mount -- get fs-root and source device for the source filesystem
372 */
1d0cd73f 373 if (mountflags & MS_BIND) {
6c40a53d 374 const char *src, *src_root;
68164f6c 375 struct libmnt_fs *src_fs;
6c40a53d 376
f84fa6f7
KZ
377 DBG(UPDATE, mnt_debug("setting FS root: bind"));
378
6c40a53d 379 src = mnt_fs_get_srcpath(fs);
dd369652 380 if (src) {
766af80b 381 rc = mnt_fs_set_bindsrc(result, src);
dd369652
KZ
382 if (rc)
383 goto err;
1d0cd73f 384 mnt = mnt_get_mountpoint(src);
dd369652 385 }
1d0cd73f
KZ
386 if (!mnt) {
387 rc = -EINVAL;
6c40a53d 388 goto err;
1d0cd73f 389 }
6c40a53d
KZ
390 root = mnt_get_fs_root(src, mnt);
391
68164f6c 392 tb = __mnt_new_table_from_file(_PATH_PROC_MOUNTINFO, MNT_FMT_MOUNTINFO);
f84fa6f7
KZ
393 if (!tb) {
394 DBG(UPDATE, mnt_debug("failed to parse mountinfo -- using default"));
6c40a53d 395 goto dflt;
f84fa6f7 396 }
68164f6c 397 src_fs = mnt_table_find_target(tb, mnt, MNT_ITER_BACKWARD);
f84fa6f7
KZ
398 if (!src_fs) {
399 DBG(UPDATE, mnt_debug("not found '%s' in mountinfo -- using default", mnt));
6c40a53d 400 goto dflt;
f84fa6f7 401 }
6c40a53d
KZ
402
403 /* set device name and fs */
404 src = mnt_fs_get_srcpath(src_fs);
766af80b 405 rc = mnt_fs_set_source(result, src);
dd369652
KZ
406 if (rc)
407 goto err;
6c40a53d 408
766af80b 409 mnt_fs_set_fstype(result, mnt_fs_get_fstype(src_fs));
6c40a53d
KZ
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
76a06ca4 436 if (mnt_fs_get_option(fs, "subvol", &vol, &volsz))
6c40a53d
KZ
437 goto dflt;
438
f84fa6f7
KZ
439 DBG(UPDATE, mnt_debug("setting FS root: btrfs subvol"));
440
6c40a53d
KZ
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 }
6c40a53d 453dflt:
68164f6c 454 mnt_free_table(tb);
1d0cd73f 455 if (!root) {
6c40a53d 456 root = strdup("/");
1d0cd73f
KZ
457 if (!root)
458 goto err;
459 }
766af80b 460 result->root = root;
dd369652
KZ
461
462 DBG(UPDATE, mnt_debug("FS root result: %s", root));
463
6c40a53d
KZ
464 free(mnt);
465 return 0;
466err:
467 free(root);
468 free(mnt);
1d0cd73f 469 return rc;
d300992d
KZ
470}
471
1d0cd73f 472/* mtab and fstab update */
68164f6c 473static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
6c40a53d 474{
76a06ca4 475 char *o;
1d0cd73f
KZ
476 char *m1, *m2, *m3, *m4;
477 int rc;
6c40a53d 478
1d0cd73f
KZ
479 assert(fs);
480 assert(f);
1b56aae8 481
76a06ca4
KZ
482 o = mnt_fs_strdup_options(fs);
483 if (!o)
484 return -ENOMEM;
485
1d0cd73f
KZ
486 m1 = mangle(mnt_fs_get_source(fs));
487 m2 = mangle(mnt_fs_get_target(fs));
488 m3 = mangle(mnt_fs_get_fstype(fs));
76a06ca4 489 m4 = mangle(o);
1b56aae8 490
1d0cd73f
KZ
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;
6c40a53d 498
76a06ca4 499 free(o);
1d0cd73f
KZ
500 free(m1);
501 free(m2);
502 free(m3);
503 free(m4);
3a5b1b1d 504
1d0cd73f
KZ
505 return rc;
506}
6c40a53d 507
68164f6c 508static int fprintf_utab_fs(FILE *f, struct libmnt_fs *fs)
1d0cd73f 509{
dd369652 510 char *p;
4e92d2b0 511
1d0cd73f
KZ
512 assert(fs);
513 assert(f);
6c40a53d 514
1d0cd73f
KZ
515 if (!fs || !f)
516 return -EINVAL;
dd369652
KZ
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 }
76a06ca4
KZ
538 p = mangle(mnt_fs_get_attributes(fs));
539 if (p) {
540 fprintf(f, "ATTRS=%s ", p);
541 free(p);
542 }
68164f6c 543 p = mangle(mnt_fs_get_user_options(fs));
dd369652
KZ
544 if (p) {
545 fprintf(f, "OPTS=%s", p);
546 free(p);
547 }
dd369652
KZ
548 fputc('\n', f);
549
550 return 0;
6c40a53d
KZ
551}
552
68164f6c 553static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
6c40a53d
KZ
554{
555 FILE *f;
1d0cd73f
KZ
556 int rc, fd;
557 char *uq = NULL;
6c40a53d 558
77417bc0 559 if (!tb || !upd->filename)
1d0cd73f 560 return -EINVAL;
6c40a53d 561
77417bc0 562 DBG(UPDATE, mnt_debug_h(upd, "%s: updating", upd->filename));
3f31a959 563
77417bc0 564 fd = mnt_open_uniq_filename(upd->filename, &uq, O_WRONLY);
1d0cd73f
KZ
565 if (fd < 0)
566 return fd; /* error */
567
568 f = fdopen(fd, "w");
6c40a53d 569 if (f) {
1d0cd73f 570 struct stat st;
68164f6c
KZ
571 struct libmnt_iter itr;
572 struct libmnt_fs *fs;
1d0cd73f
KZ
573 int fd;
574
575 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
68164f6c 576 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
1d0cd73f
KZ
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
77417bc0 585 if (!rc && stat(upd->filename, &st) == 0)
1d0cd73f
KZ
586 /* Copy uid/gid from the present file before renaming. */
587 rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
588
6c40a53d 589 fclose(f);
77417bc0 590 rc = rename(uq, upd->filename) ? -errno : 0;
1d0cd73f
KZ
591 } else {
592 rc = -errno;
593 close(fd);
6c40a53d 594 }
1d0cd73f
KZ
595
596 unlink(uq); /* be paranoid */
597 free(uq);
6c40a53d
KZ
598 return rc;
599}
600
1d0cd73f 601static int utab_lock(const char *filename)
6c40a53d 602{
1d0cd73f
KZ
603 char *lfile;
604 int fd;
6c40a53d 605
1d0cd73f 606 assert(filename);
6c40a53d 607
1d0cd73f
KZ
608 if (asprintf(&lfile, "%s.lock", filename) == -1)
609 return -1;
6c40a53d 610
1d0cd73f 611 DBG(UPDATE, mnt_debug("%s: locking", lfile));
6c40a53d 612
b0bb8fb6
KZ
613 fd = open(lfile, O_RDONLY|O_CREAT|O_CLOEXEC, S_IWUSR|
614 S_IRUSR|S_IRGRP|S_IROTH);
1d0cd73f
KZ
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;
6c40a53d 623 }
1d0cd73f
KZ
624 return fd;
625}
6c40a53d 626
1d0cd73f
KZ
627static void utab_unlock(int fd)
628{
629 if (fd >= 0) {
630 DBG(UPDATE, mnt_debug("unlocking utab"));
631 close(fd);
632 }
6c40a53d
KZ
633}
634
68164f6c 635static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
6c40a53d 636{
1d0cd73f
KZ
637 FILE *f;
638 int rc = 0, u_lc = -1;
6c40a53d 639
30493710 640 assert(upd);
1d0cd73f 641 assert(upd->fs);
6c40a53d 642
77417bc0 643 DBG(UPDATE, mnt_debug_h(upd, "%s: add entry", upd->filename));
6c40a53d 644
1d0cd73f
KZ
645 if (lc)
646 mnt_lock_file(lc);
647 else if (upd->userspace_only)
77417bc0 648 u_lc = utab_lock(upd->filename);
6c40a53d 649
77417bc0 650 f = fopen(upd->filename, "a+");
1d0cd73f
KZ
651 if (f) {
652 rc = upd->userspace_only ? fprintf_utab_fs(f, upd->fs) :
653 fprintf_mtab_fs(f, upd->fs);
77417bc0 654 DBG(UPDATE, mnt_debug_h(upd, "%s: add [rc=%d]", upd->filename, rc));
1d0cd73f
KZ
655 fclose(f);
656 } else {
77417bc0 657 DBG(UPDATE, mnt_debug_h(upd, "%s: failed: %m", upd->filename));
1d0cd73f 658 rc = -errno;
6c40a53d 659 }
1d0cd73f
KZ
660 if (lc)
661 mnt_unlock_file(lc);
662 else if (u_lc != -1)
663 utab_unlock(u_lc);
664 return rc;
665}
6c40a53d 666
68164f6c 667static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
1d0cd73f 668{
68164f6c 669 struct libmnt_table *tb;
dd369652 670 int rc = 0, u_lc = -1;
6c40a53d 671
1d0cd73f
KZ
672 assert(upd);
673 assert(upd->target);
674
77417bc0 675 DBG(UPDATE, mnt_debug_h(upd, "%s: remove entry", upd->filename));
1d0cd73f
KZ
676
677 if (lc)
678 mnt_lock_file(lc);
679 else if (upd->userspace_only)
77417bc0 680 u_lc = utab_lock(upd->filename);
1d0cd73f 681
68164f6c 682 tb = __mnt_new_table_from_file(upd->filename,
dd369652 683 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
1d0cd73f 684 if (tb) {
68164f6c 685 struct libmnt_fs *rem = mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD);
1d0cd73f 686 if (rem) {
68164f6c
KZ
687 mnt_table_remove_fs(tb, rem);
688 rc = update_table(upd, tb);
1d0cd73f
KZ
689 mnt_free_fs(rem);
690 }
68164f6c 691 mnt_free_table(tb);
1d0cd73f
KZ
692 }
693 if (lc)
694 mnt_unlock_file(lc);
695 else if (u_lc != -1)
696 utab_unlock(u_lc);
6c40a53d
KZ
697 return rc;
698}
699
68164f6c 700static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *lc)
6c40a53d 701{
68164f6c 702 struct libmnt_table *tb = NULL;
dd369652 703 int rc = 0, u_lc = -1;
1d0cd73f 704
77417bc0 705 DBG(UPDATE, mnt_debug_h(upd, "%s: modify target", upd->filename));
1d0cd73f
KZ
706
707 if (lc)
708 mnt_lock_file(lc);
709 else if (upd->userspace_only)
77417bc0 710 u_lc = utab_lock(upd->filename);
1d0cd73f 711
68164f6c 712 tb = __mnt_new_table_from_file(upd->filename,
dd369652 713 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
1d0cd73f 714 if (tb) {
68164f6c 715 struct libmnt_fs *cur = mnt_table_find_target(tb,
2915bdc0 716 mnt_fs_get_srcpath(upd->fs), MNT_ITER_BACKWARD);
1d0cd73f
KZ
717 if (cur) {
718 rc = mnt_fs_set_target(cur, mnt_fs_get_target(upd->fs));
719 if (!rc)
68164f6c 720 rc = update_table(upd, tb);
1d0cd73f 721 }
68164f6c 722 mnt_free_table(tb);
1d0cd73f
KZ
723 }
724 if (lc)
725 mnt_unlock_file(lc);
726 else if (u_lc != -1)
727 utab_unlock(u_lc);
728 return rc;
729}
6c40a53d 730
68164f6c 731static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *lc)
1d0cd73f 732{
68164f6c 733 struct libmnt_table *tb = NULL;
dd369652 734 int rc = 0, u_lc = -1;
68164f6c 735 struct libmnt_fs *fs;
6c40a53d 736
1d0cd73f
KZ
737 assert(upd);
738 assert(upd->fs);
6c40a53d 739
77417bc0 740 DBG(UPDATE, mnt_debug_h(upd, "%s: modify options", upd->filename));
1d0cd73f 741
76a06ca4
KZ
742 fs = upd->fs;
743
1d0cd73f
KZ
744 if (lc)
745 mnt_lock_file(lc);
746 else if (upd->userspace_only)
77417bc0 747 u_lc = utab_lock(upd->filename);
1d0cd73f 748
68164f6c 749 tb = __mnt_new_table_from_file(upd->filename,
dd369652 750 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
1d0cd73f 751 if (tb) {
68164f6c 752 struct libmnt_fs *cur = mnt_table_find_target(tb,
76a06ca4 753 mnt_fs_get_target(fs),
1d0cd73f
KZ
754 MNT_ITER_BACKWARD);
755 if (cur) {
76a06ca4
KZ
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)
68164f6c
KZ
763 rc = mnt_fs_set_user_options(cur,
764 mnt_fs_get_user_options(fs));
1d0cd73f 765 if (!rc)
68164f6c 766 rc = update_table(upd, tb);
1d0cd73f 767 }
68164f6c 768 mnt_free_table(tb);
6c40a53d 769 }
76a06ca4 770
1d0cd73f
KZ
771 if (lc)
772 mnt_unlock_file(lc);
773 else if (u_lc != -1)
774 utab_unlock(u_lc);
6c40a53d
KZ
775 return rc;
776}
777
778/**
68164f6c 779 * mnt_update_table:
0f32f1e2 780 * @upd: update
1d0cd73f 781 * @lc: lock
6c40a53d 782 *
77417bc0 783 * High-level API to update /etc/mtab (or private /dev/.mount/utab file).
6c40a53d 784 *
1d0cd73f 785 * Returns: 0 on success, negative number on error.
6c40a53d 786 */
68164f6c 787int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
6c40a53d 788{
1d0cd73f
KZ
789 int rc = -EINVAL;
790
30493710 791 assert(upd);
6c40a53d 792
77417bc0 793 if (!upd->filename || !upd)
1d0cd73f
KZ
794 return -EINVAL;
795 if (!upd->ready)
d300992d 796 return 0;
6c40a53d 797
77417bc0 798 DBG(UPDATE, mnt_debug_h(upd, "%s: update tab", upd->filename));
f84fa6f7
KZ
799 if (upd->fs) {
800 DBG(UPDATE, mnt_fs_print_debug(upd->fs, stderr));
801 }
77417bc0 802
1d0cd73f 803 if (!upd->fs && upd->target)
77417bc0 804 rc = update_remove_entry(upd, lc); /* umount */
1d0cd73f 805 else if (upd->mountflags & MS_MOVE)
77417bc0 806 rc = update_modify_target(upd, lc); /* move */
1d0cd73f 807 else if (upd->mountflags & MS_REMOUNT)
77417bc0 808 rc = update_modify_options(upd, lc); /* remount */
1d0cd73f 809 else if (upd->fs)
77417bc0 810 rc = update_add_entry(upd, lc); /* mount */
1d0cd73f
KZ
811
812 upd->ready = FALSE;
77417bc0
KZ
813 DBG(UPDATE, mnt_debug_h(upd, "%s: update tab: done [rc=%d]",
814 upd->filename, rc));
1d0cd73f 815 return rc;
6c40a53d
KZ
816}
817
818#ifdef TEST_PROGRAM
819
68164f6c 820struct libmnt_lock *lock;
6c40a53d
KZ
821
822static void lock_fallback(void)
823{
824 if (lock)
825 mnt_unlock_file(lock);
826}
827
68164f6c 828static int update(const char *target, struct libmnt_fs *fs, unsigned long mountflags)
6c40a53d 829{
36bda5cb 830 int rc;
68164f6c 831 struct libmnt_update *upd;
36bda5cb 832 const char *filename;
6c40a53d 833
1d0cd73f 834 DBG(UPDATE, mnt_debug("update test"));
3a5b1b1d 835
77417bc0
KZ
836 upd = mnt_new_update();
837 if (!upd)
838 return -ENOMEM;
7714c689 839
1d0cd73f 840 rc = mnt_update_set_fs(upd, mountflags, target, fs);
1d0cd73f 841 if (rc == 1) {
7c118af7 842 /* update is unnecessary */
1d0cd73f
KZ
843 rc = 0;
844 goto done;
845 }
7c118af7
KZ
846 if (rc) {
847 fprintf(stderr, "failed to set FS\n");
848 goto done;
849 }
30493710 850
1d0cd73f 851 /* [... here should be mount(2) call ...] */
30493710 852
36bda5cb
KZ
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 }
68164f6c 859 rc = mnt_update_table(upd, lock);
1d0cd73f 860done:
30493710
KZ
861 return rc;
862}
863
68164f6c 864static int test_add(struct libmnt_test *ts, int argc, char *argv[])
30493710 865{
68164f6c 866 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 867 int rc;
30493710 868
1d0cd73f 869 if (argc < 5 || !fs)
30493710
KZ
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]);
76a06ca4 874 mnt_fs_set_options(fs, argv[4]);
30493710 875
1d0cd73f 876 rc = update(NULL, fs, 0);
7714c689 877 mnt_free_fs(fs);
6c40a53d
KZ
878 return rc;
879}
880
68164f6c 881static int test_remove(struct libmnt_test *ts, int argc, char *argv[])
6c40a53d 882{
1d0cd73f 883 if (argc < 2)
6c40a53d 884 return -1;
1d0cd73f 885 return update(argv[1], NULL, 0);
6c40a53d
KZ
886}
887
68164f6c 888static int test_move(struct libmnt_test *ts, int argc, char *argv[])
6c40a53d 889{
68164f6c 890 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 891 int rc;
6c40a53d 892
1d0cd73f 893 if (argc < 3)
6c40a53d 894 return -1;
25bca458 895 mnt_fs_set_source(fs, argv[1]);
7714c689 896 mnt_fs_set_target(fs, argv[2]);
25bca458
KZ
897
898 rc = update(NULL, fs, MS_MOVE);
7714c689 899
7714c689 900 mnt_free_fs(fs);
6c40a53d
KZ
901 return rc;
902}
903
68164f6c 904static int test_remount(struct libmnt_test *ts, int argc, char *argv[])
6c40a53d 905{
68164f6c 906 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 907 int rc;
6c40a53d 908
1d0cd73f 909 if (argc < 3)
6c40a53d 910 return -1;
7714c689 911 mnt_fs_set_target(fs, argv[1]);
76a06ca4 912 mnt_fs_set_options(fs, argv[2]);
7714c689 913
1d0cd73f 914 rc = update(NULL, fs, MS_REMOUNT);
7714c689 915 mnt_free_fs(fs);
6c40a53d
KZ
916 return rc;
917}
918
919int main(int argc, char *argv[])
920{
68164f6c 921 struct libmnt_test tss[] = {
6c40a53d
KZ
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 */