diff options
Diffstat (limited to 'source3/utils/smbcontrol.c')
-rw-r--r-- | source3/utils/smbcontrol.c | 1121 |
1 files changed, 549 insertions, 572 deletions
diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index 8b984d9bd1..ec4f41cad6 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -1,11 +1,8 @@ /* Unix SMB/CIFS implementation. - - Send messages to other Samba daemons - - Copyright (C) Tim Potter 2003 + program to send control messages to Samba processes Copyright (C) Andrew Tridgell 1994-1998 - Copyright (C) Martin Pool 2001-2002 + Copyright (C) 2001, 2002 by Martin Pool Copyright (C) Simo Sorce 2002 This program is free software; you can redistribute it and/or modify @@ -25,718 +22,698 @@ #include "includes.h" -/* Default timeout value when waiting for replies (in seconds) */ - -#define DEFAULT_TIMEOUT 10 - -static int timeout = DEFAULT_TIMEOUT; -static int num_replies; /* Used by message callback fns */ +extern BOOL AllowDebugChange; -/* Send a message to a destination pid. Zero means broadcast smbd. */ - -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; -} - -/* Wait for one or more reply messages */ - -static void wait_replies(BOOL multiple_replies) -{ - time_t start_time = time(NULL); +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}, + {"tallocdump", MSG_REQ_TALLOC_USAGE}, + {NULL, -1} +}; - /* Wait around a bit. This is pretty disgusting - we have to - busy-wait here as there is no nicer way to do it. */ +time_t timeout_start; - do { - message_dispatch(); - if (num_replies > 0 && !multiple_replies) - break; - sleep(1); - } while (timeout - (time(NULL) - start_time) > 0); -} +#define MAX_WAIT 10 -/* Message handler callback that displays a string on stdout */ +/* we need these because we link to printing*.o */ -static void print_string_cb(int msg_type, pid_t pid, void *buf, size_t len) -{ - printf("%.*s", (int)len, (const char *)buf); - num_replies++; -} +void become_root(void) {} +void unbecome_root(void) {} -/* Send no message. Useful for testing. */ -static BOOL do_noop(const pid_t pid, const int argc, char **argv) +static void usage(BOOL doexit) { - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> noop\n"); - return False; + int i; + if (doexit) { + printf("Usage: smbcontrol -i -s configfile\n"); + printf(" smbcontrol <destination> <message-type> <parameters>\n\n"); + } else { + printf("<destination> <message-type> <parameters>\n\n"); } - - /* Move along, nothing to see here */ - - return True; + printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n"); + printf("\t<message-type> 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); } -/* Send a debug string */ - -static BOOL do_debug(const pid_t pid, const int argc, char **argv) +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) { - if (argc != 2) { - fprintf(stderr, "Usage: smbcontrol <dest> debug " - "<debug-string>\n"); - return False; - } + time_t timeout_end = time(NULL) + max_secs; - 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 <dest> force-election\n"); - return False; + while ((!max_replies || (*max_replies)-- > 0) + && (time(NULL) < timeout_end)) { + message_dispatch(); } - - return send_message( - pid, MSG_FORCE_ELECTION, NULL, 0, False); } -/* Ping a samba daemon process */ -static void pong_cb(int msg_type, pid_t pid, void *buf, size_t len) +/**************************************************************************** +a useful function for testing the message system +****************************************************************************/ +void pong_function(int msg_type, pid_t src, void *buf, size_t len) { - printf("PONG from pid %u\n", (unsigned int)pid); - num_replies++; + pong_count++; + printf("PONG from PID %u\n",(unsigned int)src); } -static BOOL do_ping(const pid_t pid, const int argc, char **argv) +/**************************************************************************** + Prints out the current talloc list. +****************************************************************************/ +void tallocdump_function(int msg_type, pid_t src, void *buf, size_t len) { - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> 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; + 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; } -/* Set profiling options */ - -static BOOL do_profile(const pid_t pid, const int argc, char **argv) +/**************************************************************************** +Prints out the current Debug level returned by MSG_DEBUGLEVEL +****************************************************************************/ +void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len) { - int v; - - if (argc != 2) { - fprintf(stderr, "Usage: smbcontrol <dest> profile " - "<off|count|on|flush>\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; - } + const char *levels = (char *)buf; - return send_message(pid, MSG_PROFILE, &v, sizeof(int), False); + printf("Current debug levels of PID %u are:\n",(unsigned int)src); + printf("%s\n", levels); + + got_level = True; } -/* Return the profiling level */ - -static void profilelevel_cb(int msg_type, pid_t pid, void *buf, size_t len) +/**************************************************************************** +Prints out the current Profile level returned by MSG_PROFILELEVEL +****************************************************************************/ +void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len) { - int level; - const char *s; + int level; + const char *s=NULL; + memcpy(&level, buf, sizeof(int)); - num_replies++; - - if (len != sizeof(int)) { - fprintf(stderr, "invalid message length %d returned\n", len); - return; - } - - memcpy(&level, buf, sizeof(int)); - - switch (level) { - case 0: - s = "not enabled"; - break; - case 1: + if (level) { + switch (level) { + 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; + 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); } - - printf("Profiling %s on pid %u\n",s,(unsigned int)pid); + got_level = True; } -static void profilelevel_rqst(int msg_type, pid_t pid, void *buf, size_t len) +/** + * Handle reply from POOL_USAGE. + **/ +static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len) { - int v = 0; - - /* Send back a dummy reply */ - - send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False); + printf("Got POOL_USAGE reply from pid%u:\n%.*s", + (unsigned int) src_pid, (int) len, (const char *) buf); } -static BOOL do_profilelevel(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\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); - wait_replies(pid == 0); - - /* No replies were received within the timeout period */ - - if (num_replies == 0) - printf("No replies received\n"); +/** + * 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) +{ + 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; + } - message_deregister(MSG_PROFILE); + 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; + } + } - return num_replies; + DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid)); + return message_send_pid(pid, msg_type, buf, len, duplicates); } -/* Display debug level settings */ - -static BOOL do_debuglevel(const pid_t pid, const int argc, char **argv) +/**************************************************************************** +evaluate a message type string +****************************************************************************/ +static int parse_type(char *mtype) { - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n"); - return False; + int i; + for (i=0;msg_types[i].name;i++) { + if (strequal(mtype, msg_types[i].name)) return msg_types[i].value; } + return -1; +} - /* Send a message and register our interest in a reply */ - if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False)) - return False; +static void register_all(void) +{ + message_register(MSG_POOL_USAGE, pool_usage_cb); +} - message_register(MSG_DEBUGLEVEL, print_string_cb); +/* This guy is here so we can link printing/notify.c to the smbcontrol + binary without having to pull in tons of other crap. */ - wait_replies(pid == 0); +TDB_CONTEXT *conn_tdb_ctx(void) +{ + static TDB_CONTEXT *tdb; - /* No replies were received within the timeout period */ + if (tdb) + return tdb; - if (num_replies == 0) - printf("No replies received\n"); + tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0); - message_deregister(MSG_DEBUGLEVEL); + if (!tdb) + DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n")); - return num_replies; + return tdb; } -/* Send a print notify message */ - -static BOOL do_printnotify(const pid_t pid, const int argc, char **argv) +/**************************************************************************** +do command +****************************************************************************/ +static BOOL do_command(char *dest, char *msg_name, int iparams, char **params) { - char *cmd; - - /* Check for subcommand */ - - if (argc == 1) { - fprintf(stderr, "Must specify subcommand:\n"); - fprintf(stderr, "\tqueuepause <printername>\n"); - fprintf(stderr, "\tqueueresume <printername>\n"); - fprintf(stderr, "\tjobpause <printername> <unix jobid>\n"); - fprintf(stderr, "\tjobresume <printername> <unix jobid>\n"); - fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n"); - fprintf(stderr, "\tprinter <printername> <comment|port|" - "driver> <value>\n"); - - return False; + 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); } - cmd = argv[1]; + switch (mtype) { + case MSG_DEBUG: { + char *buf, *b; + char **p; + int dim = 0; - if (strcmp(cmd, "queuepause") == 0) { - - if (argc != 3) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " queuepause <printername>\n"); - return False; + if (!params || !params[0]) { + fprintf(stderr,"MSG_DEBUG needs a parameter\n"); + return(False); } - - notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED); - goto send; - - } else if (strcmp(cmd, "queueresume") == 0) { - - if (argc != 3) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " queuereume <printername>\n"); - return False; + /* 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); } - - notify_printer_status_byname(argv[2], PRINTER_STATUS_OK); - - goto send; - - } else if (strcmp(cmd, "jobpause") == 0) { - int jobid; - - if (argc != 4) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " jobpause <printername> <unix-jobid>\n"); - 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; } + b[-1] = '\0'; - jobid = atoi(argv[3]); + send_message(dest, MSG_DEBUG, buf, dim, False); - 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; + free(buf); + + break; + } - if (argc != 4) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify" - " jobpause <printername> <unix-jobid>\n"); - return False; + case MSG_PROFILE: + if (!params || !params[0]) { + fprintf(stderr,"MSG_PROFILE needs a parameter\n"); + return(False); } - - 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 <dest> printnotify" - " jobpause <printername> <unix-jobid>\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); } + send_message(dest, MSG_PROFILE, &v, sizeof(int), False); + break; - 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); - - goto send; - - } else if (strcmp(cmd, "printer") == 0) { - uint32 attribute; - - if (argc != 5) { - fprintf(stderr, "Usage: smbcontrol <dest> printnotify " - "printer <printername> <comment|port|driver> " - "<value>\n"); - return False; + 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; - 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; + 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; + } + } + } + break; - notify_printer_byname(argv[2], attribute, argv[4]); - - goto send; - } - - fprintf(stderr, "Invalid subcommand '%s'\n", cmd); - return False; - -send: - print_notify_send_messages(0); - return True; -} - -/* Close a share */ - -static BOOL do_closeshare(const pid_t pid, const int argc, char **argv) -{ - if (argc != 2) { - fprintf(stderr, "Usage: smbcontrol <dest> close-share " - "<sharename>\n"); - return False; - } - - return send_message( - pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False); -} - -/* Force a SAM synchronisation */ - -static BOOL do_samsync(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> samsync\n"); - return False; - } - - return send_message( - pid, MSG_SMB_SAM_SYNC, NULL, 0, False); -} - -/* Force a SAM replication */ - -static BOOL do_samrepl(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n"); - return False; - } - - return send_message( - pid, MSG_SMB_SAM_REPL, NULL, 0, False); -} - -/* Display talloc pool usage */ - -static BOOL do_poolusage(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n"); - return False; - } - - /* Send a message and register our interest in a reply */ - - if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False)) - return False; + case MSG_REQ_TALLOC_USAGE: + if (!poolusage_registered) { + message_register(MSG_TALLOC_USAGE, tallocdump_function); + poolusage_registered = True; + } + got_pool = False; + retval = send_message(dest, MSG_REQ_TALLOC_USAGE, NULL, 0, True); + if (retval) { + timeout_start = time(NULL); + while (!got_pool) { + message_dispatch(); + if ((time(NULL) - timeout_start) > MAX_WAIT) { + fprintf(stderr,"tallocdump timeout\n"); + break; + } + } + } + break; - message_register(MSG_POOL_USAGE, print_string_cb); + case MSG_REQ_DEBUGLEVEL: + if (!debuglevel_registered) { + message_register(MSG_DEBUGLEVEL, debuglevel_function); + debuglevel_registered = True; + } + 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; + } + } + } + break; - wait_replies(pid == 0); + /* Send a notification message to a printer */ - /* No replies were received within the timeout period */ + case MSG_PRINTER_NOTIFY2: { + char *cmd; - if (num_replies == 0) - printf("No replies received\n"); + /* Read subcommand */ - message_deregister(MSG_POOL_USAGE); + if (!params || !params[0]) { + fprintf(stderr, "Must specify subcommand:\n"); + fprintf(stderr, "\tqueuepause <printername>\n"); + fprintf(stderr, "\tqueueresume <printername>\n"); + fprintf(stderr, "\tjobpause <printername> <unix jobid>\n"); + fprintf(stderr, "\tjobresume <printername> <unix jobid>\n"); + fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n"); + fprintf(stderr, "\tprinter <printername> <comment|port|driver> <new value>\n"); + return False; + } - return num_replies; -} + cmd = params[0]; -/* Perform a dmalloc mark */ + check_notify_msgs = True; -static BOOL do_dmalloc_mark(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n"); - return False; - } + /* Pause a print queue */ - return send_message( - pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False); -} + if (strequal(cmd, "queuepause")) { -/* Perform a dmalloc changed */ + if (!params[1]) { + fprintf(stderr, "queuepause command requires a printer name\n"); + return False; + } -static BOOL do_dmalloc_changed(const pid_t pid, const int argc, - char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> " - "dmalloc-log-changed\n"); - return False; - } + notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED); + break; + } - return send_message( - pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False); -} + /* Resume a print queue */ -/* Shutdown a server process */ + if (strequal(cmd, "queueresume")) { -static BOOL do_shutdown(const pid_t pid, const int argc, char **argv) -{ - if (argc != 1) { - fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n"); - return False; - } + if (!params[1]) { + fprintf(stderr, "queueresume command requires a printer name\n"); + return False; + } - return send_message(pid, MSG_SHUTDOWN, NULL, 0, False); -} + notify_printer_status_byname(params[1], PRINTER_STATUS_OK); + break; + } -/* Notify a driver upgrade */ + /* Pause a print job */ -static BOOL do_drvupgrade(const pid_t pid, const int argc, char **argv) -{ - if (argc != 2) { - fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade " - "<driver-name>\n"); - return False; - } + if (strequal(cmd, "jobpause")) { + int jobid; - return send_message( - pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); -} + if (!params[1] || !params[2]) { + fprintf(stderr, "jobpause command requires a printer name and a jobid\n"); + return False; + } -/* A list of message type supported */ + jobid = atoi(params[2]); -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 } -}; + notify_job_status_byname( + params[1], jobid, JOB_STATUS_PAUSED, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + break; + } -/* Yuck - we need these because we link to printing*.o even though - they aren't used. */ + /* Resume a print job */ -void become_root(void) {} -void unbecome_root(void) {} + if (strequal(cmd, "jobresume")) { + int jobid; -/* Display usage information */ + if (!params[1] || !params[2]) { + fprintf(stderr, "jobresume command requires a printer name and a jobid\n"); + return False; + } -static void usage(poptContext *pc) -{ - int i; + jobid = atoi(params[2]); - poptPrintHelp(*pc, stderr, 0); + notify_job_status_byname( + params[1], jobid, JOB_STATUS_QUEUED, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); + break; + } - fprintf(stderr, "\n"); - fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a " - "process ID\n"); + /* Delete a print job */ - fprintf(stderr, "\n"); - fprintf(stderr, "<message-type> is one of:\n"); + if (strequal(cmd, "jobdelete")) { + int jobid; - for (i = 0; msg_types[i].name; i++) - fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, - msg_types[i].help); + if (!params[1] || !params[2]) { + fprintf(stderr, "jobdelete command requires a printer name and a jobid\n"); + return False; + } - fprintf(stderr, "\n"); + jobid = atoi(params[2]); - exit(1); -} + notify_job_status_byname( + params[1], jobid, JOB_STATUS_DELETING, + SPOOLSS_NOTIFY_MSG_UNIX_JOBID); -/* Return the pid number for a string destination */ + 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; + } -static pid_t parse_dest(char *dest) -{ - pid_t pid; - /* Zero is a special return value for broadcast smbd */ + 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; - if (strequal(dest, "smbd")) - return 0; + case MSG_SMB_SAM_SYNC: + if (!strequal(dest, "smbd")) { + fprintf(stderr, "samsync can only be sent to smbd\n"); + return False; + } - /* Try self - useful for testing */ + if (params) { + fprintf(stderr, "samsync does not take any parameters\n"); + return False; + } - if (strequal(dest, "self")) - return sys_getpid(); + retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False); - /* Check for numeric pid number */ + break; - if ((pid = atoi(dest)) != 0) - return pid; + case MSG_SMB_SAM_REPL: { + uint32 seqnum; - /* Look up other destinations in pidfile directory */ + if (!strequal(dest, "smbd")) { + fprintf(stderr, "sam repl can only be sent to smbd\n"); + return False; + } - if ((pid = pidfile_pid(dest)) != 0) - return pid; + if (!params || !params[0]) { + fprintf(stderr, "SAM_REPL needs a parameter\n"); + return False; + } - fprintf(stderr,"Can't find pid for destination '%s'\n", dest); + seqnum = atoi(params[0]); - return -1; -} + retval = send_message(dest, MSG_SMB_SAM_SYNC, + (char *)&seqnum, sizeof(uint32), False); -/* Execute smbcontrol command */ + break; + } -static BOOL do_command(int argc, char **argv) -{ - char *dest = argv[0], *command = argv[1]; - pid_t pid; - int i; + 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<n;i++) { + if (iparams > 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; - /* Check destination */ + 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; - if ((pid = parse_dest(dest)) == -1) - return False; + case MSG_REQ_DMALLOC_LOG_CHANGED: + case MSG_REQ_DMALLOC_MARK: + if (!send_message(dest, mtype, NULL, 0, False)) + return False; + break; - /* Check command */ + 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); + } - 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); + if (!send_message(dest, MSG_PRINTER_DRVUPGRADE, params[0], 0, False)) + return False; + break; } - fprintf(stderr, "smbcontrol: unknown command '%s'\n", command); + /* check if we have any pending print notify messages */ - return False; + if ( check_notify_msgs ) + print_notify_send_messages(0); + + return (True); } -/* Main program */ - -int main(int argc, char **argv) + int main(int argc, char *argv[]) { - poptContext pc; int opt; + char temp[255]; + extern int optind; + BOOL interactive = False; - 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 - }; + AllowDebugChange = False; + DEBUGLEVEL = 0; setup_logging(argv[0],True); - /* Parse command line arguments using popt */ - - pc = poptGetContext( - "smbcontrol", argc, (const char **)argv, options, 0); - - poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> " - "<parameters>"); - - if (argc == 1) - usage(&pc); + if (argc < 2) usage(True); - while ((opt = poptGetNextOpt(pc)) != -1) { - switch(opt) { - case 't': /* --timeout */ - argc -= 2; + while ((opt = getopt(argc, argv,"is:")) != EOF) { + switch (opt) { + case 'i': + interactive = True; break; - case 's': /* --configfile */ + case 's': pstrcpy(dyn_CONFIGFILE, optarg); - argc -= 2; break; default: - fprintf(stderr, "Invalid option\n"); - poptPrintHelp(pc, stderr, 0); - break; + printf("Unknown option %c (%d)\n", (char)opt, opt); + usage(True); } } - /* 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. */ + lp_load(dyn_CONFIGFILE,False,False,False); - argv = (char **)poptGetArgs(pc); - argc--; /* Don't forget about argv[0] */ + if (!message_init()) exit(1); - if (argc == 1) - usage(&pc); + argc -= optind; + argv = &argv[optind]; - lp_load(dyn_CONFIGFILE,False,False,False); + register_all(); - /* 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 (!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; + + 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); } + |