trying to get HEAD building again. If you want the code
[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 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 static BOOL do_reload_config(const pid_t pid, const int argc, const char **argv)
557 {
558         if (argc != 1) {
559                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
560                 return False;
561         }
562
563         return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
564 }
565
566 /* A list of message type supported */
567
568 static const struct {
569         const char *name;       /* Option name */
570         BOOL (*fn)(const pid_t pid, const int argc, const char **argv);
571         const char *help;       /* Short help text */
572 } msg_types[] = {
573         { "debug", do_debug, "Set debuglevel"  },
574         { "force-election", do_election,
575           "Force a browse election" },
576         { "ping", do_ping, "Elicit a response" },
577         { "profile", do_profile, "" },
578         { "profilelevel", do_profilelevel, "" },
579         { "debuglevel", do_debuglevel, "Display current debuglevels" },
580         { "printnotify", do_printnotify, "Send a print notify message" },
581         { "close-share", do_closeshare, "Forcibly disconnect a share" },
582         { "samsync", do_samsync, "Initiate SAM synchronisation" },
583         { "samrepl", do_samrepl, "Initiate SAM replication" },
584         { "pool-usage", do_poolusage, "Display talloc memory usage" },
585         { "dmalloc-mark", do_dmalloc_mark, "" },
586         { "dmalloc-log-changed", do_dmalloc_changed, "" },
587         { "shutdown", do_shutdown, "Shut down daemon" },
588         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
589         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
590         { "noop", do_noop, "Do nothing" },
591         { NULL }
592 };
593
594 /* Yuck - we need these because we link to printing*.o even though
595    they aren't used. */
596
597 void become_root(void) {}
598 void unbecome_root(void) {}
599
600 /* Display usage information */
601
602 static void usage(poptContext *pc)
603 {
604         int i;
605
606         poptPrintHelp(*pc, stderr, 0);
607
608         fprintf(stderr, "\n");
609         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a "
610                 "process ID\n");
611
612         fprintf(stderr, "\n");
613         fprintf(stderr, "<message-type> is one of:\n");
614
615         for (i = 0; msg_types[i].name; i++) 
616             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
617                     msg_types[i].help);
618
619         fprintf(stderr, "\n");
620
621         exit(1);
622 }
623
624 /* Return the pid number for a string destination */
625
626 static pid_t parse_dest(const char *dest)
627 {
628         pid_t pid;
629
630         /* Zero is a special return value for broadcast smbd */
631
632         if (strequal(dest, "smbd"))
633                 return 0;
634
635         /* Try self - useful for testing */
636
637         if (strequal(dest, "self"))
638                 return sys_getpid();
639
640         /* Check for numeric pid number */
641
642         if ((pid = atoi(dest)) != 0)
643                 return pid;
644
645         /* Look up other destinations in pidfile directory */
646
647         if ((pid = pidfile_pid(dest)) != 0)
648                 return pid;
649
650         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
651
652         return -1;
653 }       
654
655 /* Execute smbcontrol command */
656
657 static BOOL do_command(int argc, const char **argv)
658 {
659         const char *dest = argv[0], *command = argv[1];
660         pid_t pid;
661         int i;
662
663         /* Check destination */
664
665         if ((pid = parse_dest(dest)) == -1)
666                 return False;
667
668         /* Check command */
669
670         for (i = 0; msg_types[i].name; i++) {
671                 if (strequal(command, msg_types[i].name))
672                         return msg_types[i].fn(pid, argc - 1, argv + 1);
673         }
674
675         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
676
677         return False;
678 }
679
680 /* Main program */
681
682 int main(int argc, const char **argv)
683 {
684         poptContext pc;
685         int opt;
686
687         static struct poptOption wbinfo_options[] = {
688                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
689                   "Set timeout value in seconds", "TIMEOUT" },
690
691                 { "configfile", 's', POPT_ARG_STRING, NULL, 's', 
692                   "Use alternative configuration file", "CONFIGFILE" },
693
694                 POPT_TABLEEND
695         };
696
697         struct poptOption options[] = {
698                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, 
699                   "Options" },
700
701                 POPT_AUTOHELP
702                 POPT_COMMON_VERSION
703                 POPT_TABLEEND
704         };
705
706         setup_logging(argv[0],True);
707         
708         /* Parse command line arguments using popt */
709
710         pc = poptGetContext(
711                 "smbcontrol", argc, (const char **)argv, options, 0);
712
713         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
714                                "<parameters>");
715
716         if (argc == 1)
717                 usage(&pc);
718
719         while ((opt = poptGetNextOpt(pc)) != -1) {
720                 switch(opt) {
721                 case 't':       /* --timeout */
722                         argc -= 2;
723                         break;
724                 case 's':       /* --configfile */
725                         pstrcpy(dyn_CONFIGFILE, optarg);
726                         argc -= 2;
727                         break;
728                 default:
729                         fprintf(stderr, "Invalid option\n");
730                         poptPrintHelp(pc, stderr, 0);
731                         break;
732                 }
733         }
734
735         /* We should now have the remaining command line arguments in
736            argv.  The argc parameter should have been decremented to the
737            correct value in the above switch statement. */
738
739         argv = (const char **)poptGetArgs(pc);
740         argc--;                 /* Don't forget about argv[0] */
741
742         if (argc == 1)
743                 usage(&pc);
744
745         lp_load(dyn_CONFIGFILE,False,False,False);
746
747         /* Need to invert sense of return code -- samba
748          * routines mostly return True==1 for success, but
749          * shell needs 0. */ 
750         
751         return !do_command(argc, argv);
752 }