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