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