X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Futils%2Fsmbcontrol.c;h=b27b8cb5610a095cca78d159bef5c67dfef1f846;hb=6b5b882073fa80c3ea7cbe52546cdc7a23a3444e;hp=5c798c79014b16c96a448795508d6c2b5f04bd5c;hpb=3cd1101c9b6dd998384e3fa9f5e0bae94a70b737;p=obnox%2Fsamba-ctdb.git diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index 5c798c7901..b27b8cb561 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -7,10 +7,11 @@ Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Martin Pool 2001-2002 Copyright (C) Simo Sorce 2002 + Copyright (C) James Peach 2006 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 2 of the License, or + 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, @@ -19,12 +20,23 @@ 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ #include "includes.h" +#if HAVE_LIBUNWIND_H +#include +#endif + +#if HAVE_LIBUNWIND_PTRACE_H +#include +#endif + +#if HAVE_SYS_PTRACE_H +#include +#endif + /* Default timeout value when waiting for replies (in seconds) */ #define DEFAULT_TIMEOUT 10 @@ -34,76 +46,94 @@ static int num_replies; /* Used by message callback fns */ /* Send a message to a destination pid. Zero means broadcast smbd. */ -static BOOL send_message(struct process_id pid, int msg_type, - const void *buf, int len, - BOOL duplicates) +static bool send_message(struct messaging_context *msg_ctx, + struct server_id pid, int msg_type, + const void *buf, int len) { - TDB_CONTEXT *tdb; - BOOL ret; + bool ret; int n_sent = 0; - if (!message_init()) - return False; - if (procid_to_pid(&pid) != 0) - return message_send_pid(pid, msg_type, buf, len, duplicates); + return NT_STATUS_IS_OK( + messaging_send_buf(msg_ctx, pid, msg_type, + (uint8 *)buf, len)); - tdb = tdb_open_log(lock_path("connections.tdb"), 0, - TDB_DEFAULT, O_RDWR, 0); - if (!tdb) { - fprintf(stderr,"Failed to open connections database" - ": %s\n", strerror(errno)); - return False; - } - - ret = message_send_all(tdb,msg_type, buf, len, duplicates, - &n_sent); + ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent); DEBUG(10,("smbcontrol/send_message: broadcast message to " "%d processes\n", n_sent)); - tdb_close(tdb); - return ret; } +static void smbcontrol_timeout(struct tevent_context *event_ctx, + struct tevent_timer *te, + struct timeval now, + void *private_data) +{ + bool *timed_out = (bool *)private_data; + TALLOC_FREE(te); + *timed_out = True; +} + /* Wait for one or more reply messages */ -static void wait_replies(BOOL multiple_replies) +static void wait_replies(struct messaging_context *msg_ctx, + bool multiple_replies) { - time_t start_time = time(NULL); + struct tevent_timer *te; + bool timed_out = False; - /* Wait around a bit. This is pretty disgusting - we have to - busy-wait here as there is no nicer way to do it. */ + if (!(te = tevent_add_timer(messaging_event_context(msg_ctx), NULL, + timeval_current_ofs(timeout, 0), + smbcontrol_timeout, (void *)&timed_out))) { + DEBUG(0, ("tevent_add_timer failed\n")); + return; + } - do { - message_dispatch(); + while (!timed_out) { + int ret; if (num_replies > 0 && !multiple_replies) break; - sleep(1); - } while (timeout - (time(NULL) - start_time) > 0); + ret = tevent_loop_once(messaging_event_context(msg_ctx)); + if (ret != 0) { + break; + } + } } /* Message handler callback that displays the PID and a string on stdout */ -static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf, size_t len) +static void print_pid_string_cb(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id pid, + DATA_BLOB *data) { - printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid), - (int)len, (const char *)buf); + char *pidstr; + + pidstr = procid_str(talloc_tos(), &pid); + printf("PID %s: %.*s", pidstr, (int)data->length, + (const char *)data->data); + TALLOC_FREE(pidstr); num_replies++; } /* Message handler callback that displays a string on stdout */ -static void print_string_cb(int msg_type, struct process_id pid, - void *buf, size_t len) +static void print_string_cb(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id pid, + DATA_BLOB *data) { - printf("%.*s", (int)len, (const char *)buf); + printf("%.*s", (int)data->length, (const char *)data->data); num_replies++; } /* Send no message. Useful for testing. */ -static BOOL do_noop(const struct process_id pid, +static bool do_noop(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -118,7 +148,8 @@ static BOOL do_noop(const struct process_id pid, /* Send a debug string */ -static BOOL do_debug(const struct process_id pid, +static bool do_debug(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 2) { @@ -127,13 +158,166 @@ static BOOL do_debug(const struct process_id pid, return False; } - return send_message( - pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); + return send_message(msg_ctx, pid, MSG_DEBUG, argv[1], + strlen(argv[1]) + 1); +} + +#if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) + +/* Return the name of a process given it's PID. This will only work on Linux, + * but that's probably moot since this whole stack tracing implementatino is + * Linux-specific anyway. + */ +static const char * procname(pid_t pid, char * buf, size_t bufsz) +{ + char path[64]; + FILE * fp; + + snprintf(path, sizeof(path), "/proc/%llu/cmdline", + (unsigned long long)pid); + if ((fp = fopen(path, "r")) == NULL) { + return NULL; + } + + fgets(buf, bufsz, fp); + + fclose(fp); + return buf; } -/* Inject a fault (fata signal) into a running smbd */ +static void print_stack_trace(pid_t pid, int * count) +{ + void * pinfo = NULL; + unw_addr_space_t aspace = NULL; + unw_cursor_t cursor; + unw_word_t ip, sp; + + char nbuf[256]; + unw_word_t off; + + int ret; + + if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { + fprintf(stderr, + "Failed to attach to process %llu: %s\n", + (unsigned long long)pid, strerror(errno)); + return; + } + + /* Wait until the attach is complete. */ + waitpid(pid, NULL, 0); + + if (((pinfo = _UPT_create(pid)) == NULL) || + ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) { + /* Probably out of memory. */ + fprintf(stderr, + "Unable to initialize stack unwind for process %llu\n", + (unsigned long long)pid); + goto cleanup; + } + + if ((ret = unw_init_remote(&cursor, aspace, pinfo))) { + fprintf(stderr, + "Unable to unwind stack for process %llu: %s\n", + (unsigned long long)pid, unw_strerror(ret)); + goto cleanup; + } + + if (*count > 0) { + printf("\n"); + } + + if (procname(pid, nbuf, sizeof(nbuf))) { + printf("Stack trace for process %llu (%s):\n", + (unsigned long long)pid, nbuf); + } else { + printf("Stack trace for process %llu:\n", + (unsigned long long)pid); + } + + while (unw_step(&cursor) > 0) { + ip = sp = off = 0; + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off); + if (ret != 0 && ret != -UNW_ENOMEM) { + snprintf(nbuf, sizeof(nbuf), ""); + } + printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n", + nbuf, (long long)off, (long long)ip, + (long long)sp); + } + + (*count)++; + +cleanup: + if (aspace) { + unw_destroy_addr_space(aspace); + } + + if (pinfo) { + _UPT_destroy(pinfo); + } + + ptrace(PTRACE_DETACH, pid, NULL, NULL); +} -static BOOL do_inject_fault(const struct process_id pid, +static int stack_trace_connection(struct db_record *rec, + const struct connections_key *key, + const struct connections_data *crec, + void *priv) +{ + print_stack_trace(procid_to_pid(&crec->pid), (int *)priv); + + return 0; +} + +static bool do_daemon_stack_trace(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + pid_t dest; + int count = 0; + + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol stacktrace\n"); + return False; + } + + dest = procid_to_pid(&pid); + + if (dest != 0) { + /* It would be nice to be able to make sure that this PID is + * the PID of a smbd/winbind/nmbd process, not some random PID + * the user liked the look of. It doesn't seem like it's worth + * the effort at the moment, however. + */ + print_stack_trace(dest, &count); + } else { + connections_forall(stack_trace_connection, &count); + } + + return True; +} + +#else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */ + +static bool do_daemon_stack_trace(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + fprintf(stderr, + "Daemon stack tracing is not supported on this platform\n"); + return False; +} + +#endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */ + +/* Inject a fault (fatal signal) into a running smbd */ + +static bool do_inject_fault(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 2) { @@ -166,15 +350,16 @@ static BOOL do_inject_fault(const struct process_id pid, return False; } - return send_message(pid, MSG_SMB_INJECT_FAULT, - &sig, sizeof(int), False); + return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT, + &sig, sizeof(int)); } #endif /* DEVELOPER */ } /* Force a browser election */ -static BOOL do_election(const struct process_id pid, +static bool do_election(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -182,13 +367,16 @@ static BOOL do_election(const struct process_id pid, return False; } - return send_message( - pid, MSG_FORCE_ELECTION, NULL, 0, False); + return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0); } /* Ping a samba daemon process */ -static void pong_cb(int msg_type, struct process_id pid, void *buf, size_t len) +static void pong_cb(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id pid, + DATA_BLOB *data) { char *src_string = procid_str(NULL, &pid); printf("PONG from pid %s\n", src_string); @@ -196,7 +384,9 @@ static void pong_cb(int msg_type, struct process_id pid, void *buf, size_t len) num_replies++; } -static BOOL do_ping(const struct process_id pid, const int argc, const char **argv) +static bool do_ping(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) { if (argc != 1) { fprintf(stderr, "Usage: smbcontrol ping\n"); @@ -205,26 +395,27 @@ static BOOL do_ping(const struct process_id pid, const int argc, const char **ar /* Send a message and register our interest in a reply */ - if (!send_message(pid, MSG_PING, NULL, 0, False)) + if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0)) return False; - message_register(MSG_PONG, pong_cb); + messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb); - wait_replies(procid_to_pid(&pid) == 0); + wait_replies(msg_ctx, procid_to_pid(&pid) == 0); /* No replies were received within the timeout period */ if (num_replies == 0) printf("No replies received\n"); - message_deregister(MSG_PONG); + messaging_deregister(msg_ctx, MSG_PONG, NULL); return num_replies; } /* Set profiling options */ -static BOOL do_profile(const struct process_id pid, +static bool do_profile(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { int v; @@ -248,25 +439,29 @@ static BOOL do_profile(const struct process_id pid, return False; } - return send_message(pid, MSG_PROFILE, &v, sizeof(int), False); + return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int)); } /* Return the profiling level */ -static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size_t len) +static void profilelevel_cb(struct messaging_context *msg_ctx, + void *private_data, + uint32_t msg_type, + struct server_id pid, + DATA_BLOB *data) { int level; const char *s; num_replies++; - if (len != sizeof(int)) { + if (data->length != sizeof(int)) { fprintf(stderr, "invalid message length %ld returned\n", - (unsigned long)len); + (unsigned long)data->length); return; } - memcpy(&level, buf, sizeof(int)); + memcpy(&level, data->data, sizeof(int)); switch (level) { case 0: @@ -289,17 +484,21 @@ static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid)); } -static void profilelevel_rqst(int msg_type, struct process_id pid, - void *buf, size_t len) +static void profilelevel_rqst(struct messaging_context *msg_ctx, + void *private_data, + uint32_t msg_type, + struct server_id pid, + DATA_BLOB *data) { int v = 0; /* Send back a dummy reply */ - send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False); + send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int)); } -static BOOL do_profilelevel(const struct process_id pid, +static bool do_profilelevel(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -309,27 +508,29 @@ static BOOL do_profilelevel(const struct process_id pid, /* Send a message and register our interest in a reply */ - if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False)) + if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0)) return False; - message_register(MSG_PROFILELEVEL, profilelevel_cb); - message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst); + messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb); + messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL, + profilelevel_rqst); - wait_replies(procid_to_pid(&pid) == 0); + wait_replies(msg_ctx, procid_to_pid(&pid) == 0); /* No replies were received within the timeout period */ if (num_replies == 0) printf("No replies received\n"); - message_deregister(MSG_PROFILE); + messaging_deregister(msg_ctx, MSG_PROFILE, NULL); return num_replies; } /* Display debug level settings */ -static BOOL do_debuglevel(const struct process_id pid, +static bool do_debuglevel(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -339,26 +540,27 @@ static BOOL do_debuglevel(const struct process_id pid, /* Send a message and register our interest in a reply */ - if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False)) + if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0)) return False; - message_register(MSG_DEBUGLEVEL, print_pid_string_cb); + messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb); - wait_replies(procid_to_pid(&pid) == 0); + wait_replies(msg_ctx, procid_to_pid(&pid) == 0); /* No replies were received within the timeout period */ if (num_replies == 0) printf("No replies received\n"); - message_deregister(MSG_DEBUGLEVEL); + messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL); return num_replies; } /* Send a print notify message */ -static BOOL do_printnotify(const struct process_id pid, +static bool do_printnotify(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { const char *cmd; @@ -471,11 +673,11 @@ static BOOL do_printnotify(const struct process_id pid, } if (strcmp(argv[3], "comment") == 0) { - attribute = PRINTER_NOTIFY_COMMENT; + attribute = PRINTER_NOTIFY_FIELD_COMMENT; } else if (strcmp(argv[3], "port") == 0) { - attribute = PRINTER_NOTIFY_PORT_NAME; + attribute = PRINTER_NOTIFY_FIELD_PORT_NAME; } else if (strcmp(argv[3], "driver") == 0) { - attribute = PRINTER_NOTIFY_DRIVER_NAME; + attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME; } else { fprintf(stderr, "Invalid printer command '%s'\n", argv[3]); @@ -492,13 +694,14 @@ static BOOL do_printnotify(const struct process_id pid, return False; send: - print_notify_send_messages(0); + print_notify_send_messages(msg_ctx, 0); return True; } /* Close a share */ -static BOOL do_closeshare(const struct process_id pid, +static bool do_closeshare(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 2) { @@ -507,13 +710,58 @@ static BOOL do_closeshare(const struct process_id pid, return False; } - return send_message( - pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False); + return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1], + strlen(argv[1]) + 1); +} + +/* Tell winbindd an IP got dropped */ + +static bool do_ip_dropped(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: smbcontrol ip-dropped " + "\n"); + return False; + } + + return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1], + strlen(argv[1]) + 1); +} + +/* force a blocking lock retry */ + +static bool do_lockretry(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol lockretry\n"); + return False; + } + + return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0); +} + +/* force a validation of all brl entries, including re-sends. */ + +static bool do_brl_revalidate(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol brl-revalidate\n"); + return False; + } + + return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0); } /* Force a SAM synchronisation */ -static BOOL do_samsync(const struct process_id pid, +static bool do_samsync(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -521,13 +769,13 @@ static BOOL do_samsync(const struct process_id pid, return False; } - return send_message( - pid, MSG_SMB_SAM_SYNC, NULL, 0, False); + return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0); } /* Force a SAM replication */ -static BOOL do_samrepl(const struct process_id pid, +static bool do_samrepl(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -535,13 +783,13 @@ static BOOL do_samrepl(const struct process_id pid, return False; } - return send_message( - pid, MSG_SMB_SAM_REPL, NULL, 0, False); + return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0); } /* Display talloc pool usage */ -static BOOL do_poolusage(const struct process_id pid, +static bool do_poolusage(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -549,28 +797,29 @@ static BOOL do_poolusage(const struct process_id pid, return False; } - message_register(MSG_POOL_USAGE, print_string_cb); + messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb); /* Send a message and register our interest in a reply */ - if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False)) + if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0)) return False; - wait_replies(procid_to_pid(&pid) == 0); + wait_replies(msg_ctx, procid_to_pid(&pid) == 0); /* No replies were received within the timeout period */ if (num_replies == 0) printf("No replies received\n"); - message_deregister(MSG_POOL_USAGE); + messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL); return num_replies; } /* Perform a dmalloc mark */ -static BOOL do_dmalloc_mark(const struct process_id pid, +static bool do_dmalloc_mark(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -578,13 +827,13 @@ static BOOL do_dmalloc_mark(const struct process_id pid, return False; } - return send_message( - pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False); + return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0); } /* Perform a dmalloc changed */ -static BOOL do_dmalloc_changed(const struct process_id pid, +static bool do_dmalloc_changed(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -593,13 +842,14 @@ static BOOL do_dmalloc_changed(const struct process_id pid, return False; } - return send_message( - pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False); + return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED, + NULL, 0); } /* Shutdown a server process */ -static BOOL do_shutdown(const struct process_id pid, +static bool do_shutdown(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -607,12 +857,13 @@ static BOOL do_shutdown(const struct process_id pid, return False; } - return send_message(pid, MSG_SHUTDOWN, NULL, 0, False); + return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0); } /* Notify a driver upgrade */ -static BOOL do_drvupgrade(const struct process_id pid, +static bool do_drvupgrade(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 2) { @@ -621,11 +872,12 @@ static BOOL do_drvupgrade(const struct process_id pid, return False; } - return send_message( - pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); + return send_message(msg_ctx, pid, MSG_DEBUG, argv[1], + strlen(argv[1]) + 1); } -static BOOL do_winbind_online(const struct process_id pid, +static bool do_winbind_online(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { TDB_CONTEXT *tdb; @@ -635,34 +887,28 @@ static BOOL do_winbind_online(const struct process_id pid, return False; } - if (!lp_winbind_offline_logon()) { - fprintf(stderr, "The parameter \"winbind offline logon\" must " - "be set in the [global] section of smb.conf for this " - "command to be allowed.\n"); - return False; - } - /* Remove the entry in the winbindd_cache tdb to tell a later starting winbindd that we're online. */ - tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600); + tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600); if (!tdb) { fprintf(stderr, "Cannot open the tdb %s for writing.\n", - lock_path("winbindd_cache.tdb")); + cache_path("winbindd_cache.tdb")); return False; } tdb_delete_bystring(tdb, "WINBINDD_OFFLINE"); tdb_close(tdb); - return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False); + return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0); } -static BOOL do_winbind_offline(const struct process_id pid, +static bool do_winbind_offline(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { TDB_CONTEXT *tdb; - BOOL ret = False; + bool ret = False; int retry = 0; if (argc != 1) { @@ -670,24 +916,17 @@ static BOOL do_winbind_offline(const struct process_id pid, return False; } - if (!lp_winbind_offline_logon()) { - fprintf(stderr, "The parameter \"winbind offline logon\" must " - "be set in the [global] section of smb.conf for this " - "command to be allowed.\n"); - return False; - } - /* Create an entry in the winbindd_cache tdb to tell a later starting winbindd that we're offline. We may actually create it here... */ - tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), + tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600); if (!tdb) { fprintf(stderr, "Cannot open the tdb %s for writing.\n", - lock_path("winbindd_cache.tdb")); + cache_path("winbindd_cache.tdb")); return False; } @@ -699,25 +938,28 @@ static BOOL do_winbind_offline(const struct process_id pid, 5 times. */ for (retry = 0; retry < 5; retry++) { - int err; TDB_DATA d; + uint8 buf[4]; + ZERO_STRUCT(d); + + SIVAL(buf, 0, time(NULL)); + d.dptr = buf; + d.dsize = 4; + tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT); - ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False); + ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE, + NULL, 0); /* Check that the entry "WINBINDD_OFFLINE" still exists. */ - tdb->ecode = 0; d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" ); - - /* As this is a key with no data we don't need to free, we - check for existence by looking at tdb_err. */ - - err = tdb_error(tdb); - - if (err == TDB_ERR_NOEXIST) { + + if (!d.dptr || d.dsize != 4) { + SAFE_FREE(d.dptr); DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n")); } else { + SAFE_FREE(d.dptr); break; } } @@ -726,7 +968,155 @@ static BOOL do_winbind_offline(const struct process_id pid, return ret; } -static BOOL do_reload_config(const struct process_id pid, +static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + struct server_id myid; + + myid = pid_to_procid(sys_getpid()); + + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n"); + return False; + } + + messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS, + print_pid_string_cb); + + if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid, + sizeof(myid))) + return False; + + wait_replies(msg_ctx, procid_to_pid(&pid) == 0); + + /* No replies were received within the timeout period */ + + if (num_replies == 0) + printf("No replies received\n"); + + messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL); + + return num_replies; +} + +static bool do_dump_event_list(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + struct server_id myid; + + myid = pid_to_procid(sys_getpid()); + + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol dump-event-list\n"); + return False; + } + + return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0); +} + +static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + const char *domain = NULL; + int domain_len = 0; + struct server_id myid; + uint8_t *buf = NULL; + int buf_len = 0; + + myid = pid_to_procid(sys_getpid()); + + if (argc < 1 || argc > 2) { + fprintf(stderr, "Usage: smbcontrol dump_domain_list " + "\n"); + return false; + } + + if (argc == 2) { + domain = argv[1]; + domain_len = strlen(argv[1]) + 1; + } + + messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST, + print_pid_string_cb); + + buf_len = sizeof(myid)+domain_len; + buf = SMB_MALLOC_ARRAY(uint8_t, buf_len); + if (!buf) { + return false; + } + + memcpy(buf, &myid, sizeof(myid)); + memcpy(&buf[sizeof(myid)], domain, domain_len); + + if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST, + buf, buf_len)) + { + SAFE_FREE(buf); + return false; + } + + wait_replies(msg_ctx, procid_to_pid(&pid) == 0); + + /* No replies were received within the timeout period */ + + SAFE_FREE(buf); + if (num_replies == 0) { + printf("No replies received\n"); + } + + messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL); + + return num_replies; +} + +static void winbind_validate_cache_cb(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id pid, + DATA_BLOB *data) +{ + char *src_string = procid_str(NULL, &pid); + printf("Winbindd cache is %svalid. (answer from pid %s)\n", + (*(data->data) == 0 ? "" : "NOT "), src_string); + TALLOC_FREE(src_string); + num_replies++; +} + +static bool do_winbind_validate_cache(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + struct server_id myid = pid_to_procid(sys_getpid()); + + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n"); + return False; + } + + messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE, + winbind_validate_cache_cb); + + if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid, + sizeof(myid))) { + return False; + } + + wait_replies(msg_ctx, procid_to_pid(&pid) == 0); + + if (num_replies == 0) { + printf("No replies received\n"); + } + + messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL); + + return num_replies; +} + +static bool do_reload_config(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { if (argc != 1) { @@ -734,7 +1124,7 @@ static BOOL do_reload_config(const struct process_id pid, return False; } - return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False); + return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0); } static void my_make_nmb_name( struct nmb_name *n, const char *name, int type) @@ -748,7 +1138,8 @@ static void my_make_nmb_name( struct nmb_name *n, const char *name, int type) push_ascii(n->scope, global_scope(), 64, STR_TERMINATE); } -static BOOL do_nodestatus(const struct process_id pid, +static bool do_nodestatus(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv) { struct packet_struct p; @@ -760,7 +1151,7 @@ static BOOL do_nodestatus(const struct process_id pid, ZERO_STRUCT(p); - p.ip = *interpret_addr2(argv[1]); + p.ip = interpret_addr2(argv[1]); p.port = 137; p.packet_type = NMB_PACKET; @@ -781,14 +1172,15 @@ static BOOL do_nodestatus(const struct process_id pid, p.packet.nmb.question.question_type = 0x21; p.packet.nmb.question.question_class = 0x1; - return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False); + return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p)); } /* A list of message type supported */ static const struct { const char *name; /* Option name */ - BOOL (*fn)(const struct process_id pid, + bool (*fn)(struct messaging_context *msg_ctx, + const struct server_id pid, const int argc, const char **argv); const char *help; /* Short help text */ } msg_types[] = { @@ -799,10 +1191,15 @@ static const struct { { "profile", do_profile, "" }, { "inject", do_inject_fault, "Inject a fatal signal into a running smbd"}, + { "stacktrace", do_daemon_stack_trace, + "Display a stack trace of a daemon" }, { "profilelevel", do_profilelevel, "" }, { "debuglevel", do_debuglevel, "Display current debuglevels" }, { "printnotify", do_printnotify, "Send a print notify message" }, { "close-share", do_closeshare, "Forcibly disconnect a share" }, + { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" }, + { "lockretry", do_lockretry, "Force a blocking lock retry" }, + { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" }, { "samsync", do_samsync, "Initiate SAM synchronisation" }, { "samrepl", do_samrepl, "Initiate SAM replication" }, { "pool-usage", do_poolusage, "Display talloc memory usage" }, @@ -814,17 +1211,22 @@ static const struct { { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"}, { "online", do_winbind_online, "Ask winbind to go into online state"}, { "offline", do_winbind_offline, "Ask winbind to go into offline state"}, + { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"}, + { "dump-event-list", do_dump_event_list, "Dump event list"}, + { "validate-cache" , do_winbind_validate_cache, + "Validate winbind's credential cache" }, + { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"}, { "noop", do_noop, "Do nothing" }, { NULL } }; /* Display usage information */ -static void usage(poptContext *pc) +static void usage(poptContext pc) { int i; - poptPrintHelp(*pc, stderr, 0); + poptPrintHelp(pc, stderr, 0); fprintf(stderr, "\n"); fprintf(stderr, " is one of \"nmbd\", \"smbd\", \"winbindd\" or a " @@ -844,15 +1246,15 @@ static void usage(poptContext *pc) /* Return the pid number for a string destination */ -static struct process_id parse_dest(const char *dest) +static struct server_id parse_dest(const char *dest) { - struct process_id result = {-1}; + struct server_id result = {-1}; pid_t pid; - /* Zero is a special return value for broadcast smbd */ + /* Zero is a special return value for broadcast to all processes */ - if (strequal(dest, "smbd")) { - return interpret_pid("0"); + if (strequal(dest, "all")) { + return interpret_pid(MSG_BROADCAST_PID_STR); } /* Try self - useful for testing */ @@ -866,16 +1268,12 @@ static struct process_id parse_dest(const char *dest) dest = "winbindd"; } - - if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) { - /* Check for numeric pid number */ + /* Check for numeric pid number */ + result = interpret_pid(dest); - result = interpret_pid(dest); - - /* Zero isn't valid if not smbd. */ - if (result.pid && procid_valid(&result)) { - return result; - } + /* Zero isn't valid if not "all". */ + if (result.pid && procid_valid(&result)) { + return result; } /* Look up other destinations in pidfile directory */ @@ -887,14 +1285,15 @@ static struct process_id parse_dest(const char *dest) fprintf(stderr,"Can't find pid for destination '%s'\n", dest); return result; -} +} /* Execute smbcontrol command */ -static BOOL do_command(int argc, const char **argv) +static bool do_command(struct messaging_context *msg_ctx, + int argc, const char **argv) { const char *dest = argv[0], *command = argv[1]; - struct process_id pid; + struct server_id pid; int i; /* Check destination */ @@ -908,7 +1307,8 @@ static BOOL do_command(int argc, const char **argv) for (i = 0; msg_types[i].name; i++) { if (strequal(command, msg_types[i].name)) - return msg_types[i].fn(pid, argc - 1, argv + 1); + return msg_types[i].fn(msg_ctx, pid, + argc - 1, argv + 1); } fprintf(stderr, "smbcontrol: unknown command '%s'\n", command); @@ -916,31 +1316,50 @@ static BOOL do_command(int argc, const char **argv) return False; } +static void smbcontrol_help(poptContext pc, + enum poptCallbackReason preason, + struct poptOption * poption, + const char * parg, + void * pdata) +{ + if (poption->shortName != '?') { + poptPrintUsage(pc, stdout, 0); + } else { + usage(pc); + } + + exit(0); +} + +struct poptOption help_options[] = { + { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0', + NULL, NULL }, + { "help", '?', 0, NULL, '?', "Show this help message", NULL }, + { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL }, + { NULL } +} ; + /* Main program */ int main(int argc, const char **argv) { poptContext pc; int opt; + struct tevent_context *evt_ctx; + struct messaging_context *msg_ctx; - static struct poptOption wbinfo_options[] = { + static struct poptOption long_options[] = { + /* POPT_AUTOHELP */ + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options, + 0, "Help options:", NULL }, { "timeout", 't', POPT_ARG_INT, &timeout, 't', "Set timeout value in seconds", "TIMEOUT" }, - { "configfile", 's', POPT_ARG_STRING, NULL, 's', - "Use alternative configuration file", "CONFIGFILE" }, - - POPT_TABLEEND - }; - - struct poptOption options[] = { - { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, - "Options" }, - - POPT_AUTOHELP - POPT_COMMON_VERSION + POPT_COMMON_SAMBA POPT_TABLEEND }; + TALLOC_CTX *frame = talloc_stackframe(); + int ret = 0; load_case_tables(); @@ -949,22 +1368,17 @@ int main(int argc, const char **argv) /* Parse command line arguments using popt */ pc = poptGetContext( - "smbcontrol", argc, (const char **)argv, options, 0); + "smbcontrol", argc, (const char **)argv, long_options, 0); poptSetOtherOptionHelp(pc, "[OPTION...] " ""); if (argc == 1) - usage(&pc); + usage(pc); while ((opt = poptGetNextOpt(pc)) != -1) { switch(opt) { case 't': /* --timeout */ - argc -= 2; - break; - case 's': /* --configfile */ - pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc)); - argc -= 2; break; default: fprintf(stderr, "Invalid option\n"); @@ -978,16 +1392,30 @@ int main(int argc, const char **argv) correct value in the above switch statement. */ argv = (const char **)poptGetArgs(pc); - argc--; /* Don't forget about argv[0] */ + argc = 0; + if (argv != NULL) { + while (argv[argc] != NULL) { + argc++; + } + } - if (argc == 1) - usage(&pc); + if (argc <= 1) + usage(pc); - lp_load(dyn_CONFIGFILE,False,False,False,True); + lp_load(get_dyn_CONFIGFILE(),False,False,False,True); /* Need to invert sense of return code -- samba * routines mostly return True==1 for success, but * shell needs 0. */ - return !do_command(argc, argv); + if (!(evt_ctx = tevent_context_init(NULL)) || + !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) { + fprintf(stderr, "could not init messaging context\n"); + TALLOC_FREE(frame); + exit(1); + } + + ret = !do_command(msg_ctx, argc, argv); + TALLOC_FREE(frame); + return ret; }