From a72eafee542c2b15e1ffb369d277209b63daa0e9 Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Wed, 9 Apr 2003 05:52:01 +0000 Subject: Rewrite of smbcontrol - it was a bit of a mess. It should now be much nicer to use and more hackable. - converted to popt - text message destinations (except for broadcast smbd) are resolved using files in piddir so the string 'winbindd' is now a destination - added --timeout option to specify timeout value - deleted complicated handling of debug args as separate command line arguments: use shell quoting instead - deleted interactive mode as punishment for using strtok() (-: - much improved command line argument checking Some of this stuff was broken before I started (print notify, profiling) but the basics still work (ping, pool-usage, debug, debuglevel). (This used to be commit 269f838dee257ee9badcae190f2c70b898676bc5) --- source3/utils/smbcontrol.c | 1103 +++++++++++++++++++++++--------------------- 1 file changed, 573 insertions(+), 530 deletions(-) (limited to 'source3') diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index 44b18d57cd..8b984d9bd1 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -1,8 +1,11 @@ /* Unix SMB/CIFS implementation. - program to send control messages to Samba processes + + Send messages to other Samba daemons + + Copyright (C) Tim Potter 2003 Copyright (C) Andrew Tridgell 1994-1998 - Copyright (C) 2001, 2002 by Martin Pool + Copyright (C) Martin Pool 2001-2002 Copyright (C) Simo Sorce 2002 This program is free software; you can redistribute it and/or modify @@ -22,678 +25,718 @@ #include "includes.h" -extern BOOL AllowDebugChange; +/* Default timeout value when waiting for replies (in seconds) */ -static const struct { - const char *name; - int value; -} msg_types[] = { - {"debug", MSG_DEBUG}, - {"force-election", MSG_FORCE_ELECTION}, - {"ping", MSG_PING}, - {"profile", MSG_PROFILE}, - {"profilelevel", MSG_REQ_PROFILELEVEL}, - {"debuglevel", MSG_REQ_DEBUGLEVEL}, - {"printnotify", MSG_PRINTER_NOTIFY2 }, - {"close-share", MSG_SMB_FORCE_TDIS}, - {"samsync", MSG_SMB_SAM_SYNC}, - {"samrepl", MSG_SMB_SAM_REPL}, - {"pool-usage", MSG_REQ_POOL_USAGE }, - {"dmalloc-mark", MSG_REQ_DMALLOC_MARK }, - {"dmalloc-log-changed", MSG_REQ_DMALLOC_LOG_CHANGED }, - {"shutdown", MSG_SHUTDOWN }, - {"drvupgrade", MSG_PRINTER_DRVUPGRADE}, - {NULL, -1} -}; +#define DEFAULT_TIMEOUT 10 -time_t timeout_start; +static int timeout = DEFAULT_TIMEOUT; +static int num_replies; /* Used by message callback fns */ -#define MAX_WAIT 10 +/* Send a message to a destination pid. Zero means broadcast smbd. */ -/* we need these because we link to printing*.o */ +static BOOL send_message(pid_t pid, int msg_type, void *buf, int len, + BOOL duplicates) +{ + TDB_CONTEXT *tdb; + BOOL ret; + int n_sent = 0; + + if (!message_init()) + return False; + + if (pid != 0) + return message_send_pid(pid, msg_type, buf, len, duplicates); + + 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); + DEBUG(10,("smbcontrol/send_message: broadcast message to " + "%d processes\n", n_sent)); + + tdb_close(tdb); + + return ret; +} -void become_root(void) {} -void unbecome_root(void) {} +/* Wait for one or more reply messages */ + +static void wait_replies(BOOL multiple_replies) +{ + time_t start_time = time(NULL); + /* Wait around a bit. This is pretty disgusting - we have to + busy-wait here as there is no nicer way to do it. */ -static void usage(BOOL doexit) + do { + message_dispatch(); + if (num_replies > 0 && !multiple_replies) + break; + sleep(1); + } while (timeout - (time(NULL) - start_time) > 0); +} + +/* Message handler callback that displays a string on stdout */ + +static void print_string_cb(int msg_type, pid_t pid, void *buf, size_t len) { - int i; - if (doexit) { - printf("Usage: smbcontrol -i -s configfile\n"); - printf(" smbcontrol \n\n"); - } else { - printf(" \n\n"); + printf("%.*s", (int)len, (const char *)buf); + num_replies++; +} + +/* Send no message. Useful for testing. */ + +static BOOL do_noop(const pid_t pid, const int argc, char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol noop\n"); + return False; } - printf("\t is one of \"nmbd\", \"smbd\" or a process ID\n"); - printf("\t is one of:\n"); - for (i=0; msg_types[i].name; i++) - printf("\t\t%s\n", msg_types[i].name); - printf("\n"); - if (doexit) exit(1); + + /* Move along, nothing to see here */ + + return True; } -static int pong_count; -static BOOL got_level; -static BOOL got_pool; -static BOOL pong_registered = False; -static BOOL debuglevel_registered = False; -static BOOL poolusage_registered = False; -static BOOL profilelevel_registered = False; - - -/** - * Wait for replies for up to @p *max_secs seconds, or until @p - * max_replies are received. max_replies may be NULL in which case it - * is ignored. - * - * @note This is a pretty lame timeout; all it means is that after - * max_secs we won't look for any more messages. - **/ -static void wait_for_replies(int max_secs, int *max_replies) +/* Send a debug string */ + +static BOOL do_debug(const pid_t pid, const int argc, char **argv) { - time_t timeout_end = time(NULL) + max_secs; + if (argc != 2) { + fprintf(stderr, "Usage: smbcontrol debug " + "\n"); + return False; + } - while ((!max_replies || (*max_replies)-- > 0) - && (time(NULL) < timeout_end)) { - message_dispatch(); + return send_message( + pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); +} + +/* Force a browser election */ + +static BOOL do_election(const pid_t pid, const int argc, char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol force-election\n"); + return False; } + + return send_message( + pid, MSG_FORCE_ELECTION, NULL, 0, False); } +/* Ping a samba daemon process */ -/**************************************************************************** -a useful function for testing the message system -****************************************************************************/ -void pong_function(int msg_type, pid_t src, void *buf, size_t len) +static void pong_cb(int msg_type, pid_t pid, void *buf, size_t len) { - pong_count++; - printf("PONG from PID %u\n",(unsigned int)src); + printf("PONG from pid %u\n", (unsigned int)pid); + num_replies++; } -/**************************************************************************** - Prints out the current talloc list. -****************************************************************************/ -void tallocdump_function(int msg_type, pid_t src, void *buf, size_t len) +static BOOL do_ping(const pid_t pid, const int argc, char **argv) { - char *info = (char *)buf; - - printf("Current talloc contexts for process %u\n", (unsigned int)src ); - if (len == 0) - printf("None returned\n"); - else - printf(info); - printf("\n"); - got_pool = True; + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol ping\n"); + return False; + } + + /* Send a message and register our interest in a reply */ + + if (!send_message(pid, MSG_PING, NULL, 0, False)) + return False; + + message_register(MSG_PONG, pong_cb); + + wait_replies(pid == 0); + + /* No replies were received within the timeout period */ + + if (num_replies == 0) + printf("No replies received\n"); + + message_deregister(MSG_PONG); + + return num_replies; } -/**************************************************************************** -Prints out the current Debug level returned by MSG_DEBUGLEVEL -****************************************************************************/ -void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len) +/* Set profiling options */ + +static BOOL do_profile(const pid_t pid, const int argc, char **argv) { - const char *levels = (char *)buf; + int v; - printf("Current debug levels of PID %u are:\n",(unsigned int)src); - printf("%s\n", levels); - - got_level = True; + if (argc != 2) { + fprintf(stderr, "Usage: smbcontrol profile " + "\n"); + return False; + } + + if (strcmp(argv[1], "off") == 0) { + v = 0; + } else if (strcmp(argv[1], "count") == 0) { + v = 1; + } else if (strcmp(argv[1], "on") == 0) { + v = 2; + } else if (strcmp(argv[1], "flush") == 0) { + v = 3; + } else { + fprintf(stderr, "Unknown profile command '%s'\n", argv[1]); + return False; + } + + return send_message(pid, MSG_PROFILE, &v, sizeof(int), False); } -/**************************************************************************** -Prints out the current Profile level returned by MSG_PROFILELEVEL -****************************************************************************/ -void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len) +/* Return the profiling level */ + +static void profilelevel_cb(int msg_type, pid_t pid, void *buf, size_t len) { - int level; - const char *s=NULL; - memcpy(&level, buf, sizeof(int)); + int level; + const char *s; + + num_replies++; + + if (len != sizeof(int)) { + fprintf(stderr, "invalid message length %d returned\n", len); + return; + } - if (level) { - switch (level) { - case 1: + memcpy(&level, buf, sizeof(int)); + + switch (level) { + case 0: + s = "not enabled"; + break; + case 1: s = "off"; break; - case 3: + case 3: s = "count only"; break; - case 7: + case 7: s = "count and time"; break; - default: - s = "BOGUS"; - break; - } - printf("Profiling %s on PID %u\n",s,(unsigned int)src); - } else { - printf("Profiling not available on PID %u\n",(unsigned int)src); + default: + s = "BOGUS"; + break; } - got_level = True; + + printf("Profiling %s on pid %u\n",s,(unsigned int)pid); } -/** - * Handle reply from POOL_USAGE. - **/ -static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len) +static void profilelevel_rqst(int msg_type, pid_t pid, void *buf, size_t len) { - printf("Got POOL_USAGE reply from pid %u:\n%.*s", - (unsigned int) src_pid, (int) len, (const char *) buf); -} + int v = 0; + + /* Send back a dummy reply */ + send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False); +} -/** - * Send a message to a named destination - * - * @return False if an error occurred. - **/ -static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates) +static BOOL do_profilelevel(const pid_t pid, const int argc, char **argv) { - pid_t pid; - /* "smbd" is the only broadcast operation */ - if (strequal(dest,"smbd")) { - TDB_CONTEXT *tdb; - BOOL ret; - int n_sent = 0; - - tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0); - if (!tdb) { - fprintf(stderr,"Failed to open connections database in send_message.\n"); - return False; - } + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol profilelevel\n"); + return False; + } - ret = message_send_all(tdb,msg_type, buf, len, duplicates, - &n_sent); - DEBUG(10,("smbcontrol/send_message: broadcast message to " - "%d processes\n", n_sent)); - tdb_close(tdb); - - return ret; - } else if (strequal(dest,"nmbd")) { - pid = pidfile_pid(dest); - if (pid == 0) { - fprintf(stderr,"Can't find pid for nmbd\n"); - return False; - } - } else if (strequal(dest,"self")) { - pid = sys_getpid(); - } else { - pid = atoi(dest); - if (pid == 0) { - fprintf(stderr,"Not a valid pid\n"); - return False; - } - } + /* Send a message and register our interest in a reply */ + + if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False)) + return False; + + message_register(MSG_PROFILELEVEL, profilelevel_cb); + message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst); - DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid)); - return message_send_pid(pid, msg_type, buf, len, duplicates); + wait_replies(pid == 0); + + /* No replies were received within the timeout period */ + + if (num_replies == 0) + printf("No replies received\n"); + + message_deregister(MSG_PROFILE); + + return num_replies; } -/**************************************************************************** -evaluate a message type string -****************************************************************************/ -static int parse_type(char *mtype) +/* Display debug level settings */ + +static BOOL do_debuglevel(const pid_t pid, const int argc, char **argv) { - int i; - for (i=0;msg_types[i].name;i++) { - if (strequal(mtype, msg_types[i].name)) return msg_types[i].value; + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol debuglevel\n"); + return False; } - return -1; -} + /* Send a message and register our interest in a reply */ -static void register_all(void) -{ - message_register(MSG_POOL_USAGE, pool_usage_cb); -} + if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False)) + return False; -/* This guy is here so we can link printing/notify.c to the smbcontrol - binary without having to pull in tons of other crap. */ + message_register(MSG_DEBUGLEVEL, print_string_cb); -TDB_CONTEXT *conn_tdb_ctx(void) -{ - static TDB_CONTEXT *tdb; + wait_replies(pid == 0); - if (tdb) - return tdb; + /* No replies were received within the timeout period */ - tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0); + if (num_replies == 0) + printf("No replies received\n"); - if (!tdb) - DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n")); + message_deregister(MSG_DEBUGLEVEL); - return tdb; + return num_replies; } -/**************************************************************************** -do command -****************************************************************************/ -static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) +/* Send a print notify message */ + +static BOOL do_printnotify(const pid_t pid, const int argc, char **argv) { - int i, n, v; - int mtype; - BOOL retval=False; - BOOL check_notify_msgs = False; - - mtype = parse_type(msg_name); - if (mtype == -1) { - fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name); - return(False); + char *cmd; + + /* Check for subcommand */ + + if (argc == 1) { + fprintf(stderr, "Must specify subcommand:\n"); + fprintf(stderr, "\tqueuepause \n"); + fprintf(stderr, "\tqueueresume \n"); + fprintf(stderr, "\tjobpause \n"); + fprintf(stderr, "\tjobresume \n"); + fprintf(stderr, "\tjobdelete \n"); + fprintf(stderr, "\tprinter \n"); + + return False; } - switch (mtype) { - case MSG_DEBUG: { - char *buf, *b; - char **p; - int dim = 0; + cmd = argv[1]; - if (!params || !params[0]) { - fprintf(stderr,"MSG_DEBUG needs a parameter\n"); - return(False); - } + if (strcmp(cmd, "queuepause") == 0) { - /* first pass retrieve total lenght */ - for (p = params; p && *p ; p++) - dim += (strnlen(*p, 1024) +1); /* lenght + space */ - b = buf = malloc(dim); - if (!buf) { - fprintf(stderr, "Out of memory!"); - return(False); - } - /* now build a single string with all parameters */ - for(p = params; p && *p; p++) { - int l = strnlen(*p, 1024); - strncpy(b, *p, l); - b[l] = ' '; - b = b + l + 1; + if (argc != 3) { + fprintf(stderr, "Usage: smbcontrol printnotify" + " queuepause \n"); + return False; } - b[-1] = '\0'; + + notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED); - send_message(dest, MSG_DEBUG, buf, dim, False); + goto send; - free(buf); - - break; - } + } else if (strcmp(cmd, "queueresume") == 0) { - case MSG_PROFILE: - if (!params || !params[0]) { - fprintf(stderr,"MSG_PROFILE needs a parameter\n"); - return(False); - } - if (strequal(params[0], "off")) { - v = 0; - } else if (strequal(params[0], "count")) { - v = 1; - } else if (strequal(params[0], "on")) { - v = 2; - } else if (strequal(params[0], "flush")) { - v = 3; - } else { - fprintf(stderr, - "MSG_PROFILE parameter must be off, count, on, or flush\n"); - return(False); + if (argc != 3) { + fprintf(stderr, "Usage: smbcontrol printnotify" + " queuereume \n"); + return False; } - send_message(dest, MSG_PROFILE, &v, sizeof(int), False); - break; + + notify_printer_status_byname(argv[2], PRINTER_STATUS_OK); - case MSG_FORCE_ELECTION: - if (!strequal(dest, "nmbd")) { - fprintf(stderr,"force-election can only be sent to nmbd\n"); - return(False); - } - send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False); - break; + goto send; - case MSG_REQ_PROFILELEVEL: - if (!profilelevel_registered) { - message_register(MSG_PROFILELEVEL, profilelevel_function); - profilelevel_registered = True; - } - got_level = False; - retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True); - if (retval) { - timeout_start = time(NULL); - while (!got_level) { - message_dispatch(); - if ((time(NULL) - timeout_start) > MAX_WAIT) { - fprintf(stderr,"profilelevel timeout\n"); - break; - } - } + } else if (strcmp(cmd, "jobpause") == 0) { + int jobid; + + if (argc != 4) { + fprintf(stderr, "Usage: smbcontrol printnotify" + " jobpause \n"); + return False; } - break; - case MSG_REQ_DEBUGLEVEL: - if (!debuglevel_registered) { - message_register(MSG_DEBUGLEVEL, debuglevel_function); - debuglevel_registered = True; + jobid = atoi(argv[3]); + + notify_job_status_byname( + argv[2], jobid, JOB_STATUS_PAUSED, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + + goto send; + + } else if (strcmp(cmd, "jobresume") == 0) { + int jobid; + + if (argc != 4) { + fprintf(stderr, "Usage: smbcontrol printnotify" + " jobpause \n"); + return False; } - got_level = False; - retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True); - if (retval) { - timeout_start = time(NULL); - while (!got_level) { - message_dispatch(); - if ((time(NULL) - timeout_start) > MAX_WAIT) { - fprintf(stderr,"debuglevel timeout\n"); - break; - } - } + + jobid = atoi(argv[3]); + + notify_job_status_byname( + argv[2], jobid, JOB_STATUS_QUEUED, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + + goto send; + + } else if (strcmp(cmd, "jobdelete") == 0) { + int jobid; + + if (argc != 4) { + fprintf(stderr, "Usage: smbcontrol printnotify" + " jobpause \n"); + return False; } - break; - /* Send a notification message to a printer */ + jobid = atoi(argv[3]); + + notify_job_status_byname( + argv[2], jobid, JOB_STATUS_DELETING, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + + notify_job_status_byname( + argv[2], jobid, JOB_STATUS_DELETING| + JOB_STATUS_DELETED, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); - case MSG_PRINTER_NOTIFY2: { - char *cmd; + goto send; - /* Read subcommand */ + } else if (strcmp(cmd, "printer") == 0) { + uint32 attribute; + + if (argc != 5) { + fprintf(stderr, "Usage: smbcontrol printnotify " + "printer " + "\n"); + return False; + } - if (!params || !params[0]) { - fprintf(stderr, "Must specify subcommand:\n"); - fprintf(stderr, "\tqueuepause \n"); - fprintf(stderr, "\tqueueresume \n"); - fprintf(stderr, "\tjobpause \n"); - fprintf(stderr, "\tjobresume \n"); - fprintf(stderr, "\tjobdelete \n"); - fprintf(stderr, "\tprinter \n"); + if (strcmp(argv[3], "comment") == 0) { + attribute = PRINTER_NOTIFY_COMMENT; + } else if (strcmp(argv[3], "port") == 0) { + attribute = PRINTER_NOTIFY_PORT_NAME; + } else if (strcmp(argv[3], "driver") == 0) { + attribute = PRINTER_NOTIFY_DRIVER_NAME; + } else { + fprintf(stderr, "Invalid printer command '%s'\n", + argv[3]); return False; } - cmd = params[0]; + notify_printer_byname(argv[2], attribute, argv[4]); - check_notify_msgs = True; + goto send; + } - /* Pause a print queue */ + fprintf(stderr, "Invalid subcommand '%s'\n", cmd); + return False; - if (strequal(cmd, "queuepause")) { +send: + print_notify_send_messages(0); + return True; +} - if (!params[1]) { - fprintf(stderr, "queuepause command requires a printer name\n"); - return False; - } +/* Close a share */ - notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED); - break; - } +static BOOL do_closeshare(const pid_t pid, const int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: smbcontrol close-share " + "\n"); + return False; + } - /* Resume a print queue */ + return send_message( + pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False); +} - if (strequal(cmd, "queueresume")) { +/* Force a SAM synchronisation */ - if (!params[1]) { - fprintf(stderr, "queueresume command requires a printer name\n"); - return False; - } +static BOOL do_samsync(const pid_t pid, const int argc, char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol samsync\n"); + return False; + } - notify_printer_status_byname(params[1], PRINTER_STATUS_OK); - break; - } + return send_message( + pid, MSG_SMB_SAM_SYNC, NULL, 0, False); +} - /* Pause a print job */ +/* Force a SAM replication */ - if (strequal(cmd, "jobpause")) { - int jobid; +static BOOL do_samrepl(const pid_t pid, const int argc, char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol samrepl\n"); + return False; + } - if (!params[1] || !params[2]) { - fprintf(stderr, "jobpause command requires a printer name and a jobid\n"); - return False; - } + return send_message( + pid, MSG_SMB_SAM_REPL, NULL, 0, False); +} - jobid = atoi(params[2]); +/* Display talloc pool usage */ - notify_job_status_byname( - params[1], jobid, JOB_STATUS_PAUSED, - SPOOLSS_NOTIFY_MSG_UNIX_JOBID); - break; - } +static BOOL do_poolusage(const pid_t pid, const int argc, char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol pool-usage\n"); + return False; + } - /* Resume a print job */ + /* Send a message and register our interest in a reply */ - if (strequal(cmd, "jobresume")) { - int jobid; + if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False)) + return False; - if (!params[1] || !params[2]) { - fprintf(stderr, "jobresume command requires a printer name and a jobid\n"); - return False; - } + message_register(MSG_POOL_USAGE, print_string_cb); - jobid = atoi(params[2]); + wait_replies(pid == 0); - notify_job_status_byname( - params[1], jobid, JOB_STATUS_QUEUED, - SPOOLSS_NOTIFY_MSG_UNIX_JOBID); - break; - } + /* No replies were received within the timeout period */ - /* Delete a print job */ + if (num_replies == 0) + printf("No replies received\n"); - if (strequal(cmd, "jobdelete")) { - int jobid; + message_deregister(MSG_POOL_USAGE); - if (!params[1] || !params[2]) { - fprintf(stderr, "jobdelete command requires a printer name and a jobid\n"); - return False; - } + return num_replies; +} - jobid = atoi(params[2]); +/* Perform a dmalloc mark */ - notify_job_status_byname( - params[1], jobid, JOB_STATUS_DELETING, - SPOOLSS_NOTIFY_MSG_UNIX_JOBID); +static BOOL do_dmalloc_mark(const pid_t pid, const int argc, char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol dmalloc-mark\n"); + return False; + } - notify_job_status_byname( - params[1], jobid, JOB_STATUS_DELETING| - JOB_STATUS_DELETED, - SPOOLSS_NOTIFY_MSG_UNIX_JOBID); - } - - /* printer change notify */ - - if (strequal(cmd, "printer")) { - int attribute = -1; - - if (!params[1] || !params[2] || !params[3]) { - fprintf(stderr, "printer command requires an and attribute name and value!\n"); - fprintf(stderr, "supported attributes:\n"); - fprintf(stderr, "\tcomment:\n"); - fprintf(stderr, "\tport:\n"); - fprintf(stderr, "\tdriver:\n"); - return False; - } - if ( strequal(params[2], "comment") ) - attribute = PRINTER_NOTIFY_COMMENT; - else if ( strequal(params[2], "port") ) - attribute = PRINTER_NOTIFY_PORT_NAME; - else if ( strequal(params[2], "driver") ) - attribute = PRINTER_NOTIFY_DRIVER_NAME; - - if ( attribute == -1 ) { - fprintf(stderr, "bad attribute!\n"); - return False; - } - - notify_printer_byname( params[1], attribute, params[3]); - - break; - } - - break; - } + return send_message( + pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False); +} +/* Perform a dmalloc changed */ - case MSG_SMB_FORCE_TDIS: - if (!strequal(dest, "smbd")) { - fprintf(stderr,"close-share can only be sent to smbd\n"); - return(False); - } - if (!params || !params[0]) { - fprintf(stderr, "close-share needs a share name or '*'\n"); - return (False); - } - retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0], - strlen(params[0]) + 1, False); - break; +static BOOL do_dmalloc_changed(const pid_t pid, const int argc, + char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol " + "dmalloc-log-changed\n"); + return False; + } - case MSG_SMB_SAM_SYNC: - if (!strequal(dest, "smbd")) { - fprintf(stderr, "samsync can only be sent to smbd\n"); - return False; - } + return send_message( + pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False); +} - if (params) { - fprintf(stderr, "samsync does not take any parameters\n"); - return False; - } +/* Shutdown a server process */ - retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False); +static BOOL do_shutdown(const pid_t pid, const int argc, char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: smbcontrol shutdown\n"); + return False; + } - break; + return send_message(pid, MSG_SHUTDOWN, NULL, 0, False); +} - case MSG_SMB_SAM_REPL: { - uint32 seqnum; +/* Notify a driver upgrade */ - if (!strequal(dest, "smbd")) { - fprintf(stderr, "sam repl can only be sent to smbd\n"); - return False; - } +static BOOL do_drvupgrade(const pid_t pid, const int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: smbcontrol drvupgrade " + "\n"); + return False; + } - if (!params || !params[0]) { - fprintf(stderr, "SAM_REPL needs a parameter\n"); - return False; - } + return send_message( + pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); +} - seqnum = atoi(params[0]); +/* A list of message type supported */ - retval = send_message(dest, MSG_SMB_SAM_SYNC, - (char *)&seqnum, sizeof(uint32), False); +static const struct { + const char *name; /* Option name */ + BOOL (*fn)(const pid_t pid, const int argc, char **argv); + const char *help; /* Short help text */ +} msg_types[] = { + { "debug", do_debug, "Set debuglevel" }, + { "force-election", do_election, + "Force a browse election" }, + { "ping", do_ping, "Elicit a response" }, + { "profile", do_profile, "" }, + { "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" }, + { "samsync", do_samsync, "Initiate SAM synchronisation" }, + { "samrepl", do_samrepl, "Initiate SAM replication" }, + { "pool-usage", do_poolusage, "Display talloc memory usage" }, + { "dmalloc-mark", do_dmalloc_mark, "" }, + { "dmalloc-log-changed", do_dmalloc_changed, "" }, + { "shutdown", do_shutdown, "Shut down daemon" }, + { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" }, + { "noop", do_noop, "Do nothing" }, + { NULL } +}; - break; - } +/* Yuck - we need these because we link to printing*.o even though + they aren't used. */ - case MSG_PING: - if (!pong_registered) { - message_register(MSG_PONG, pong_function); - pong_registered = True; - } - if (!params || !params[0]) { - fprintf(stderr,"MSG_PING needs a parameter\n"); - return(False); - } - n = atoi(params[0]); - pong_count = 0; - for (i=0;i 1) - retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True); - else - retval = send_message(dest, MSG_PING, NULL, 0, True); - if (retval == False) - return False; - } - wait_for_replies(MAX_WAIT, &n); - if (n > 0) { - fprintf(stderr,"PING timeout\n"); - } - break; +void become_root(void) {} +void unbecome_root(void) {} - case MSG_REQ_POOL_USAGE: - if (!send_message(dest, MSG_REQ_POOL_USAGE, NULL, 0, True)) - return False; - wait_for_replies(MAX_WAIT, NULL); - - break; +/* Display usage information */ - case MSG_REQ_DMALLOC_LOG_CHANGED: - case MSG_REQ_DMALLOC_MARK: - if (!send_message(dest, mtype, NULL, 0, False)) - return False; - break; +static void usage(poptContext *pc) +{ + int i; - case MSG_SHUTDOWN: - if (!send_message(dest, MSG_SHUTDOWN, NULL, 0, False)) - return False; - break; - case MSG_PRINTER_DRVUPGRADE: - if (!params || !params[0]) { - fprintf(stderr,"drvupgrade needs a parameter\n"); - return(False); - } + poptPrintHelp(*pc, stderr, 0); - if (!send_message(dest, MSG_PRINTER_DRVUPGRADE, params[0], 0, False)) - return False; - break; + fprintf(stderr, "\n"); + fprintf(stderr, " is one of \"nmbd\", \"smbd\" or a " + "process ID\n"); + + fprintf(stderr, "\n"); + fprintf(stderr, " is one of:\n"); + + for (i = 0; msg_types[i].name; i++) + fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, + msg_types[i].help); + + fprintf(stderr, "\n"); + + exit(1); +} + +/* Return the pid number for a string destination */ + +static pid_t parse_dest(char *dest) +{ + pid_t pid; + + /* Zero is a special return value for broadcast smbd */ + + if (strequal(dest, "smbd")) + return 0; + + /* Try self - useful for testing */ + + if (strequal(dest, "self")) + return sys_getpid(); + + /* Check for numeric pid number */ + + if ((pid = atoi(dest)) != 0) + return pid; + + /* Look up other destinations in pidfile directory */ + + if ((pid = pidfile_pid(dest)) != 0) + return pid; + + fprintf(stderr,"Can't find pid for destination '%s'\n", dest); + + return -1; +} + +/* Execute smbcontrol command */ + +static BOOL do_command(int argc, char **argv) +{ + char *dest = argv[0], *command = argv[1]; + pid_t pid; + int i; + + /* Check destination */ + + if ((pid = parse_dest(dest)) == -1) + return False; + + /* Check command */ + + 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); } - /* check if we have any pending print notify messages */ + fprintf(stderr, "smbcontrol: unknown command '%s'\n", command); - if ( check_notify_msgs ) - print_notify_send_messages(0); - - return (True); + return False; } - int main(int argc, char *argv[]) +/* Main program */ + +int main(int argc, char **argv) { + poptContext pc; int opt; - char temp[255]; - extern int optind; - BOOL interactive = False; - AllowDebugChange = False; - DEBUGLEVEL = 0; + struct poptOption wbinfo_options[] = { + { "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_TABLEEND + }; setup_logging(argv[0],True); - if (argc < 2) usage(True); + /* Parse command line arguments using popt */ + + pc = poptGetContext( + "smbcontrol", argc, (const char **)argv, options, 0); + + poptSetOtherOptionHelp(pc, "[OPTION...] " + ""); + + if (argc == 1) + usage(&pc); - while ((opt = getopt(argc, argv,"is:")) != EOF) { - switch (opt) { - case 'i': - interactive = True; + while ((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + case 't': /* --timeout */ + argc -= 2; break; - case 's': + case 's': /* --configfile */ pstrcpy(dyn_CONFIGFILE, optarg); + argc -= 2; break; default: - printf("Unknown option %c (%d)\n", (char)opt, opt); - usage(True); + fprintf(stderr, "Invalid option\n"); + poptPrintHelp(pc, stderr, 0); + break; } } - lp_load(dyn_CONFIGFILE,False,False,False); - - if (!message_init()) exit(1); + /* We should now have the remaining command line arguments in + argv. The argc parameter should have been decremented to the + correct value in the above switch statement. */ - argc -= optind; - argv = &argv[optind]; + argv = (char **)poptGetArgs(pc); + argc--; /* Don't forget about argv[0] */ - register_all(); + if (argc == 1) + usage(&pc); - if (!interactive) { - if (argc < 2) usage(True); - /* Need to invert sense of return code -- samba - * routines mostly return True==1 for success, but - * shell needs 0. */ - return ! do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0); - } - - while (True) { - char *myargv[4]; - int myargc; + lp_load(dyn_CONFIGFILE,False,False,False); - printf("smbcontrol> "); - if (!fgets(temp, sizeof(temp)-1, stdin)) break; - myargc = 0; - while ((myargc < 4) && - (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) { - myargc++; - } - if (!myargc) break; - if (strequal(myargv[0],"q")) break; - if (myargc < 2) - usage(False); - else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0)) - usage(False); - } - return(0); + /* Need to invert sense of return code -- samba + * routines mostly return True==1 for success, but + * shell needs 0. */ + + return !do_command(argc, argv); } - -- cgit