mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-31 14:50:37 +03:00
lvmpolld: introduce client functionality
as of now lvmpolld works as client utility for querying running instance of lvmpolld server on metadata, state, etc. Currently the only request implemented is the '--dump'. It prints out full lvmpolld state (mimics lvmdump -p command).
This commit is contained in:
parent
04c77bd886
commit
b91e1ea95e
@ -1,5 +1,6 @@
|
||||
Version 2.02.120 -
|
||||
===============================
|
||||
add lvmpolld client mode for querying running server instance for status info.
|
||||
Fix some libdaemon socket creation and reuse error paths.
|
||||
Daemons (libdaemon) support exit on idle also in non-systemd environment.
|
||||
Provide make dist and make rpm targets
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "daemon-server.h"
|
||||
#include "daemon-log.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <poll.h>
|
||||
#include <wait.h>
|
||||
|
||||
@ -61,21 +62,23 @@ static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void usage(const char *prog, FILE *file)
|
||||
static void _usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage:\n"
|
||||
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n"
|
||||
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n"
|
||||
"%s --dump [-s path]\n"
|
||||
" -V Show version info\n"
|
||||
" -h Show this help information\n"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" --dump Dump full lvmpolld state\n"
|
||||
" -l Logging message level (-l {all|wire|debug})\n"
|
||||
" -p Set path to the pidfile\n"
|
||||
" -s Set path to the socket to listen on\n"
|
||||
" -s Set path to the communication socket\n"
|
||||
" -B Path to lvm2 binary\n"
|
||||
" -t Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog);
|
||||
" -t Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog, prog);
|
||||
}
|
||||
|
||||
static int init(struct daemon_state *s)
|
||||
static int _init(struct daemon_state *s)
|
||||
{
|
||||
struct lvmpolld_state *ls = s->private;
|
||||
ls->log = s->log;
|
||||
@ -109,35 +112,35 @@ static int init(struct daemon_state *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void lvmpolld_stores_lock(struct lvmpolld_state *ls)
|
||||
static void _lvmpolld_stores_lock(struct lvmpolld_state *ls)
|
||||
{
|
||||
pdst_lock(ls->id_to_pdlv_poll);
|
||||
pdst_lock(ls->id_to_pdlv_abort);
|
||||
}
|
||||
|
||||
static void lvmpolld_stores_unlock(struct lvmpolld_state *ls)
|
||||
static void _lvmpolld_stores_unlock(struct lvmpolld_state *ls)
|
||||
{
|
||||
pdst_unlock(ls->id_to_pdlv_abort);
|
||||
pdst_unlock(ls->id_to_pdlv_poll);
|
||||
}
|
||||
|
||||
static void lvmpolld_global_lock(struct lvmpolld_state *ls)
|
||||
static void _lvmpolld_global_lock(struct lvmpolld_state *ls)
|
||||
{
|
||||
lvmpolld_stores_lock(ls);
|
||||
_lvmpolld_stores_lock(ls);
|
||||
|
||||
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_poll);
|
||||
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_abort);
|
||||
}
|
||||
|
||||
static void lvmpolld_global_unlock(struct lvmpolld_state *ls)
|
||||
static void _lvmpolld_global_unlock(struct lvmpolld_state *ls)
|
||||
{
|
||||
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_abort);
|
||||
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_poll);
|
||||
|
||||
lvmpolld_stores_unlock(ls);
|
||||
_lvmpolld_stores_unlock(ls);
|
||||
}
|
||||
|
||||
static int fini(struct daemon_state *s)
|
||||
static int _fini(struct daemon_state *s)
|
||||
{
|
||||
int done;
|
||||
const struct timespec t = { .tv_nsec = 250000000 }; /* .25 sec */
|
||||
@ -147,18 +150,18 @@ static int fini(struct daemon_state *s)
|
||||
|
||||
DEBUGLOG(s, "sending cancel requests");
|
||||
|
||||
lvmpolld_global_lock(ls);
|
||||
_lvmpolld_global_lock(ls);
|
||||
pdst_locked_send_cancel(ls->id_to_pdlv_poll);
|
||||
pdst_locked_send_cancel(ls->id_to_pdlv_abort);
|
||||
lvmpolld_global_unlock(ls);
|
||||
_lvmpolld_global_unlock(ls);
|
||||
|
||||
DEBUGLOG(s, "waiting for background threads to finish");
|
||||
|
||||
while(1) {
|
||||
lvmpolld_stores_lock(ls);
|
||||
_lvmpolld_stores_lock(ls);
|
||||
done = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
|
||||
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
|
||||
lvmpolld_stores_unlock(ls);
|
||||
_lvmpolld_stores_unlock(ls);
|
||||
if (done)
|
||||
break;
|
||||
nanosleep(&t, NULL);
|
||||
@ -166,10 +169,10 @@ static int fini(struct daemon_state *s)
|
||||
|
||||
DEBUGLOG(s, "destroying internal data structures");
|
||||
|
||||
lvmpolld_stores_lock(ls);
|
||||
_lvmpolld_stores_lock(ls);
|
||||
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_poll);
|
||||
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_abort);
|
||||
lvmpolld_stores_unlock(ls);
|
||||
_lvmpolld_stores_unlock(ls);
|
||||
|
||||
pdst_destroy(ls->id_to_pdlv_poll);
|
||||
pdst_destroy(ls->id_to_pdlv_abort);
|
||||
@ -199,12 +202,12 @@ static void update_idle_state(struct lvmpolld_state *ls)
|
||||
if (!ls->idle)
|
||||
return;
|
||||
|
||||
lvmpolld_stores_lock(ls);
|
||||
_lvmpolld_stores_lock(ls);
|
||||
|
||||
ls->idle->is_idle = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
|
||||
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
|
||||
|
||||
lvmpolld_stores_unlock(ls);
|
||||
_lvmpolld_stores_unlock(ls);
|
||||
|
||||
DEBUGLOG(ls, "%s: %s %s%s", PD_LOG_PREFIX, "daemon is", ls->idle->is_idle ? "" : "not ", "idle");
|
||||
}
|
||||
@ -703,7 +706,7 @@ static response dump_state(client_handle h, struct lvmpolld_state *ls, request r
|
||||
|
||||
buffer_init(b);
|
||||
|
||||
lvmpolld_global_lock(ls);
|
||||
_lvmpolld_global_lock(ls);
|
||||
|
||||
buffer_append(b, "# Registered polling operations\n\n");
|
||||
buffer_append(b, "poll {\n");
|
||||
@ -715,12 +718,12 @@ static response dump_state(client_handle h, struct lvmpolld_state *ls, request r
|
||||
pdst_locked_dump(ls->id_to_pdlv_abort, b);
|
||||
buffer_append(b, "}");
|
||||
|
||||
lvmpolld_global_unlock(ls);
|
||||
_lvmpolld_global_unlock(ls);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static response handler(struct daemon_state s, client_handle h, request r)
|
||||
static response _handler(struct daemon_state s, client_handle h, request r)
|
||||
{
|
||||
struct lvmpolld_state *ls = s.private;
|
||||
const char *rq = daemon_request_str(r, "request", "NONE");
|
||||
@ -755,16 +758,149 @@ static int process_timeout_arg(const char *str, unsigned *max_timeouts)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Client functionality */
|
||||
typedef int (*action_fn_t) (void *args);
|
||||
|
||||
struct log_line_baton {
|
||||
const char *prefix;
|
||||
};
|
||||
|
||||
daemon_handle _lvmpolld = { .error = 0 };
|
||||
|
||||
static daemon_handle _lvmpolld_open(const char *socket)
|
||||
{
|
||||
daemon_info lvmpolld_info = {
|
||||
.path = "lvmpolld",
|
||||
.socket = socket ?: DEFAULT_RUN_DIR "/lvmpolld.socket",
|
||||
.protocol = LVMPOLLD_PROTOCOL,
|
||||
.protocol_version = LVMPOLLD_PROTOCOL_VERSION
|
||||
};
|
||||
|
||||
return daemon_open(lvmpolld_info);
|
||||
}
|
||||
|
||||
static void _log_line(const char *line, void *baton) {
|
||||
struct log_line_baton *b = baton;
|
||||
fprintf(stdout, "%s%s\n", b->prefix, line);
|
||||
}
|
||||
|
||||
static int printout_raw_response(const char *prefix, const char *msg)
|
||||
{
|
||||
struct log_line_baton b = { .prefix = prefix };
|
||||
char *buf;
|
||||
char *pos;
|
||||
|
||||
buf = dm_strdup(msg);
|
||||
pos = buf;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
while (pos) {
|
||||
char *next = strchr(pos, '\n');
|
||||
if (next)
|
||||
*next = 0;
|
||||
_log_line(pos, &b);
|
||||
pos = next ? next + 1 : 0;
|
||||
}
|
||||
dm_free(buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* place all action implementations below */
|
||||
|
||||
static int action_dump(void *args __attribute__((unused)))
|
||||
{
|
||||
daemon_request req;
|
||||
daemon_reply repl;
|
||||
int r = 0;
|
||||
|
||||
req = daemon_request_make(LVMPD_REQ_DUMP);
|
||||
if (!req.cft) {
|
||||
fprintf(stderr, "Failed to create lvmpolld " LVMPD_REQ_DUMP " request.\n");
|
||||
goto out_req;
|
||||
}
|
||||
|
||||
repl = daemon_send(_lvmpolld, req);
|
||||
if (repl.error) {
|
||||
fprintf(stderr, "Failed to send a request or receive response.\n");
|
||||
goto out_rep;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is dumb copy & paste from libdaemon log routines.
|
||||
*/
|
||||
if (!printout_raw_response(" ", repl.buffer.mem)) {
|
||||
fprintf(stderr, "Failed to print out the response.\n");
|
||||
goto out_rep;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out_rep:
|
||||
daemon_reply_destroy(repl);
|
||||
out_req:
|
||||
daemon_request_destroy(req);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
enum action_index {
|
||||
ACTION_DUMP = 0,
|
||||
ACTION_MAX /* keep at the end */
|
||||
};
|
||||
|
||||
static const action_fn_t const actions[] = { [ACTION_DUMP] = action_dump };
|
||||
|
||||
static int _make_action(enum action_index idx, void *args)
|
||||
{
|
||||
return idx < ACTION_MAX ? actions[idx](args) : 0;
|
||||
}
|
||||
|
||||
static int _lvmpolld_client(const char *socket, unsigned action)
|
||||
{
|
||||
int r;
|
||||
|
||||
_lvmpolld = _lvmpolld_open(socket);
|
||||
|
||||
if (_lvmpolld.error || _lvmpolld.socket_fd < 0) {
|
||||
fprintf(stderr, "Failed to establish connection with lvmpolld.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = _make_action(action, NULL);
|
||||
|
||||
daemon_close(_lvmpolld);
|
||||
|
||||
return r ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static int action_idx = ACTION_MAX;
|
||||
static struct option long_options[] = {
|
||||
/* Have actions always at the beginning of the array. */
|
||||
{"dump", no_argument, &action_idx, ACTION_DUMP }, /* or an option_index ? */
|
||||
|
||||
/* other options */
|
||||
{"help", no_argument, 0, 'h' },
|
||||
{"socket", required_argument, 0, 's' },
|
||||
{"version", no_argument, 0, 'V' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
signed char opt;
|
||||
int opt;
|
||||
int option_index = 0;
|
||||
int client = 0, server = 0;
|
||||
unsigned action = ACTION_MAX;
|
||||
struct timeval timeout;
|
||||
daemon_idle di = { .ptimeout = &timeout };
|
||||
struct lvmpolld_state ls = { .log_config = "" };
|
||||
daemon_state s = {
|
||||
.daemon_fini = fini,
|
||||
.daemon_init = init,
|
||||
.handler = handler,
|
||||
.daemon_fini = _fini,
|
||||
.daemon_init = _init,
|
||||
.handler = _handler,
|
||||
.name = "lvmpolld",
|
||||
.pidfile = getenv("LVM_LVMPOLLD_PIDFILE") ?: LVMPOLLD_PIDFILE,
|
||||
.private = &ls,
|
||||
@ -773,28 +909,42 @@ int main(int argc, char *argv[])
|
||||
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
|
||||
};
|
||||
|
||||
while ((opt = getopt(argc, argv, "?fhVl:p:s:B:t:")) != EOF) {
|
||||
while ((opt = getopt_long(argc, argv, "?fhVl:p:s:B:t:", long_options, &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 0 :
|
||||
if (action < ACTION_MAX) {
|
||||
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
|
||||
long_options[action].name);
|
||||
_usage(argv[0], stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
action = action_idx;
|
||||
client = 1;
|
||||
break;
|
||||
case '?':
|
||||
usage(argv[0], stderr);
|
||||
exit(0);
|
||||
_usage(argv[0], stderr);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'B': /* --binary */
|
||||
ls.lvm_binary = optarg;
|
||||
server = 1;
|
||||
break;
|
||||
case 'V':
|
||||
printf("lvmpolld version: " LVM_VERSION "\n");
|
||||
exit(1);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'f':
|
||||
s.foreground = 1;
|
||||
server = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
exit(0);
|
||||
_usage(argv[0], stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'l':
|
||||
ls.log_config = optarg;
|
||||
server = 1;
|
||||
break;
|
||||
case 'p':
|
||||
s.pidfile = optarg;
|
||||
server = 1;
|
||||
break;
|
||||
case 's': /* --socket */
|
||||
s.socket_path = optarg;
|
||||
@ -802,16 +952,27 @@ int main(int argc, char *argv[])
|
||||
case 't': /* --timeout in seconds */
|
||||
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
|
||||
fprintf(stderr, "Invalid value of timeout parameter");
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* 0 equals to wait indefinitely */
|
||||
if (di.max_timeouts)
|
||||
s.idle = ls.idle = &di;
|
||||
server = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (client && server) {
|
||||
fprintf(stderr, "Invalid combination of client and server parameters.\n\n");
|
||||
_usage(argv[0], stdout);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (client)
|
||||
return _lvmpolld_client(s.socket_path, action);
|
||||
|
||||
/* Server */
|
||||
daemon_start(s);
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user