From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- ctdb/server/ctdb_lock_helper.c | 350 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 ctdb/server/ctdb_lock_helper.c (limited to 'ctdb/server/ctdb_lock_helper.c') diff --git a/ctdb/server/ctdb_lock_helper.c b/ctdb/server/ctdb_lock_helper.c new file mode 100644 index 0000000..51d2992 --- /dev/null +++ b/ctdb/server/ctdb_lock_helper.c @@ -0,0 +1,350 @@ +/* + ctdb lock helper + + Copyright (C) Amitay Isaacs 2013 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/network.h" +#include "system/wait.h" + +#include +#include +#include + +#include "lib/util/sys_rw.h" +#include "lib/util/tevent_unix.h" + +#include "protocol/protocol.h" + +#include "common/system.h" + +static bool realtime = true; + +struct lock_state { + struct tdb_context *tdb; + TDB_DATA key; +}; + +static void set_priority(void) +{ + const char *ptr; + + ptr = getenv("CTDB_NOSETSCHED"); + if (ptr != NULL) { + realtime = false; + } + + if (! realtime) { + return; + } + + realtime = set_scheduler(); + if (! realtime) { + fprintf(stderr, + "locking: Unable to set real-time scheduler priority\n"); + } +} + +static void reset_priority(void) +{ + if (realtime) { + reset_scheduler(); + } +} + +static void send_result(int fd, char result) +{ + sys_write(fd, &result, 1); + if (result == 1) { + exit(1); + } +} + + +static void usage(const char *progname) +{ + fprintf(stderr, "\n"); + fprintf(stderr, "Usage: %s RECORD \n", progname); + fprintf(stderr, " %s DB \n", progname); +} + +static uint8_t *hex_decode_talloc(TALLOC_CTX *mem_ctx, + const char *hex_in, size_t *len) +{ + unsigned int i; + int num; + uint8_t *buffer; + + *len = strlen(hex_in) / 2; + buffer = talloc_array(mem_ctx, unsigned char, *len); + + for (i=0; i<*len; i++) { + sscanf(&hex_in[i*2], "%02X", &num); + buffer[i] = (uint8_t)num; + } + + return buffer; +} + +static int lock_record(const char *dbpath, const char *dbflags, + const char *dbkey, struct lock_state *state) +{ + int tdb_flags; + + /* No error checking since CTDB always passes sane values */ + tdb_flags = strtol(dbflags, NULL, 0); + + /* Convert hex key to key */ + if (strcmp(dbkey, "NULL") == 0) { + state->key.dptr = NULL; + state->key.dsize = 0; + } else { + state->key.dptr = hex_decode_talloc(NULL, dbkey, + &state->key.dsize); + } + + state->tdb = tdb_open(dbpath, 0, tdb_flags, O_RDWR, 0600); + if (state->tdb == NULL) { + fprintf(stderr, "locking: Error opening database %s\n", dbpath); + return 1; + } + + set_priority(); + + if (tdb_chainlock(state->tdb, state->key) < 0) { + fprintf(stderr, "locking: Error getting record lock (%s)\n", + tdb_errorstr(state->tdb)); + return 1; + } + + reset_priority(); + + return 0; + +} + +static int lock_db(const char *dbpath, const char *dbflags, + struct lock_state *state) +{ + int tdb_flags; + + /* No error checking since CTDB always passes sane values */ + tdb_flags = strtol(dbflags, NULL, 0); + + state->tdb = tdb_open(dbpath, 0, tdb_flags, O_RDWR, 0600); + if (state->tdb == NULL) { + fprintf(stderr, "locking: Error opening database %s\n", dbpath); + return 1; + } + + set_priority(); + + if (tdb_lockall(state->tdb) < 0) { + fprintf(stderr, "locking: Error getting db lock (%s)\n", + tdb_errorstr(state->tdb)); + return 1; + } + + reset_priority(); + + return 0; +} + +struct wait_for_parent_state { + struct tevent_context *ev; + pid_t ppid; +}; + +static void wait_for_parent_check(struct tevent_req *subreq); + +static struct tevent_req *wait_for_parent_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + pid_t ppid) +{ + struct tevent_req *req, *subreq; + struct wait_for_parent_state *state; + + req = tevent_req_create(mem_ctx, &state, struct wait_for_parent_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->ppid = ppid; + + if (ppid == 1) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = tevent_wakeup_send(state, ev, + tevent_timeval_current_ofs(5,0)); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wait_for_parent_check, req); + + return req; +} + +static void wait_for_parent_check(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wait_for_parent_state *state = tevent_req_data( + req, struct wait_for_parent_state); + bool status; + + status = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (! status) { + /* Ignore error */ + fprintf(stderr, "locking: tevent_wakeup_recv() failed\n"); + } + + if (kill(state->ppid, 0) == -1 && errno == ESRCH) { + tevent_req_done(req); + return; + } + + subreq = tevent_wakeup_send(state, state->ev, + tevent_timeval_current_ofs(5,0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wait_for_parent_check, req); +} + +static bool wait_for_parent_recv(struct tevent_req *req, int *perr) +{ + if (tevent_req_is_unix_error(req, perr)) { + return false; + } + + return true; +} + +static void cleanup(struct lock_state *state) +{ + if (state->tdb != NULL) { + if (state->key.dsize == 0) { + tdb_unlockall(state->tdb); + } else { + tdb_chainunlock(state->tdb, state->key); + } + tdb_close(state->tdb); + } +} + +static void signal_handler(struct tevent_context *ev, + struct tevent_signal *se, + int signum, int count, void *siginfo, + void *private_data) +{ + struct lock_state *state = (struct lock_state *)private_data; + + cleanup(state); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct tevent_context *ev; + struct tevent_signal *se; + struct tevent_req *req; + struct lock_state state = { 0 }; + int write_fd; + char result = 0; + int ppid; + const char *lock_type; + bool status; + int err; + + reset_scheduler(); + + if (argc < 4) { + usage(argv[0]); + exit(1); + } + + ppid = atoi(argv[1]); + write_fd = atoi(argv[2]); + lock_type = argv[3]; + + ev = tevent_context_init(NULL); + if (ev == NULL) { + fprintf(stderr, "locking: tevent_context_init() failed\n"); + exit(1); + } + + se = tevent_add_signal(ev, ev, SIGTERM, 0, + signal_handler, &state); + if (se == NULL) { + fprintf(stderr, "locking: tevent_add_signal() failed\n"); + talloc_free(ev); + exit(1); + } + + if (strcmp(lock_type, "RECORD") == 0) { + if (argc != 7) { + fprintf(stderr, + "locking: Invalid number of arguments (%d)\n", + argc); + usage(argv[0]); + exit(1); + } + result = lock_record(argv[4], argv[5], argv[6], &state); + + } else if (strcmp(lock_type, "DB") == 0) { + if (argc != 6) { + fprintf(stderr, + "locking: Invalid number of arguments (%d)\n", + argc); + usage(argv[0]); + exit(1); + } + result = lock_db(argv[4], argv[5], &state); + + } else { + fprintf(stderr, "locking: Invalid lock-type '%s'\n", lock_type); + usage(argv[0]); + exit(1); + } + + send_result(write_fd, result); + + req = wait_for_parent_send(ev, ev, ppid); + if (req == NULL) { + fprintf(stderr, "locking: wait_for_parent_send() failed\n"); + cleanup(&state); + exit(1); + } + + tevent_req_poll(req, ev); + + status = wait_for_parent_recv(req, &err); + if (! status) { + fprintf(stderr, + "locking: wait_for_parent_recv() failed (%d)\n", + err); + } + + talloc_free(ev); + cleanup(&state); + return 0; +} -- cgit v1.2.3