/* * Copyright (C) 2010 Karel Zak * * This file may be redistributed under the terms of the * GNU Lesser General Public License. * * Option-maps * ----------- * The mount(2) linux syscall uses two arguments for mount options: * * 1) mountflags (see MS_* macros in linux/fs.h) * 2) mountdata (usully a comma separated string of options) * * The libmount uses options-map(s) to describe mount options. The number of * maps is unlimited. The libmount options parser could be easily extended * (e.g. by mnt_optls_add_map()) to work with new options. * * The option description (map entry) includes: * * - option name and argument type (e.g. "loop[=%s]") * - option ID (in the map unique identifier or a mountflags, e.g MS_RDONLY) * - mask (MNT_INVERT, MNT_MDATA, MNT_MFLAG, MNT_NOMTAB) * * The option argument type is defined by: * * "=" -- required argument * "[=]" -- optional argument * * where the is sscanf() format string or * * {item0,item1,...} -- enum (mnt_option_get_number() converts the value * to 0..N number) * * The options argument format is used for parsing only. The library internally * stores the option argument as a string. The conversion to the data type is * on-demant by mnt_option_get_value_*() functions. * * The library checks options argument according to format for simple * formats only: * * %s, %d, %ld, %lld, %u, %lu, %llu, %x, %o and {enum} * * The libmount defines two basic built-in options maps: * * - MNT_LINUX_MAP -- fs-independent kernel mount options (usually MS_* flags) * - MNT_USERSPACE_MAP -- userspace specific mount options (e.g. "user", "loop") * */ #include #include #include #include #include "nls.h" #include "mountP.h" /* * fs-independent mount flags (built-in MNT_LINUX_MAP) */ static const struct mnt_optmap linux_flags_map[] = { { "ro", MS_RDONLY, MNT_MFLAG }, /* read-only */ { "rw", MS_RDONLY, MNT_MFLAG | MNT_INVERT }, /* read-write */ { "exec", MS_NOEXEC, MNT_MFLAG | MNT_INVERT }, /* permit execution of binaries */ { "noexec", MS_NOEXEC, MNT_MFLAG }, /* don't execute binaries */ { "suid", MS_NOSUID, MNT_MFLAG | MNT_INVERT }, /* honor suid executables */ { "nosuid", MS_NOSUID, MNT_MFLAG }, /* don't honor suid executables */ { "dev", MS_NODEV, MNT_MFLAG | MNT_INVERT }, /* interpret device files */ { "nodev", MS_NODEV, MNT_MFLAG }, /* don't interpret devices */ { "sync", MS_SYNCHRONOUS, MNT_MFLAG }, /* synchronous I/O */ { "async", MS_SYNCHRONOUS, MNT_MFLAG | MNT_INVERT }, /* asynchronous I/O */ { "dirsync", MS_DIRSYNC, MNT_MFLAG }, /* synchronous directory modifications */ { "remount", MS_REMOUNT, MNT_MFLAG }, /* Alter flags of mounted FS */ { "bind", MS_BIND, MNT_MFLAG }, /* Remount part of tree elsewhere */ { "rbind", MS_BIND|MS_REC, MNT_MFLAG }, /* Idem, plus mounted subtrees */ #ifdef MS_NOSUB { "sub", MS_NOSUB, MNT_MFLAG | MNT_INVERT }, /* allow submounts */ { "nosub", MS_NOSUB, MNT_MFLAG }, /* don't allow submounts */ #endif #ifdef MS_SILENT { "quiet", MS_SILENT, MNT_MFLAG }, /* be quiet */ { "loud", MS_SILENT, MNT_MFLAG | MNT_INVERT }, /* print out messages. */ #endif #ifdef MS_MANDLOCK { "mand", MS_MANDLOCK, MNT_MFLAG }, /* Allow mandatory locks on this FS */ { "nomand", MS_MANDLOCK, MNT_MFLAG | MNT_INVERT },/* Forbid mandatory locks on this FS */ #endif #ifdef MS_NOATIME { "atime", MS_NOATIME, MNT_MFLAG | MNT_INVERT }, /* Update access time */ { "noatime", MS_NOATIME, MNT_MFLAG }, /* Do not update access time */ #endif #ifdef MS_I_VERSION { "iversion", MS_I_VERSION, MNT_MFLAG }, /* Update inode I_version time */ { "noiversion", MS_I_VERSION, MNT_MFLAG | MNT_INVERT}, /* Don't update inode I_version time */ #endif #ifdef MS_NODIRATIME { "diratime", MS_NODIRATIME, MNT_MFLAG | MNT_INVERT }, /* Update dir access times */ { "nodiratime", MS_NODIRATIME, MNT_MFLAG }, /* Do not update dir access times */ #endif #ifdef MS_RELATIME { "relatime", MS_RELATIME, MNT_MFLAG }, /* Update access times relative to mtime/ctime */ { "norelatime", MS_RELATIME, MNT_MFLAG | MNT_INVERT }, /* Update access time without regard to mtime/ctime */ #endif #ifdef MS_STRICTATIME { "strictatime", MS_STRICTATIME, MNT_MFLAG }, /* Strict atime semantics */ { "nostrictatime", MS_STRICTATIME, MNT_MFLAG | MNT_INVERT }, /* kernel default atime */ #endif { NULL, 0, 0 } }; /* * userspace mount option (built-in MNT_USERSPACE_MAP) */ static const struct mnt_optmap userspace_opts_map[] = { { "defaults", MNT_MS_DFLTS, MNT_NOMTAB }, /* default options */ { "auto", MNT_MS_NOAUTO, MNT_INVERT | MNT_NOMTAB }, /* Can be mounted using -a */ { "noauto", MNT_MS_NOAUTO, MNT_NOMTAB }, /* Can only be mounted explicitly */ { "user[=%s]", MNT_MS_USER }, /* Allow ordinary user to mount (mtab) */ { "nouser", MNT_MS_USER, MNT_INVERT | MNT_NOMTAB }, /* Forbid ordinary user to mount */ { "users", MNT_MS_USERS, MNT_NOMTAB }, /* Allow ordinary users to mount */ { "nousers", MNT_MS_USERS, MNT_INVERT | MNT_NOMTAB }, /* Forbid ordinary users to mount */ { "owner", MNT_MS_OWNER, MNT_NOMTAB }, /* Let the owner of the device mount */ { "noowner", MNT_MS_OWNER, MNT_INVERT | MNT_NOMTAB }, /* Device owner has no special privs */ { "group", MNT_MS_GROUP, MNT_NOMTAB }, /* Let the group of the device mount */ { "nogroup", MNT_MS_GROUP, MNT_INVERT | MNT_NOMTAB }, /* Device group has no special privs */ { "_netdev", MNT_MS_NETDEV }, /* Device requires network */ { "comment=%s", MNT_MS_COMMENT, MNT_NOMTAB }, /* fstab comment only */ { "loop[=%s]", MNT_MS_LOOP }, /* use the loop device */ { "nofail", MNT_MS_NOFAIL, MNT_NOMTAB }, /* Do not fail if ENOENT on dev */ { NULL, 0, 0 } }; /** * mnt_get_builtin_map: * @id: map id -- MNT_LINUX_MAP or MNT_USERSPACE_MAP * * MNT_LINUX_MAP - Linux kernel fs-independent mount options * (usually MS_* flags, see linux/fs.h) * * MNT_USERSPACE_MAP - userpace mount(8) specific mount options * (e.g user=, _netdev, ...) * * Returns internal (static) libmount map. */ const struct mnt_optmap *mnt_get_builtin_optmap(int id) { assert(id); if (id == MNT_LINUX_MAP) return linux_flags_map; else if (id == MNT_USERSPACE_MAP) return userspace_opts_map; return NULL; } /* * Lookups for the @name in @maps and returns a map and in @mapent * returns the map entry */ const struct mnt_optmap *mnt_optmap_get_entry( struct mnt_optmap const **maps, int nmaps, const char *name, size_t namelen, const struct mnt_optmap **mapent) { int i; assert(maps); assert(nmaps); assert(name); assert(namelen); assert(mapent); *mapent = NULL; for (i = 0; i < nmaps; i++) { const struct mnt_optmap *map = maps[i]; const struct mnt_optmap *ent; const char *p; for (ent = map; ent && ent->name; ent++) { if (strncmp(ent->name, name, namelen)) continue; p = ent->name + namelen; if (*p == '\0' || *p == '=' || *p == '[') { *mapent = ent; return map; } } } return NULL; } /* * Converts @rawdata to number according to enum definition in the @mapent. */ int mnt_optmap_enum_to_number(const struct mnt_optmap *mapent, const char *rawdata, size_t len) { const char *p, *end = NULL, *begin = NULL; int n = -1; if (!rawdata || !*rawdata || !mapent || !len) return -1; p = strrchr(mapent->name, '='); if (!p || *(p + 1) == '{') return -1; /* value unexpected or not "enum" */ p += 2; if (!*p || *(p + 1) == '}') return -1; /* hmm... option is "={" or "={}" */ /* we cannot use strstr(), @rawdata is not terminated */ for (; p && *p; p++) { if (!begin) begin = p; /* begin of the item */ if (*p == ',') end = p; /* terminate the item */ if (*(p + 1) == '}') end = p + 1; /* end of enum definition */ if (!begin || !end) continue; if (end <= begin) return -1; n++; if (len == end - begin && strncasecmp(begin, rawdata, len) == 0) return n; p = end; } return -1; } /* * Returns data type defined in the @mapent. */ const char *mnt_optmap_get_type(const struct mnt_optmap *mapent) { char *type; assert(mapent); assert(mapent->name); type = strrchr(mapent->name, '='); if (!type) return NULL; /* value is unexpected */ if (type == mapent->name) return NULL; /* wrong format of type definition */ type++; if (*type != '%' && *type != '{') return NULL; /* wrong format of type definition */ return type ? : NULL; } /* * Does the option (that is described by @mntent) require any value? (e.g. * uid=) */ int mnt_optmap_require_value(const struct mnt_optmap *mapent) { char *type; assert(mapent); assert(mapent->name); type = strchr(mapent->name, '='); if (!type) return 0; /* value is unexpected */ if (type == mapent->name) return 0; /* wrong format of type definition */ if (*(type - 1) == '[') return 0; /* optional */ return 1; }