Add two more memory-debug smbcontrol messages: these ones should
[ira/wip.git] / source3 / utils / smbcontrol.c
index a273f82151c7715ee8a5c9a4f6cbd6e5efe02364..318e1657cc1e8367b26792bbf2913caa088f6fda 100644 (file)
@@ -3,6 +3,7 @@
    Version 3.0
    program to send control messages to Samba processes
    Copyright (C) Andrew Tridgell 1994-1998
+   Copyright (C) 2001, 2002 by Martin Pool
    
    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;
@@ -32,6 +35,12 @@ static struct {
        {"profilelevel", MSG_REQ_PROFILELEVEL},
        {"debuglevel", MSG_REQ_DEBUGLEVEL},
        {"printer-notify", MSG_PRINTER_NOTIFY},
+       {"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 },
        {NULL, -1}
 };
 
@@ -43,7 +52,7 @@ static void usage(BOOL doexit)
 {
        int i;
        if (doexit) {
-               printf("Usage: smbcontrol -i\n");
+               printf("Usage: smbcontrol -i -s configfile\n");
                printf("       smbcontrol <destination> <message-type> <parameters>\n\n");
        } else {
                printf("<destination> <message-type> <parameters>\n\n");
@@ -63,13 +72,32 @@ 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
 ****************************************************************************/
 void pong_function(int msg_type, pid_t src, void *buf, size_t len)
 {
        pong_count++;
-       printf("PONG from PID %d\n",src);
+       printf("PONG from PID %u\n",(unsigned int)src);
 }
 
 /****************************************************************************
@@ -77,10 +105,17 @@ 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 level;
-        memcpy(&level, buf, sizeof(int));
+       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");
 
-       printf("Current debug level of PID %d is %d\n",src,level);
        got_level = True;
 }
 
@@ -90,7 +125,7 @@ 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;
-       char *s;
+       char *s=NULL;
         memcpy(&level, buf, sizeof(int));
 
        if (level) {
@@ -105,29 +140,58 @@ void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
                s = "count and time";
                break;
            }
-           printf("Profiling %s on PID %d\n",s,src);
+           printf("Profiling %s on PID %u\n",s,(unsigned int)src);
        } else {
-           printf("Profiling not available on PID %d\n",src);
+           printf("Profiling not available on PID %u\n",(unsigned int)src);
        }
        got_level = True;
 }
 
-/****************************************************************************
-send a message to a named destination
-****************************************************************************/
-static BOOL send_message(char *dest, int msg_type, void *buf, int len)
+/**
+ * Handle reply from POOL_USAGE.
+ **/
+static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len)
 {
-       pid_t pid;
+       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;
        /* "smbd" is the only broadcast operation */
        if (strequal(dest,"smbd")) {
-               return message_send_all(msg_type, buf, len);
+               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;
+               }
+
+               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 = getpid();
        } else {
                pid = atoi(dest);
                if (pid == 0) {
@@ -136,7 +200,8 @@ static BOOL send_message(char *dest, int msg_type, void *buf, int len)
                }               
        } 
 
-       return message_send_pid(pid, msg_type, buf, len);
+       DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid));
+       return message_send_pid(pid, msg_type, buf, len, duplicates);
 }
 
 /****************************************************************************
@@ -152,14 +217,20 @@ static int parse_type(char *mtype)
 }
 
 
+static void register_all(void)
+{
+       message_register(MSG_POOL_USAGE, pool_usage_cb);
+}
+
+
 /****************************************************************************
 do command
 ****************************************************************************/
-static BOOL do_command(char *dest, char *msg_name, char *params)
+static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
 {
        int i, n, v;
        int mtype;
-       BOOL retval;
+       BOOL retval=False;
 
        mtype = parse_type(msg_name);
        if (mtype == -1) {
@@ -168,34 +239,42 @@ static BOOL do_command(char *dest, char *msg_name, char *params)
        }
 
        switch (mtype) {
-       case MSG_DEBUG:
-               if (!params) {
+       case MSG_DEBUG: {
+               struct debuglevel_message dm;
+
+               if (!params || !params[0]) {
                        fprintf(stderr,"MSG_DEBUG needs a parameter\n");
                        return(False);
                }
-               v = atoi(params);
-               send_message(dest, MSG_DEBUG, &v, sizeof(int));
+
+               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");
+                       return(False);
+               } else
+                       send_message(dest, MSG_DEBUG, &dm, sizeof(dm), False);
                break;
+       }
 
        case MSG_PROFILE:
-               if (!params) {
+               if (!params || !params[0]) {
                        fprintf(stderr,"MSG_PROFILE needs a parameter\n");
                        return(False);
                }
-               if (strequal(params, "off")) {
+               if (strequal(params[0], "off")) {
                        v = 0;
-               } else if (strequal(params, "count")) {
+               } else if (strequal(params[0], "count")) {
                        v = 1;
-               } else if (strequal(params, "on")) {
+               } else if (strequal(params[0], "on")) {
                        v = 2;
-               } else if (strequal(params, "flush")) {
+               } 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));
+               send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
                break;
 
        case MSG_FORCE_ELECTION:
@@ -203,7 +282,7 @@ static BOOL do_command(char *dest, char *msg_name, char *params)
                        fprintf(stderr,"force-election can only be sent to nmbd\n");
                        return(False);
                }
-               send_message(dest, MSG_FORCE_ELECTION, NULL, 0);
+               send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
                break;
 
        case MSG_REQ_PROFILELEVEL:
@@ -212,7 +291,7 @@ static BOOL do_command(char *dest, char *msg_name, char *params)
                    profilelevel_registered = True;
                }
                got_level = False;
-               retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0);
+               retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
                if (retval) {
                        timeout_start = time(NULL);
                        while (!got_level) {
@@ -231,7 +310,7 @@ static BOOL do_command(char *dest, char *msg_name, char *params)
                    debuglevel_registered = True;
                }
                got_level = False;
-               retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0);
+               retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
                if (retval) {
                        timeout_start = time(NULL);
                        while (!got_level) {
@@ -249,43 +328,102 @@ static BOOL do_command(char *dest, char *msg_name, char *params)
                        fprintf(stderr,"printer-notify can only be sent to smbd\n");
                        return(False);
                }
-               if (!params) {
+               if (!params || !params[0]) {
                        fprintf(stderr, "printer-notify needs a printer name\n");
                        return (False);
                }
-               retval = send_message(dest, MSG_PRINTER_NOTIFY, params,
-                                     strlen(params) + 1);
+               retval = send_message(dest, MSG_PRINTER_NOTIFY, params[0],
+                                     strlen(params[0]) + 1, False);
                break;
 
+       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;
+
+        case MSG_SMB_SAM_SYNC:
+                if (!strequal(dest, "smbd")) {
+                        fprintf(stderr, "samsync can only be sent to smbd\n");
+                        return False;
+                }
+
+                if (params) {
+                        fprintf(stderr, "samsync does not take any parameters\n");
+                        return False;
+                }
+
+                retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False);
+
+                break;
+
+        case MSG_SMB_SAM_REPL: {
+                uint32 seqnum;
+
+                if (!strequal(dest, "smbd")) {
+                        fprintf(stderr, "sam repl can only be sent to smbd\n");
+                        return False;
+                }
+
+                if (!params || !params[0]) {
+                        fprintf(stderr, "SAM_REPL needs a parameter\n");
+                        return False;
+                }
+
+                seqnum = atoi(params[0]);
+
+                retval = send_message(dest, MSG_SMB_SAM_SYNC, 
+                                      (char *)&seqnum, sizeof(uint32), False); 
+
+                break;
+        }
+
        case MSG_PING:
                if (!pong_registered) {
                    message_register(MSG_PONG, pong_function);
                    pong_registered = True;
                }
-               if (!params) {
+               if (!params || !params[0]) {
                        fprintf(stderr,"MSG_PING needs a parameter\n");
                        return(False);
                }
-               n = atoi(params);
+               n = atoi(params[0]);
                pong_count = 0;
                for (i=0;i<n;i++) {
-                       retval = send_message(dest, MSG_PING, NULL, 0);
-                       if (retval == False) break;
+                       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;
                }
-               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;
        }
-       
+
        return (True);
 }
 
@@ -294,46 +432,54 @@ static BOOL do_command(char *dest, char *msg_name, char *params)
        int opt;
        char temp[255];
        extern int optind;
-       pstring servicesf = CONFIGFILE;
        BOOL interactive = False;
 
-       TimeInit();
+       AllowDebugChange = False;
+       DEBUGLEVEL = 0;
+
        setup_logging(argv[0],True);
        
-       charset_initialise();
-       lp_load(servicesf,False,False,False);
-
-       if (!message_init()) exit(1);
-
        if (argc < 2) usage(True);
 
-       while ((opt = getopt(argc, argv,"i")) != EOF) {
+       while ((opt = getopt(argc, argv,"is:")) != EOF) {
                switch (opt) {
                case 'i':
                        interactive = True;
                        break;
+               case 's':
+                       pstrcpy(dyn_CONFIGFILE, optarg);
+                       break;
                default:
                        printf("Unknown option %c (%d)\n", (char)opt, opt);
                        usage(True);
                }
        }
 
+       lp_load(dyn_CONFIGFILE,False,False,False);
+
+       if (!message_init()) exit(1);
+
        argc -= optind;
        argv = &argv[optind];
 
+       register_all();
+
        if (!interactive) {
                if (argc < 2) usage(True);
-               return (do_command(argv[0],argv[1],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) {
-               char *myargv[3];
+               char *myargv[4];
                int myargc;
 
                printf("smbcontrol> ");
                if (!fgets(temp, sizeof(temp)-1, stdin)) break;
                myargc = 0;
-               while ((myargc < 3) && 
+               while ((myargc < 4) && 
                       (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
                        myargc++;
                }
@@ -341,7 +487,7 @@ static BOOL do_command(char *dest, char *msg_name, char *params)
                if (strequal(myargv[0],"q")) break;
                if (myargc < 2)
                        usage(False);
-               else if (!do_command(myargv[0],myargv[1],myargc > 2 ? myargv[2] : 0))
+               else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0))
                        usage(False);
        }
        return(0);