mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
202 lines
3.8 KiB
C
202 lines
3.8 KiB
C
// This file contains the unit testable parts of
|
|
// lvm2_activation_generator_systemd_red_hat
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h> /* For PATH_MAX for musl libc */
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
//----------------------------------------------------------------
|
|
|
|
static void _error(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
|
|
|
|
//----------------------------------------------------------------
|
|
|
|
// I'm rolling my own version of popen() here because I do not want to
|
|
// go through the shell.
|
|
|
|
struct child_process {
|
|
pid_t pid;
|
|
FILE *fp;
|
|
};
|
|
|
|
static bool _open_child(struct child_process *child, const char *cmd, const char *argv[])
|
|
{
|
|
int r, pipe_fd[2];
|
|
|
|
r = pipe(pipe_fd);
|
|
if (r < 0) {
|
|
_error("call to pipe() failed: %d\n", r);
|
|
return false;
|
|
}
|
|
|
|
child->pid = fork();
|
|
if (child->pid < 0) {
|
|
close(pipe_fd[0]);
|
|
close(pipe_fd[1]);
|
|
_error("call to fork() failed: %d\n", r);
|
|
return false;
|
|
}
|
|
|
|
if (child->pid == 0) {
|
|
// child
|
|
close(pipe_fd[0]);
|
|
if (pipe_fd[1] != STDOUT_FILENO) {
|
|
dup2(pipe_fd[1], STDOUT_FILENO);
|
|
close(pipe_fd[1]);
|
|
}
|
|
|
|
if (execv(cmd, (char *const *) argv) < 0)
|
|
_error("execv failed: %s\n", strerror(errno));
|
|
// Shouldn't get here unless exec failed.
|
|
exit(1);
|
|
} else {
|
|
// parent
|
|
close(pipe_fd[1]);
|
|
child->fp = fdopen(pipe_fd[0], "r");
|
|
if (!child->fp) {
|
|
_error("call to fdopen() failed\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Returns the child's exit status
|
|
static bool _close_child(struct child_process *child)
|
|
{
|
|
int status;
|
|
|
|
fclose(child->fp);
|
|
|
|
while (waitpid(child->pid, &status, 0) < 0)
|
|
if (errno != EINTR)
|
|
return -1;
|
|
|
|
if (WIFEXITED(status) && !WEXITSTATUS(status))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Aquiring config from the lvmconfig process
|
|
|
|
#define LVM_CONF_USE_LVMETAD "global/use_lvmetad"
|
|
#define LVM_CONF_USE_LVMPOLLD "global/use_lvmpolld"
|
|
|
|
struct config {
|
|
bool use_lvmetad;
|
|
bool sysinit_needed;
|
|
};
|
|
|
|
static bool _begins_with(const char *line, const char *prefix, const char **rest)
|
|
{
|
|
size_t len = strlen(prefix);
|
|
|
|
if (strlen(line) < len)
|
|
return false;
|
|
|
|
if (strncmp(line, prefix, len))
|
|
return false;
|
|
|
|
*rest = line + len;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool _parse_bool(const char *val, bool * result)
|
|
{
|
|
const char *b = val, *e;
|
|
|
|
while (*b && isspace(*b))
|
|
b++;
|
|
|
|
if (!*b)
|
|
goto parse_error;
|
|
|
|
e = b;
|
|
while (*e && !isspace(*e))
|
|
e++;
|
|
|
|
if ((e - b) != 1)
|
|
goto parse_error;
|
|
|
|
// We only handle '1', or '0'
|
|
if (*b == '1') {
|
|
*result = true;
|
|
return true;
|
|
|
|
} else if (*b == '0') {
|
|
*result = false;
|
|
return true;
|
|
}
|
|
// Fallthrough
|
|
|
|
parse_error:
|
|
_error("couldn't parse bool value '%s'\n", val);
|
|
return false;
|
|
}
|
|
|
|
static bool _parse_line(const char *line, struct config *cfg)
|
|
{
|
|
const char *val;
|
|
|
|
if (_begins_with(line, "use_lvmetad=", &val)) {
|
|
return _parse_bool(val, &cfg->use_lvmetad);
|
|
|
|
} else if (_begins_with(line, "use_lvmpolld=", &val)) {
|
|
bool r;
|
|
if (!_parse_bool(val, &r))
|
|
return false;
|
|
cfg->sysinit_needed = !r;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool _get_config(struct config *cfg, const char *lvmconfig_path)
|
|
{
|
|
static const char *_argv[] = {
|
|
"lvmconfig", LVM_CONF_USE_LVMETAD, LVM_CONF_USE_LVMPOLLD, NULL
|
|
};
|
|
|
|
bool r = true;
|
|
char buffer[256];
|
|
struct child_process child;
|
|
|
|
cfg->use_lvmetad = false;
|
|
cfg->sysinit_needed = true;
|
|
|
|
if (!_open_child(&child, lvmconfig_path, _argv)) {
|
|
_error("couldn't open lvmconfig process\n");
|
|
return false;
|
|
}
|
|
|
|
while (fgets(buffer, sizeof(buffer), child.fp)) {
|
|
if (!_parse_line(buffer, cfg)) {
|
|
_error("_parse_line() failed\n");
|
|
r = false;
|
|
}
|
|
}
|
|
|
|
if (!_close_child(&child)) {
|
|
_error("lvmconfig failed\n");
|
|
r = false;
|
|
}
|
|
|
|
return r;
|
|
}
|