From: Ondrej Oprala Date: Fri, 14 Jun 2013 10:41:30 +0000 (+0200) Subject: libmount: add functions to handle comments in fs tables X-Git-Tag: v2.24-rc1~460 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cb90e24e804e2f95eadf01e96561749092c858c1;p=thirdparty%2Futil-linux.git libmount: add functions to handle comments in fs tables Co-Author: Karel Zak Signed-off-by: Ondrej Oprala Signed-off-by: Karel Zak --- diff --git a/libmount/src/fs.c b/libmount/src/fs.c index 75e3bbb26d..bcf250597c 100644 --- a/libmount/src/fs.c +++ b/libmount/src/fs.c @@ -62,6 +62,7 @@ void mnt_free_fs(struct libmnt_fs *fs) free(fs->user_optstr); free(fs->attrs); free(fs->opt_fields); + free(fs->comment); free(fs); } @@ -1280,6 +1281,60 @@ int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name, return rc; } +/** + * mnt_fs_get_comment: + * @fs: fstab/mtab/mountinfo entry pointer + * + * Returns: 0 on success, 1 when not found the @name or negative number in case of error. + */ +const char *mnt_fs_get_comment(struct libmnt_fs *fs) +{ + assert(fs); + if (!fs) + return NULL; + return fs->comment; +} + +/** + * mnt_fs_set_comment: + * @fs: fstab entry pointer + * @comm: comment string + * + * Returns: 0 on success or <0 in case of error. + */ +int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm) +{ + char *p = NULL; + + assert(fs); + if (!fs) + return -EINVAL; + if (comm) { + p = strdup(comm); + if (!p) + return -ENOMEM; + } + + free(fs->comment); + fs->comment = p; + return 0; +} + +/** + * mnt_fs_append_comment: + * @fs: fstab entry pointer + * + * Returns: 0 on success or <0 in case of error. + */ +int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm) +{ + assert(fs); + if (!fs) + return -EINVAL; + + return append_string(&fs->comment, comm); +} + /** * mnt_fs_match_target: * @fs: filesystem @@ -1496,6 +1551,8 @@ int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file) minor(mnt_fs_get_devno(fs))); if (mnt_fs_get_tid(fs)) fprintf(file, "tid: %d\n", mnt_fs_get_tid(fs)); + if (mnt_fs_get_comment(fs)) + fprintf(file, "comment: '%s'\n", mnt_fs_get_comment(fs)); return 0; } diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in index db479e1865..74d21c7c5b 100644 --- a/libmount/src/libmount.h.in +++ b/libmount/src/libmount.h.in @@ -369,6 +369,10 @@ extern off_t mnt_fs_get_size(struct libmnt_fs *fs); extern off_t mnt_fs_get_usedsize(struct libmnt_fs *fs); extern int mnt_fs_get_priority(struct libmnt_fs *fs); +extern const char *mnt_fs_get_comment(struct libmnt_fs *fs); +extern int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm); +extern int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm); + extern int mnt_fs_match_target(struct libmnt_fs *fs, const char *target, struct libmnt_cache *cache); extern int mnt_fs_match_source(struct libmnt_fs *fs, const char *source, @@ -408,6 +412,15 @@ extern void mnt_free_table(struct libmnt_table *tb); extern int mnt_reset_table(struct libmnt_table *tb); extern int mnt_table_get_nents(struct libmnt_table *tb); + +extern void mnt_table_enable_comments(struct libmnt_table *tb, int enable); +extern const char *mnt_table_get_intro_comment(struct libmnt_table *tb); +extern int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm); +extern int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm); +extern int mnt_table_set_tailing_comment(struct libmnt_table *tb, const char *comm); +extern const char *mnt_table_get_tailing_comment(struct libmnt_table *tb); +extern int mnt_table_append_tailing_comment(struct libmnt_table *tb, const char *comm); + extern int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc); extern struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb); extern int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs); diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym index 2ea4839894..f72a8f8369 100644 --- a/libmount/src/libmount.sym +++ b/libmount/src/libmount.sym @@ -256,3 +256,17 @@ global: mnt_context_find_umount_fs; mnt_table_find_mountpoint; } MOUNT_2.22; + +MOUNT_2.24 { +global: + mnt_fs_append_comment; + mnt_fs_get_comment; + mnt_fs_set_comment; + mnt_table_append_intro_comment; + mnt_table_append_tailing_comment; + mnt_table_enable_comments; + mnt_table_get_intro_comment; + mnt_table_get_tailing_comment; + mnt_table_set_intro_comment; + mnt_table_set_tailing_comment; +} MOUNT_2.23; diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index c6b70e29f3..28b77d0c31 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -243,6 +243,8 @@ struct libmnt_fs { int flags; /* MNT_FS_* flags */ pid_t tid; /* /proc//mountinfo otherwise zero */ + char *comment; /* fstab comment */ + void *userdata; /* library independent data */ }; @@ -265,6 +267,9 @@ struct libmnt_fs { struct libmnt_table { int fmt; /* MNT_FMT_* file format */ int nents; /* number of valid entries */ + int comms; /* enable/disable comment parsing */ + char *comm_intro; /* First comment in file */ + char *comm_tail; /* Last comment in file */ struct libmnt_cache *cache; /* canonicalized paths/tags cache */ diff --git a/libmount/src/tab.c b/libmount/src/tab.c index b3e47bd6e7..5ac252ce19 100644 --- a/libmount/src/tab.c +++ b/libmount/src/tab.c @@ -110,6 +110,8 @@ void mnt_free_table(struct libmnt_table *tb) mnt_reset_table(tb); DBG(TAB, mnt_debug_h(tb, "free")); + free(tb->comm_intro); + free(tb->comm_tail); free(tb); } @@ -125,6 +127,148 @@ int mnt_table_get_nents(struct libmnt_table *tb) return tb ? tb->nents : 0; } +/** + * mnt_table_enable_comments: + * @tb: pointer to tab + * + * Enables parsing of comments. + * + * The initial (intro) file comment is accessible by + * mnt_table_get_intro_comment(). The intro and the comment of the first fstab + * entry has to be separated by blank line. The filesystem comments are + * accessible by mnt_fs_get_comment(). The tailing fstab comment is accessible + * by mnt_table_get_tailing_comment(). + * + * + * + * # + * # Intro comment + * # + * + * # this comments belongs to the first fs + * LABEL=foo /mnt/foo auto defaults 1 2 + * # this comments belongs to the second fs + * LABEL=bar /mnt/bar auto defaults 1 2 + * # tailing comment + * + * + */ +void mnt_table_enable_comments(struct libmnt_table *tb, int enable) +{ + assert(tb); + if (tb) + tb->comms = enable; +} + +/** + * mnt_table_get_intro_comment: + * @tb: pointer to tab + * + * Returns: initial comment in tb + */ +const char *mnt_table_get_intro_comment(struct libmnt_table *tb) +{ + assert(tb); + return tb ? tb->comm_intro : NULL; +} + +/** + * mnt_table_set_into_comment: + * @tb: pointer to tab + * @comm: comment or NULL + * + * Sets initial comment in tb. + * + * Returns: 0 on success or negative number in case of error. + */ +int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm) +{ + char *p = NULL; + + assert(tb); + if (!tb) + return -EINVAL; + if (comm) { + p = strdup(comm); + if (!p) + return -ENOMEM; + } + free(tb->comm_intro); + tb->comm_intro = p; + return 0; +} + +/** + * mnt_table_append_into_comment: + * @tb: pointer to tab + * @comm: comment of NULL + * + * Appends the initial comment in tb. + * + * Returns: 0 on success or negative number in case of error. + */ +int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm) +{ + assert(tb); + if (!tb) + return -EINVAL; + return append_string(&tb->comm_intro, comm); +} + +/** + * mnt_table_get_tailing_comment: + * @tb: pointer to tab + * + * Returns: table tailing comment + */ +const char *mnt_table_get_tailing_comment(struct libmnt_table *tb) +{ + assert(tb); + return tb ? tb->comm_tail : NULL; +} + +/** + * mnt_table_set_tailing_comment + * @tb: pointer to tab + * + * Sets tailing comment in table. + * + * Returns: 0 on success or negative number in case of error. + */ +int mnt_table_set_tailing_comment(struct libmnt_table *tb, const char *comm) +{ + char *p = NULL; + + assert(tb); + if (!tb) + return -EINVAL; + if (comm) { + p = strdup(comm); + if (!p) + return -ENOMEM; + } + free(tb->comm_tail); + tb->comm_tail = p; + return 0; +} + +/** + * mnt_table_append_tailing_comment: + * @tb: pointer to tab + * @comm: comment of NULL + * + * Appends to the tailing table comment. + * + * Returns: 0 on success or negative number in case of error. + */ +int mnt_table_append_tailing_comment(struct libmnt_table *tb, const char *comm) +{ + assert(tb); + if (!tb) + return -EINVAL; + return append_string(&tb->comm_tail, comm); +} + /** * mnt_table_set_cache: * @tb: pointer to tab @@ -1079,7 +1223,7 @@ static int parser_errcb(struct libmnt_table *tb, const char *filename, int line) return 1; /* all errors are recoverable -- this is default */ } -struct libmnt_table *create_table(const char *file) +struct libmnt_table *create_table(const char *file, int comments) { struct libmnt_table *tb; @@ -1089,6 +1233,7 @@ struct libmnt_table *create_table(const char *file) if (!tb) goto err; + mnt_table_enable_comments(tb, comments); mnt_table_set_parser_errcb(tb, parser_errcb); if (mnt_table_parse_file(tb, file) != 0) @@ -1106,7 +1251,7 @@ int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[]) struct libmnt_fs *fs; int rc = -1; - tb = create_table(argv[1]); + tb = create_table(argv[1], FALSE); if (!tb) return -1; @@ -1136,8 +1281,12 @@ int test_parse(struct libmnt_test *ts, int argc, char *argv[]) struct libmnt_iter *itr = NULL; struct libmnt_fs *fs; int rc = -1; + int parse_comments = FALSE; + + if (argc == 3 && !strcmp(argv[2], "--comments")) + parse_comments = TRUE; - tb = create_table(argv[1]); + tb = create_table(argv[1], parse_comments); if (!tb) return -1; @@ -1145,8 +1294,16 @@ int test_parse(struct libmnt_test *ts, int argc, char *argv[]) if (!itr) goto done; + if (mnt_table_get_intro_comment(tb)) + fprintf(stdout, "Initial comment:\n\"%s\"\n", + mnt_table_get_intro_comment(tb)); + while(mnt_table_next_fs(tb, itr, &fs) == 0) mnt_fs_print_debug(fs, stdout); + + if (mnt_table_get_tailing_comment(tb)) + fprintf(stdout, "Trailing comment:\n\"%s\"\n", + mnt_table_get_tailing_comment(tb)); rc = 0; done: mnt_free_iter(itr); @@ -1169,7 +1326,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr) file = argv[1], find = argv[2], what = argv[3]; - tb = create_table(file); + tb = create_table(file, FALSE); if (!tb) goto done; @@ -1213,7 +1370,7 @@ int test_find_pair(struct libmnt_test *ts, int argc, char *argv[]) struct libmnt_cache *mpc = NULL; int rc = -1; - tb = create_table(argv[1]); + tb = create_table(argv[1], FALSE); if (!tb) return -1; mpc = mnt_new_cache(); @@ -1274,7 +1431,7 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[]) return -1; } - fstab = create_table(argv[1]); + fstab = create_table(argv[1], FALSE); if (!fstab) goto done; @@ -1310,7 +1467,7 @@ done: int main(int argc, char *argv[]) { struct libmnt_test tss[] = { - { "--parse", test_parse, " parse and print tab" }, + { "--parse", test_parse, " [--comments] parse and print tab" }, { "--find-forward", test_find_fw, " " }, { "--find-backward", test_find_bw, " " }, { "--find-pair", test_find_pair, " " }, diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c index e930fd8417..527e14ee24 100644 --- a/libmount/src/tab_parse.c +++ b/libmount/src/tab_parse.c @@ -344,10 +344,82 @@ static int guess_table_format(char *line) return MNT_FMT_FSTAB; /* fstab, mtab or /proc/mounts */ } +static int is_comment_line(char *line) +{ + char *p = skip_spaces(line); + + if (p && (*p == '#' || *p == '\n')) + return 1; + return 0; +} + +/* returns 1 if the last line in the @str is blank */ +static int is_terminated_by_blank(const char *str) +{ + size_t sz = str ? strlen(str) : 0; + const char *p = sz ? str + (sz - 1) : NULL; + + if (!sz || !p || *p != '\n') + return 0; /* empty or not terminated by '\n' */ + if (p == str) + return 1; /* only '\n' */ + p--; + while (p >= str && (*p == ' ' || *p == '\t')) + p--; + return *p == '\n' ? 1 : 0; +} + +/* + * Reads the next line from the file. + * + * Returns 0 if the line is comment + * 1 if the line is not comment + * <0 on error + */ +static int next_comment_line(char *buf, size_t bufsz, + FILE *f, char **last, int *nlines) +{ + if (fgets(buf, bufsz, f) == NULL) + return feof(f) ? 1 : -EINVAL; + + ++*nlines; + *last = strchr(buf, '\n'); + + return is_comment_line(buf) ? 0 : 1; +} + +static int append_comment(struct libmnt_table *tb, + struct libmnt_fs *fs, + const char *comm, + int eof) +{ + int rc, intro = mnt_table_get_nents(tb) == 0; + + if (intro && is_terminated_by_blank(mnt_table_get_intro_comment(tb))) + intro = 0; + + DBG(TAB, mnt_debug_h(tb, "appending %s comment", + intro ? "intro" : + eof ? "tailing" : "fs")); + if (intro) + rc = mnt_table_append_intro_comment(tb, comm); + else if (eof) { + rc = mnt_table_set_tailing_comment(tb, + mnt_fs_get_comment(fs)); + if (!rc) + rc = mnt_table_append_tailing_comment(tb, comm); + if (!rc) + rc = mnt_fs_set_comment(fs, NULL); + } else + rc = mnt_fs_append_comment(fs, comm); + return rc; +} + /* * Read and parse the next line from {fs,m}tab or mountinfo */ -static int mnt_table_parse_next(struct libmnt_table *tb, FILE *f, struct libmnt_fs *fs, +static int mnt_table_parse_next(struct libmnt_table *tb, FILE *f, + struct libmnt_fs *fs, const char *filename, int *nlines) { char buf[BUFSIZ]; @@ -379,6 +451,26 @@ next_line: goto err; } } + + /* comments parser */ + if (tb->comms + && (tb->fmt == MNT_FMT_GUESS || tb->fmt == MNT_FMT_FSTAB) + && is_comment_line(buf)) { + do { + rc = append_comment(tb, fs, buf, feof(f)); + if (!rc) + rc = next_comment_line(buf, + sizeof(buf), + f, &s, nlines); + } while (rc == 0); + + if (rc == 1 && feof(f)) + rc = append_comment(tb, fs, NULL, 1); + if (rc < 0) + return rc; + + } + *s = '\0'; if (--s >= buf && *s == '\r') *s = '\0'; diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c index 1e7f32be0d..b83c1dd37a 100644 --- a/libmount/src/tab_update.c +++ b/libmount/src/tab_update.c @@ -408,13 +408,14 @@ err: */ static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs) { - const char *o, *src, *fstype; + const char *o, *src, *fstype, *comm; char *m1, *m2, *m3, *m4; int rc; assert(fs); assert(f); + comm = mnt_fs_get_comment(fs); src = mnt_fs_get_source(fs); fstype = mnt_fs_get_fstype(fs); o = mnt_fs_get_options(fs); @@ -425,6 +426,8 @@ static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs) m4 = o ? mangle(o) : "rw"; if (m1 && m2 && m3 && m4) { + if (comm) + fputs(comm, f); rc = fprintf(f, "%s %s %s %s %d %d\n", m1, m2, m3, m4, mnt_fs_get_freq(fs), @@ -527,6 +530,10 @@ static int update_table(struct libmnt_update *upd, struct libmnt_table *tb) struct libmnt_fs *fs; mnt_reset_iter(&itr, MNT_ITER_FORWARD); + + if (tb->comms && mnt_table_get_intro_comment(tb)) + fputs(mnt_table_get_intro_comment(tb), f); + while(mnt_table_next_fs(tb, &itr, &fs) == 0) { if (upd->userspace_only) rc = fprintf_utab_fs(f, fs); @@ -538,6 +545,8 @@ static int update_table(struct libmnt_update *upd, struct libmnt_table *tb) goto leave; } } + if (tb->comms && mnt_table_get_tailing_comment(tb)) + fputs(mnt_table_get_tailing_comment(tb), f); if (fflush(f) != 0) { rc = -errno; diff --git a/tests/expected/libmount/tabfiles-parse-fstab-full b/tests/expected/libmount/tabfiles-parse-fstab-full new file mode 100644 index 0000000000..d46416d8d5 --- /dev/null +++ b/tests/expected/libmount/tabfiles-parse-fstab-full @@ -0,0 +1,77 @@ +Initial comment: +"# this is a leading comment + +" +------ fs: +source: UUID=d3a8f783-df75-4dc8-9163-975a891052c0 +target: / +fstype: ext3 +Non-data: +"# this comments belongs to the first fs +" +------ fs: +source: UUID=fef7ccb3-821c-4de8-88dc-71472be5946f +target: /boot +fstype: ext3 +optstr: noatime,defaults +VFS-optstr: noatime +freq: 1 +pass: 2 +------ fs: +source: UUID=1f2aa318-9c34-462e-8d29-260819ffd657 +target: swap +fstype: swap +Non-data: +" +# 3rd fs comment + newline padding + +" +------ fs: +source: tmpfs +target: /dev/shm +fstype: tmpfs +optstr: defaults +------ fs: +source: devpts +target: /dev/pts +fstype: devpts +optstr: gid=5,mode=620 +FS-opstr: gid=5,mode=620 +------ fs: +source: sysfs +target: /sys +fstype: sysfs +optstr: defaults +------ fs: +source: proc +target: /proc +fstype: proc +optstr: defaults +------ fs: +source: /dev/mapper/foo +target: /home/foo +fstype: ext4 +Non-data: +"# this is comment +" +------ fs: +source: foo.com:/mnt/share +target: /mnt/remote +fstype: nfs +optstr: noauto +user-optstr: noauto +------ fs: +source: //bar.com/gogogo +target: /mnt/gogogo +fstype: cifs +optstr: user=SRGROUP/baby,noauto +user-optstr: user=SRGROUP/baby,noauto +------ fs: +source: /dev/foo +target: /any/foo/ +fstype: auto +optstr: defaults +Trailing comment: +" +#this is a trailing comment +" diff --git a/tests/ts/libmount/files/fstab.comment b/tests/ts/libmount/files/fstab.comment new file mode 100644 index 0000000000..656e663afd --- /dev/null +++ b/tests/ts/libmount/files/fstab.comment @@ -0,0 +1,22 @@ +# + # this is a leading comment +# + +# this comments belongs to the first fs +UUID=d3a8f783-df75-4dc8-9163-975a891052c0 / ext3 noatime,defaults 1 1 +UUID=fef7ccb3-821c-4de8-88dc-71472be5946f /boot ext3 noatime,defaults 1 2 + +# 3rd fs comment + newline padding + +UUID=1f2aa318-9c34-462e-8d29-260819ffd657 swap swap defaults 0 0 +tmpfs /dev/shm tmpfs defaults 0 0 +devpts /dev/pts devpts gid=5,mode=620 0 0 +sysfs /sys sysfs defaults 0 0 +proc /proc proc defaults 0 0 +# this is comment +/dev/mapper/foo /home/foo ext4 noatime,defaults 0 0 +foo.com:/mnt/share /mnt/remote nfs noauto +//bar.com/gogogo /mnt/gogogo cifs user=SRGROUP/baby,noauto +/dev/foo /any/foo/ auto defaults 0 0 + +#this is a trailing comment diff --git a/tests/ts/libmount/tabfiles b/tests/ts/libmount/tabfiles index 671c649bbe..c6fa360b3f 100755 --- a/tests/ts/libmount/tabfiles +++ b/tests/ts/libmount/tabfiles @@ -17,6 +17,11 @@ ts_valgrind $TESTPROG --parse "$TS_SELF/files/fstab" &> $TS_OUTPUT sed -i -e 's/fs: 0x.*/fs:/g' $TS_OUTPUT ts_finalize_subtest +ts_init_subtest "parse-fstab-full" +ts_valgrind $TESTPROG --parse "$TS_SELF/files/fstab.comment" --comments &> $TS_OUTPUT +sed -i -e 's/fs: 0x.*/fs:/g' $TS_OUTPUT +ts_finalize_subtest + ts_init_subtest "parse-mtab" ts_valgrind $TESTPROG --parse "$TS_SELF/files/mtab" &> $TS_OUTPUT sed -i -e 's/fs: 0x.*/fs:/g' $TS_OUTPUT