Some const correctness. Stop tdb being used as a remote backend. If an
[samba.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 a string on stdout */
86
87 static void print_string_cb(int msg_type, pid_t pid, void *buf, size_t len)
88 {
89         printf("%.*s", (int)len, (const char *)buf);
90         num_replies++;
91 }
92
93 /* Send no message.  Useful for testing. */
94
95 static BOOL do_noop(const pid_t pid, const int argc, const char **argv)
96 {
97         if (argc != 1) {
98                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
99                 return False;
100         }
101
102         /* Move along, nothing to see here */
103
104         return True;
105 }
106
107 /* Send a debug string */
108
109 static BOOL do_debug(const pid_t pid, const int argc, const char **argv)
110 {
111         if (argc != 2) {
112                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
113                         "<debug-string>\n");
114                 return False;
115         }
116
117         return send_message(
118                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
119 }
120
121 /* Force a browser election */
122
123 static BOOL do_election(const pid_t pid, const int argc, const char **argv)
124 {
125         if (argc != 1) {
126                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
127                 return False;
128         }
129
130         return send_message(
131                 pid, MSG_FORCE_ELECTION, NULL, 0, False);
132 }
133
134 /* Ping a samba daemon process */
135
136 static void pong_cb(int msg_type, pid_t pid, void *buf, size_t len)
137 {
138         printf("PONG from pid %u\n", (unsigned int)pid);
139         num_replies++;
140 }
141
142 static BOOL do_ping(const pid_t pid, const int argc, const char **argv)
143 {
144         if (argc != 1) {
145                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
146                 return False;
147         }
148
149         /* Send a message and register our interest in a reply */
150
151         if (!send_message(pid, MSG_PING, NULL, 0, False))
152                 return False;
153
154         message_register(MSG_PONG, pong_cb);
155
156         wait_replies(pid == 0);
157
158         /* No replies were received within the timeout period */
159
160         if (num_replies == 0)
161                 printf("No replies received\n");
162
163         message_deregister(MSG_PONG);
164
165         return num_replies;
166 }
167
168 /* Set profiling options */
169
170 static BOOL do_profile(const pid_t pid, const int argc, const char **argv)
171 {
172         int v;
173
174         if (argc != 2) {
175                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
176                         "<off|count|on|flush>\n");
177                 return False;
178         }
179
180         if (strcmp(argv[1], "off") == 0) {
181                 v = 0;
182         } else if (strcmp(argv[1], "count") == 0) {
183                 v = 1;
184         } else if (strcmp(argv[1], "on") == 0) {
185                 v = 2;
186         } else if (strcmp(argv[1], "flush") == 0) {
187                 v = 3;
188         } else {
189                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
190                 return False;
191         }
192
193         return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
194 }
195
196 /* Return the profiling level */
197
198 static void profilelevel_cb(int msg_type, pid_t pid, void *buf, size_t len)
199 {
200         int level;
201         const char *s;
202
203         num_replies++;
204
205         if (len != sizeof(int)) {
206                 fprintf(stderr, "invalid message length %d returned\n", len);
207                 return;
208         }
209
210         memcpy(&level, buf, sizeof(int));
211
212         switch (level) {
213         case 0:
214                 s = "not enabled";
215                 break;
216         case 1:
217                 s = "off";
218                 break;
219         case 3:
220                 s = "count only";
221                 break;
222         case 7:
223                 s = "count and time";
224                 break;
225         default:
226                 s = "BOGUS";
227                 break;
228         }
229         
230         printf("Profiling %s on pid %u\n",s,(unsigned int)pid);
231 }
232
233 static void profilelevel_rqst(int msg_type, pid_t pid, void *buf, size_t len)
234 {
235         int v = 0;
236
237         /* Send back a dummy reply */
238
239         send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
240 }
241
242 static BOOL do_profilelevel(const pid_t pid, const int argc, const char **argv)
243 {
244         if (argc != 1) {
245                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
246                 return False;
247         }
248
249         /* Send a message and register our interest in a reply */
250
251         if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
252                 return False;
253
254         message_register(MSG_PROFILELEVEL, profilelevel_cb);
255         message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst);
256
257         wait_replies(pid == 0);
258
259         /* No replies were received within the timeout period */
260
261         if (num_replies == 0)
262                 printf("No replies received\n");
263
264         message_deregister(MSG_PROFILE);
265
266         return num_replies;
267 }
268
269 /* Display debug level settings */
270
271 static BOOL do_debuglevel(const pid_t pid, const int argc, const char **argv)
272 {
273         if (argc != 1) {
274                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
275                 return False;
276         }
277
278         /* Send a message and register our interest in a reply */
279
280         if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
281                 return False;
282
283         message_register(MSG_DEBUGLEVEL, print_string_cb);
284
285         wait_replies(pid == 0);
286
287         /* No replies were received within the timeout period */
288
289         if (num_replies == 0)
290                 printf("No replies received\n");
291
292         message_deregister(MSG_DEBUGLEVEL);
293
294         return num_replies;
295 }
296
297 /* Send a print notify message */
298
299 static BOOL do_printnotify(const pid_t pid, const int argc, const char **argv)
300 {
301         const char *cmd;
302
303         /* Check for subcommand */
304
305         if (argc == 1) {
306                 fprintf(stderr, "Must specify subcommand:\n");
307                 fprintf(stderr, "\tqueuepause <printername>\n");
308                 fprintf(stderr, "\tqueueresume <printername>\n");
309                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
310                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
311                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
312                 fprintf(stderr, "\tprinter <printername> <comment|port|"
313                         "driver> <value>\n");
314                 
315                 return False;
316         }
317
318         cmd = argv[1];
319
320         if (strcmp(cmd, "queuepause") == 0) {
321
322                 if (argc != 3) {
323                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
324                                 " queuepause <printername>\n");
325                         return False;
326                 }
327                 
328                 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
329
330                 goto send;
331
332         } else if (strcmp(cmd, "queueresume") == 0) {
333
334                 if (argc != 3) {
335                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
336                                 " queuereume <printername>\n");
337                         return False;
338                 }
339                 
340                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
341
342                 goto send;
343
344         } else if (strcmp(cmd, "jobpause") == 0) {
345                 int jobid;
346
347                 if (argc != 4) {
348                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
349                                 " jobpause <printername> <unix-jobid>\n");
350                         return False;
351                 }
352
353                 jobid = atoi(argv[3]);
354
355                 notify_job_status_byname(
356                         argv[2], jobid, JOB_STATUS_PAUSED, 
357                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
358
359                 goto send;
360
361         } else if (strcmp(cmd, "jobresume") == 0) {
362                 int jobid;
363
364                 if (argc != 4) {
365                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
366                                 " jobpause <printername> <unix-jobid>\n");
367                         return False;
368                 }
369
370                 jobid = atoi(argv[3]);
371
372                 notify_job_status_byname(
373                         argv[2], jobid, JOB_STATUS_QUEUED, 
374                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
375
376                 goto send;
377
378         } else if (strcmp(cmd, "jobdelete") == 0) {
379                 int jobid;
380
381                 if (argc != 4) {
382                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
383                                 " jobpause <printername> <unix-jobid>\n");
384                         return False;
385                 }
386
387                 jobid = atoi(argv[3]);
388
389                 notify_job_status_byname(
390                         argv[2], jobid, JOB_STATUS_DELETING,
391                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
392                 
393                 notify_job_status_byname(
394                         argv[2], jobid, JOB_STATUS_DELETING|
395                         JOB_STATUS_DELETED,
396                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
397
398                 goto send;
399
400         } else if (strcmp(cmd, "printer") == 0) {
401                 uint32 attribute;
402                 
403                 if (argc != 5) {
404                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
405                                 "printer <printername> <comment|port|driver> "
406                                 "<value>\n");
407                         return False;
408                 }
409
410                 if (strcmp(argv[3], "comment") == 0) {
411                         attribute = PRINTER_NOTIFY_COMMENT;
412                 } else if (strcmp(argv[3], "port") == 0) {
413                         attribute = PRINTER_NOTIFY_PORT_NAME;
414                 } else if (strcmp(argv[3], "driver") == 0) {
415                         attribute = PRINTER_NOTIFY_DRIVER_NAME;
416                 } else {
417                         fprintf(stderr, "Invalid printer command '%s'\n",
418                                 argv[3]);
419                         return False;
420                 }
421
422                 notify_printer_byname(argv[2], attribute, argv[4]);
423
424                 goto send;
425         }
426
427         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
428         return False;
429
430 send:
431         print_notify_send_messages(0);
432         return True;
433 }
434
435 /* Close a share */
436
437 static BOOL do_closeshare(const pid_t pid, const int argc, const char **argv)
438 {
439         if (argc != 2) {
440                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
441                         "<sharename>\n");
442                 return False;
443         }
444
445         return send_message(
446                 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
447 }
448
449 /* Force a SAM synchronisation */
450
451 static BOOL do_samsync(const pid_t pid, const int argc, const char **argv)
452 {
453         if (argc != 1) {
454                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
455                 return False;
456         }
457
458         return send_message(
459                 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
460 }
461
462 /* Force a SAM replication */
463
464 static BOOL do_samrepl(const pid_t pid, const int argc, const char **argv)
465 {
466         if (argc != 1) {
467                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
468                 return False;
469         }
470
471         return send_message(
472                 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
473 }
474
475 /* Display talloc pool usage */
476
477 static BOOL do_poolusage(const pid_t pid, const int argc, const char **argv)
478 {
479         if (argc != 1) {
480                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
481                 return False;
482         }
483
484         /* Send a message and register our interest in a reply */
485
486         if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
487                 return False;
488
489         message_register(MSG_POOL_USAGE, print_string_cb);
490
491         wait_replies(pid == 0);
492
493         /* No replies were received within the timeout period */
494
495         if (num_replies == 0)
496                 printf("No replies received\n");
497
498         message_deregister(MSG_POOL_USAGE);
499
500         return num_replies;
501 }
502
503 /* Perform a dmalloc mark */
504
505 static BOOL do_dmalloc_mark(const pid_t pid, const int argc, const char **argv)
506 {
507         if (argc != 1) {
508                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
509                 return False;
510         }
511
512         return send_message(
513                 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
514 }
515
516 /* Perform a dmalloc changed */
517
518 static BOOL do_dmalloc_changed(const pid_t pid, const int argc, const char **argv)
519 {
520         if (argc != 1) {
521                 fprintf(stderr, "Usage: smbcontrol <dest> "
522                         "dmalloc-log-changed\n");
523                 return False;
524         }
525
526         return send_message(
527                 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
528 }
529
530 /* Shutdown a server process */
531
532 static BOOL do_shutdown(const pid_t pid, const int argc, const char **argv)
533 {
534         if (argc != 1) {
535                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
536                 return False;
537         }
538
539         return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
540 }
541
542 /* Notify a driver upgrade */
543
544 static BOOL do_drvupgrade(const pid_t pid, const int argc, const char **argv)
545 {
546         if (argc != 2) {
547                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
548                         "<driver-name>\n");
549                 return False;
550         }
551
552         return send_message(
553                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
554 }
555
556 /* A list of message type supported */
557
558 static const struct {
559         const char *name;       /* Option name */
560         BOOL (*fn)(const pid_t pid, const int argc, const char **argv);
561         const char *help;       /* Short help text */
562 } msg_types[] = {
563         { "debug", do_debug, "Set debuglevel"  },
564         { "force-election", do_election,
565           "Force a browse election" },
566         { "ping", do_ping, "Elicit a response" },
567         { "profile", do_profile, "" },
568         { "profilelevel", do_profilelevel, "" },
569         { "debuglevel", do_debuglevel, "Display current debuglevels" },
570         { "printnotify", do_printnotify, "Send a print notify message" },
571         { "close-share", do_closeshare, "Forcibly disconnect a share" },
572         { "samsync", do_samsync, "Initiate SAM synchronisation" },
573         { "samrepl", do_samrepl, "Initiate SAM replication" },
574         { "pool-usage", do_poolusage, "Display talloc memory usage" },
575         { "dmalloc-mark", do_dmalloc_mark, "" },
576         { "dmalloc-log-changed", do_dmalloc_changed, "" },
577         { "shutdown", do_shutdown, "Shut down daemon" },
578         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
579         { "noop", do_noop, "Do nothing" },
580         { NULL }
581 };
582
583 /* Yuck - we need these because we link to printing*.o even though
584    they aren't used. */
585
586 void become_root(void) {}
587 void unbecome_root(void) {}
588
589 /* Display usage information */
590
591 static void usage(poptContext *pc)
592 {
593         int i;
594
595         poptPrintHelp(*pc, stderr, 0);
596
597         fprintf(stderr, "\n");
598         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a "
599                 "process ID\n");
600
601         fprintf(stderr, "\n");
602         fprintf(stderr, "<message-type> is one of:\n");
603
604         for (i = 0; msg_types[i].name; i++) 
605             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
606                     msg_types[i].help);
607
608         fprintf(stderr, "\n");
609
610         exit(1);
611 }
612
613 /* Return the pid number for a string destination */
614
615 static pid_t parse_dest(const char *dest)
616 {
617         pid_t pid;
618
619         /* Zero is a special return value for broadcast smbd */
620
621         if (strequal(dest, "smbd"))
622                 return 0;
623
624         /* Try self - useful for testing */
625
626         if (strequal(dest, "self"))
627                 return sys_getpid();
628
629         /* Check for numeric pid number */
630
631         if ((pid = atoi(dest)) != 0)
632                 return pid;
633
634         /* Look up other destinations in pidfile directory */
635
636         if ((pid = pidfile_pid(dest)) != 0)
637                 return pid;
638
639         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
640
641         return -1;
642 }       
643
644 /* Execute smbcontrol command */
645
646 static BOOL do_command(int argc, const char **argv)
647 {
648         const char *dest = argv[0], *command = argv[1];
649         pid_t pid;
650         int i;
651
652         /* Check destination */
653
654         if ((pid = parse_dest(dest)) == -1)
655                 return False;
656
657         /* Check command */
658
659         for (i = 0; msg_types[i].name; i++) {
660                 if (strequal(command, msg_types[i].name))
661                         return msg_types[i].fn(pid, argc - 1, argv + 1);
662         }
663
664         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
665
666         return False;
667 }
668
669 /* Main program */
670
671 int main(int argc, const char **argv)
672 {
673         poptContext pc;
674         int opt;
675
676         static struct poptOption wbinfo_options[] = {
677                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
678                   "Set timeout value in seconds", "TIMEOUT" },
679
680                 { "configfile", 's', POPT_ARG_STRING, NULL, 's', 
681                   "Use alternative configuration file", "CONFIGFILE" },
682
683                 POPT_TABLEEND
684         };
685
686         struct poptOption options[] = {
687                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, 
688                   "Options" },
689
690                 POPT_AUTOHELP
691                 POPT_COMMON_VERSION
692                 POPT_TABLEEND
693         };
694
695         setup_logging(argv[0],True);
696         
697         /* Parse command line arguments using popt */
698
699         pc = poptGetContext(
700                 "smbcontrol", argc, (const char **)argv, options, 0);
701
702         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
703                                "<parameters>");
704
705         if (argc == 1)
706                 usage(&pc);
707
708         while ((opt = poptGetNextOpt(pc)) != -1) {
709                 switch(opt) {
710                 case 't':       /* --timeout */
711                         argc -= 2;
712                         break;
713                 case 's':       /* --configfile */
714                         pstrcpy(dyn_CONFIGFILE, optarg);
715                         argc -= 2;
716                         break;
717                 default:
718                         fprintf(stderr, "Invalid option\n");
719                         poptPrintHelp(pc, stderr, 0);
720                         break;
721                 }
722         }
723
724         /* We should now have the remaining command line arguments in
725            argv.  The argc parameter should have been decremented to the
726            correct value in the above switch statement. */
727
728         argv = (const char **)poptGetArgs(pc);
729         argc--;                 /* Don't forget about argv[0] */
730
731         if (argc == 1)
732                 usage(&pc);
733
734         lp_load(dyn_CONFIGFILE,False,False,False);
735
736         /* Need to invert sense of return code -- samba
737          * routines mostly return True==1 for success, but
738          * shell needs 0. */ 
739         
740         return !do_command(argc, argv);
741 }