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