s3: Fix some nonempty blank lines
[nivanova/samba-autobuild/.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    Copyright (C) James Peach 2006
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "librpc/gen_ndr/messaging.h"
28 #include "librpc/gen_ndr/spoolss.h"
29 #include "nt_printing.h"
30
31 #if HAVE_LIBUNWIND_H
32 #include <libunwind.h>
33 #endif
34
35 #if HAVE_LIBUNWIND_PTRACE_H
36 #include <libunwind-ptrace.h>
37 #endif
38
39 #if HAVE_SYS_PTRACE_H
40 #include <sys/ptrace.h>
41 #endif
42
43 /* Default timeout value when waiting for replies (in seconds) */
44
45 #define DEFAULT_TIMEOUT 10
46
47 static int timeout = DEFAULT_TIMEOUT;
48 static int num_replies;         /* Used by message callback fns */
49
50 /* Send a message to a destination pid.  Zero means broadcast smbd. */
51
52 static bool send_message(struct messaging_context *msg_ctx,
53                          struct server_id pid, int msg_type,
54                          const void *buf, int len)
55 {
56         bool ret;
57         int n_sent = 0;
58
59         if (procid_to_pid(&pid) != 0)
60                 return NT_STATUS_IS_OK(
61                         messaging_send_buf(msg_ctx, pid, msg_type,
62                                            (uint8 *)buf, len));
63
64         ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
65         DEBUG(10,("smbcontrol/send_message: broadcast message to "
66                   "%d processes\n", n_sent));
67
68         return ret;
69 }
70
71 static void smbcontrol_timeout(struct tevent_context *event_ctx,
72                                struct tevent_timer *te,
73                                struct timeval now,
74                                void *private_data)
75 {
76         bool *timed_out = (bool *)private_data;
77         TALLOC_FREE(te);
78         *timed_out = True;
79 }
80
81 /* Wait for one or more reply messages */
82
83 static void wait_replies(struct messaging_context *msg_ctx,
84                          bool multiple_replies)
85 {
86         struct tevent_timer *te;
87         bool timed_out = False;
88
89         if (!(te = tevent_add_timer(messaging_event_context(msg_ctx), NULL,
90                                     timeval_current_ofs(timeout, 0),
91                                     smbcontrol_timeout, (void *)&timed_out))) {
92                 DEBUG(0, ("tevent_add_timer failed\n"));
93                 return;
94         }
95
96         while (!timed_out) {
97                 int ret;
98                 if (num_replies > 0 && !multiple_replies)
99                         break;
100                 ret = tevent_loop_once(messaging_event_context(msg_ctx));
101                 if (ret != 0) {
102                         break;
103                 }
104         }
105 }
106
107 /* Message handler callback that displays the PID and a string on stdout */
108
109 static void print_pid_string_cb(struct messaging_context *msg,
110                                 void *private_data, 
111                                 uint32_t msg_type, 
112                                 struct server_id pid,
113                                 DATA_BLOB *data)
114 {
115         char *pidstr;
116
117         pidstr = procid_str(talloc_tos(), &pid);
118         printf("PID %s: %.*s", pidstr, (int)data->length,
119                (const char *)data->data);
120         TALLOC_FREE(pidstr);
121         num_replies++;
122 }
123
124 /* Message handler callback that displays a string on stdout */
125
126 static void print_string_cb(struct messaging_context *msg,
127                             void *private_data, 
128                             uint32_t msg_type, 
129                             struct server_id pid,
130                             DATA_BLOB *data)
131 {
132         printf("%*s", (int)data->length, (const char *)data->data);
133         num_replies++;
134 }
135
136 /* Send no message.  Useful for testing. */
137
138 static bool do_noop(struct messaging_context *msg_ctx,
139                     const struct server_id pid,
140                     const int argc, const char **argv)
141 {
142         if (argc != 1) {
143                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
144                 return False;
145         }
146
147         /* Move along, nothing to see here */
148
149         return True;
150 }
151
152 /* Send a debug string */
153
154 static bool do_debug(struct messaging_context *msg_ctx,
155                      const struct server_id pid,
156                      const int argc, const char **argv)
157 {
158         if (argc != 2) {
159                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
160                         "<debug-string>\n");
161                 return False;
162         }
163
164         return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
165                             strlen(argv[1]) + 1);
166 }
167
168 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
169
170 /* Return the name of a process given it's PID. This will only work on Linux,
171  * but that's probably moot since this whole stack tracing implementatino is
172  * Linux-specific anyway.
173  */
174 static const char * procname(pid_t pid, char * buf, size_t bufsz)
175 {
176         char path[64];
177         FILE * fp;
178
179         snprintf(path, sizeof(path), "/proc/%llu/cmdline",
180                 (unsigned long long)pid);
181         if ((fp = fopen(path, "r")) == NULL) {
182                 return NULL;
183         }
184
185         fgets(buf, bufsz, fp);
186
187         fclose(fp);
188         return buf;
189 }
190
191 static void print_stack_trace(pid_t pid, int * count)
192 {
193         void *              pinfo = NULL;
194         unw_addr_space_t    aspace = NULL;
195         unw_cursor_t        cursor;
196         unw_word_t          ip, sp;
197
198         char                nbuf[256];
199         unw_word_t          off;
200
201         int ret;
202
203         if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
204                 fprintf(stderr,
205                         "Failed to attach to process %llu: %s\n",
206                         (unsigned long long)pid, strerror(errno));
207                 return;
208         }
209
210         /* Wait until the attach is complete. */
211         waitpid(pid, NULL, 0);
212
213         if (((pinfo = _UPT_create(pid)) == NULL) ||
214             ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
215                 /* Probably out of memory. */
216                 fprintf(stderr,
217                         "Unable to initialize stack unwind for process %llu\n",
218                         (unsigned long long)pid);
219                 goto cleanup;
220         }
221
222         if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
223                 fprintf(stderr,
224                         "Unable to unwind stack for process %llu: %s\n",
225                         (unsigned long long)pid, unw_strerror(ret));
226                 goto cleanup;
227         }
228
229         if (*count > 0) {
230                 printf("\n");
231         }
232
233         if (procname(pid, nbuf, sizeof(nbuf))) {
234                 printf("Stack trace for process %llu (%s):\n",
235                         (unsigned long long)pid, nbuf);
236         } else {
237                 printf("Stack trace for process %llu:\n",
238                         (unsigned long long)pid);
239         }
240
241         while (unw_step(&cursor) > 0) {
242                 ip = sp = off = 0;
243                 unw_get_reg(&cursor, UNW_REG_IP, &ip);
244                 unw_get_reg(&cursor, UNW_REG_SP, &sp);
245
246                 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
247                 if (ret != 0 && ret != -UNW_ENOMEM) {
248                         snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
249                 }
250                 printf("    %s + %#llx [ip=%#llx] [sp=%#llx]\n",
251                         nbuf, (long long)off, (long long)ip,
252                         (long long)sp);
253         }
254
255         (*count)++;
256
257 cleanup:
258         if (aspace) {
259                 unw_destroy_addr_space(aspace);
260         }
261
262         if (pinfo) {
263                 _UPT_destroy(pinfo);
264         }
265
266         ptrace(PTRACE_DETACH, pid, NULL, NULL);
267 }
268
269 static int stack_trace_connection(const struct connections_key *key,
270                                   const struct connections_data *crec,
271                                   void *priv)
272 {
273         print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
274
275         return 0;
276 }
277
278 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
279                                   const struct server_id pid,
280                        const int argc, const char **argv)
281 {
282         pid_t   dest;
283         int     count = 0;
284
285         if (argc != 1) {
286                 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
287                 return False;
288         }
289
290         dest = procid_to_pid(&pid);
291
292         if (dest != 0) {
293                 /* It would be nice to be able to make sure that this PID is
294                  * the PID of a smbd/winbind/nmbd process, not some random PID
295                  * the user liked the look of. It doesn't seem like it's worth
296                  * the effort at the moment, however.
297                  */
298                 print_stack_trace(dest, &count);
299         } else {
300                 connections_forall_read(stack_trace_connection, &count);
301         }
302
303         return True;
304 }
305
306 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
307
308 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
309                                   const struct server_id pid,
310                        const int argc, const char **argv)
311 {
312         fprintf(stderr,
313                 "Daemon stack tracing is not supported on this platform\n");
314         return False;
315 }
316
317 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
318
319 /* Inject a fault (fatal signal) into a running smbd */
320
321 static bool do_inject_fault(struct messaging_context *msg_ctx,
322                             const struct server_id pid,
323                        const int argc, const char **argv)
324 {
325         if (argc != 2) {
326                 fprintf(stderr, "Usage: smbcontrol <dest> inject "
327                         "<bus|hup|term|internal|segv>\n");
328                 return False;
329         }
330
331 #ifndef DEVELOPER
332         fprintf(stderr, "Fault injection is only available in "
333                 "developer builds\n");
334         return False;
335 #else /* DEVELOPER */
336         {
337                 int sig = 0;
338
339                 if (strcmp(argv[1], "bus") == 0) {
340                         sig = SIGBUS;
341                 } else if (strcmp(argv[1], "hup") == 0) {
342                         sig = SIGHUP;
343                 } else if (strcmp(argv[1], "term") == 0) {
344                         sig = SIGTERM;
345                 } else if (strcmp(argv[1], "segv") == 0) {
346                         sig = SIGSEGV;
347                 } else if (strcmp(argv[1], "internal") == 0) {
348                         /* Force an internal error, ie. an unclean exit. */
349                         sig = -1;
350                 } else {
351                         fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
352                         return False;
353                 }
354
355                 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
356                                     &sig, sizeof(int));
357         }
358 #endif /* DEVELOPER */
359 }
360
361 /* Force a browser election */
362
363 static bool do_election(struct messaging_context *msg_ctx,
364                         const struct server_id pid,
365                         const int argc, const char **argv)
366 {
367         if (argc != 1) {
368                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
369                 return False;
370         }
371
372         return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
373 }
374
375 /* Ping a samba daemon process */
376
377 static void pong_cb(struct messaging_context *msg,
378                     void *private_data, 
379                     uint32_t msg_type, 
380                     struct server_id pid,
381                     DATA_BLOB *data)
382 {
383         char *src_string = procid_str(NULL, &pid);
384         printf("PONG from pid %s\n", src_string);
385         TALLOC_FREE(src_string);
386         num_replies++;
387 }
388
389 static bool do_ping(struct messaging_context *msg_ctx,
390                     const struct server_id pid,
391                     const int argc, const char **argv)
392 {
393         if (argc != 1) {
394                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
395                 return False;
396         }
397
398         /* Send a message and register our interest in a reply */
399
400         if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
401                 return False;
402
403         messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
404
405         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
406
407         /* No replies were received within the timeout period */
408
409         if (num_replies == 0)
410                 printf("No replies received\n");
411
412         messaging_deregister(msg_ctx, MSG_PONG, NULL);
413
414         return num_replies;
415 }
416
417 /* Set profiling options */
418
419 static bool do_profile(struct messaging_context *msg_ctx,
420                        const struct server_id pid,
421                        const int argc, const char **argv)
422 {
423         int v;
424
425         if (argc != 2) {
426                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
427                         "<off|count|on|flush>\n");
428                 return False;
429         }
430
431         if (strcmp(argv[1], "off") == 0) {
432                 v = 0;
433         } else if (strcmp(argv[1], "count") == 0) {
434                 v = 1;
435         } else if (strcmp(argv[1], "on") == 0) {
436                 v = 2;
437         } else if (strcmp(argv[1], "flush") == 0) {
438                 v = 3;
439         } else {
440                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
441                 return False;
442         }
443
444         return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
445 }
446
447 /* Return the profiling level */
448
449 static void profilelevel_cb(struct messaging_context *msg_ctx,
450                             void *private_data, 
451                             uint32_t msg_type, 
452                             struct server_id pid,
453                             DATA_BLOB *data)
454 {
455         int level;
456         const char *s;
457
458         num_replies++;
459
460         if (data->length != sizeof(int)) {
461                 fprintf(stderr, "invalid message length %ld returned\n", 
462                         (unsigned long)data->length);
463                 return;
464         }
465
466         memcpy(&level, data->data, sizeof(int));
467
468         switch (level) {
469         case 0:
470                 s = "not enabled";
471                 break;
472         case 1:
473                 s = "off";
474                 break;
475         case 3:
476                 s = "count only";
477                 break;
478         case 7:
479                 s = "count and time";
480                 break;
481         default:
482                 s = "BOGUS";
483                 break;
484         }
485
486         printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
487 }
488
489 static void profilelevel_rqst(struct messaging_context *msg_ctx,
490                               void *private_data, 
491                               uint32_t msg_type, 
492                               struct server_id pid,
493                               DATA_BLOB *data)
494 {
495         int v = 0;
496
497         /* Send back a dummy reply */
498
499         send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
500 }
501
502 static bool do_profilelevel(struct messaging_context *msg_ctx,
503                             const struct server_id pid,
504                             const int argc, const char **argv)
505 {
506         if (argc != 1) {
507                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
508                 return False;
509         }
510
511         /* Send a message and register our interest in a reply */
512
513         if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
514                 return False;
515
516         messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
517         messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
518                            profilelevel_rqst);
519
520         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
521
522         /* No replies were received within the timeout period */
523
524         if (num_replies == 0)
525                 printf("No replies received\n");
526
527         messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
528
529         return num_replies;
530 }
531
532 /* Display debug level settings */
533
534 static bool do_debuglevel(struct messaging_context *msg_ctx,
535                           const struct server_id pid,
536                           const int argc, const char **argv)
537 {
538         if (argc != 1) {
539                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
540                 return False;
541         }
542
543         /* Send a message and register our interest in a reply */
544
545         if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
546                 return False;
547
548         messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
549
550         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
551
552         /* No replies were received within the timeout period */
553
554         if (num_replies == 0)
555                 printf("No replies received\n");
556
557         messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
558
559         return num_replies;
560 }
561
562 /* Send a print notify message */
563
564 static bool do_printnotify(struct messaging_context *msg_ctx,
565                            const struct server_id pid,
566                            const int argc, const char **argv)
567 {
568         const char *cmd;
569
570         /* Check for subcommand */
571
572         if (argc == 1) {
573                 fprintf(stderr, "Must specify subcommand:\n");
574                 fprintf(stderr, "\tqueuepause <printername>\n");
575                 fprintf(stderr, "\tqueueresume <printername>\n");
576                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
577                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
578                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
579                 fprintf(stderr, "\tprinter <printername> <comment|port|"
580                         "driver> <value>\n");
581
582                 return False;
583         }
584
585         cmd = argv[1];
586
587         if (strcmp(cmd, "queuepause") == 0) {
588
589                 if (argc != 3) {
590                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
591                                 " queuepause <printername>\n");
592                         return False;
593                 }
594
595                 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
596
597                 goto send;
598
599         } else if (strcmp(cmd, "queueresume") == 0) {
600
601                 if (argc != 3) {
602                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
603                                 " queuereume <printername>\n");
604                         return False;
605                 }
606
607                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
608
609                 goto send;
610
611         } else if (strcmp(cmd, "jobpause") == 0) {
612                 int jobid;
613
614                 if (argc != 4) {
615                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
616                                 " jobpause <printername> <unix-jobid>\n");
617                         return False;
618                 }
619
620                 jobid = atoi(argv[3]);
621
622                 notify_job_status_byname(
623                         argv[2], jobid, JOB_STATUS_PAUSED, 
624                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
625
626                 goto send;
627
628         } else if (strcmp(cmd, "jobresume") == 0) {
629                 int jobid;
630
631                 if (argc != 4) {
632                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
633                                 " jobpause <printername> <unix-jobid>\n");
634                         return False;
635                 }
636
637                 jobid = atoi(argv[3]);
638
639                 notify_job_status_byname(
640                         argv[2], jobid, JOB_STATUS_QUEUED, 
641                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
642
643                 goto send;
644
645         } else if (strcmp(cmd, "jobdelete") == 0) {
646                 int jobid;
647
648                 if (argc != 4) {
649                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
650                                 " jobpause <printername> <unix-jobid>\n");
651                         return False;
652                 }
653
654                 jobid = atoi(argv[3]);
655
656                 notify_job_status_byname(
657                         argv[2], jobid, JOB_STATUS_DELETING,
658                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
659
660                 notify_job_status_byname(
661                         argv[2], jobid, JOB_STATUS_DELETING|
662                         JOB_STATUS_DELETED,
663                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
664
665                 goto send;
666
667         } else if (strcmp(cmd, "printer") == 0) {
668                 uint32 attribute;
669
670                 if (argc != 5) {
671                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
672                                 "printer <printername> <comment|port|driver> "
673                                 "<value>\n");
674                         return False;
675                 }
676
677                 if (strcmp(argv[3], "comment") == 0) {
678                         attribute = PRINTER_NOTIFY_FIELD_COMMENT;
679                 } else if (strcmp(argv[3], "port") == 0) {
680                         attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
681                 } else if (strcmp(argv[3], "driver") == 0) {
682                         attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
683                 } else {
684                         fprintf(stderr, "Invalid printer command '%s'\n",
685                                 argv[3]);
686                         return False;
687                 }
688
689                 notify_printer_byname(argv[2], attribute,
690                                       CONST_DISCARD(char *, argv[4]));
691
692                 goto send;
693         }
694
695         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
696         return False;
697
698 send:
699         print_notify_send_messages(msg_ctx, 0);
700         return True;
701 }
702
703 /* Close a share */
704
705 static bool do_closeshare(struct messaging_context *msg_ctx,
706                           const struct server_id pid,
707                           const int argc, const char **argv)
708 {
709         if (argc != 2) {
710                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
711                         "<sharename>\n");
712                 return False;
713         }
714
715         return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
716                             strlen(argv[1]) + 1);
717 }
718
719 /* force a blocking lock retry */
720
721 static bool do_lockretry(struct messaging_context *msg_ctx,
722                          const struct server_id pid,
723                          const int argc, const char **argv)
724 {
725         if (argc != 1) {
726                 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
727                 return False;
728         }
729
730         return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
731 }
732
733 /* force a validation of all brl entries, including re-sends. */
734
735 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
736                               const struct server_id pid,
737                               const int argc, const char **argv)
738 {
739         if (argc != 1) {
740                 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
741                 return False;
742         }
743
744         return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
745 }
746
747 /* Force a SAM synchronisation */
748
749 static bool do_samsync(struct messaging_context *msg_ctx,
750                        const struct server_id pid,
751                        const int argc, const char **argv)
752 {
753         if (argc != 1) {
754                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
755                 return False;
756         }
757
758         return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
759 }
760
761 /* Force a SAM replication */
762
763 static bool do_samrepl(struct messaging_context *msg_ctx,
764                        const struct server_id pid,
765                        const int argc, const char **argv)
766 {
767         if (argc != 1) {
768                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
769                 return False;
770         }
771
772         return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
773 }
774
775 /* Display talloc pool usage */
776
777 static bool do_poolusage(struct messaging_context *msg_ctx,
778                          const struct server_id pid,
779                          const int argc, const char **argv)
780 {
781         if (argc != 1) {
782                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
783                 return False;
784         }
785
786         messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
787
788         /* Send a message and register our interest in a reply */
789
790         if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
791                 return False;
792
793         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
794
795         /* No replies were received within the timeout period */
796
797         if (num_replies == 0)
798                 printf("No replies received\n");
799
800         messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
801
802         return num_replies;
803 }
804
805 /* Perform a dmalloc mark */
806
807 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
808                             const struct server_id pid,
809                             const int argc, const char **argv)
810 {
811         if (argc != 1) {
812                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
813                 return False;
814         }
815
816         return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
817 }
818
819 /* Perform a dmalloc changed */
820
821 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
822                                const struct server_id pid,
823                                const int argc, const char **argv)
824 {
825         if (argc != 1) {
826                 fprintf(stderr, "Usage: smbcontrol <dest> "
827                         "dmalloc-log-changed\n");
828                 return False;
829         }
830
831         return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
832                             NULL, 0);
833 }
834
835 /* Shutdown a server process */
836
837 static bool do_shutdown(struct messaging_context *msg_ctx,
838                         const struct server_id pid,
839                         const int argc, const char **argv)
840 {
841         if (argc != 1) {
842                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
843                 return False;
844         }
845
846         return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
847 }
848
849 /* Notify a driver upgrade */
850
851 static bool do_drvupgrade(struct messaging_context *msg_ctx,
852                           const struct server_id pid,
853                           const int argc, const char **argv)
854 {
855         if (argc != 2) {
856                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
857                         "<driver-name>\n");
858                 return False;
859         }
860
861         return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
862                             strlen(argv[1]) + 1);
863 }
864
865 static bool do_winbind_online(struct messaging_context *msg_ctx,
866                               const struct server_id pid,
867                              const int argc, const char **argv)
868 {
869         TDB_CONTEXT *tdb;
870
871         if (argc != 1) {
872                 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
873                 return False;
874         }
875
876         /* Remove the entry in the winbindd_cache tdb to tell a later
877            starting winbindd that we're online. */
878
879         tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
880         if (!tdb) {
881                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
882                         cache_path("winbindd_cache.tdb"));
883                 return False;
884         }
885
886         tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
887         tdb_close(tdb);
888
889         return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
890 }
891
892 static bool do_winbind_offline(struct messaging_context *msg_ctx,
893                                const struct server_id pid,
894                              const int argc, const char **argv)
895 {
896         TDB_CONTEXT *tdb;
897         bool ret = False;
898         int retry = 0;
899
900         if (argc != 1) {
901                 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
902                 return False;
903         }
904
905         /* Create an entry in the winbindd_cache tdb to tell a later
906            starting winbindd that we're offline. We may actually create
907            it here... */
908
909         tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
910                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
911                                 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
912
913         if (!tdb) {
914                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
915                         cache_path("winbindd_cache.tdb"));
916                 return False;
917         }
918
919         /* There's a potential race condition that if a child
920            winbindd detects a domain is online at the same time
921            we're trying to tell it to go offline that it might 
922            delete the record we add between us adding it and
923            sending the message. Minimize this by retrying up to
924            5 times. */
925
926         for (retry = 0; retry < 5; retry++) {
927                 TDB_DATA d;
928                 uint8 buf[4];
929
930                 ZERO_STRUCT(d);
931
932                 SIVAL(buf, 0, time(NULL));
933                 d.dptr = buf;
934                 d.dsize = 4;
935
936                 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
937
938                 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
939                                    NULL, 0);
940
941                 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
942                 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
943
944                 if (!d.dptr || d.dsize != 4) {
945                         SAFE_FREE(d.dptr);
946                         DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
947                 } else {
948                         SAFE_FREE(d.dptr);
949                         break;
950                 }
951         }
952
953         tdb_close(tdb);
954         return ret;
955 }
956
957 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
958                                     const struct server_id pid,
959                                     const int argc, const char **argv)
960 {
961         struct server_id myid;
962
963         myid = procid_self();
964
965         if (argc != 1) {
966                 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
967                 return False;
968         }
969
970         messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
971                            print_pid_string_cb);
972
973         if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
974                           sizeof(myid)))
975                 return False;
976
977         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
978
979         /* No replies were received within the timeout period */
980
981         if (num_replies == 0)
982                 printf("No replies received\n");
983
984         messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
985
986         return num_replies;
987 }
988
989 static bool do_dump_event_list(struct messaging_context *msg_ctx,
990                                const struct server_id pid,
991                                const int argc, const char **argv)
992 {
993         struct server_id myid;
994
995         myid = procid_self();
996
997         if (argc != 1) {
998                 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
999                 return False;
1000         }
1001
1002         return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1003 }
1004
1005 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
1006                                         const struct server_id pid,
1007                                         const int argc, const char **argv)
1008 {
1009         const char *domain = NULL;
1010         int domain_len = 0;
1011         struct server_id myid;
1012         uint8_t *buf = NULL;
1013         int buf_len = 0;
1014
1015         myid = procid_self();
1016
1017         if (argc < 1 || argc > 2) {
1018                 fprintf(stderr, "Usage: smbcontrol <dest> dump_domain_list "
1019                         "<domain>\n");
1020                 return false;
1021         }
1022
1023         if (argc == 2) {
1024                 domain = argv[1];
1025                 domain_len = strlen(argv[1]) + 1;
1026         }
1027
1028         messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1029                            print_pid_string_cb);
1030
1031         buf_len = sizeof(myid)+domain_len;
1032         buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1033         if (!buf) {
1034                 return false;
1035         }
1036
1037         memcpy(buf, &myid, sizeof(myid));
1038         memcpy(&buf[sizeof(myid)], domain, domain_len);
1039
1040         if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1041                           buf, buf_len))
1042         {
1043                 SAFE_FREE(buf);
1044                 return false;
1045         }
1046
1047         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1048
1049         /* No replies were received within the timeout period */
1050
1051         SAFE_FREE(buf);
1052         if (num_replies == 0) {
1053                 printf("No replies received\n");
1054         }
1055
1056         messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1057
1058         return num_replies;
1059 }
1060
1061 static void winbind_validate_cache_cb(struct messaging_context *msg,
1062                                       void *private_data,
1063                                       uint32_t msg_type,
1064                                       struct server_id pid,
1065                                       DATA_BLOB *data)
1066 {
1067         char *src_string = procid_str(NULL, &pid);
1068         printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1069                (*(data->data) == 0 ? "" : "NOT "), src_string);
1070         TALLOC_FREE(src_string);
1071         num_replies++;
1072 }
1073
1074 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1075                                       const struct server_id pid,
1076                                       const int argc, const char **argv)
1077 {
1078         struct server_id myid = procid_self();
1079
1080         if (argc != 1) {
1081                 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1082                 return False;
1083         }
1084
1085         messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1086                            winbind_validate_cache_cb);
1087
1088         if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1089                           sizeof(myid))) {
1090                 return False;
1091         }
1092
1093         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1094
1095         if (num_replies == 0) {
1096                 printf("No replies received\n");
1097         }
1098
1099         messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1100
1101         return num_replies;
1102 }
1103
1104 static bool do_reload_config(struct messaging_context *msg_ctx,
1105                              const struct server_id pid,
1106                              const int argc, const char **argv)
1107 {
1108         if (argc != 1) {
1109                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1110                 return False;
1111         }
1112
1113         return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1114 }
1115
1116 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1117 {
1118         fstring unix_name;
1119         memset( (char *)n, '\0', sizeof(struct nmb_name) );
1120         fstrcpy(unix_name, name);
1121         strupper_m(unix_name);
1122         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1123         n->name_type = (unsigned int)type & 0xFF;
1124         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
1125 }
1126
1127 static bool do_nodestatus(struct messaging_context *msg_ctx,
1128                           const struct server_id pid,
1129                           const int argc, const char **argv)
1130 {
1131         struct packet_struct p;
1132
1133         if (argc != 2) {
1134                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1135                 return False;
1136         }
1137
1138         ZERO_STRUCT(p);
1139
1140         p.ip = interpret_addr2(argv[1]);
1141         p.port = 137;
1142         p.packet_type = NMB_PACKET;
1143
1144         p.packet.nmb.header.name_trn_id = 10;
1145         p.packet.nmb.header.opcode = 0;
1146         p.packet.nmb.header.response = False;
1147         p.packet.nmb.header.nm_flags.bcast = False;
1148         p.packet.nmb.header.nm_flags.recursion_available = False;
1149         p.packet.nmb.header.nm_flags.recursion_desired = False;
1150         p.packet.nmb.header.nm_flags.trunc = False;
1151         p.packet.nmb.header.nm_flags.authoritative = False;
1152         p.packet.nmb.header.rcode = 0;
1153         p.packet.nmb.header.qdcount = 1;
1154         p.packet.nmb.header.ancount = 0;
1155         p.packet.nmb.header.nscount = 0;
1156         p.packet.nmb.header.arcount = 0;
1157         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1158         p.packet.nmb.question.question_type = 0x21;
1159         p.packet.nmb.question.question_class = 0x1;
1160
1161         return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1162 }
1163
1164 /* A list of message type supported */
1165
1166 static const struct {
1167         const char *name;       /* Option name */
1168         bool (*fn)(struct messaging_context *msg_ctx,
1169                    const struct server_id pid,
1170                    const int argc, const char **argv);
1171         const char *help;       /* Short help text */
1172 } msg_types[] = {
1173         { "debug", do_debug, "Set debuglevel"  },
1174         { "force-election", do_election,
1175           "Force a browse election" },
1176         { "ping", do_ping, "Elicit a response" },
1177         { "profile", do_profile, "" },
1178         { "inject", do_inject_fault,
1179             "Inject a fatal signal into a running smbd"},
1180         { "stacktrace", do_daemon_stack_trace,
1181             "Display a stack trace of a daemon" },
1182         { "profilelevel", do_profilelevel, "" },
1183         { "debuglevel", do_debuglevel, "Display current debuglevels" },
1184         { "printnotify", do_printnotify, "Send a print notify message" },
1185         { "close-share", do_closeshare, "Forcibly disconnect a share" },
1186         { "lockretry", do_lockretry, "Force a blocking lock retry" },
1187         { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1188         { "samsync", do_samsync, "Initiate SAM synchronisation" },
1189         { "samrepl", do_samrepl, "Initiate SAM replication" },
1190         { "pool-usage", do_poolusage, "Display talloc memory usage" },
1191         { "dmalloc-mark", do_dmalloc_mark, "" },
1192         { "dmalloc-log-changed", do_dmalloc_changed, "" },
1193         { "shutdown", do_shutdown, "Shut down daemon" },
1194         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1195         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1196         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1197         { "online", do_winbind_online, "Ask winbind to go into online state"},
1198         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1199         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1200         { "dump-event-list", do_dump_event_list, "Dump event list"},
1201         { "validate-cache" , do_winbind_validate_cache,
1202           "Validate winbind's credential cache" },
1203         { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1204         { "noop", do_noop, "Do nothing" },
1205         { NULL }
1206 };
1207
1208 /* Display usage information */
1209
1210 static void usage(poptContext pc)
1211 {
1212         int i;
1213
1214         poptPrintHelp(pc, stderr, 0);
1215
1216         fprintf(stderr, "\n");
1217         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1218                 "process ID\n");
1219
1220         fprintf(stderr, "\n");
1221         fprintf(stderr, "<message-type> is one of:\n");
1222
1223         for (i = 0; msg_types[i].name; i++) 
1224             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
1225                     msg_types[i].help);
1226
1227         fprintf(stderr, "\n");
1228
1229         exit(1);
1230 }
1231
1232 /* Return the pid number for a string destination */
1233
1234 static struct server_id parse_dest(const char *dest)
1235 {
1236         struct server_id result = {-1};
1237         pid_t pid;
1238
1239         /* Zero is a special return value for broadcast to all processes */
1240
1241         if (strequal(dest, "all")) {
1242                 return interpret_pid(MSG_BROADCAST_PID_STR);
1243         }
1244
1245         /* Try self - useful for testing */
1246
1247         if (strequal(dest, "self")) {
1248                 return procid_self();
1249         }
1250
1251         /* Fix winbind typo. */
1252         if (strequal(dest, "winbind")) {
1253                 dest = "winbindd";
1254         }
1255
1256         /* Check for numeric pid number */
1257         result = interpret_pid(dest);
1258
1259         /* Zero isn't valid if not "all". */
1260         if (result.pid && procid_valid(&result)) {
1261                 return result;
1262         }
1263
1264         /* Look up other destinations in pidfile directory */
1265
1266         if ((pid = pidfile_pid(dest)) != 0) {
1267                 return pid_to_procid(pid);
1268         }
1269
1270         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1271
1272         return result;
1273 }
1274
1275 /* Execute smbcontrol command */
1276
1277 static bool do_command(struct messaging_context *msg_ctx,
1278                        int argc, const char **argv)
1279 {
1280         const char *dest = argv[0], *command = argv[1];
1281         struct server_id pid;
1282         int i;
1283
1284         /* Check destination */
1285
1286         pid = parse_dest(dest);
1287         if (!procid_valid(&pid)) {
1288                 return False;
1289         }
1290
1291         /* Check command */
1292
1293         for (i = 0; msg_types[i].name; i++) {
1294                 if (strequal(command, msg_types[i].name))
1295                         return msg_types[i].fn(msg_ctx, pid,
1296                                                argc - 1, argv + 1);
1297         }
1298
1299         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1300
1301         return False;
1302 }
1303
1304 static void smbcontrol_help(poptContext pc,
1305                     enum poptCallbackReason preason,
1306                     struct poptOption * poption,
1307                     const char * parg,
1308                     void * pdata)
1309 {
1310         if (poption->shortName != '?') {
1311                 poptPrintUsage(pc, stdout, 0);
1312         } else {
1313                 usage(pc);
1314         }
1315
1316         exit(0);
1317 }
1318
1319 struct poptOption help_options[] = {
1320         { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1321           NULL, NULL },
1322         { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1323         { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1324         { NULL }
1325 } ;
1326
1327 /* Main program */
1328
1329 int main(int argc, const char **argv)
1330 {
1331         poptContext pc;
1332         int opt;
1333         struct tevent_context *evt_ctx;
1334         struct messaging_context *msg_ctx;
1335
1336         static struct poptOption long_options[] = {
1337                 /* POPT_AUTOHELP */
1338                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1339                                         0, "Help options:", NULL },
1340                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
1341                   "Set timeout value in seconds", "TIMEOUT" },
1342
1343                 POPT_COMMON_SAMBA
1344                 POPT_TABLEEND
1345         };
1346         TALLOC_CTX *frame = talloc_stackframe();
1347         int ret = 0;
1348
1349         load_case_tables();
1350
1351         setup_logging(argv[0],True);
1352
1353         /* Parse command line arguments using popt */
1354
1355         pc = poptGetContext(
1356                 "smbcontrol", argc, (const char **)argv, long_options, 0);
1357
1358         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1359                                "<parameters>");
1360
1361         if (argc == 1)
1362                 usage(pc);
1363
1364         while ((opt = poptGetNextOpt(pc)) != -1) {
1365                 switch(opt) {
1366                 case 't':       /* --timeout */
1367                         break;
1368                 default:
1369                         fprintf(stderr, "Invalid option\n");
1370                         poptPrintHelp(pc, stderr, 0);
1371                         break;
1372                 }
1373         }
1374
1375         /* We should now have the remaining command line arguments in
1376            argv.  The argc parameter should have been decremented to the
1377            correct value in the above switch statement. */
1378
1379         argv = (const char **)poptGetArgs(pc);
1380         argc = 0;
1381         if (argv != NULL) {
1382                 while (argv[argc] != NULL) {
1383                         argc++;
1384                 }
1385         }
1386
1387         if (argc <= 1)
1388                 usage(pc);
1389
1390         lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1391
1392         /* Need to invert sense of return code -- samba
1393          * routines mostly return True==1 for success, but
1394          * shell needs 0. */ 
1395
1396         if (!(evt_ctx = tevent_context_init(NULL)) ||
1397             !(msg_ctx = messaging_init(NULL, procid_self(), evt_ctx))) {
1398                 fprintf(stderr, "could not init messaging context\n");
1399                 TALLOC_FREE(frame);
1400                 exit(1);
1401         }
1402
1403         ret = !do_command(msg_ctx, argc, argv);
1404         TALLOC_FREE(frame);
1405         return ret;
1406 }