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