s3-popt: Only include popt-common.h when needed.
[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 "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(argv[2], PRINTER_STATUS_PAUSED);
597
598                 goto send;
599
600         } else if (strcmp(cmd, "queueresume") == 0) {
601
602                 if (argc != 3) {
603                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
604                                 " queuereume <printername>\n");
605                         return False;
606                 }
607
608                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
609
610                 goto send;
611
612         } else if (strcmp(cmd, "jobpause") == 0) {
613                 int jobid;
614
615                 if (argc != 4) {
616                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
617                                 " jobpause <printername> <unix-jobid>\n");
618                         return False;
619                 }
620
621                 jobid = atoi(argv[3]);
622
623                 notify_job_status_byname(
624                         argv[2], jobid, JOB_STATUS_PAUSED, 
625                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
626
627                 goto send;
628
629         } else if (strcmp(cmd, "jobresume") == 0) {
630                 int jobid;
631
632                 if (argc != 4) {
633                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
634                                 " jobpause <printername> <unix-jobid>\n");
635                         return False;
636                 }
637
638                 jobid = atoi(argv[3]);
639
640                 notify_job_status_byname(
641                         argv[2], jobid, JOB_STATUS_QUEUED, 
642                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
643
644                 goto send;
645
646         } else if (strcmp(cmd, "jobdelete") == 0) {
647                 int jobid;
648
649                 if (argc != 4) {
650                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
651                                 " jobpause <printername> <unix-jobid>\n");
652                         return False;
653                 }
654
655                 jobid = atoi(argv[3]);
656
657                 notify_job_status_byname(
658                         argv[2], jobid, JOB_STATUS_DELETING,
659                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
660
661                 notify_job_status_byname(
662                         argv[2], jobid, JOB_STATUS_DELETING|
663                         JOB_STATUS_DELETED,
664                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
665
666                 goto send;
667
668         } else if (strcmp(cmd, "printer") == 0) {
669                 uint32 attribute;
670
671                 if (argc != 5) {
672                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
673                                 "printer <printername> <comment|port|driver> "
674                                 "<value>\n");
675                         return False;
676                 }
677
678                 if (strcmp(argv[3], "comment") == 0) {
679                         attribute = PRINTER_NOTIFY_FIELD_COMMENT;
680                 } else if (strcmp(argv[3], "port") == 0) {
681                         attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
682                 } else if (strcmp(argv[3], "driver") == 0) {
683                         attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
684                 } else {
685                         fprintf(stderr, "Invalid printer command '%s'\n",
686                                 argv[3]);
687                         return False;
688                 }
689
690                 notify_printer_byname(argv[2], attribute,
691                                       CONST_DISCARD(char *, argv[4]));
692
693                 goto send;
694         }
695
696         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
697         return False;
698
699 send:
700         print_notify_send_messages(msg_ctx, 0);
701         return True;
702 }
703
704 /* Close a share */
705
706 static bool do_closeshare(struct messaging_context *msg_ctx,
707                           const struct server_id pid,
708                           const int argc, const char **argv)
709 {
710         if (argc != 2) {
711                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
712                         "<sharename>\n");
713                 return False;
714         }
715
716         return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
717                             strlen(argv[1]) + 1);
718 }
719
720 /* force a blocking lock retry */
721
722 static bool do_lockretry(struct messaging_context *msg_ctx,
723                          const struct server_id pid,
724                          const int argc, const char **argv)
725 {
726         if (argc != 1) {
727                 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
728                 return False;
729         }
730
731         return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
732 }
733
734 /* force a validation of all brl entries, including re-sends. */
735
736 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
737                               const struct server_id pid,
738                               const int argc, const char **argv)
739 {
740         if (argc != 1) {
741                 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
742                 return False;
743         }
744
745         return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
746 }
747
748 /* Force a SAM synchronisation */
749
750 static bool do_samsync(struct messaging_context *msg_ctx,
751                        const struct server_id pid,
752                        const int argc, const char **argv)
753 {
754         if (argc != 1) {
755                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
756                 return False;
757         }
758
759         return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
760 }
761
762 /* Force a SAM replication */
763
764 static bool do_samrepl(struct messaging_context *msg_ctx,
765                        const struct server_id pid,
766                        const int argc, const char **argv)
767 {
768         if (argc != 1) {
769                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
770                 return False;
771         }
772
773         return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
774 }
775
776 /* Display talloc pool usage */
777
778 static bool do_poolusage(struct messaging_context *msg_ctx,
779                          const struct server_id pid,
780                          const int argc, const char **argv)
781 {
782         if (argc != 1) {
783                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
784                 return False;
785         }
786
787         messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
788
789         /* Send a message and register our interest in a reply */
790
791         if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
792                 return False;
793
794         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
795
796         /* No replies were received within the timeout period */
797
798         if (num_replies == 0)
799                 printf("No replies received\n");
800
801         messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
802
803         return num_replies;
804 }
805
806 /* Perform a dmalloc mark */
807
808 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
809                             const struct server_id pid,
810                             const int argc, const char **argv)
811 {
812         if (argc != 1) {
813                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
814                 return False;
815         }
816
817         return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
818 }
819
820 /* Perform a dmalloc changed */
821
822 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
823                                const struct server_id pid,
824                                const int argc, const char **argv)
825 {
826         if (argc != 1) {
827                 fprintf(stderr, "Usage: smbcontrol <dest> "
828                         "dmalloc-log-changed\n");
829                 return False;
830         }
831
832         return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
833                             NULL, 0);
834 }
835
836 /* Shutdown a server process */
837
838 static bool do_shutdown(struct messaging_context *msg_ctx,
839                         const struct server_id pid,
840                         const int argc, const char **argv)
841 {
842         if (argc != 1) {
843                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
844                 return False;
845         }
846
847         return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
848 }
849
850 /* Notify a driver upgrade */
851
852 static bool do_drvupgrade(struct messaging_context *msg_ctx,
853                           const struct server_id pid,
854                           const int argc, const char **argv)
855 {
856         if (argc != 2) {
857                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
858                         "<driver-name>\n");
859                 return False;
860         }
861
862         return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
863                             strlen(argv[1]) + 1);
864 }
865
866 static bool do_winbind_online(struct messaging_context *msg_ctx,
867                               const struct server_id pid,
868                              const int argc, const char **argv)
869 {
870         TDB_CONTEXT *tdb;
871
872         if (argc != 1) {
873                 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
874                 return False;
875         }
876
877         /* Remove the entry in the winbindd_cache tdb to tell a later
878            starting winbindd that we're online. */
879
880         tdb = tdb_open_log(cache_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
881         if (!tdb) {
882                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
883                         cache_path("winbindd_cache.tdb"));
884                 return False;
885         }
886
887         tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
888         tdb_close(tdb);
889
890         return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
891 }
892
893 static bool do_winbind_offline(struct messaging_context *msg_ctx,
894                                const struct server_id pid,
895                              const int argc, const char **argv)
896 {
897         TDB_CONTEXT *tdb;
898         bool ret = False;
899         int retry = 0;
900
901         if (argc != 1) {
902                 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
903                 return False;
904         }
905
906         /* Create an entry in the winbindd_cache tdb to tell a later
907            starting winbindd that we're offline. We may actually create
908            it here... */
909
910         tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
911                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
912                                 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
913
914         if (!tdb) {
915                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
916                         cache_path("winbindd_cache.tdb"));
917                 return False;
918         }
919
920         /* There's a potential race condition that if a child
921            winbindd detects a domain is online at the same time
922            we're trying to tell it to go offline that it might 
923            delete the record we add between us adding it and
924            sending the message. Minimize this by retrying up to
925            5 times. */
926
927         for (retry = 0; retry < 5; retry++) {
928                 TDB_DATA d;
929                 uint8 buf[4];
930
931                 ZERO_STRUCT(d);
932
933                 SIVAL(buf, 0, time(NULL));
934                 d.dptr = buf;
935                 d.dsize = 4;
936
937                 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
938
939                 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
940                                    NULL, 0);
941
942                 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
943                 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
944
945                 if (!d.dptr || d.dsize != 4) {
946                         SAFE_FREE(d.dptr);
947                         DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
948                 } else {
949                         SAFE_FREE(d.dptr);
950                         break;
951                 }
952         }
953
954         tdb_close(tdb);
955         return ret;
956 }
957
958 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
959                                     const struct server_id pid,
960                                     const int argc, const char **argv)
961 {
962         struct server_id myid;
963
964         myid = procid_self();
965
966         if (argc != 1) {
967                 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
968                 return False;
969         }
970
971         messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
972                            print_pid_string_cb);
973
974         if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
975                           sizeof(myid)))
976                 return False;
977
978         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
979
980         /* No replies were received within the timeout period */
981
982         if (num_replies == 0)
983                 printf("No replies received\n");
984
985         messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
986
987         return num_replies;
988 }
989
990 static bool do_dump_event_list(struct messaging_context *msg_ctx,
991                                const struct server_id pid,
992                                const int argc, const char **argv)
993 {
994         struct server_id myid;
995
996         myid = procid_self();
997
998         if (argc != 1) {
999                 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1000                 return False;
1001         }
1002
1003         return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1004 }
1005
1006 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
1007                                         const struct server_id pid,
1008                                         const int argc, const char **argv)
1009 {
1010         const char *domain = NULL;
1011         int domain_len = 0;
1012         struct server_id myid;
1013         uint8_t *buf = NULL;
1014         int buf_len = 0;
1015
1016         myid = procid_self();
1017
1018         if (argc < 1 || argc > 2) {
1019                 fprintf(stderr, "Usage: smbcontrol <dest> dump_domain_list "
1020                         "<domain>\n");
1021                 return false;
1022         }
1023
1024         if (argc == 2) {
1025                 domain = argv[1];
1026                 domain_len = strlen(argv[1]) + 1;
1027         }
1028
1029         messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1030                            print_pid_string_cb);
1031
1032         buf_len = sizeof(myid)+domain_len;
1033         buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1034         if (!buf) {
1035                 return false;
1036         }
1037
1038         memcpy(buf, &myid, sizeof(myid));
1039         memcpy(&buf[sizeof(myid)], domain, domain_len);
1040
1041         if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1042                           buf, buf_len))
1043         {
1044                 SAFE_FREE(buf);
1045                 return false;
1046         }
1047
1048         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1049
1050         /* No replies were received within the timeout period */
1051
1052         SAFE_FREE(buf);
1053         if (num_replies == 0) {
1054                 printf("No replies received\n");
1055         }
1056
1057         messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1058
1059         return num_replies;
1060 }
1061
1062 static void winbind_validate_cache_cb(struct messaging_context *msg,
1063                                       void *private_data,
1064                                       uint32_t msg_type,
1065                                       struct server_id pid,
1066                                       DATA_BLOB *data)
1067 {
1068         char *src_string = procid_str(NULL, &pid);
1069         printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1070                (*(data->data) == 0 ? "" : "NOT "), src_string);
1071         TALLOC_FREE(src_string);
1072         num_replies++;
1073 }
1074
1075 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1076                                       const struct server_id pid,
1077                                       const int argc, const char **argv)
1078 {
1079         struct server_id myid = procid_self();
1080
1081         if (argc != 1) {
1082                 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1083                 return False;
1084         }
1085
1086         messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1087                            winbind_validate_cache_cb);
1088
1089         if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1090                           sizeof(myid))) {
1091                 return False;
1092         }
1093
1094         wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1095
1096         if (num_replies == 0) {
1097                 printf("No replies received\n");
1098         }
1099
1100         messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1101
1102         return num_replies;
1103 }
1104
1105 static bool do_reload_config(struct messaging_context *msg_ctx,
1106                              const struct server_id pid,
1107                              const int argc, const char **argv)
1108 {
1109         if (argc != 1) {
1110                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1111                 return False;
1112         }
1113
1114         return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1115 }
1116
1117 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1118 {
1119         fstring unix_name;
1120         memset( (char *)n, '\0', sizeof(struct nmb_name) );
1121         fstrcpy(unix_name, name);
1122         strupper_m(unix_name);
1123         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1124         n->name_type = (unsigned int)type & 0xFF;
1125         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
1126 }
1127
1128 static bool do_nodestatus(struct messaging_context *msg_ctx,
1129                           const struct server_id pid,
1130                           const int argc, const char **argv)
1131 {
1132         struct packet_struct p;
1133
1134         if (argc != 2) {
1135                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1136                 return False;
1137         }
1138
1139         ZERO_STRUCT(p);
1140
1141         p.ip = interpret_addr2(argv[1]);
1142         p.port = 137;
1143         p.packet_type = NMB_PACKET;
1144
1145         p.packet.nmb.header.name_trn_id = 10;
1146         p.packet.nmb.header.opcode = 0;
1147         p.packet.nmb.header.response = False;
1148         p.packet.nmb.header.nm_flags.bcast = False;
1149         p.packet.nmb.header.nm_flags.recursion_available = False;
1150         p.packet.nmb.header.nm_flags.recursion_desired = False;
1151         p.packet.nmb.header.nm_flags.trunc = False;
1152         p.packet.nmb.header.nm_flags.authoritative = False;
1153         p.packet.nmb.header.rcode = 0;
1154         p.packet.nmb.header.qdcount = 1;
1155         p.packet.nmb.header.ancount = 0;
1156         p.packet.nmb.header.nscount = 0;
1157         p.packet.nmb.header.arcount = 0;
1158         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1159         p.packet.nmb.question.question_type = 0x21;
1160         p.packet.nmb.question.question_class = 0x1;
1161
1162         return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1163 }
1164
1165 /* A list of message type supported */
1166
1167 static const struct {
1168         const char *name;       /* Option name */
1169         bool (*fn)(struct messaging_context *msg_ctx,
1170                    const struct server_id pid,
1171                    const int argc, const char **argv);
1172         const char *help;       /* Short help text */
1173 } msg_types[] = {
1174         { "debug", do_debug, "Set debuglevel"  },
1175         { "force-election", do_election,
1176           "Force a browse election" },
1177         { "ping", do_ping, "Elicit a response" },
1178         { "profile", do_profile, "" },
1179         { "inject", do_inject_fault,
1180             "Inject a fatal signal into a running smbd"},
1181         { "stacktrace", do_daemon_stack_trace,
1182             "Display a stack trace of a daemon" },
1183         { "profilelevel", do_profilelevel, "" },
1184         { "debuglevel", do_debuglevel, "Display current debuglevels" },
1185         { "printnotify", do_printnotify, "Send a print notify message" },
1186         { "close-share", do_closeshare, "Forcibly disconnect a share" },
1187         { "lockretry", do_lockretry, "Force a blocking lock retry" },
1188         { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1189         { "samsync", do_samsync, "Initiate SAM synchronisation" },
1190         { "samrepl", do_samrepl, "Initiate SAM replication" },
1191         { "pool-usage", do_poolusage, "Display talloc memory usage" },
1192         { "dmalloc-mark", do_dmalloc_mark, "" },
1193         { "dmalloc-log-changed", do_dmalloc_changed, "" },
1194         { "shutdown", do_shutdown, "Shut down daemon" },
1195         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1196         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1197         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1198         { "online", do_winbind_online, "Ask winbind to go into online state"},
1199         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1200         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1201         { "dump-event-list", do_dump_event_list, "Dump event list"},
1202         { "validate-cache" , do_winbind_validate_cache,
1203           "Validate winbind's credential cache" },
1204         { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1205         { "noop", do_noop, "Do nothing" },
1206         { NULL }
1207 };
1208
1209 /* Display usage information */
1210
1211 static void usage(poptContext pc)
1212 {
1213         int i;
1214
1215         poptPrintHelp(pc, stderr, 0);
1216
1217         fprintf(stderr, "\n");
1218         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1219                 "process ID\n");
1220
1221         fprintf(stderr, "\n");
1222         fprintf(stderr, "<message-type> is one of:\n");
1223
1224         for (i = 0; msg_types[i].name; i++) 
1225             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
1226                     msg_types[i].help);
1227
1228         fprintf(stderr, "\n");
1229
1230         exit(1);
1231 }
1232
1233 /* Return the pid number for a string destination */
1234
1235 static struct server_id parse_dest(const char *dest)
1236 {
1237         struct server_id result = {-1};
1238         pid_t pid;
1239
1240         /* Zero is a special return value for broadcast to all processes */
1241
1242         if (strequal(dest, "all")) {
1243                 return interpret_pid(MSG_BROADCAST_PID_STR);
1244         }
1245
1246         /* Try self - useful for testing */
1247
1248         if (strequal(dest, "self")) {
1249                 return procid_self();
1250         }
1251
1252         /* Fix winbind typo. */
1253         if (strequal(dest, "winbind")) {
1254                 dest = "winbindd";
1255         }
1256
1257         /* Check for numeric pid number */
1258         result = interpret_pid(dest);
1259
1260         /* Zero isn't valid if not "all". */
1261         if (result.pid && procid_valid(&result)) {
1262                 return result;
1263         }
1264
1265         /* Look up other destinations in pidfile directory */
1266
1267         if ((pid = pidfile_pid(dest)) != 0) {
1268                 return pid_to_procid(pid);
1269         }
1270
1271         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1272
1273         return result;
1274 }
1275
1276 /* Execute smbcontrol command */
1277
1278 static bool do_command(struct messaging_context *msg_ctx,
1279                        int argc, const char **argv)
1280 {
1281         const char *dest = argv[0], *command = argv[1];
1282         struct server_id pid;
1283         int i;
1284
1285         /* Check destination */
1286
1287         pid = parse_dest(dest);
1288         if (!procid_valid(&pid)) {
1289                 return False;
1290         }
1291
1292         /* Check command */
1293
1294         for (i = 0; msg_types[i].name; i++) {
1295                 if (strequal(command, msg_types[i].name))
1296                         return msg_types[i].fn(msg_ctx, pid,
1297                                                argc - 1, argv + 1);
1298         }
1299
1300         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1301
1302         return False;
1303 }
1304
1305 static void smbcontrol_help(poptContext pc,
1306                     enum poptCallbackReason preason,
1307                     struct poptOption * poption,
1308                     const char * parg,
1309                     void * pdata)
1310 {
1311         if (poption->shortName != '?') {
1312                 poptPrintUsage(pc, stdout, 0);
1313         } else {
1314                 usage(pc);
1315         }
1316
1317         exit(0);
1318 }
1319
1320 struct poptOption help_options[] = {
1321         { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1322           NULL, NULL },
1323         { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1324         { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1325         { NULL }
1326 } ;
1327
1328 /* Main program */
1329
1330 int main(int argc, const char **argv)
1331 {
1332         poptContext pc;
1333         int opt;
1334         struct tevent_context *evt_ctx;
1335         struct messaging_context *msg_ctx;
1336
1337         static struct poptOption long_options[] = {
1338                 /* POPT_AUTOHELP */
1339                 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1340                                         0, "Help options:", NULL },
1341                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
1342                   "Set timeout value in seconds", "TIMEOUT" },
1343
1344                 POPT_COMMON_SAMBA
1345                 POPT_TABLEEND
1346         };
1347         TALLOC_CTX *frame = talloc_stackframe();
1348         int ret = 0;
1349
1350         load_case_tables();
1351
1352         setup_logging(argv[0],True);
1353
1354         /* Parse command line arguments using popt */
1355
1356         pc = poptGetContext(
1357                 "smbcontrol", argc, (const char **)argv, long_options, 0);
1358
1359         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1360                                "<parameters>");
1361
1362         if (argc == 1)
1363                 usage(pc);
1364
1365         while ((opt = poptGetNextOpt(pc)) != -1) {
1366                 switch(opt) {
1367                 case 't':       /* --timeout */
1368                         break;
1369                 default:
1370                         fprintf(stderr, "Invalid option\n");
1371                         poptPrintHelp(pc, stderr, 0);
1372                         break;
1373                 }
1374         }
1375
1376         /* We should now have the remaining command line arguments in
1377            argv.  The argc parameter should have been decremented to the
1378            correct value in the above switch statement. */
1379
1380         argv = (const char **)poptGetArgs(pc);
1381         argc = 0;
1382         if (argv != NULL) {
1383                 while (argv[argc] != NULL) {
1384                         argc++;
1385                 }
1386         }
1387
1388         if (argc <= 1)
1389                 usage(pc);
1390
1391         lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1392
1393         /* Need to invert sense of return code -- samba
1394          * routines mostly return True==1 for success, but
1395          * shell needs 0. */ 
1396
1397         if (!(evt_ctx = tevent_context_init(NULL)) ||
1398             !(msg_ctx = messaging_init(NULL, procid_self(), evt_ctx))) {
1399                 fprintf(stderr, "could not init messaging context\n");
1400                 TALLOC_FREE(frame);
1401                 exit(1);
1402         }
1403
1404         ret = !do_command(msg_ctx, argc, argv);
1405         TALLOC_FREE(frame);
1406         return ret;
1407 }