/** * mnt_optstr_prepend_option: * @optstr: option string or NULL, returns a reallocated string * @name: value name * @value: value * * Returns: 0 on success or -1 in case of error. After an error the @optstr should * be unmodified. */ int mnt_optstr_prepend_option(char **optstr, const char *name, const char *value) { int rc = 0; char *tmp = *optstr; assert(optstr); if (!name || !*name) return 0; *optstr = NULL; rc = mnt_optstr_append_option(optstr, name, value); if (!rc && tmp && *tmp) rc = mnt_optstr_append_option(optstr, tmp, NULL); if (!rc) { free(tmp); return 0; } free(*optstr); *optstr = tmp; DBG(OPTIONS, mnt_debug("failed to prepend '%s[=%s]' to '%s'", name, value, *optstr)); return rc; }
/* * Store mount options to mtab (or /dev/.mount/utab), called from mount.nfs. * * Note that on systems without /etc/mtab the fs-specific options are not * managed by libmount at all. We have to use "mount attributes" that are * private for mount.<type> helpers. */ static void store_mount_options(struct libmnt_fs *fs, const char *nfs_opts) { char *o = NULL; mnt_fs_set_attributes(fs, nfs_opts); /* for non-mtab systems */ /* for mtab create a new options list */ mnt_optstr_append_option(&o, mnt_fs_get_vfs_options(fs), NULL); mnt_optstr_append_option(&o, nfs_opts, NULL); mnt_optstr_append_option(&o, mnt_fs_get_user_options(fs), NULL); mnt_fs_set_options(fs, o); free(o); }
int mnt_context_is_loopdev(struct libmnt_context *cxt) { const char *type, *src; assert(cxt); /* The mount flags have to be merged, otherwise we have to use * expensive mnt_context_get_user_mflags() instead of cxt->user_mountflags. */ assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (!cxt->fs) return 0; src = mnt_fs_get_srcpath(cxt->fs); if (!src) return 0; /* backing file not set */ if (cxt->user_mountflags & (MNT_MS_LOOP | MNT_MS_OFFSET | MNT_MS_SIZELIMIT)) { DBG(LOOP, ul_debugobj(cxt, "loopdev specific options detected")); return 1; } if ((cxt->mountflags & (MS_BIND | MS_MOVE)) || mnt_context_propagation_only(cxt)) return 0; /* Automatically create a loop device from a regular file if a * filesystem is not specified or the filesystem is known for libblkid * (these filesystems work with block devices only). The file size * should be at least 1KiB, otherwise we will create an empty loopdev with * no mountable filesystem... * * Note that there is no restriction (on kernel side) that would prevent a regular * file as a mount(2) source argument. A filesystem that is able to mount * regular files could be implemented. */ type = mnt_fs_get_fstype(cxt->fs); if (mnt_fs_is_regular(cxt->fs) && (!type || strcmp(type, "auto") == 0 || blkid_known_fstype(type))) { struct stat st; if (stat(src, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 1024) { DBG(LOOP, ul_debugobj(cxt, "automatically enabling loop= option")); cxt->user_mountflags |= MNT_MS_LOOP; mnt_optstr_append_option(&cxt->fs->user_optstr, "loop", NULL); return 1; } } return 0; }
/** * mnt_optstr_set_option: * @optstr: string with a comma separated list of options * @name: requested option * @value: new value or NULL * * Set or unset the option @value. * * Returns: 0 on success, 1 when not found the @name or negative number in case * of error. */ int mnt_optstr_set_option(char **optstr, const char *name, const char *value) { struct libmnt_optloc ol; char *nameend; int rc = 1; assert(optstr); assert(name); if (!optstr) return -EINVAL; mnt_init_optloc(&ol); if (*optstr) rc = mnt_optstr_locate_option(*optstr, name, &ol); if (rc < 0) return rc; /* parse error */ if (rc == 1) return mnt_optstr_append_option(optstr, name, value); /* not found */ nameend = ol.begin + ol.namesz; if (value == NULL && ol.value && ol.valsz) /* remove unwanted "=value" */ mnt_optstr_remove_option_at(optstr, nameend, ol.end); else if (value && ol.value == NULL) /* insert "=value" */ rc = insert_value(optstr, nameend, value, NULL); else if (value && ol.value && strlen(value) == ol.valsz) /* simply replace =value */ memcpy(ol.value, value, ol.valsz); else if (value && ol.value) { mnt_optstr_remove_option_at(optstr, nameend, ol.end); rc = insert_value(optstr, nameend, value, NULL); } return rc; }
/** * mnt_optstr_apply_flags: * @optstr: string with comma separated list of options * @flags: returns mount flags * @map: options map * * Removes/adds options to the @optstr according to flags. For example: * * MS_NOATIME and "foo,bar,noexec" --returns-> "foo,bar,noatime" * * Returns: 0 on success or negative number in case of error. */ int mnt_optstr_apply_flags(char **optstr, unsigned long flags, const struct libmnt_optmap *map) { struct libmnt_optmap const *maps[1]; char *name, *next, *val; size_t namesz = 0, valsz = 0; unsigned long fl; int rc = 0; assert(optstr); if (!optstr || !map) return -EINVAL; DBG(CXT, mnt_debug("applying 0x%08lu flags to '%s'", flags, *optstr)); maps[0] = map; next = *optstr; fl = flags; /* * There is a convention that 'rw/ro' flags are always at the beginning of * the string (although the 'rw' is unnecessary). */ if (map == mnt_get_builtin_optmap(MNT_LINUX_MAP)) { const char *o = (fl & MS_RDONLY) ? "ro" : "rw"; if (next && (!strncmp(next, "rw", 2) || !strncmp(next, "ro", 2)) && (*(next + 2) == '\0' || *(next + 2) == ',')) { /* already set, be paranoid and fix it */ memcpy(next, o, 2); } else { rc = mnt_optstr_prepend_option(optstr, o, NULL); if (rc) goto err; next = *optstr; /* because realloc() */ } fl &= ~MS_RDONLY; next += 2; if (*next == ',') next++; } if (next && *next) { /* * scan @optstr and remove options that are missing in * @flags */ while(!mnt_optstr_next_option(&next, &name, &namesz, &val, &valsz)) { const struct libmnt_optmap *ent; if (mnt_optmap_get_entry(maps, 1, name, namesz, &ent)) { /* * remove unwanted option (rw/ro is already set) */ if (!ent || !ent->id) continue; /* ignore name=<value> if options map expects <name> only */ if (valsz && mnt_optmap_entry_novalue(ent)) continue; if (ent->id == MS_RDONLY || (ent->mask & MNT_INVERT) || (fl & ent->id) != (unsigned long) ent->id) { char *end = val ? val + valsz : name + namesz; next = name; rc = mnt_optstr_remove_option_at( optstr, name, end); if (rc) goto err; } if (!(ent->mask & MNT_INVERT)) fl &= ~ent->id; } } } /* add missing options */ if (fl) { const struct libmnt_optmap *ent; char *p; for (ent = map; ent && ent->name; ent++) { if ((ent->mask & MNT_INVERT) || ent->id == 0 || (fl & ent->id) != (unsigned long) ent->id) continue; /* don't add options which require values (e.g. offset=%d) */ p = strchr(ent->name, '='); if (p) { if (p > ent->name && *(p - 1) == '[') p--; /* name[=] */ else continue; /* name= */ p = strndup(ent->name, p - ent->name); if (!p) { rc = -ENOMEM; goto err; } mnt_optstr_append_option(optstr, p, NULL); free(p); } else mnt_optstr_append_option(optstr, ent->name, NULL); } } DBG(CXT, mnt_debug("new optstr '%s'", *optstr)); return rc; err: DBG(CXT, mnt_debug("failed to apply flags [rc=%d]", rc)); return rc; }