Back out lp_modules() check - this one got in by accident when I added poptSetOtherOp...
[kai/samba.git] / source3 / utils / smbcontrol.c
index ce04d7a215825ad083573fa86b4d33e526576354..7c292dd521c5db510ba8596c108067423eee9972 100644 (file)
@@ -1,8 +1,9 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 3.0
+   Unix SMB/CIFS implementation.
    program to send control messages to Samba processes
    Copyright (C) Andrew Tridgell 1994-1998
+   Copyright (C) 2001, 2002 by Martin Pool
+   Copyright (C) Simo Sorce 2002
    
    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
@@ -21,6 +22,8 @@
 
 #include "includes.h"
 
+extern BOOL AllowDebugChange;
+
 static struct {
        char *name;
        int value;
@@ -31,10 +34,15 @@ static struct {
        {"profile", MSG_PROFILE},
        {"profilelevel", MSG_REQ_PROFILELEVEL},
        {"debuglevel", MSG_REQ_DEBUGLEVEL},
-       {"printer-notify", MSG_PRINTER_NOTIFY},
+       {"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 },
+       {"change_id", MSG_PRINTER_DRVUPGRADE},
        {NULL, -1}
 };
 
@@ -66,6 +74,25 @@ static BOOL debuglevel_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)
+{
+       time_t timeout_end = time(NULL) + max_secs;
+
+       while ((!max_replies || (*max_replies)-- > 0)
+              &&  (time(NULL) < timeout_end)) {
+               message_dispatch();
+       }
+}
+
+
 /****************************************************************************
 a useful function for testing the message system
 ****************************************************************************/
@@ -80,17 +107,14 @@ 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 i;
-       int debuglevel_class[DBGC_LAST];
-
-       memcpy(debuglevel_class, buf, len);
-
-       printf("Current debug level of PID %u is %d ",(unsigned int)src, debuglevel_class[0]);
-       for (i=1;i<DBGC_LAST;i++)
-               if (debuglevel_class[i])
-                       printf("%s:%d ", debug_classname_from_index(i), debuglevel_class[i]);
-       printf("\n");
+       char *levels = (char *)buf;
+       pstring dbgcl;
 
+       printf("Current debug levels of PID %u are:\n",(unsigned int)src);
+       
+       while(next_token(&levels, dbgcl, " ", sizeof(pstring)))
+               printf("%s\n", dbgcl);
+       
        got_level = True;
 }
 
@@ -114,6 +138,9 @@ void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
            case 7:
                s = "count and time";
                break;
+           default:
+                   s = "BOGUS";
+                   break;
            }
            printf("Profiling %s on PID %u\n",s,(unsigned int)src);
        } else {
@@ -122,9 +149,21 @@ void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
        got_level = True;
 }
 
-/****************************************************************************
-send a message to a named destination
-****************************************************************************/
+/**
+ * Handle reply from POOL_USAGE.
+ **/
+static void pool_usage_cb(int msg_type, pid_t src_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);
+}
+
+
+/**
+ * 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;
@@ -132,6 +171,7 @@ static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL dupl
        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) {
@@ -139,7 +179,10 @@ static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL dupl
                        return False;
                }
 
-               ret = message_send_all(tdb,msg_type, buf, len, duplicates);
+               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;
@@ -150,7 +193,7 @@ static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL dupl
                        return False;
                }
        } else if (strequal(dest,"self")) {
-               pid = getpid();
+               pid = sys_getpid();
        } else {
                pid = atoi(dest);
                if (pid == 0) {
@@ -159,6 +202,7 @@ static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL dupl
                }               
        } 
 
+       DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid));
        return message_send_pid(pid, msg_type, buf, len, duplicates);
 }
 
@@ -175,6 +219,29 @@ static int parse_type(char *mtype)
 }
 
 
+static void register_all(void)
+{
+       message_register(MSG_POOL_USAGE, pool_usage_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. */
+
+TDB_CONTEXT *conn_tdb_ctx(void)
+{
+       static TDB_CONTEXT *tdb;
+
+       if (tdb)
+               return tdb;
+
+       tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
+
+       if (!tdb)
+               DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
+
+       return tdb;
+}
+
 /****************************************************************************
 do command
 ****************************************************************************/
@@ -192,19 +259,36 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
 
        switch (mtype) {
        case MSG_DEBUG: {
-               struct debuglevel_message dm;
+               char *buf, *b;
+               char **p;
+               int dim = 0;
 
                if (!params || !params[0]) {
                        fprintf(stderr,"MSG_DEBUG needs a parameter\n");
                        return(False);
                }
 
-               ZERO_STRUCT(dm);
-               if (!debug_parse_params(params, dm.debuglevel_class, dm.debuglevel_class_isset)) {
-                       fprintf(stderr, "MSG_DEBUG error. Expected <class name>:level\n");
+               /* 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);
-               } else
-                       send_message(dest, MSG_DEBUG, &dm, sizeof(dm), 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';
+
+               send_message(dest, MSG_DEBUG, buf, dim, False);
+
+               free(buf);
+  
                break;
        }
 
@@ -275,18 +359,112 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
                }
                break;
 
-       case MSG_PRINTER_NOTIFY:
-               if (!strequal(dest, "smbd")) {
-                       fprintf(stderr,"printer-notify can only be sent to smbd\n");
-                       return(False);
-               }
+               /* Send a notification message to a printer */
+               /* NB. None of these currently work due to changes in the printing notify mechanisms. */
+
+#if 0
+       case MSG_PRINTER_NOTIFY2: {
+               char *cmd;
+
+               /* Read subcommand */
+
                if (!params || !params[0]) {
-                       fprintf(stderr, "printer-notify needs a printer name\n");
-                       return (False);
+                       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");
+                       return False;
                }
-               retval = send_message(dest, MSG_PRINTER_NOTIFY, params[0],
-                                     strlen(params[0]) + 1, False);
+
+               cmd = params[0];
+
+               /* Pause a print queue */
+
+               if (strequal(cmd, "queuepause")) {
+
+                       if (!params[1]) {
+                               fprintf(stderr, "queuepause command requires a printer name\n");
+                               return False;
+                       }
+
+                       notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED);
+                       break;
+               }
+
+               /* Resume a print queue */
+
+               if (strequal(cmd, "queueresume")) {
+
+                       if (!params[1]) {
+                               fprintf(stderr, "queueresume command requires a printer name\n");
+                               return False;
+                       }
+
+                       notify_printer_status_byname(params[1], PRINTER_STATUS_OK);
+                       break;
+               }
+
+               /* Pause a print job */
+
+               if (strequal(cmd, "jobpause")) {
+                       int jobid;
+
+                       if (!params[1] || !params[2]) {
+                               fprintf(stderr, "jobpause command requires a printer name and a jobid\n");
+                               return False;
+                       }
+
+                       jobid = atoi(params[2]);
+
+                       notify_job_status_byname(
+                               params[1], jobid, JOB_STATUS_PAUSED, 
+                               SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+               }
+
+               /* Resume a print job */
+
+               if (strequal(cmd, "jobresume")) {
+                       int jobid;
+
+                       if (!params[1] || !params[2]) {
+                               fprintf(stderr, "jobresume command requires a printer name and a jobid\n");
+                               return False;
+                       }
+
+                       jobid = atoi(params[2]);
+
+                       notify_job_status_byname(
+                               params[1], jobid, JOB_STATUS_QUEUED,
+                               SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+               }
+
+               /* Delete a print job */
+
+               if (strequal(cmd, "jobdelete")) {
+                       int jobid;
+
+                       if (!params[1] || !params[2]) {
+                               fprintf(stderr, "jobdelete command requires a printer name and a jobid\n");
+                               return False;
+                       }
+
+                       jobid = atoi(params[2]);
+
+                       notify_job_status_byname(
+                               params[1], jobid, JOB_STATUS_DELETING,
+                               SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+
+                       notify_job_status_byname(
+                               params[1], jobid, JOB_STATUS_DELETING|
+                               JOB_STATUS_DELETED,
+                               SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+               }
+
                break;
+         }
+#endif
 
        case MSG_SMB_FORCE_TDIS:
                if (!strequal(dest, "smbd")) {
@@ -353,22 +531,38 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
                                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) break;
+                       if (retval == False)
+                               return False;
                }
-               if (retval) {
-                       timeout_start = time(NULL);
-                       while (pong_count < n) {
-                               message_dispatch();
-                               if ((time(NULL) - timeout_start) > MAX_WAIT) {
-                                       fprintf(stderr,"PING timeout\n");
-                                       break;
-                               }
-                       }
+               wait_for_replies(MAX_WAIT, &n);
+               if (n > 0) {
+                       fprintf(stderr,"PING timeout\n");
                }
                break;
 
+       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;
+
+       case MSG_REQ_DMALLOC_LOG_CHANGED:
+       case MSG_REQ_DMALLOC_MARK:
+               if (!send_message(dest, mtype, NULL, 0, False))
+                       return False;
+               break;
+
+       case MSG_SHUTDOWN:
+               if (!send_message(dest, MSG_SHUTDOWN, NULL, 0, False))
+                       return False;
+               break;
+       case MSG_PRINTER_DRVUPGRADE:
+               if (!send_message(dest, MSG_PRINTER_DRVUPGRADE, params[0], 0, False))
+                       return False;
+               break;
        }
-       
+
        return (True);
 }
 
@@ -379,6 +573,9 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
        extern int optind;
        BOOL interactive = False;
 
+       AllowDebugChange = False;
+       DEBUGLEVEL = 0;
+
        setup_logging(argv[0],True);
        
        if (argc < 2) usage(True);
@@ -404,9 +601,14 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
        argc -= optind;
        argv = &argv[optind];
 
+       register_all();
+
        if (!interactive) {
                if (argc < 2) usage(True);
-               return (do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0));
+               /* 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) {