f03387c6e0dd02df746cece5618b263b16cd9b7f
[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    Copyright (C) 2001 by Martin Pool
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 extern BOOL AllowDebugChange;
26
27 static struct {
28         char *name;
29         int value;
30 } msg_types[] = {
31         {"debug", MSG_DEBUG},
32         {"force-election", MSG_FORCE_ELECTION},
33         {"ping", MSG_PING},
34         {"profile", MSG_PROFILE},
35         {"profilelevel", MSG_REQ_PROFILELEVEL},
36         {"debuglevel", MSG_REQ_DEBUGLEVEL},
37         {"printer-notify", MSG_PRINTER_NOTIFY},
38         {"close-share", MSG_SMB_FORCE_TDIS},
39         {"samsync", MSG_SMB_SAM_SYNC},
40         {"samrepl", MSG_SMB_SAM_REPL},
41         {"pool-usage", MSG_REQ_POOL_USAGE },
42         {NULL, -1}
43 };
44
45 time_t timeout_start;
46
47 #define MAX_WAIT        10
48
49 static void usage(BOOL doexit)
50 {
51         int i;
52         if (doexit) {
53                 printf("Usage: smbcontrol -i -s configfile\n");
54                 printf("       smbcontrol <destination> <message-type> <parameters>\n\n");
55         } else {
56                 printf("<destination> <message-type> <parameters>\n\n");
57         }
58         printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n");
59         printf("\t<message-type> is one of: ");
60         for (i=0; msg_types[i].name; i++) 
61             printf("%s%s", i?", ":"",msg_types[i].name);
62         printf("\n");
63         if (doexit) exit(1);
64 }
65
66 static int pong_count;
67 static BOOL got_level;
68 static BOOL pong_registered = False;
69 static BOOL debuglevel_registered = False;
70 static BOOL profilelevel_registered = False;
71 static BOOL pool_usage_registered = False;
72
73
74 /**
75  * Wait for replies for up to @p *max_secs seconds, or until @p
76  * max_replies are received.  max_replies may be NULL in which case it
77  * is ignored.
78  *
79  * @note This is a pretty lame timeout; all it means is that after
80  * max_secs we won't look for any more messages.
81  **/
82 static void wait_for_replies(int max_secs, int *max_replies)
83 {
84         time_t timeout_end = time(NULL) + max_secs;
85
86         while ((!max_replies || (*max_replies)-- > 0)
87                &&  (time(NULL) < timeout_end)) {
88                 message_dispatch();
89         }
90 }
91
92
93 /****************************************************************************
94 a useful function for testing the message system
95 ****************************************************************************/
96 void pong_function(int msg_type, pid_t src, void *buf, size_t len)
97 {
98         pong_count++;
99         printf("PONG from PID %u\n",(unsigned int)src);
100 }
101
102 /****************************************************************************
103 Prints out the current Debug level returned by MSG_DEBUGLEVEL
104 ****************************************************************************/
105 void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len)
106 {
107         int i;
108         int debuglevel_class[DBGC_LAST];
109
110         memcpy(debuglevel_class, buf, len);
111
112         printf("Current debug level of PID %u is %d ",(unsigned int)src, debuglevel_class[0]);
113         for (i=1;i<DBGC_LAST;i++)
114                 if (debuglevel_class[i])
115                         printf("%s:%d ", debug_classname_from_index(i), debuglevel_class[i]);
116         printf("\n");
117
118         got_level = True;
119 }
120
121 /****************************************************************************
122 Prints out the current Profile level returned by MSG_PROFILELEVEL
123 ****************************************************************************/
124 void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
125 {
126         int level;
127         char *s=NULL;
128         memcpy(&level, buf, sizeof(int));
129
130         if (level) {
131             switch (level) {
132             case 1:
133                 s = "off";
134                 break;
135             case 3:
136                 s = "count only";
137                 break;
138             case 7:
139                 s = "count and time";
140                 break;
141             }
142             printf("Profiling %s on PID %u\n",s,(unsigned int)src);
143         } else {
144             printf("Profiling not available on PID %u\n",(unsigned int)src);
145         }
146         got_level = True;
147 }
148
149 /**
150  * Handle reply from POOL_USAGE.
151  **/
152 static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len)
153 {
154         printf("Got POOL_USAGE reply from pid%u:\n%.*s",
155                (unsigned int) src_pid, (int) len, (const char *) buf);
156 }
157
158
159 /**
160  * Send a message to a named destination
161  *
162  * @return False if an error occurred.
163  **/
164 static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates)
165 {
166         pid_t pid;
167         /* "smbd" is the only broadcast operation */
168         if (strequal(dest,"smbd")) {
169                 TDB_CONTEXT *tdb;
170                 BOOL ret;
171                 int n_sent = 0;
172
173                 tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0);
174                 if (!tdb) {
175                         fprintf(stderr,"Failed to open connections database in send_message.\n");
176                         return False;
177                 }
178
179                 ret = message_send_all(tdb,msg_type, buf, len, duplicates,
180                                        &n_sent);
181                 DEBUG(10,("smbcontrol/send_message: broadcast message to "
182                           "%d processes\n", n_sent));
183                 tdb_close(tdb);
184
185                 return ret;
186         } else if (strequal(dest,"nmbd")) {
187                 pid = pidfile_pid(dest);
188                 if (pid == 0) {
189                         fprintf(stderr,"Can't find pid for nmbd\n");
190                         return False;
191                 }
192         } else if (strequal(dest,"self")) {
193                 pid = getpid();
194         } else {
195                 pid = atoi(dest);
196                 if (pid == 0) {
197                         fprintf(stderr,"Not a valid pid\n");
198                         return False;
199                 }               
200         } 
201
202         DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid));
203         return message_send_pid(pid, msg_type, buf, len, duplicates);
204 }
205
206 /****************************************************************************
207 evaluate a message type string
208 ****************************************************************************/
209 static int parse_type(char *mtype)
210 {
211         int i;
212         for (i=0;msg_types[i].name;i++) {
213                 if (strequal(mtype, msg_types[i].name)) return msg_types[i].value;
214         }
215         return -1;
216 }
217
218
219 /****************************************************************************
220 do command
221 ****************************************************************************/
222 static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
223 {
224         int i, n, v;
225         int mtype;
226         BOOL retval=False;
227
228         mtype = parse_type(msg_name);
229         if (mtype == -1) {
230                 fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name);
231                 return(False);
232         }
233
234         switch (mtype) {
235         case MSG_DEBUG: {
236                 struct debuglevel_message dm;
237
238                 if (!params || !params[0]) {
239                         fprintf(stderr,"MSG_DEBUG needs a parameter\n");
240                         return(False);
241                 }
242
243                 ZERO_STRUCT(dm);
244                 if (!debug_parse_params(params, dm.debuglevel_class, dm.debuglevel_class_isset)) {
245                         fprintf(stderr, "MSG_DEBUG error. Expected <class name>:level\n");
246                         return(False);
247                 } else
248                         send_message(dest, MSG_DEBUG, &dm, sizeof(dm), False);
249                 break;
250         }
251
252         case MSG_PROFILE:
253                 if (!params || !params[0]) {
254                         fprintf(stderr,"MSG_PROFILE needs a parameter\n");
255                         return(False);
256                 }
257                 if (strequal(params[0], "off")) {
258                         v = 0;
259                 } else if (strequal(params[0], "count")) {
260                         v = 1;
261                 } else if (strequal(params[0], "on")) {
262                         v = 2;
263                 } else if (strequal(params[0], "flush")) {
264                         v = 3;
265                 } else {
266                     fprintf(stderr,
267                         "MSG_PROFILE parameter must be off, count, on, or flush\n");
268                     return(False);
269                 }
270                 send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
271                 break;
272
273         case MSG_FORCE_ELECTION:
274                 if (!strequal(dest, "nmbd")) {
275                         fprintf(stderr,"force-election can only be sent to nmbd\n");
276                         return(False);
277                 }
278                 send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
279                 break;
280
281         case MSG_REQ_PROFILELEVEL:
282                 if (!profilelevel_registered) {
283                     message_register(MSG_PROFILELEVEL, profilelevel_function);
284                     profilelevel_registered = True;
285                 }
286                 got_level = False;
287                 retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
288                 if (retval) {
289                         timeout_start = time(NULL);
290                         while (!got_level) {
291                                 message_dispatch();
292                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
293                                         fprintf(stderr,"profilelevel timeout\n");
294                                         break;
295                                 }
296                         }
297                 }
298                 break;
299
300         case MSG_REQ_DEBUGLEVEL:
301                 if (!debuglevel_registered) {
302                     message_register(MSG_DEBUGLEVEL, debuglevel_function);
303                     debuglevel_registered = True;
304                 }
305                 got_level = False;
306                 retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
307                 if (retval) {
308                         timeout_start = time(NULL);
309                         while (!got_level) {
310                                 message_dispatch();
311                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
312                                         fprintf(stderr,"debuglevel timeout\n");
313                                         break;
314                                 }
315                         }
316                 }
317                 break;
318
319         case MSG_PRINTER_NOTIFY:
320                 if (!strequal(dest, "smbd")) {
321                         fprintf(stderr,"printer-notify can only be sent to smbd\n");
322                         return(False);
323                 }
324                 if (!params || !params[0]) {
325                         fprintf(stderr, "printer-notify needs a printer name\n");
326                         return (False);
327                 }
328                 retval = send_message(dest, MSG_PRINTER_NOTIFY, params[0],
329                                       strlen(params[0]) + 1, False);
330                 break;
331
332         case MSG_SMB_FORCE_TDIS:
333                 if (!strequal(dest, "smbd")) {
334                         fprintf(stderr,"close-share can only be sent to smbd\n");
335                         return(False);
336                 }
337                 if (!params || !params[0]) {
338                         fprintf(stderr, "close-share needs a share name or '*'\n");
339                         return (False);
340                 }
341                 retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0],
342                                       strlen(params[0]) + 1, False);
343                 break;
344
345         case MSG_SMB_SAM_SYNC:
346                 if (!strequal(dest, "smbd")) {
347                         fprintf(stderr, "samsync can only be sent to smbd\n");
348                         return False;
349                 }
350
351                 if (params) {
352                         fprintf(stderr, "samsync does not take any parameters\n");
353                         return False;
354                 }
355
356                 retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False);
357
358                 break;
359
360         case MSG_SMB_SAM_REPL: {
361                 uint32 seqnum;
362
363                 if (!strequal(dest, "smbd")) {
364                         fprintf(stderr, "sam repl can only be sent to smbd\n");
365                         return False;
366                 }
367
368                 if (!params || !params[0]) {
369                         fprintf(stderr, "SAM_REPL needs a parameter\n");
370                         return False;
371                 }
372
373                 seqnum = atoi(params[0]);
374
375                 retval = send_message(dest, MSG_SMB_SAM_SYNC, 
376                                       (char *)&seqnum, sizeof(uint32), False); 
377
378                 break;
379         }
380
381         case MSG_PING:
382                 if (!pong_registered) {
383                     message_register(MSG_PONG, pong_function);
384                     pong_registered = True;
385                 }
386                 if (!params || !params[0]) {
387                         fprintf(stderr,"MSG_PING needs a parameter\n");
388                         return(False);
389                 }
390                 n = atoi(params[0]);
391                 pong_count = 0;
392                 for (i=0;i<n;i++) {
393                         if (iparams > 1)
394                                 retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True);
395                         else
396                                 retval = send_message(dest, MSG_PING, NULL, 0, True);
397                         if (retval == False)
398                                 return False;
399                 }
400                 wait_for_replies(MAX_WAIT, &n);
401                 if (n > 0) {
402                         fprintf(stderr,"PING timeout\n");
403                 }
404                 break;
405
406         case MSG_REQ_POOL_USAGE:
407                 if (!pool_usage_registered) {
408                         message_register(MSG_POOL_USAGE, pool_usage_cb);
409                         pool_usage_registered = True;
410                 }
411                 if (!send_message(dest, MSG_REQ_POOL_USAGE, NULL, 0, True))
412                         return False;
413                 wait_for_replies(MAX_WAIT, NULL);
414                 
415                 break;
416         }
417
418         return (True);
419 }
420
421  int main(int argc, char *argv[])
422 {
423         int opt;
424         char temp[255];
425         extern int optind;
426         BOOL interactive = False;
427
428         AllowDebugChange = False;
429         DEBUGLEVEL = 0;
430
431         setup_logging(argv[0],True);
432         
433         if (argc < 2) usage(True);
434
435         while ((opt = getopt(argc, argv,"is:")) != EOF) {
436                 switch (opt) {
437                 case 'i':
438                         interactive = True;
439                         break;
440                 case 's':
441                         pstrcpy(dyn_CONFIGFILE, optarg);
442                         break;
443                 default:
444                         printf("Unknown option %c (%d)\n", (char)opt, opt);
445                         usage(True);
446                 }
447         }
448
449         lp_load(dyn_CONFIGFILE,False,False,False);
450
451         if (!message_init()) exit(1);
452
453         argc -= optind;
454         argv = &argv[optind];
455
456         if (!interactive) {
457                 if (argc < 2) usage(True);
458                 /* Need to invert sense of return code -- samba
459                  * routines mostly return True==1 for success, but
460                  * shell needs 0. */ 
461                 return ! do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0);
462         }
463
464         while (True) {
465                 char *myargv[4];
466                 int myargc;
467
468                 printf("smbcontrol> ");
469                 if (!fgets(temp, sizeof(temp)-1, stdin)) break;
470                 myargc = 0;
471                 while ((myargc < 4) && 
472                        (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
473                         myargc++;
474                 }
475                 if (!myargc) break;
476                 if (strequal(myargv[0],"q")) break;
477                 if (myargc < 2)
478                         usage(False);
479                 else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0))
480                         usage(False);
481         }
482         return(0);
483 }
484