The REQ_DEBUGLEVEL message returns a string not a list of integers.
[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    Copyright (C) Simo Sorce 2002
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 const struct {
28         const 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         {"printnotify", MSG_PRINTER_NOTIFY2 },
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         {"dmalloc-mark", MSG_REQ_DMALLOC_MARK },
43         {"dmalloc-log-changed", MSG_REQ_DMALLOC_LOG_CHANGED },
44         {"shutdown", MSG_SHUTDOWN },
45         {"drvupgrade", MSG_PRINTER_DRVUPGRADE},
46         {"tallocdump", MSG_REQ_TALLOC_USAGE},
47         {NULL, -1}
48 };
49
50 time_t timeout_start;
51
52 #define MAX_WAIT        10
53
54 /* we need these because we link to printing*.o */
55
56 void become_root(void) {}
57 void unbecome_root(void) {}
58
59
60 static void usage(BOOL doexit)
61 {
62         int i;
63         if (doexit) {
64                 printf("Usage: smbcontrol -i -s configfile\n");
65                 printf("       smbcontrol <destination> <message-type> <parameters>\n\n");
66         } else {
67                 printf("<destination> <message-type> <parameters>\n\n");
68         }
69         printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n");
70         printf("\t<message-type> is one of:\n");
71         for (i=0; msg_types[i].name; i++) 
72             printf("\t\t%s\n", msg_types[i].name);
73         printf("\n");
74         if (doexit) exit(1);
75 }
76
77 static int pong_count;
78 static BOOL got_level;
79 static BOOL got_pool;
80 static BOOL pong_registered = False;
81 static BOOL debuglevel_registered = False;
82 static BOOL poolusage_registered = False;
83 static BOOL profilelevel_registered = False;
84
85
86 /**
87  * Wait for replies for up to @p *max_secs seconds, or until @p
88  * max_replies are received.  max_replies may be NULL in which case it
89  * is ignored.
90  *
91  * @note This is a pretty lame timeout; all it means is that after
92  * max_secs we won't look for any more messages.
93  **/
94 static void wait_for_replies(int max_secs, int *max_replies)
95 {
96         time_t timeout_end = time(NULL) + max_secs;
97
98         while ((!max_replies || (*max_replies)-- > 0)
99                &&  (time(NULL) < timeout_end)) {
100                 message_dispatch();
101         }
102 }
103
104
105 /****************************************************************************
106 a useful function for testing the message system
107 ****************************************************************************/
108 void pong_function(int msg_type, pid_t src, void *buf, size_t len)
109 {
110         pong_count++;
111         printf("PONG from PID %u\n",(unsigned int)src);
112 }
113
114 /****************************************************************************
115  Prints out the current talloc list.
116 ****************************************************************************/
117 void tallocdump_function(int msg_type, pid_t src, void *buf, size_t len)
118 {
119         char *info = (char *)buf;
120
121         printf("Current talloc contexts for process %u\n", (unsigned int)src );
122         if (len == 0)
123                 printf("None returned\n");
124         else
125                 printf(info);
126         printf("\n");
127         got_pool = True;
128 }
129
130 /****************************************************************************
131 Prints out the current Debug level returned by MSG_DEBUGLEVEL
132 ****************************************************************************/
133 void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len)
134 {
135         const char *levels = (char *)buf;
136
137         printf("Current debug levels of PID %u are:\n",(unsigned int)src);
138         printf("%s\n", levels);
139         
140         got_level = True;
141 }
142
143 /****************************************************************************
144 Prints out the current Profile level returned by MSG_PROFILELEVEL
145 ****************************************************************************/
146 void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
147 {
148         int level;
149         const char *s=NULL;
150         memcpy(&level, buf, sizeof(int));
151
152         if (level) {
153             switch (level) {
154             case 1:
155                 s = "off";
156                 break;
157             case 3:
158                 s = "count only";
159                 break;
160             case 7:
161                 s = "count and time";
162                 break;
163             default:
164                     s = "BOGUS";
165                     break;
166             }
167             printf("Profiling %s on PID %u\n",s,(unsigned int)src);
168         } else {
169             printf("Profiling not available on PID %u\n",(unsigned int)src);
170         }
171         got_level = True;
172 }
173
174 /**
175  * Handle reply from POOL_USAGE.
176  **/
177 static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len)
178 {
179         printf("Got POOL_USAGE reply from pid%u:\n%.*s",
180                (unsigned int) src_pid, (int) len, (const char *) buf);
181 }
182
183
184 /**
185  * Send a message to a named destination
186  *
187  * @return False if an error occurred.
188  **/
189 static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates)
190 {
191         pid_t pid;
192         /* "smbd" is the only broadcast operation */
193         if (strequal(dest,"smbd")) {
194                 TDB_CONTEXT *tdb;
195                 BOOL ret;
196                 int n_sent = 0;
197
198                 tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0);
199                 if (!tdb) {
200                         fprintf(stderr,"Failed to open connections database in send_message.\n");
201                         return False;
202                 }
203
204                 ret = message_send_all(tdb,msg_type, buf, len, duplicates,
205                                        &n_sent);
206                 DEBUG(10,("smbcontrol/send_message: broadcast message to "
207                           "%d processes\n", n_sent));
208                 tdb_close(tdb);
209
210                 return ret;
211         } else if (strequal(dest,"nmbd")) {
212                 pid = pidfile_pid(dest);
213                 if (pid == 0) {
214                         fprintf(stderr,"Can't find pid for nmbd\n");
215                         return False;
216                 }
217         } else if (strequal(dest,"self")) {
218                 pid = sys_getpid();
219         } else {
220                 pid = atoi(dest);
221                 if (pid == 0) {
222                         fprintf(stderr,"Not a valid pid\n");
223                         return False;
224                 }               
225         } 
226
227         DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid));
228         return message_send_pid(pid, msg_type, buf, len, duplicates);
229 }
230
231 /****************************************************************************
232 evaluate a message type string
233 ****************************************************************************/
234 static int parse_type(char *mtype)
235 {
236         int i;
237         for (i=0;msg_types[i].name;i++) {
238                 if (strequal(mtype, msg_types[i].name)) return msg_types[i].value;
239         }
240         return -1;
241 }
242
243
244 static void register_all(void)
245 {
246         message_register(MSG_POOL_USAGE, pool_usage_cb);
247 }
248
249 /* This guy is here so we can link printing/notify.c to the smbcontrol
250    binary without having to pull in tons of other crap. */
251
252 TDB_CONTEXT *conn_tdb_ctx(void)
253 {
254         static TDB_CONTEXT *tdb;
255
256         if (tdb)
257                 return tdb;
258
259         tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
260
261         if (!tdb)
262                 DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
263
264         return tdb;
265 }
266
267 /****************************************************************************
268 do command
269 ****************************************************************************/
270 static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
271 {
272         int i, n, v;
273         int mtype;
274         BOOL retval=False;
275         BOOL check_notify_msgs = False;
276
277         mtype = parse_type(msg_name);
278         if (mtype == -1) {
279                 fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name);
280                 return(False);
281         }
282
283         switch (mtype) {
284         case MSG_DEBUG: {
285                 char *buf, *b;
286                 char **p;
287                 int dim = 0;
288
289                 if (!params || !params[0]) {
290                         fprintf(stderr,"MSG_DEBUG needs a parameter\n");
291                         return(False);
292                 }
293
294                 /* first pass retrieve total lenght */
295                 for (p = params; p && *p ; p++)
296                         dim += (strnlen(*p, 1024) +1); /* lenght + space */
297                 b = buf = malloc(dim);
298                 if (!buf) {
299                         fprintf(stderr, "Out of memory!");
300                         return(False);
301                 }
302                 /* now build a single string with all parameters */
303                 for(p = params; p && *p; p++) {
304                         int l = strnlen(*p, 1024);
305                         strncpy(b, *p, l);
306                         b[l] = ' ';
307                         b = b + l + 1;
308                 }
309                 b[-1] = '\0';
310
311                 send_message(dest, MSG_DEBUG, buf, dim, False);
312
313                 free(buf);
314   
315                 break;
316         }
317
318         case MSG_PROFILE:
319                 if (!params || !params[0]) {
320                         fprintf(stderr,"MSG_PROFILE needs a parameter\n");
321                         return(False);
322                 }
323                 if (strequal(params[0], "off")) {
324                         v = 0;
325                 } else if (strequal(params[0], "count")) {
326                         v = 1;
327                 } else if (strequal(params[0], "on")) {
328                         v = 2;
329                 } else if (strequal(params[0], "flush")) {
330                         v = 3;
331                 } else {
332                     fprintf(stderr,
333                         "MSG_PROFILE parameter must be off, count, on, or flush\n");
334                     return(False);
335                 }
336                 send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
337                 break;
338
339         case MSG_FORCE_ELECTION:
340                 if (!strequal(dest, "nmbd")) {
341                         fprintf(stderr,"force-election can only be sent to nmbd\n");
342                         return(False);
343                 }
344                 send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
345                 break;
346
347         case MSG_REQ_PROFILELEVEL:
348                 if (!profilelevel_registered) {
349                     message_register(MSG_PROFILELEVEL, profilelevel_function);
350                     profilelevel_registered = True;
351                 }
352                 got_level = False;
353                 retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
354                 if (retval) {
355                         timeout_start = time(NULL);
356                         while (!got_level) {
357                                 message_dispatch();
358                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
359                                         fprintf(stderr,"profilelevel timeout\n");
360                                         break;
361                                 }
362                         }
363                 }
364                 break;
365
366         case MSG_REQ_TALLOC_USAGE:
367                 if (!poolusage_registered) {
368                         message_register(MSG_TALLOC_USAGE, tallocdump_function);
369                         poolusage_registered = True;
370                 }
371                 got_pool = False;
372                 retval = send_message(dest, MSG_REQ_TALLOC_USAGE, NULL, 0, True);
373                 if (retval) {
374                         timeout_start = time(NULL);
375                         while (!got_pool) {
376                                 message_dispatch();
377                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
378                                         fprintf(stderr,"tallocdump timeout\n");
379                                         break;
380                                 }
381                         }
382                 }
383                 break;
384
385         case MSG_REQ_DEBUGLEVEL:
386                 if (!debuglevel_registered) {
387                     message_register(MSG_DEBUGLEVEL, debuglevel_function);
388                     debuglevel_registered = True;
389                 }
390                 got_level = False;
391                 retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
392                 if (retval) {
393                         timeout_start = time(NULL);
394                         while (!got_level) {
395                                 message_dispatch();
396                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
397                                         fprintf(stderr,"debuglevel timeout\n");
398                                         break;
399                                 }
400                         }
401                 }
402                 break;
403
404                 /* Send a notification message to a printer */
405
406         case MSG_PRINTER_NOTIFY2: {
407                 char *cmd;
408
409                 /* Read subcommand */
410
411                 if (!params || !params[0]) {
412                         fprintf(stderr, "Must specify subcommand:\n");
413                         fprintf(stderr, "\tqueuepause <printername>\n");
414                         fprintf(stderr, "\tqueueresume <printername>\n");
415                         fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
416                         fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
417                         fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
418                         fprintf(stderr, "\tprinter <printername> <comment|port|driver> <new value>\n");
419                         return False;
420                 }
421
422                 cmd = params[0];
423
424                 check_notify_msgs = True;
425
426                 /* Pause a print queue */
427
428                 if (strequal(cmd, "queuepause")) {
429
430                         if (!params[1]) {
431                                 fprintf(stderr, "queuepause command requires a printer name\n");
432                                 return False;
433                         }
434
435                         notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED);
436                         break;
437                 }
438
439                 /* Resume a print queue */
440
441                 if (strequal(cmd, "queueresume")) {
442
443                         if (!params[1]) {
444                                 fprintf(stderr, "queueresume command requires a printer name\n");
445                                 return False;
446                         }
447
448                         notify_printer_status_byname(params[1], PRINTER_STATUS_OK);
449                         break;
450                 }
451
452                 /* Pause a print job */
453
454                 if (strequal(cmd, "jobpause")) {
455                         int jobid;
456
457                         if (!params[1] || !params[2]) {
458                                 fprintf(stderr, "jobpause command requires a printer name and a jobid\n");
459                                 return False;
460                         }
461
462                         jobid = atoi(params[2]);
463
464                         notify_job_status_byname(
465                                 params[1], jobid, JOB_STATUS_PAUSED, 
466                                 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
467                         break;
468                 }
469
470                 /* Resume a print job */
471
472                 if (strequal(cmd, "jobresume")) {
473                         int jobid;
474
475                         if (!params[1] || !params[2]) {
476                                 fprintf(stderr, "jobresume command requires a printer name and a jobid\n");
477                                 return False;
478                         }
479
480                         jobid = atoi(params[2]);
481
482                         notify_job_status_byname(
483                                 params[1], jobid, JOB_STATUS_QUEUED,
484                                 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
485                         break;
486                 }
487
488                 /* Delete a print job */
489
490                 if (strequal(cmd, "jobdelete")) {
491                         int jobid;
492
493                         if (!params[1] || !params[2]) {
494                                 fprintf(stderr, "jobdelete command requires a printer name and a jobid\n");
495                                 return False;
496                         }
497
498                         jobid = atoi(params[2]);
499
500                         notify_job_status_byname(
501                                 params[1], jobid, JOB_STATUS_DELETING,
502                                 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
503
504                         notify_job_status_byname(
505                                 params[1], jobid, JOB_STATUS_DELETING|
506                                 JOB_STATUS_DELETED,
507                                 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
508                 }
509                 
510                 /* printer change notify */
511                 
512                 if (strequal(cmd, "printer")) {
513                         int attribute = -1;
514                         
515                         if (!params[1] || !params[2] || !params[3]) {
516                                 fprintf(stderr, "printer command requires an and attribute name and value!\n");
517                                 fprintf(stderr, "supported attributes:\n");
518                                 fprintf(stderr, "\tcomment:\n");
519                                 fprintf(stderr, "\tport:\n");
520                                 fprintf(stderr, "\tdriver:\n");
521                                 return False;
522                         }
523                         if ( strequal(params[2], "comment") )
524                                 attribute = PRINTER_NOTIFY_COMMENT;
525                         else if ( strequal(params[2], "port") )
526                                 attribute = PRINTER_NOTIFY_PORT_NAME;
527                         else if ( strequal(params[2], "driver") )
528                                 attribute = PRINTER_NOTIFY_DRIVER_NAME;
529                         
530                         if ( attribute == -1 ) {
531                                 fprintf(stderr, "bad attribute!\n");
532                                 return False;
533                         }
534                         
535                         notify_printer_byname( params[1], attribute, params[3]);
536                         
537                         break;
538                 }
539                 
540                 break;
541           }
542
543
544         case MSG_SMB_FORCE_TDIS:
545                 if (!strequal(dest, "smbd")) {
546                         fprintf(stderr,"close-share can only be sent to smbd\n");
547                         return(False);
548                 }
549                 if (!params || !params[0]) {
550                         fprintf(stderr, "close-share needs a share name or '*'\n");
551                         return (False);
552                 }
553                 retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0],
554                                       strlen(params[0]) + 1, False);
555                 break;
556
557         case MSG_SMB_SAM_SYNC:
558                 if (!strequal(dest, "smbd")) {
559                         fprintf(stderr, "samsync can only be sent to smbd\n");
560                         return False;
561                 }
562
563                 if (params) {
564                         fprintf(stderr, "samsync does not take any parameters\n");
565                         return False;
566                 }
567
568                 retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False);
569
570                 break;
571
572         case MSG_SMB_SAM_REPL: {
573                 uint32 seqnum;
574
575                 if (!strequal(dest, "smbd")) {
576                         fprintf(stderr, "sam repl can only be sent to smbd\n");
577                         return False;
578                 }
579
580                 if (!params || !params[0]) {
581                         fprintf(stderr, "SAM_REPL needs a parameter\n");
582                         return False;
583                 }
584
585                 seqnum = atoi(params[0]);
586
587                 retval = send_message(dest, MSG_SMB_SAM_SYNC, 
588                                       (char *)&seqnum, sizeof(uint32), False); 
589
590                 break;
591         }
592
593         case MSG_PING:
594                 if (!pong_registered) {
595                     message_register(MSG_PONG, pong_function);
596                     pong_registered = True;
597                 }
598                 if (!params || !params[0]) {
599                         fprintf(stderr,"MSG_PING needs a parameter\n");
600                         return(False);
601                 }
602                 n = atoi(params[0]);
603                 pong_count = 0;
604                 for (i=0;i<n;i++) {
605                         if (iparams > 1)
606                                 retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True);
607                         else
608                                 retval = send_message(dest, MSG_PING, NULL, 0, True);
609                         if (retval == False)
610                                 return False;
611                 }
612                 wait_for_replies(MAX_WAIT, &n);
613                 if (n > 0) {
614                         fprintf(stderr,"PING timeout\n");
615                 }
616                 break;
617
618         case MSG_REQ_POOL_USAGE:
619                 if (!send_message(dest, MSG_REQ_POOL_USAGE, NULL, 0, True))
620                         return False;
621                 wait_for_replies(MAX_WAIT, NULL);
622                 
623                 break;
624
625         case MSG_REQ_DMALLOC_LOG_CHANGED:
626         case MSG_REQ_DMALLOC_MARK:
627                 if (!send_message(dest, mtype, NULL, 0, False))
628                         return False;
629                 break;
630
631         case MSG_SHUTDOWN:
632                 if (!send_message(dest, MSG_SHUTDOWN, NULL, 0, False))
633                         return False;
634                 break;
635         case MSG_PRINTER_DRVUPGRADE:
636                 if (!send_message(dest, MSG_PRINTER_DRVUPGRADE, params[0], 0, False))
637                         return False;
638                 break;
639         }
640
641         /* check if we have any pending print notify messages */
642
643         if ( check_notify_msgs )
644                 print_notify_send_messages();
645                 
646         return (True);
647 }
648
649  int main(int argc, char *argv[])
650 {
651         int opt;
652         char temp[255];
653         extern int optind;
654         BOOL interactive = False;
655
656         AllowDebugChange = False;
657         DEBUGLEVEL = 0;
658
659         setup_logging(argv[0],True);
660         
661         if (argc < 2) usage(True);
662
663         while ((opt = getopt(argc, argv,"is:")) != EOF) {
664                 switch (opt) {
665                 case 'i':
666                         interactive = True;
667                         break;
668                 case 's':
669                         pstrcpy(dyn_CONFIGFILE, optarg);
670                         break;
671                 default:
672                         printf("Unknown option %c (%d)\n", (char)opt, opt);
673                         usage(True);
674                 }
675         }
676
677         lp_load(dyn_CONFIGFILE,False,False,False);
678
679         if (!message_init()) exit(1);
680
681         argc -= optind;
682         argv = &argv[optind];
683
684         register_all();
685
686         if (!interactive) {
687                 if (argc < 2) usage(True);
688                 /* Need to invert sense of return code -- samba
689                  * routines mostly return True==1 for success, but
690                  * shell needs 0. */ 
691                 return ! do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0);
692         }
693
694         while (True) {
695                 char *myargv[4];
696                 int myargc;
697
698                 printf("smbcontrol> ");
699                 if (!fgets(temp, sizeof(temp)-1, stdin)) break;
700                 myargc = 0;
701                 while ((myargc < 4) && 
702                        (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
703                         myargc++;
704                 }
705                 if (!myargc) break;
706                 if (strequal(myargv[0],"q")) break;
707                 if (myargc < 2)
708                         usage(False);
709                 else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0))
710                         usage(False);
711         }
712         return(0);
713 }
714