Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3152223
util.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
util.c
View Options
#include "util.h"
#include "libgfscontrol.h"
extern char *prog_name;
extern char *fsname;
extern int verbose;
static int gfs_controld_fd;
/* opt_map stuff from util-linux */
struct opt_map {
char *opt; /* option name */
int skip; /* skip in mtab option string (gfs: not used) */
int inv; /* true if flag value should be inverted */
int mask; /* flag mask value */
};
static struct opt_map opt_map[] = {
{ "defaults", 0, 0, 0 }, /* default options */
{ "ro", 1, 0, MS_RDONLY }, /* read-only */
{ "rw", 1, 1, MS_RDONLY }, /* read-write */
{ "exec", 0, 1, MS_NOEXEC }, /* permit execution of binaries */
{ "noexec", 0, 0, MS_NOEXEC }, /* don't execute binaries */
{ "suid", 0, 1, MS_NOSUID }, /* honor suid executables */
{ "nosuid", 0, 0, MS_NOSUID }, /* don't honor suid executables */
{ "dev", 0, 1, MS_NODEV }, /* interpret device files */
{ "nodev", 0, 0, MS_NODEV }, /* don't interpret devices */
{ "sync", 0, 0, MS_SYNCHRONOUS}, /* synchronous I/O */
{ "async", 0, 1, MS_SYNCHRONOUS}, /* asynchronous I/O */
{ "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */
{ "bind", 0, 0, MS_BIND }, /* Remount part of tree elsewhere */
{ "mand", 0, 0, MS_MANDLOCK }, /* Allow mandatory locks on this FS */
{ "nomand", 0, 1, MS_MANDLOCK }, /* Forbid mandatory locks on this FS */
{ "atime", 0, 1, MS_NOATIME }, /* Update access time */
{ "noatime", 0, 0, MS_NOATIME }, /* Do not update access time */
{ "diratime", 0, 1, MS_NODIRATIME }, /* Update dir access times */
{ "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
/* options used by the mount command only (not in sys/mount.h): */
{ "dirsync", 0, 0, 0 }, /* synchronous directory modifications */
{ "loop", 1, 0, 0 }, /* use a loop device */
{ "auto", 0, 1, 0 }, /* Can be mounted using -a */
{ "noauto", 0, 0, 0 }, /* Can only be mounted explicitly */
{ "users", 0, 0, 0 }, /* Allow ordinary user to mount */
{ "nousers", 0, 1, 0 }, /* Forbid ordinary user to mount */
{ "user", 0, 0, 0 }, /* Allow ordinary user to mount */
{ "nouser", 0, 1, 0 }, /* Forbid ordinary user to mount */
{ "owner", 0, 0, 0 }, /* Let the owner of the device mount */
{ "noowner", 0, 1, 0 }, /* Device owner has no special privs */
{ "_netdev", 0, 0, 0 }, /* Network device required (netfs) */
{ NULL, 0, 0, 0 }
};
/* if option has a corresponding MS_XXX, set the bit in the flags */
static int set_flag(char *o, int *flags)
{
struct opt_map *om;
for (om = opt_map; om->opt; om++) {
if (strcmp(om->opt, o))
continue;
if (om->inv)
*flags &= ~om->mask;
else
*flags |= om->mask;
log_debug(" %s flag %x for \"%s\", flags = %x",
om->inv ? "clear" : "set", om->mask, om->opt, *flags);
return 1;
}
return 0;
}
/* opts is the string of all mount options, this function finds
the options that have MS_XXX flags and sets the appropriate flag
bit. The options without an MS_ flag are copied into the extra
string. The values of some specific options are saved for later
internal use. */
void parse_opts(struct mount_options *mo)
{
char data[PATH_MAX+1];
char *options, *o, *v;
int extra_len = 0;
log_debug("parse_opts: opts = \"%s\"", mo->opts);
memset(data, 0, sizeof(data));
strncpy(data, mo->opts, PATH_MAX);
for (options = data; (o = strsep(&options, ",")); ) {
if (!*o)
continue;
if (set_flag(o, &mo->flags))
continue;
if (!strncmp("hostdata", o, 8)) {
if (mo->hostdata[0])
warn("duplicate hostdata strings");
else
strcat(mo->hostdata, o);
continue;
}
if (extra_len + 1 + strlen(o) > PATH_MAX)
die("extra options string is too long\n");
if (mo->extra[0]) {
strcat(mo->extra, ",");
extra_len += 1;
}
log_debug(" add extra %s", o);
strcat(mo->extra, o);
extra_len += strlen(o);
v = strchr(o, '=');
if (v)
*v++ = 0;
/* we grab these now so we don't have to parse them out
again later when doing proto-specific stuff */
if (!strcmp(o, "lockproto")) {
if (!v)
die("option lockproto needs value\n");
strncpy(mo->lockproto, v, 255);
}
if (!strcmp(o, "locktable")) {
if (!v)
die("option locktable needs value\n");
strncpy(mo->locktable, v, 255);
}
}
/* Hack to get the noatime/nodiratime option through to gfs */
if ((mo->flags & (MS_NOATIME | MS_NODIRATIME)) &&
(strcmp(mo->type, "gfs") == 0)) {
strcat(mo->extra, "gfs_noatime");
extra_len += strlen("gfs_noatime");
}
log_debug("parse_opts: flags = %x", mo->flags);
log_debug("parse_opts: extra = \"%s\"", mo->extra);
log_debug("parse_opts: hostdata = \"%s\"", mo->hostdata);
log_debug("parse_opts: lockproto = \"%s\"", mo->lockproto);
log_debug("parse_opts: locktable = \"%s\"", mo->locktable);
}
/* - when unmounting, we don't know the dev and need this function to set it;
we also want to select the _last_ line with a matching dir since it will
be the top-most fs that the umount(2) will unmount
- when mounting, we do know the dev and need this function to use it in the
comparison (for multiple fs's with the same mountpoint) */
void read_proc_mounts(struct mount_options *mo)
{
FILE *file;
char line[PATH_MAX];
char path[PATH_MAX];
char type[PATH_MAX];
char opts[PATH_MAX];
char device[PATH_MAX];
char save_line[PATH_MAX];
char save_opts[PATH_MAX];
char save_device[PATH_MAX];
int found = 0;
file = fopen("/proc/mounts", "r");
if (!file)
die("can't open /proc/mounts: %s\n", strerror(errno));
while (fgets(line, PATH_MAX, file)) {
if (sscanf(line, "%s %s %s %s", device, path, type, opts) != 4)
continue;
if (strcmp(path, mo->dir))
continue;
if (mo->dev[0] && strcmp(device, mo->dev))
continue;
if (strcmp(type, fsname))
die("%s is not a %s filesystem\n", mo->dir, fsname);
/* when there is an input dev specified (mount), we should get
only one matching line; when there is no input dev specified
(umount), we want the _last_ matching line */
strncpy(save_device, device, PATH_MAX);
strncpy(save_opts, opts, PATH_MAX);
strncpy(save_line, line, PATH_MAX);
found = 1;
}
fclose(file);
if (!found)
die("can't find /proc/mounts entry for directory %s\n", mo->dir);
else {
strncpy(mo->dev, save_device, PATH_MAX);
strncpy(mo->opts, save_opts, PATH_MAX);
strncpy(mo->proc_entry, save_line, PATH_MAX);
}
log_debug("read_proc_mounts: device = \"%s\"", mo->dev);
log_debug("read_proc_mounts: opts = \"%s\"", mo->opts);
}
void gfs2_inum_in(struct gfs2_inum *no, char *buf)
{
struct gfs2_inum *str = (struct gfs2_inum *)buf;
no->no_formal_ino = be64_to_cpu(str->no_formal_ino);
no->no_addr = be64_to_cpu(str->no_addr);
}
void gfs2_meta_header_in(struct gfs2_meta_header *mh, char *buf)
{
struct gfs2_meta_header *str = (struct gfs2_meta_header *)buf;
mh->mh_magic = be32_to_cpu(str->mh_magic);
mh->mh_type = be32_to_cpu(str->mh_type);
mh->mh_format = be32_to_cpu(str->mh_format);
}
void gfs2_sb_in(struct gfs2_sb *sb, char *buf)
{
struct gfs2_sb *str = (struct gfs2_sb *)buf;
gfs2_meta_header_in(&sb->sb_header, buf);
sb->sb_fs_format = be32_to_cpu(str->sb_fs_format);
sb->sb_multihost_format = be32_to_cpu(str->sb_multihost_format);
sb->sb_bsize = be32_to_cpu(str->sb_bsize);
sb->sb_bsize_shift = be32_to_cpu(str->sb_bsize_shift);
gfs2_inum_in(&sb->sb_master_dir, (char *)&str->sb_master_dir);
gfs2_inum_in(&sb->sb_root_dir, (char *)&str->sb_root_dir);
memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
}
int get_sb(char *device, struct gen_sb *sb_out)
{
int fd;
fd = open(device, O_RDONLY);
if (fd < 0)
die("can't open %s: %s\n", device, strerror(errno));
if (!strcmp(fsname, "gfs2")) {
char buf[GFS2_BASIC_BLOCK];
struct gfs2_sb sb;
do_lseek(fd, GFS2_SB_ADDR * GFS2_BASIC_BLOCK);
do_read(fd, buf, GFS2_BASIC_BLOCK);
gfs2_sb_in(&sb, buf);
if (sb.sb_header.mh_magic != GFS2_MAGIC ||
sb.sb_header.mh_type != GFS2_METATYPE_SB) {
die("there isn't a GFS2 filesystem on %s, "
"magic=%x type=%x\n", device,
sb.sb_header.mh_magic, sb.sb_header.mh_type);
}
if (sb.sb_fs_format != GFS2_FORMAT_FS ||
sb.sb_multihost_format != GFS2_FORMAT_MULTI) {
die("there appears to be a GFS, not GFS2, filesystem "
"on %s\n", device);
}
strncpy(sb_out->lockproto, sb.sb_lockproto, 256);
strncpy(sb_out->locktable, sb.sb_locktable, 256);
} else if (!strcmp(fsname, "gfs")) {
char buf[GFS_BASIC_BLOCK];
struct gfs_sb sb;
do_lseek(fd, GFS_SB_ADDR * GFS_BASIC_BLOCK);
do_read(fd, buf, GFS2_BASIC_BLOCK);
gfs_sb_in(&sb, buf);
if (sb.sb_header.mh_magic != GFS_MAGIC ||
sb.sb_header.mh_type != GFS_METATYPE_SB) {
die("there isn't a GFS filesystem on %s\n", device);
}
if (sb.sb_fs_format != GFS_FORMAT_FS ||
sb.sb_multihost_format != GFS_FORMAT_MULTI) {
die("there appears to be a GFS2, not GFS, filesystem "
"on %s\n", device);
}
strncpy(sb_out->lockproto, sb.sb_lockproto, 256);
strncpy(sb_out->locktable, sb.sb_locktable, 256);
}
close(fd);
return 0;
}
char *select_lockproto(struct mount_options *mo, struct gen_sb *sb)
{
/* find the effective lockproto, proto specified in mount options
overrides the sb lockproto */
if (mo->lockproto[0])
return mo->lockproto;
else
return sb->lockproto;
}
int lock_dlm_join(struct mount_options *mo, struct gen_sb *sb)
{
struct gfsc_mount_args ma;
int fd, rv, result;
memset(&ma, 0, sizeof(ma));
strncpy(ma.dir, mo->dir, PATH_MAX);
strncpy(ma.type, fsname, PATH_MAX);
strncpy(ma.proto, "lock_dlm", PATH_MAX);
strncpy(ma.options, mo->opts, PATH_MAX);
strncpy(ma.dev, mo->dev, PATH_MAX);
if (mo->locktable[0])
strncpy(ma.table, mo->locktable, PATH_MAX);
else
strncpy(ma.table, sb->locktable, PATH_MAX);
fd = gfsc_fs_connect();
if (fd < 0) {
warn("gfs_controld join connect error: %s", strerror(errno));
return fd;
}
/* tell gfs_controld to join the mountgroup */
rv = gfsc_fs_join(fd, &ma);
if (rv < 0) {
warn("gfs_controld join write error: %s", strerror(errno));
goto fail;
}
/* read the result of the join from gfs_controld */
rv = gfsc_fs_result(fd, &result, &ma);
if (rv < 0) {
warn("gfs_controld result read error: %s", strerror(errno));
goto fail;
}
rv = result;
switch (rv) {
case 0:
case -EALREADY:
break;
case -EPROTONOSUPPORT:
warn("lockproto not supported");
goto fail;
case -EOPNOTSUPP:
warn("jid, first and id are reserved options");
goto fail;
case -EBADFD:
warn("no colon found in table name");
goto fail;
case -ENAMETOOLONG:
warn("fs name too long");
goto fail;
case -ESTALE:
warn("fs is being unmounted");
goto fail;
case -EADDRINUSE:
warn("different fs appears to exist with the same name");
goto fail;
case -EBUSY:
warn("mount point already used or other mount in progress");
goto fail;
case -ENOMEM:
warn("out of memory");
goto fail;
case -EBADR:
warn("fs is for a different cluster");
goto fail;
case -ENOANO:
warn("node not a member of the default fence domain");
goto fail;
case -EROFS:
warn("read-only mount invalid with spectator option");
goto fail;
case -EMLINK:
warn("option string too long");
goto fail;
default:
warn("gfs_controld join error: %d", rv);
goto fail;
}
/*
* In addition to the result, gfs_controld also returns
* "hostdata=jid=X:id=Y:first=Z" in ma.hostdata.
* This is first combined with any hostdata the user gave on
* the command line and then the full hostdata is combined
* with the "extra" mount otions into the "extra_plus" string.
*/
if (strlen(mo->hostdata) + strlen(ma.hostdata) + 1 > PATH_MAX) {
warn("hostdata too long");
rv = -1;
goto fail;
}
if (!mo->hostdata[0])
snprintf(mo->hostdata, PATH_MAX, "%s", ma.hostdata);
else {
char *p = strstr(ma.hostdata, "=") + 1;
strcat(mo->hostdata, ":");
strcat(mo->hostdata, p);
}
log_debug("lock_dlm_join: hostdata: \"%s\"", mo->hostdata);
if (strlen(mo->extra) == 0)
snprintf(mo->extra_plus, PATH_MAX, "%s", mo->hostdata);
else
snprintf(mo->extra_plus, PATH_MAX, "%s,%s",
mo->extra, mo->hostdata);
/* keep gfs_controld connection open and reuse it below to
send the result of mount(2) to gfs_controld, except in
the case of another mount (EALREADY) */
if (rv == -EALREADY)
gfsc_fs_disconnect(fd);
else
gfs_controld_fd = fd;
return 0;
fail:
gfsc_fs_disconnect(fd);
return rv;
}
void lock_dlm_mount_done(struct mount_options *mo, struct gen_sb *sb,
int result)
{
struct gfsc_mount_args ma;
int rv;
if (!gfs_controld_fd)
return;
memset(&ma, 0, sizeof(ma));
strncpy(ma.dir, mo->dir, PATH_MAX);
strncpy(ma.type, fsname, PATH_MAX);
strncpy(ma.proto, "lock_dlm", PATH_MAX);
strncpy(ma.options, mo->opts, PATH_MAX);
strncpy(ma.dev, mo->dev, PATH_MAX);
if (mo->locktable[0])
strncpy(ma.table, mo->locktable, PATH_MAX);
else
strncpy(ma.table, sb->locktable, PATH_MAX);
/* tell gfs_controld the result of mount(2) */
rv = gfsc_fs_mount_done(gfs_controld_fd, &ma, result);
if (rv)
warn("gfs_controld mount_done write error: %s", strerror(errno));
gfsc_fs_disconnect(gfs_controld_fd);
}
int lock_dlm_leave(struct mount_options *mo, struct gen_sb *sb, int mnterr)
{
struct gfsc_mount_args ma;
int rv;
memset(&ma, 0, sizeof(ma));
strncpy(ma.dir, mo->dir, PATH_MAX);
strncpy(ma.type, fsname, PATH_MAX);
if (mo->locktable[0])
strncpy(ma.table, mo->locktable, PATH_MAX);
else
strncpy(ma.table, sb->locktable, PATH_MAX);
rv = gfsc_fs_leave(&ma, mnterr);
if (rv)
warn("leave: gfs_controld leave error: %s", strerror(errno));
return rv;
}
int lock_dlm_remount(struct mount_options *mo, struct gen_sb *sb)
{
struct gfsc_mount_args ma;
char *mode;
int fd, rv, result;
memset(&ma, 0, sizeof(ma));
if (strstr(mo->extra, "spectator")) {
warn("spectator remounts not allowed");
return -1;
}
if (mo->flags & MS_RDONLY)
mode = "ro";
else
mode = "rw";
strncpy(ma.dir, mo->dir, PATH_MAX);
strncpy(ma.type, fsname, PATH_MAX);
strncpy(ma.options, mode, PATH_MAX);
if (mo->locktable[0])
strncpy(ma.table, mo->locktable, PATH_MAX);
else
strncpy(ma.table, sb->locktable, PATH_MAX);
fd = gfsc_fs_connect();
if (fd < 0) {
warn("gfs_controld remount connect error: %s", strerror(errno));
return fd;
}
/* tell gfs_controld about the new mount options */
rv = gfsc_fs_remount(fd, &ma);
if (rv) {
warn("gfs_controld remount write error: %s", strerror(errno));
goto out;
}
/* read the result of the remount from gfs_controld */
rv = gfsc_fs_result(fd, &result, &ma);
if (rv < 0) {
warn("gfs_controld result read error: %s", strerror(errno));
goto out;
}
rv = result;
if (rv)
warn("remount not allowed from gfs_controld");
out:
gfsc_fs_disconnect(fd);
return rv;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Mon, Feb 24, 5:58 PM (3 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464388
Default Alt Text
util.c (14 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment