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