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