154bc5b1ae429d8dde252c169e2dea031b621b5b
[samba.git] / source / 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, (char *) argv[4]);
432
433                 goto send;
434         }
435
436         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
437         return False;
438
439 send:
440         print_notify_send_messages(0);
441         return True;
442 }
443
444 /* Close a share */
445
446 static BOOL do_closeshare(const pid_t pid, const int argc, const char **argv)
447 {
448         if (argc != 2) {
449                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
450                         "<sharename>\n");
451                 return False;
452         }
453
454         return send_message(
455                 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
456 }
457
458 /* Force a SAM synchronisation */
459
460 static BOOL do_samsync(const pid_t pid, const int argc, const char **argv)
461 {
462         if (argc != 1) {
463                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
464                 return False;
465         }
466
467         return send_message(
468                 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
469 }
470
471 /* Force a SAM replication */
472
473 static BOOL do_samrepl(const pid_t pid, const int argc, const char **argv)
474 {
475         if (argc != 1) {
476                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
477                 return False;
478         }
479
480         return send_message(
481                 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
482 }
483
484 /* Display talloc pool usage */
485
486 static BOOL do_poolusage(const pid_t pid, const int argc, const char **argv)
487 {
488         if (argc != 1) {
489                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
490                 return False;
491         }
492
493         /* Send a message and register our interest in a reply */
494
495         if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
496                 return False;
497
498         message_register(MSG_POOL_USAGE, print_string_cb);
499
500         wait_replies(pid == 0);
501
502         /* No replies were received within the timeout period */
503
504         if (num_replies == 0)
505                 printf("No replies received\n");
506
507         message_deregister(MSG_POOL_USAGE);
508
509         return num_replies;
510 }
511
512 /* Perform a dmalloc mark */
513
514 static BOOL do_dmalloc_mark(const pid_t pid, const int argc, const char **argv)
515 {
516         if (argc != 1) {
517                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
518                 return False;
519         }
520
521         return send_message(
522                 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
523 }
524
525 /* Perform a dmalloc changed */
526
527 static BOOL do_dmalloc_changed(const pid_t pid, const int argc, const char **argv)
528 {
529         if (argc != 1) {
530                 fprintf(stderr, "Usage: smbcontrol <dest> "
531                         "dmalloc-log-changed\n");
532                 return False;
533         }
534
535         return send_message(
536                 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
537 }
538
539 /* Shutdown a server process */
540
541 static BOOL do_shutdown(const pid_t pid, const int argc, const char **argv)
542 {
543         if (argc != 1) {
544                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
545                 return False;
546         }
547
548         return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
549 }
550
551 /* Notify a driver upgrade */
552
553 static BOOL do_drvupgrade(const pid_t pid, const int argc, const char **argv)
554 {
555         if (argc != 2) {
556                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
557                         "<driver-name>\n");
558                 return False;
559         }
560
561         return send_message(
562                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
563 }
564
565 static BOOL do_reload_config(const pid_t pid, const int argc, const char **argv)
566 {
567         if (argc != 1) {
568                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
569                 return False;
570         }
571
572         return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
573 }
574
575 /* A list of message type supported */
576
577 static const struct {
578         const char *name;       /* Option name */
579         BOOL (*fn)(const pid_t pid, const int argc, const char **argv);
580         const char *help;       /* Short help text */
581 } msg_types[] = {
582         { "debug", do_debug, "Set debuglevel"  },
583         { "force-election", do_election,
584           "Force a browse election" },
585         { "ping", do_ping, "Elicit a response" },
586         { "profile", do_profile, "" },
587         { "profilelevel", do_profilelevel, "" },
588         { "debuglevel", do_debuglevel, "Display current debuglevels" },
589         { "printnotify", do_printnotify, "Send a print notify message" },
590         { "close-share", do_closeshare, "Forcibly disconnect a share" },
591         { "samsync", do_samsync, "Initiate SAM synchronisation" },
592         { "samrepl", do_samrepl, "Initiate SAM replication" },
593         { "pool-usage", do_poolusage, "Display talloc memory usage" },
594         { "dmalloc-mark", do_dmalloc_mark, "" },
595         { "dmalloc-log-changed", do_dmalloc_changed, "" },
596         { "shutdown", do_shutdown, "Shut down daemon" },
597         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
598         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
599         { "noop", do_noop, "Do nothing" },
600         { NULL }
601 };
602
603 /* Display usage information */
604
605 static void usage(poptContext *pc)
606 {
607         int i;
608
609         poptPrintHelp(*pc, stderr, 0);
610
611         fprintf(stderr, "\n");
612         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a "
613                 "process ID\n");
614
615         fprintf(stderr, "\n");
616         fprintf(stderr, "<message-type> is one of:\n");
617
618         for (i = 0; msg_types[i].name; i++) 
619             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
620                     msg_types[i].help);
621
622         fprintf(stderr, "\n");
623
624         exit(1);
625 }
626
627 /* Return the pid number for a string destination */
628
629 static pid_t parse_dest(const char *dest)
630 {
631         pid_t pid;
632
633         /* Zero is a special return value for broadcast smbd */
634
635         if (strequal(dest, "smbd"))
636                 return 0;
637
638         /* Try self - useful for testing */
639
640         if (strequal(dest, "self"))
641                 return sys_getpid();
642
643         /* Check for numeric pid number */
644
645         if ((pid = atoi(dest)) != 0)
646                 return pid;
647
648         /* Look up other destinations in pidfile directory */
649
650         if ((pid = pidfile_pid(dest)) != 0)
651                 return pid;
652
653         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
654
655         return -1;
656 }       
657
658 /* Execute smbcontrol command */
659
660 static BOOL do_command(int argc, const char **argv)
661 {
662         const char *dest = argv[0], *command = argv[1];
663         pid_t pid;
664         int i;
665
666         /* Check destination */
667
668         if ((pid = parse_dest(dest)) == -1)
669                 return False;
670
671         /* Check command */
672
673         for (i = 0; msg_types[i].name; i++) {
674                 if (strequal(command, msg_types[i].name))
675                         return msg_types[i].fn(pid, argc - 1, argv + 1);
676         }
677
678         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
679
680         return False;
681 }
682
683 /* Main program */
684
685 int main(int argc, const char **argv)
686 {
687         poptContext pc;
688         int opt;
689
690         static struct poptOption wbinfo_options[] = {
691                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
692                   "Set timeout value in seconds", "TIMEOUT" },
693
694                 { "configfile", 's', POPT_ARG_STRING, NULL, 's', 
695                   "Use alternative configuration file", "CONFIGFILE" },
696
697                 POPT_TABLEEND
698         };
699
700         struct poptOption options[] = {
701                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, 
702                   "Options" },
703
704                 POPT_AUTOHELP
705                 POPT_COMMON_VERSION
706                 POPT_TABLEEND
707         };
708
709         setup_logging(argv[0],True);
710         
711         /* Parse command line arguments using popt */
712
713         pc = poptGetContext(
714                 "smbcontrol", argc, (const char **)argv, options, 0);
715
716         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
717                                "<parameters>");
718
719         if (argc == 1)
720                 usage(&pc);
721
722         while ((opt = poptGetNextOpt(pc)) != -1) {
723                 switch(opt) {
724                 case 't':       /* --timeout */
725                         argc -= 2;
726                         break;
727                 case 's':       /* --configfile */
728                         pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc));
729                         argc -= 2;
730                         break;
731                 default:
732                         fprintf(stderr, "Invalid option\n");
733                         poptPrintHelp(pc, stderr, 0);
734                         break;
735                 }
736         }
737
738         /* We should now have the remaining command line arguments in
739            argv.  The argc parameter should have been decremented to the
740            correct value in the above switch statement. */
741
742         argv = (const char **)poptGetArgs(pc);
743         argc--;                 /* Don't forget about argv[0] */
744
745         if (argc == 1)
746                 usage(&pc);
747
748         lp_load(dyn_CONFIGFILE,False,False,False);
749
750         /* Need to invert sense of return code -- samba
751          * routines mostly return True==1 for success, but
752          * shell needs 0. */ 
753         
754         return !do_command(argc, argv);
755 }