示例#1
0
/**
 * mnt_update_force_rdonly:
 * @upd: update
 * @rdonly: is read-only?
 *
 * Returns: 0 on success and negative number in case of error.
 */
int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly)
{
	int rc = 0;

	if (!upd || !upd->fs)
		return -EINVAL;

	if (rdonly && (upd->mountflags & MS_RDONLY))
		return 0;
	if (!rdonly && !(upd->mountflags & MS_RDONLY))
		return 0;

	if (!upd->userspace_only) {
		/* /etc/mtab -- we care about VFS options there */
		const char *o = mnt_fs_get_options(upd->fs);
		char *n = o ? strdup(o) : NULL;

		if (n)
			mnt_optstr_remove_option(&n, rdonly ? "rw" : "ro");
		if (!mnt_optstr_prepend_option(&n, rdonly ? "ro" : "rw", NULL))
			rc = mnt_fs_set_options(upd->fs, n);

		free(n);
	}

	if (rdonly)
		upd->mountflags &= ~MS_RDONLY;
	else
		upd->mountflags |= MS_RDONLY;

	return rc;
}
示例#2
0
/**
 * 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;
}