support smbcontrol sending messages to itself (for testing purposes)
[ira/wip.git] / source3 / utils / smbcontrol.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    program to send control messages to Samba processes
5    Copyright (C) Andrew Tridgell 1994-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 static struct {
25         char *name;
26         int value;
27 } msg_types[] = {
28         {"debug", MSG_DEBUG},
29         {"force-election", MSG_FORCE_ELECTION},
30         {"ping", MSG_PING},
31         {"profile", MSG_PROFILE},
32         {"profilelevel", MSG_REQ_PROFILELEVEL},
33         {"debuglevel", MSG_REQ_DEBUGLEVEL},
34         {"printer-notify", MSG_PRINTER_NOTIFY},
35         {NULL, -1}
36 };
37
38 time_t timeout_start;
39
40 #define MAX_WAIT        10
41
42 static void usage(BOOL doexit)
43 {
44         int i;
45         if (doexit) {
46                 printf("Usage: smbcontrol -i\n");
47                 printf("       smbcontrol <destination> <message-type> <parameters>\n\n");
48         } else {
49                 printf("<destination> <message-type> <parameters>\n\n");
50         }
51         printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n");
52         printf("\t<message-type> is one of: ");
53         for (i=0; msg_types[i].name; i++) 
54             printf("%s%s", i?", ":"",msg_types[i].name);
55         printf("\n");
56         if (doexit) exit(1);
57 }
58
59 static int pong_count;
60 static BOOL got_level;
61 static BOOL pong_registered = False;
62 static BOOL debuglevel_registered = False;
63 static BOOL profilelevel_registered = False;
64
65
66 /****************************************************************************
67 a useful function for testing the message system
68 ****************************************************************************/
69 void pong_function(int msg_type, pid_t src, void *buf, size_t len)
70 {
71         pong_count++;
72         printf("PONG from PID %d\n",src);
73 }
74
75 /****************************************************************************
76 Prints out the current Debug level returned by MSG_DEBUGLEVEL
77 ****************************************************************************/
78 void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len)
79 {
80         int level;
81         memcpy(&level, buf, sizeof(int));
82
83         printf("Current debug level of PID %d is %d\n",src,level);
84         got_level = True;
85 }
86
87 /****************************************************************************
88 Prints out the current Profile level returned by MSG_PROFILELEVEL
89 ****************************************************************************/
90 void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
91 {
92         int level;
93         char *s;
94         memcpy(&level, buf, sizeof(int));
95
96         if (level) {
97             switch (level) {
98             case 1:
99                 s = "off";
100                 break;
101             case 3:
102                 s = "count only";
103                 break;
104             case 7:
105                 s = "count and time";
106                 break;
107             }
108             printf("Profiling %s on PID %d\n",s,src);
109         } else {
110             printf("Profiling not available on PID %d\n",src);
111         }
112         got_level = True;
113 }
114
115 /****************************************************************************
116 send a message to a named destination
117 ****************************************************************************/
118 static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates)
119 {
120         pid_t pid;
121
122         /* "smbd" is the only broadcast operation */
123         if (strequal(dest,"smbd")) {
124                 return message_send_all(msg_type, buf, len, duplicates);
125         } else if (strequal(dest,"nmbd")) {
126                 pid = pidfile_pid(dest);
127                 if (pid == 0) {
128                         fprintf(stderr,"Can't find pid for nmbd\n");
129                         return False;
130                 }
131         } else if (strequal(dest,"self")) {
132                 pid = getpid();
133         } else {
134                 pid = atoi(dest);
135                 if (pid == 0) {
136                         fprintf(stderr,"Not a valid pid\n");
137                         return False;
138                 }               
139         } 
140
141         return message_send_pid(pid, msg_type, buf, len, duplicates);
142 }
143
144 /****************************************************************************
145 evaluate a message type string
146 ****************************************************************************/
147 static int parse_type(char *mtype)
148 {
149         int i;
150         for (i=0;msg_types[i].name;i++) {
151                 if (strequal(mtype, msg_types[i].name)) return msg_types[i].value;
152         }
153         return -1;
154 }
155
156
157 /****************************************************************************
158 do command
159 ****************************************************************************/
160 static BOOL do_command(char *dest, char *msg_name, char *params)
161 {
162         int i, n, v;
163         int mtype;
164         BOOL retval;
165
166         mtype = parse_type(msg_name);
167         if (mtype == -1) {
168                 fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name);
169                 return(False);
170         }
171
172         switch (mtype) {
173         case MSG_DEBUG:
174                 if (!params) {
175                         fprintf(stderr,"MSG_DEBUG needs a parameter\n");
176                         return(False);
177                 }
178                 v = atoi(params);
179                 send_message(dest, MSG_DEBUG, &v, sizeof(int), False);
180                 break;
181
182         case MSG_PROFILE:
183                 if (!params) {
184                         fprintf(stderr,"MSG_PROFILE needs a parameter\n");
185                         return(False);
186                 }
187                 if (strequal(params, "off")) {
188                         v = 0;
189                 } else if (strequal(params, "count")) {
190                         v = 1;
191                 } else if (strequal(params, "on")) {
192                         v = 2;
193                 } else if (strequal(params, "flush")) {
194                         v = 3;
195                 } else {
196                     fprintf(stderr,
197                         "MSG_PROFILE parameter must be off, count, on, or flush\n");
198                     return(False);
199                 }
200                 send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
201                 break;
202
203         case MSG_FORCE_ELECTION:
204                 if (!strequal(dest, "nmbd")) {
205                         fprintf(stderr,"force-election can only be sent to nmbd\n");
206                         return(False);
207                 }
208                 send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
209                 break;
210
211         case MSG_REQ_PROFILELEVEL:
212                 if (!profilelevel_registered) {
213                     message_register(MSG_PROFILELEVEL, profilelevel_function);
214                     profilelevel_registered = True;
215                 }
216                 got_level = False;
217                 retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
218                 if (retval) {
219                         timeout_start = time(NULL);
220                         while (!got_level) {
221                                 message_dispatch();
222                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
223                                         fprintf(stderr,"profilelevel timeout\n");
224                                         break;
225                                 }
226                         }
227                 }
228                 break;
229
230         case MSG_REQ_DEBUGLEVEL:
231                 if (!debuglevel_registered) {
232                     message_register(MSG_DEBUGLEVEL, debuglevel_function);
233                     debuglevel_registered = True;
234                 }
235                 got_level = False;
236                 retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
237                 if (retval) {
238                         timeout_start = time(NULL);
239                         while (!got_level) {
240                                 message_dispatch();
241                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
242                                         fprintf(stderr,"debuglevel timeout\n");
243                                         break;
244                                 }
245                         }
246                 }
247                 break;
248
249         case MSG_PRINTER_NOTIFY:
250                 if (!strequal(dest, "smbd")) {
251                         fprintf(stderr,"printer-notify can only be sent to smbd\n");
252                         return(False);
253                 }
254                 if (!params) {
255                         fprintf(stderr, "printer-notify needs a printer name\n");
256                         return (False);
257                 }
258                 retval = send_message(dest, MSG_PRINTER_NOTIFY, params,
259                                       strlen(params) + 1, False);
260                 break;
261
262         case MSG_PING:
263                 if (!pong_registered) {
264                     message_register(MSG_PONG, pong_function);
265                     pong_registered = True;
266                 }
267                 if (!params) {
268                         fprintf(stderr,"MSG_PING needs a parameter\n");
269                         return(False);
270                 }
271                 n = atoi(params);
272                 pong_count = 0;
273                 for (i=0;i<n;i++) {
274                         retval = send_message(dest, MSG_PING, NULL, 0, True);
275                         if (retval == False) break;
276                 }
277                 if (retval) {
278                         timeout_start = time(NULL);
279                         while (pong_count < n) {
280                                 message_dispatch();
281                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
282                                         fprintf(stderr,"PING timeout\n");
283                                         break;
284                                 }
285                         }
286                 }
287                 break;
288
289         }
290         
291         return (True);
292 }
293
294  int main(int argc, char *argv[])
295 {
296         int opt;
297         char temp[255];
298         extern int optind;
299         pstring servicesf = CONFIGFILE;
300         BOOL interactive = False;
301
302         TimeInit();
303         setup_logging(argv[0],True);
304         
305         charset_initialise();
306         lp_load(servicesf,False,False,False);
307
308         if (!message_init()) exit(1);
309
310         if (argc < 2) usage(True);
311
312         while ((opt = getopt(argc, argv,"i")) != EOF) {
313                 switch (opt) {
314                 case 'i':
315                         interactive = True;
316                         break;
317                 default:
318                         printf("Unknown option %c (%d)\n", (char)opt, opt);
319                         usage(True);
320                 }
321         }
322
323         argc -= optind;
324         argv = &argv[optind];
325
326         if (!interactive) {
327                 if (argc < 2) usage(True);
328                 return (do_command(argv[0],argv[1],argc > 2 ? argv[2] : 0));
329         }
330
331         while (True) {
332                 char *myargv[3];
333                 int myargc;
334
335                 printf("smbcontrol> ");
336                 if (!fgets(temp, sizeof(temp)-1, stdin)) break;
337                 myargc = 0;
338                 while ((myargc < 3) && 
339                        (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
340                         myargc++;
341                 }
342                 if (!myargc) break;
343                 if (strequal(myargv[0],"q")) break;
344                 if (myargc < 2)
345                         usage(False);
346                 else if (!do_command(myargv[0],myargv[1],myargc > 2 ? myargv[2] : 0))
347                         usage(False);
348         }
349         return(0);
350 }
351