r6149: Fixes bugs #2498 and 2484.
[obnox/samba/samba-obnox.git] / source3 / utils / smbcontrol.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Send messages to other Samba daemons
5
6    Copyright (C) Tim Potter 2003
7    Copyright (C) Andrew Tridgell 1994-1998
8    Copyright (C) Martin Pool 2001-2002
9    Copyright (C) Simo Sorce 2002
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "includes.h"
27
28 /* Default timeout value when waiting for replies (in seconds) */
29
30 #define DEFAULT_TIMEOUT 10
31
32 static int timeout = DEFAULT_TIMEOUT;
33 static int num_replies;         /* Used by message callback fns */
34
35 /* Send a message to a destination pid.  Zero means broadcast smbd. */
36
37 static BOOL send_message(pid_t pid, int msg_type, const void *buf, int len,
38                          BOOL duplicates)
39 {
40         TDB_CONTEXT *tdb;
41         BOOL ret;
42         int n_sent = 0;
43
44         if (!message_init())
45                 return False;
46
47         if (pid != 0)
48                 return message_send_pid(pid, msg_type, buf, len, duplicates);
49
50         tdb = tdb_open_log(lock_path("connections.tdb"), 0, 
51                            TDB_DEFAULT, O_RDWR, 0);
52         if (!tdb) {
53                 fprintf(stderr,"Failed to open connections database"
54                         ": %s\n", strerror(errno));
55                 return False;
56         }
57         
58         ret = message_send_all(tdb,msg_type, buf, len, duplicates,
59                                &n_sent);
60         DEBUG(10,("smbcontrol/send_message: broadcast message to "
61                   "%d processes\n", n_sent));
62         
63         tdb_close(tdb);
64         
65         return ret;
66 }
67
68 /* Wait for one or more reply messages */
69
70 static void wait_replies(BOOL multiple_replies)
71 {
72         time_t start_time = time(NULL);
73
74         /* Wait around a bit.  This is pretty disgusting - we have to
75            busy-wait here as there is no nicer way to do it. */
76
77         do {
78                 message_dispatch();
79                 if (num_replies > 0 && !multiple_replies)
80                         break;
81                 sleep(1);
82         } while (timeout - (time(NULL) - start_time) > 0);
83 }
84
85 /* Message handler callback that displays the PID and a string on stdout */
86
87 static void print_pid_string_cb(int msg_type, pid_t pid, void *buf, size_t len)
88 {
89         printf("PID %u: %.*s", (unsigned int)pid, (int)len, (const char *)buf);
90         num_replies++;
91 }
92
93 /* Message handler callback that displays a string on stdout */
94
95 static void print_string_cb(int msg_type, pid_t pid, void *buf, size_t len)
96 {
97         printf("%.*s", (int)len, (const char *)buf);
98         num_replies++;
99 }
100
101 /* Send no message.  Useful for testing. */
102
103 static BOOL do_noop(const pid_t pid, const int argc, const char **argv)
104 {
105         if (argc != 1) {
106                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
107                 return False;
108         }
109
110         /* Move along, nothing to see here */
111
112         return True;
113 }
114
115 /* Send a debug string */
116
117 static BOOL do_debug(const pid_t pid, const int argc, const char **argv)
118 {
119         if (argc != 2) {
120                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
121                         "<debug-string>\n");
122                 return False;
123         }
124
125         return send_message(
126                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
127 }
128
129 /* Force a browser election */
130
131 static BOOL do_election(const pid_t pid, const int argc, const char **argv)
132 {
133         if (argc != 1) {
134                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
135                 return False;
136         }
137
138         return send_message(
139                 pid, MSG_FORCE_ELECTION, NULL, 0, False);
140 }
141
142 /* Ping a samba daemon process */
143
144 static void pong_cb(int msg_type, pid_t pid, void *buf, size_t len)
145 {
146         printf("PONG from pid %u\n", (unsigned int)pid);
147         num_replies++;
148 }
149
150 static BOOL do_ping(const pid_t pid, const int argc, const char **argv)
151 {
152         if (argc != 1) {
153                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
154                 return False;
155         }
156
157         /* Send a message and register our interest in a reply */
158
159         if (!send_message(pid, MSG_PING, NULL, 0, False))
160                 return False;
161
162         message_register(MSG_PONG, pong_cb);
163
164         wait_replies(pid == 0);
165
166         /* No replies were received within the timeout period */
167
168         if (num_replies == 0)
169                 printf("No replies received\n");
170
171         message_deregister(MSG_PONG);
172
173         return num_replies;
174 }
175
176 /* Set profiling options */
177
178 static BOOL do_profile(const pid_t pid, const int argc, const char **argv)
179 {
180         int v;
181
182         if (argc != 2) {
183                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
184                         "<off|count|on|flush>\n");
185                 return False;
186         }
187
188         if (strcmp(argv[1], "off") == 0) {
189                 v = 0;
190         } else if (strcmp(argv[1], "count") == 0) {
191                 v = 1;
192         } else if (strcmp(argv[1], "on") == 0) {
193                 v = 2;
194         } else if (strcmp(argv[1], "flush") == 0) {
195                 v = 3;
196         } else {
197                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
198                 return False;
199         }
200
201         return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
202 }
203
204 /* Return the profiling level */
205
206 static void profilelevel_cb(int msg_type, pid_t pid, void *buf, size_t len)
207 {
208         int level;
209         const char *s;
210
211         num_replies++;
212
213         if (len != sizeof(int)) {
214                 fprintf(stderr, "invalid message length %ld returned\n", 
215                         (unsigned long)len);
216                 return;
217         }
218
219         memcpy(&level, buf, sizeof(int));
220
221         switch (level) {
222         case 0:
223                 s = "not enabled";
224                 break;
225         case 1:
226                 s = "off";
227                 break;
228         case 3:
229                 s = "count only";
230                 break;
231         case 7:
232                 s = "count and time";
233                 break;
234         default:
235                 s = "BOGUS";
236                 break;
237         }
238         
239         printf("Profiling %s on pid %u\n",s,(unsigned int)pid);
240 }
241
242 static void profilelevel_rqst(int msg_type, pid_t pid, void *buf, size_t len)
243 {
244         int v = 0;
245
246         /* Send back a dummy reply */
247
248         send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
249 }
250
251 static BOOL do_profilelevel(const pid_t pid, const int argc, const char **argv)
252 {
253         if (argc != 1) {
254                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
255                 return False;
256         }
257
258         /* Send a message and register our interest in a reply */
259
260         if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
261                 return False;
262
263         message_register(MSG_PROFILELEVEL, profilelevel_cb);
264         message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst);
265
266         wait_replies(pid == 0);
267
268         /* No replies were received within the timeout period */
269
270         if (num_replies == 0)
271                 printf("No replies received\n");
272
273         message_deregister(MSG_PROFILE);
274
275         return num_replies;
276 }
277
278 /* Display debug level settings */
279
280 static BOOL do_debuglevel(const pid_t pid, const int argc, const char **argv)
281 {
282         if (argc != 1) {
283                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
284                 return False;
285         }
286
287         /* Send a message and register our interest in a reply */
288
289         if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
290                 return False;
291
292         message_register(MSG_DEBUGLEVEL, print_pid_string_cb);
293
294         wait_replies(pid == 0);
295
296         /* No replies were received within the timeout period */
297
298         if (num_replies == 0)
299                 printf("No replies received\n");
300
301         message_deregister(MSG_DEBUGLEVEL);
302
303         return num_replies;
304 }
305
306 /* Send a print notify message */
307
308 static BOOL do_printnotify(const pid_t pid, const int argc, const char **argv)
309 {
310         const char *cmd;
311
312         /* Check for subcommand */
313
314         if (argc == 1) {
315                 fprintf(stderr, "Must specify subcommand:\n");
316                 fprintf(stderr, "\tqueuepause <printername>\n");
317                 fprintf(stderr, "\tqueueresume <printername>\n");
318                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
319                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
320                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
321                 fprintf(stderr, "\tprinter <printername> <comment|port|"
322                         "driver> <value>\n");
323                 
324                 return False;
325         }
326
327         cmd = argv[1];
328
329         if (strcmp(cmd, "queuepause") == 0) {
330
331                 if (argc != 3) {
332                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
333                                 " queuepause <printername>\n");
334                         return False;
335                 }
336                 
337                 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
338
339                 goto send;
340
341         } else if (strcmp(cmd, "queueresume") == 0) {
342
343                 if (argc != 3) {
344                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
345                                 " queuereume <printername>\n");
346                         return False;
347                 }
348                 
349                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
350
351                 goto send;
352
353         } else if (strcmp(cmd, "jobpause") == 0) {
354                 int jobid;
355
356                 if (argc != 4) {
357                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
358                                 " jobpause <printername> <unix-jobid>\n");
359                         return False;
360                 }
361
362                 jobid = atoi(argv[3]);
363
364                 notify_job_status_byname(
365                         argv[2], jobid, JOB_STATUS_PAUSED, 
366                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
367
368                 goto send;
369
370         } else if (strcmp(cmd, "jobresume") == 0) {
371                 int jobid;
372
373                 if (argc != 4) {
374                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
375                                 " jobpause <printername> <unix-jobid>\n");
376                         return False;
377                 }
378
379                 jobid = atoi(argv[3]);
380
381                 notify_job_status_byname(
382                         argv[2], jobid, JOB_STATUS_QUEUED, 
383                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
384
385                 goto send;
386
387         } else if (strcmp(cmd, "jobdelete") == 0) {
388                 int jobid;
389
390                 if (argc != 4) {
391                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
392                                 " jobpause <printername> <unix-jobid>\n");
393                         return False;
394                 }
395
396                 jobid = atoi(argv[3]);
397
398                 notify_job_status_byname(
399                         argv[2], jobid, JOB_STATUS_DELETING,
400                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
401                 
402                 notify_job_status_byname(
403                         argv[2], jobid, JOB_STATUS_DELETING|
404                         JOB_STATUS_DELETED,
405                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
406
407                 goto send;
408
409         } else if (strcmp(cmd, "printer") == 0) {
410                 uint32 attribute;
411                 
412                 if (argc != 5) {
413                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
414                                 "printer <printername> <comment|port|driver> "
415                                 "<value>\n");
416                         return False;
417                 }
418
419                 if (strcmp(argv[3], "comment") == 0) {
420                         attribute = PRINTER_NOTIFY_COMMENT;
421                 } else if (strcmp(argv[3], "port") == 0) {
422                         attribute = PRINTER_NOTIFY_PORT_NAME;
423                 } else if (strcmp(argv[3], "driver") == 0) {
424                         attribute = PRINTER_NOTIFY_DRIVER_NAME;
425                 } else {
426                         fprintf(stderr, "Invalid printer command '%s'\n",
427                                 argv[3]);
428                         return False;
429                 }
430
431                 notify_printer_byname(argv[2], attribute,
432                                       CONST_DISCARD(char *, argv[4]));
433
434                 goto send;
435         }
436
437         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
438         return False;
439
440 send:
441         print_notify_send_messages(0);
442         return True;
443 }
444
445 /* Close a share */
446
447 static BOOL do_closeshare(const pid_t pid, const int argc, const char **argv)
448 {
449         if (argc != 2) {
450                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
451                         "<sharename>\n");
452                 return False;
453         }
454
455         return send_message(
456                 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
457 }
458
459 /* Force a SAM synchronisation */
460
461 static BOOL do_samsync(const pid_t pid, const int argc, const char **argv)
462 {
463         if (argc != 1) {
464                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
465                 return False;
466         }
467
468         return send_message(
469                 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
470 }
471
472 /* Force a SAM replication */
473
474 static BOOL do_samrepl(const pid_t pid, const int argc, const char **argv)
475 {
476         if (argc != 1) {
477                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
478                 return False;
479         }
480
481         return send_message(
482                 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
483 }
484
485 /* Display talloc pool usage */
486
487 static BOOL do_poolusage(const pid_t pid, const int argc, const char **argv)
488 {
489         if (argc != 1) {
490                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
491                 return False;
492         }
493
494         /* Send a message and register our interest in a reply */
495
496         if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
497                 return False;
498
499         message_register(MSG_POOL_USAGE, print_string_cb);
500
501         wait_replies(pid == 0);
502
503         /* No replies were received within the timeout period */
504
505         if (num_replies == 0)
506                 printf("No replies received\n");
507
508         message_deregister(MSG_POOL_USAGE);
509
510         return num_replies;
511 }
512
513 /* Perform a dmalloc mark */
514
515 static BOOL do_dmalloc_mark(const pid_t pid, const int argc, const char **argv)
516 {
517         if (argc != 1) {
518                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
519                 return False;
520         }
521
522         return send_message(
523                 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
524 }
525
526 /* Perform a dmalloc changed */
527
528 static BOOL do_dmalloc_changed(const pid_t pid, const int argc, const char **argv)
529 {
530         if (argc != 1) {
531                 fprintf(stderr, "Usage: smbcontrol <dest> "
532                         "dmalloc-log-changed\n");
533                 return False;
534         }
535
536         return send_message(
537                 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
538 }
539
540 /* Shutdown a server process */
541
542 static BOOL do_shutdown(const pid_t pid, const int argc, const char **argv)
543 {
544         if (argc != 1) {
545                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
546                 return False;
547         }
548
549         return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
550 }
551
552 /* Notify a driver upgrade */
553
554 static BOOL do_drvupgrade(const pid_t pid, const int argc, const char **argv)
555 {
556         if (argc != 2) {
557                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
558                         "<driver-name>\n");
559                 return False;
560         }
561
562         return send_message(
563                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
564 }
565
566 static BOOL do_reload_config(const pid_t pid, const int argc, const char **argv)
567 {
568         if (argc != 1) {
569                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
570                 return False;
571         }
572
573         return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
574 }
575
576 /* A list of message type supported */
577
578 static const struct {
579         const char *name;       /* Option name */
580         BOOL (*fn)(const pid_t pid, const int argc, const char **argv);
581         const char *help;       /* Short help text */
582 } msg_types[] = {
583         { "debug", do_debug, "Set debuglevel"  },
584         { "force-election", do_election,
585           "Force a browse election" },
586         { "ping", do_ping, "Elicit a response" },
587         { "profile", do_profile, "" },
588         { "profilelevel", do_profilelevel, "" },
589         { "debuglevel", do_debuglevel, "Display current debuglevels" },
590         { "printnotify", do_printnotify, "Send a print notify message" },
591         { "close-share", do_closeshare, "Forcibly disconnect a share" },
592         { "samsync", do_samsync, "Initiate SAM synchronisation" },
593         { "samrepl", do_samrepl, "Initiate SAM replication" },
594         { "pool-usage", do_poolusage, "Display talloc memory usage" },
595         { "dmalloc-mark", do_dmalloc_mark, "" },
596         { "dmalloc-log-changed", do_dmalloc_changed, "" },
597         { "shutdown", do_shutdown, "Shut down daemon" },
598         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
599         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
600         { "noop", do_noop, "Do nothing" },
601         { NULL }
602 };
603
604 /* Display usage information */
605
606 static void usage(poptContext *pc)
607 {
608         int i;
609
610         poptPrintHelp(*pc, stderr, 0);
611
612         fprintf(stderr, "\n");
613         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a "
614                 "process ID\n");
615
616         fprintf(stderr, "\n");
617         fprintf(stderr, "<message-type> is one of:\n");
618
619         for (i = 0; msg_types[i].name; i++) 
620             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
621                     msg_types[i].help);
622
623         fprintf(stderr, "\n");
624
625         exit(1);
626 }
627
628 /* Return the pid number for a string destination */
629
630 static pid_t parse_dest(const char *dest)
631 {
632         pid_t pid;
633
634         /* Zero is a special return value for broadcast smbd */
635
636         if (strequal(dest, "smbd"))
637                 return 0;
638
639         /* Try self - useful for testing */
640
641         if (strequal(dest, "self"))
642                 return sys_getpid();
643
644         /* Check for numeric pid number */
645
646         if ((pid = atoi(dest)) != 0)
647                 return pid;
648
649         /* Look up other destinations in pidfile directory */
650
651         if ((pid = pidfile_pid(dest)) != 0)
652                 return pid;
653
654         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
655
656         return -1;
657 }       
658
659 /* Execute smbcontrol command */
660
661 static BOOL do_command(int argc, const char **argv)
662 {
663         const char *dest = argv[0], *command = argv[1];
664         pid_t pid;
665         int i;
666
667         /* Check destination */
668
669         if ((pid = parse_dest(dest)) == -1)
670                 return False;
671
672         /* Check command */
673
674         for (i = 0; msg_types[i].name; i++) {
675                 if (strequal(command, msg_types[i].name))
676                         return msg_types[i].fn(pid, argc - 1, argv + 1);
677         }
678
679         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
680
681         return False;
682 }
683
684 /* Main program */
685
686 int main(int argc, const char **argv)
687 {
688         poptContext pc;
689         int opt;
690
691         static struct poptOption wbinfo_options[] = {
692                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
693                   "Set timeout value in seconds", "TIMEOUT" },
694
695                 { "configfile", 's', POPT_ARG_STRING, NULL, 's', 
696                   "Use alternative configuration file", "CONFIGFILE" },
697
698                 POPT_TABLEEND
699         };
700
701         struct poptOption options[] = {
702                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, 
703                   "Options" },
704
705                 POPT_AUTOHELP
706                 POPT_COMMON_VERSION
707                 POPT_TABLEEND
708         };
709
710         setup_logging(argv[0],True);
711         
712         /* Parse command line arguments using popt */
713
714         pc = poptGetContext(
715                 "smbcontrol", argc, (const char **)argv, options, 0);
716
717         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
718                                "<parameters>");
719
720         if (argc == 1)
721                 usage(&pc);
722
723         while ((opt = poptGetNextOpt(pc)) != -1) {
724                 switch(opt) {
725                 case 't':       /* --timeout */
726                         argc -= 2;
727                         break;
728                 case 's':       /* --configfile */
729                         pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc));
730                         argc -= 2;
731                         break;
732                 default:
733                         fprintf(stderr, "Invalid option\n");
734                         poptPrintHelp(pc, stderr, 0);
735                         break;
736                 }
737         }
738
739         /* We should now have the remaining command line arguments in
740            argv.  The argc parameter should have been decremented to the
741            correct value in the above switch statement. */
742
743         argv = (const char **)poptGetArgs(pc);
744         argc--;                 /* Don't forget about argv[0] */
745
746         if (argc == 1)
747                 usage(&pc);
748
749         lp_load(dyn_CONFIGFILE,False,False,False);
750
751         /* Need to invert sense of return code -- samba
752          * routines mostly return True==1 for success, but
753          * shell needs 0. */ 
754         
755         return !do_command(argc, argv);
756 }