smbstatus: add json items to traverse_struct
[Samba.git] / source3 / utils / smbcontrol.c
blobab57bd4804248ae3f857244aa6b43c4105a99662
1 /*
2 Unix SMB/CIFS implementation.
4 Send messages to other Samba daemons
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
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.
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.
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/>.
26 #include "includes.h"
27 #include "system/filesys.h"
28 #include "lib/util/server_id.h"
29 #include "lib/cmdline/cmdline.h"
30 #include "librpc/gen_ndr/spoolss.h"
31 #include "nt_printing.h"
32 #include "printing/notify.h"
33 #include "libsmb/nmblib.h"
34 #include "messages.h"
35 #include "util_tdb.h"
36 #include "../lib/util/pidfile.h"
37 #include "serverid.h"
38 #include "cmdline_contexts.h"
39 #include "lib/util/string_wrappers.h"
40 #include "lib/global_contexts.h"
42 #ifdef HAVE_LIBUNWIND_H
43 #include <libunwind.h>
44 #endif
46 #ifdef HAVE_LIBUNWIND_PTRACE_H
47 #include <libunwind-ptrace.h>
48 #endif
50 #ifdef HAVE_SYS_PTRACE_H
51 #include <sys/ptrace.h>
52 #endif
54 /* Default timeout value when waiting for replies (in seconds) */
56 #define DEFAULT_TIMEOUT 10
58 static int timeout = DEFAULT_TIMEOUT;
59 static int num_replies; /* Used by message callback fns */
61 /* Send a message to a destination pid. Zero means broadcast smbd. */
63 static bool send_message(struct messaging_context *msg_ctx,
64 struct server_id pid, int msg_type,
65 const void *buf, int len)
67 if (procid_to_pid(&pid) != 0)
68 return NT_STATUS_IS_OK(
69 messaging_send_buf(msg_ctx, pid, msg_type,
70 (const uint8_t *)buf, len));
72 messaging_send_all(msg_ctx, msg_type, buf, len);
74 return true;
77 static void smbcontrol_timeout(struct tevent_context *event_ctx,
78 struct tevent_timer *te,
79 struct timeval now,
80 void *private_data)
82 bool *timed_out = (bool *)private_data;
83 TALLOC_FREE(te);
84 *timed_out = True;
87 /* Wait for one or more reply messages */
89 static void wait_replies(struct tevent_context *ev_ctx,
90 struct messaging_context *msg_ctx,
91 bool multiple_replies)
93 struct tevent_timer *te;
94 bool timed_out = False;
96 te = tevent_add_timer(ev_ctx, NULL,
97 timeval_current_ofs(timeout, 0),
98 smbcontrol_timeout, (void *)&timed_out);
99 if (te == NULL) {
100 DEBUG(0, ("tevent_add_timer failed\n"));
101 return;
104 while (!timed_out) {
105 int ret;
106 if (num_replies > 0 && !multiple_replies)
107 break;
108 ret = tevent_loop_once(ev_ctx);
109 if (ret != 0) {
110 break;
115 /* Message handler callback that displays the PID and a string on stdout */
117 static void print_pid_string_cb(struct messaging_context *msg,
118 void *private_data,
119 uint32_t msg_type,
120 struct server_id pid,
121 DATA_BLOB *data)
123 struct server_id_buf pidstr;
125 printf("PID %s: %.*s", server_id_str_buf(pid, &pidstr),
126 (int)data->length, (const char *)data->data);
127 num_replies++;
130 /* Send no message. Useful for testing. */
132 static bool do_noop(struct tevent_context *ev_ctx,
133 struct messaging_context *msg_ctx,
134 const struct server_id pid,
135 const int argc, const char **argv)
137 if (argc != 1) {
138 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
139 return False;
142 /* Move along, nothing to see here */
144 return True;
147 /* Send a debug string */
149 static bool do_debug(struct tevent_context *ev_ctx,
150 struct messaging_context *msg_ctx,
151 const struct server_id pid,
152 const int argc, const char **argv)
154 if (argc != 2) {
155 fprintf(stderr, "Usage: smbcontrol <dest> debug "
156 "<debug-string>\n");
157 return False;
160 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
161 strlen(argv[1]) + 1);
165 static bool do_idmap(struct tevent_context *ev,
166 struct messaging_context *msg_ctx,
167 const struct server_id pid,
168 const int argc, const char **argv)
170 static const char* usage = "Usage: "
171 "smbcontrol <dest> idmap <cmd> [arg]\n"
172 "\tcmd:"
173 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
174 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
175 const char* arg = NULL;
176 int arglen = 0;
177 int msg_type;
179 switch (argc) {
180 case 2:
181 break;
182 case 3:
183 arg = argv[2];
184 arglen = strlen(arg) + 1;
185 break;
186 default:
187 fprintf(stderr, "%s", usage);
188 return false;
191 if (strcmp(argv[1], "delete") == 0) {
192 msg_type = ID_CACHE_DELETE;
194 else if (strcmp(argv[1], "kill") == 0) {
195 msg_type = ID_CACHE_KILL;
197 else if (strcmp(argv[1], "help") == 0) {
198 fprintf(stdout, "%s", usage);
199 return true;
201 else {
202 fprintf(stderr, "%s", usage);
203 return false;
206 return send_message(msg_ctx, pid, msg_type, arg, arglen);
210 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
212 /* Return the name of a process given it's PID. This will only work on Linux,
213 * but that's probably moot since this whole stack tracing implementation is
214 * Linux-specific anyway.
216 static const char * procname(pid_t pid, char * buf, size_t bufsz)
218 char path[64];
219 FILE * fp;
221 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
222 (unsigned long long)pid);
223 if ((fp = fopen(path, "r")) == NULL) {
224 return NULL;
227 fgets(buf, bufsz, fp);
229 fclose(fp);
230 return buf;
233 static void print_stack_trace(pid_t pid, int * count)
235 void * pinfo = NULL;
236 unw_addr_space_t aspace = NULL;
237 unw_cursor_t cursor;
238 unw_word_t ip, sp;
240 char nbuf[256];
241 unw_word_t off;
243 int ret;
245 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
246 fprintf(stderr,
247 "Failed to attach to process %llu: %s\n",
248 (unsigned long long)pid, strerror(errno));
249 return;
252 /* Wait until the attach is complete. */
253 waitpid(pid, NULL, 0);
255 if (((pinfo = _UPT_create(pid)) == NULL) ||
256 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
257 /* Probably out of memory. */
258 fprintf(stderr,
259 "Unable to initialize stack unwind for process %llu\n",
260 (unsigned long long)pid);
261 goto cleanup;
264 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
265 fprintf(stderr,
266 "Unable to unwind stack for process %llu: %s\n",
267 (unsigned long long)pid, unw_strerror(ret));
268 goto cleanup;
271 if (*count > 0) {
272 printf("\n");
275 if (procname(pid, nbuf, sizeof(nbuf))) {
276 printf("Stack trace for process %llu (%s):\n",
277 (unsigned long long)pid, nbuf);
278 } else {
279 printf("Stack trace for process %llu:\n",
280 (unsigned long long)pid);
283 while (unw_step(&cursor) > 0) {
284 ip = sp = off = 0;
285 unw_get_reg(&cursor, UNW_REG_IP, &ip);
286 unw_get_reg(&cursor, UNW_REG_SP, &sp);
288 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
289 if (ret != 0 && ret != -UNW_ENOMEM) {
290 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
292 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
293 nbuf, (long long)off, (long long)ip,
294 (long long)sp);
297 (*count)++;
299 cleanup:
300 if (aspace) {
301 unw_destroy_addr_space(aspace);
304 if (pinfo) {
305 _UPT_destroy(pinfo);
308 ptrace(PTRACE_DETACH, pid, NULL, NULL);
311 static int stack_trace_server(pid_t pid, void *priv)
313 print_stack_trace(pid, (int *)priv);
314 return 0;
317 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
318 struct messaging_context *msg_ctx,
319 const struct server_id pid,
320 const int argc, const char **argv)
322 pid_t dest;
323 int count = 0;
325 if (argc != 1) {
326 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
327 return False;
330 dest = procid_to_pid(&pid);
332 if (dest != 0) {
333 /* It would be nice to be able to make sure that this PID is
334 * the PID of a smbd/winbind/nmbd process, not some random PID
335 * the user liked the look of. It doesn't seem like it's worth
336 * the effort at the moment, however.
338 print_stack_trace(dest, &count);
339 } else {
340 messaging_dgm_forall(stack_trace_server, &count);
343 return True;
346 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
348 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
349 struct messaging_context *msg_ctx,
350 const struct server_id pid,
351 const int argc, const char **argv)
353 fprintf(stderr,
354 "Daemon stack tracing is not supported on this platform\n");
355 return False;
358 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
360 /* Inject a fault (fatal signal) into a running smbd */
362 static bool do_inject_fault(struct tevent_context *ev_ctx,
363 struct messaging_context *msg_ctx,
364 const struct server_id pid,
365 const int argc, const char **argv)
367 if (argc != 2) {
368 fprintf(stderr, "Usage: smbcontrol <dest> inject "
369 "<bus|hup|term|internal|segv>\n");
370 return False;
373 #if !defined(DEVELOPER) && !defined(ENABLE_SELFTEST)
374 fprintf(stderr, "Fault injection is only available in "
375 "developer and self test builds\n");
376 return False;
377 #else /* DEVELOPER || ENABLE_SELFTEST */
379 int sig = 0;
381 if (strcmp(argv[1], "bus") == 0) {
382 sig = SIGBUS;
383 } else if (strcmp(argv[1], "hup") == 0) {
384 sig = SIGHUP;
385 } else if (strcmp(argv[1], "term") == 0) {
386 sig = SIGTERM;
387 } else if (strcmp(argv[1], "segv") == 0) {
388 sig = SIGSEGV;
389 } else if (strcmp(argv[1], "internal") == 0) {
390 /* Force an internal error, ie. an unclean exit. */
391 sig = -1;
392 } else {
393 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
394 return False;
397 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
398 &sig, sizeof(int));
400 #endif /* DEVELOPER || ENABLE_SELFTEST */
403 static bool do_sleep(struct tevent_context *ev_ctx,
404 struct messaging_context *msg_ctx,
405 const struct server_id pid,
406 const int argc, const char **argv)
408 #if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
409 unsigned int seconds;
410 long input;
411 const long MAX_SLEEP = 60 * 60; /* One hour maximum sleep */
412 #endif
414 if (argc != 2) {
415 fprintf(stderr, "Usage: smbcontrol <dest> sleep seconds\n");
416 return False;
419 #if !defined(DEVELOPER) && !defined(ENABLE_SELFTEST)
420 fprintf(stderr, "Sleep is only available in "
421 "developer and self test builds\n");
422 return False;
423 #else /* DEVELOPER || ENABLE_SELFTEST */
425 input = atol(argv[1]);
426 if (input < 1 || input > MAX_SLEEP) {
427 fprintf(stderr,
428 "Invalid duration for sleep '%s'\n"
429 "It should be at least 1 second and no more than %ld\n",
430 argv[1],
431 MAX_SLEEP);
432 return False;
434 seconds = input;
435 return send_message(msg_ctx, pid,
436 MSG_SMB_SLEEP,
437 &seconds,
438 sizeof(unsigned int));
439 #endif /* DEVELOPER || ENABLE_SELFTEST */
442 /* Force a browser election */
444 static bool do_election(struct tevent_context *ev_ctx,
445 struct messaging_context *msg_ctx,
446 const struct server_id pid,
447 const int argc, const char **argv)
449 if (argc != 1) {
450 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
451 return False;
454 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
457 /* Ping a samba daemon process */
459 static void pong_cb(struct messaging_context *msg,
460 void *private_data,
461 uint32_t msg_type,
462 struct server_id pid,
463 DATA_BLOB *data)
465 struct server_id_buf src_string;
466 printf("PONG from pid %s\n", server_id_str_buf(pid, &src_string));
467 num_replies++;
470 static bool do_ping(struct tevent_context *ev_ctx,
471 struct messaging_context *msg_ctx,
472 const struct server_id pid,
473 const int argc, const char **argv)
475 if (argc != 1) {
476 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
477 return False;
480 /* Send a message and register our interest in a reply */
482 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
483 return False;
485 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
487 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
489 /* No replies were received within the timeout period */
491 if (num_replies == 0)
492 printf("No replies received\n");
494 messaging_deregister(msg_ctx, MSG_PONG, NULL);
496 return num_replies;
499 /* Set profiling options */
501 static bool do_profile(struct tevent_context *ev_ctx,
502 struct messaging_context *msg_ctx,
503 const struct server_id pid,
504 const int argc, const char **argv)
506 int v;
508 if (argc != 2) {
509 fprintf(stderr, "Usage: smbcontrol <dest> profile "
510 "<off|count|on|flush>\n");
511 return False;
514 if (strcmp(argv[1], "off") == 0) {
515 v = 0;
516 } else if (strcmp(argv[1], "count") == 0) {
517 v = 1;
518 } else if (strcmp(argv[1], "on") == 0) {
519 v = 2;
520 } else if (strcmp(argv[1], "flush") == 0) {
521 v = 3;
522 } else {
523 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
524 return False;
527 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
530 /* Return the profiling level */
532 static void profilelevel_cb(struct messaging_context *msg_ctx,
533 void *private_data,
534 uint32_t msg_type,
535 struct server_id pid,
536 DATA_BLOB *data)
538 int level;
539 const char *s;
541 num_replies++;
543 if (data->length != sizeof(int)) {
544 fprintf(stderr, "invalid message length %ld returned\n",
545 (unsigned long)data->length);
546 return;
549 memcpy(&level, data->data, sizeof(int));
551 switch (level) {
552 case 0:
553 s = "not enabled";
554 break;
555 case 1:
556 s = "off";
557 break;
558 case 3:
559 s = "count only";
560 break;
561 case 7:
562 s = "count and time";
563 break;
564 default:
565 s = "BOGUS";
566 break;
569 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
572 static void profilelevel_rqst(struct messaging_context *msg_ctx,
573 void *private_data,
574 uint32_t msg_type,
575 struct server_id pid,
576 DATA_BLOB *data)
578 int v = 0;
580 /* Send back a dummy reply */
582 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
585 static bool do_profilelevel(struct tevent_context *ev_ctx,
586 struct messaging_context *msg_ctx,
587 const struct server_id pid,
588 const int argc, const char **argv)
590 if (argc != 1) {
591 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
592 return False;
595 /* Send a message and register our interest in a reply */
597 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
598 return False;
600 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
601 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
602 profilelevel_rqst);
604 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
606 /* No replies were received within the timeout period */
608 if (num_replies == 0)
609 printf("No replies received\n");
611 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
613 return num_replies;
616 /* Display debug level settings */
618 static bool do_debuglevel(struct tevent_context *ev_ctx,
619 struct messaging_context *msg_ctx,
620 const struct server_id pid,
621 const int argc, const char **argv)
623 if (argc != 1) {
624 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
625 return False;
628 /* Send a message and register our interest in a reply */
630 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
631 return False;
633 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
635 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
637 /* No replies were received within the timeout period */
639 if (num_replies == 0)
640 printf("No replies received\n");
642 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
644 return num_replies;
647 /* Send a print notify message */
649 static bool do_printnotify(struct tevent_context *ev_ctx,
650 struct messaging_context *msg_ctx,
651 const struct server_id pid,
652 const int argc, const char **argv)
654 const char *cmd;
656 /* Check for subcommand */
658 if (argc == 1) {
659 fprintf(stderr, "Must specify subcommand:\n");
660 fprintf(stderr, "\tqueuepause <printername>\n");
661 fprintf(stderr, "\tqueueresume <printername>\n");
662 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
663 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
664 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
665 fprintf(stderr, "\tprinter <printername> <comment|port|"
666 "driver> <value>\n");
668 return False;
671 cmd = argv[1];
673 if (strcmp(cmd, "queuepause") == 0) {
675 if (argc != 3) {
676 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
677 " queuepause <printername>\n");
678 return False;
681 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
682 PRINTER_STATUS_PAUSED);
684 goto send;
686 } else if (strcmp(cmd, "queueresume") == 0) {
688 if (argc != 3) {
689 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
690 " queuereume <printername>\n");
691 return False;
694 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
695 PRINTER_STATUS_OK);
697 goto send;
699 } else if (strcmp(cmd, "jobpause") == 0) {
700 int jobid;
702 if (argc != 4) {
703 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
704 " jobpause <printername> <unix-jobid>\n");
705 return False;
708 jobid = atoi(argv[3]);
710 notify_job_status_byname(
711 ev_ctx, msg_ctx,
712 argv[2], jobid, JOB_STATUS_PAUSED,
713 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
715 goto send;
717 } else if (strcmp(cmd, "jobresume") == 0) {
718 int jobid;
720 if (argc != 4) {
721 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
722 " jobpause <printername> <unix-jobid>\n");
723 return False;
726 jobid = atoi(argv[3]);
728 notify_job_status_byname(
729 ev_ctx, msg_ctx,
730 argv[2], jobid, JOB_STATUS_QUEUED,
731 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
733 goto send;
735 } else if (strcmp(cmd, "jobdelete") == 0) {
736 int jobid;
738 if (argc != 4) {
739 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
740 " jobpause <printername> <unix-jobid>\n");
741 return False;
744 jobid = atoi(argv[3]);
746 notify_job_status_byname(
747 ev_ctx, msg_ctx,
748 argv[2], jobid, JOB_STATUS_DELETING,
749 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
751 notify_job_status_byname(
752 ev_ctx, msg_ctx,
753 argv[2], jobid, JOB_STATUS_DELETING|
754 JOB_STATUS_DELETED,
755 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
757 goto send;
759 } else if (strcmp(cmd, "printer") == 0) {
760 uint32_t attribute;
762 if (argc != 5) {
763 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
764 "printer <printername> <comment|port|driver> "
765 "<value>\n");
766 return False;
769 if (strcmp(argv[3], "comment") == 0) {
770 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
771 } else if (strcmp(argv[3], "port") == 0) {
772 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
773 } else if (strcmp(argv[3], "driver") == 0) {
774 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
775 } else {
776 fprintf(stderr, "Invalid printer command '%s'\n",
777 argv[3]);
778 return False;
781 notify_printer_byname(ev_ctx, msg_ctx, argv[2], attribute,
782 discard_const_p(char, argv[4]));
784 goto send;
787 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
788 return False;
790 send:
791 print_notify_send_messages(msg_ctx, 0);
792 return True;
795 /* Close a share */
797 static bool do_closeshare(struct tevent_context *ev_ctx,
798 struct messaging_context *msg_ctx,
799 const struct server_id pid,
800 const int argc, const char **argv)
802 if (argc != 2) {
803 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
804 "<sharename>\n");
805 return False;
808 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
809 strlen(argv[1]) + 1);
813 * Close a share if access denied by now
816 static bool do_close_denied_share(
817 struct tevent_context *ev_ctx,
818 struct messaging_context *msg_ctx,
819 const struct server_id pid,
820 const int argc, const char **argv)
822 if (argc != 2) {
823 fprintf(stderr, "Usage: smbcontrol <dest> close-denied-share "
824 "<sharename>\n");
825 return False;
828 return send_message(
829 msg_ctx,
830 pid,
831 MSG_SMB_FORCE_TDIS_DENIED,
832 argv[1],
833 strlen(argv[1]) + 1);
836 /* Kill a client by IP address */
837 static bool do_kill_client_by_ip(struct tevent_context *ev_ctx,
838 struct messaging_context *msg_ctx,
839 const struct server_id pid,
840 const int argc, const char **argv)
842 if (argc != 2) {
843 fprintf(stderr, "Usage: smbcontrol <dest> kill-client-ip "
844 "<IP address>\n");
845 return false;
848 if (!is_ipaddress_v4(argv[1]) && !is_ipaddress_v6(argv[1])) {
849 fprintf(stderr, "%s is not a valid IP address!\n", argv[1]);
850 return false;
853 return send_message(msg_ctx, pid, MSG_SMB_KILL_CLIENT_IP,
854 argv[1], strlen(argv[1]) + 1);
857 /* Tell winbindd an IP got dropped */
859 static bool do_ip_dropped(struct tevent_context *ev_ctx,
860 struct messaging_context *msg_ctx,
861 const struct server_id pid,
862 const int argc, const char **argv)
864 if (argc != 2) {
865 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
866 "<ip-address>\n");
867 return False;
870 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
871 strlen(argv[1]) + 1);
874 /* Display talloc pool usage */
876 static bool do_poolusage(struct tevent_context *ev_ctx,
877 struct messaging_context *msg_ctx,
878 const struct server_id dst,
879 const int argc, const char **argv)
881 pid_t pid = procid_to_pid(&dst);
882 int stdout_fd = 1;
884 if (argc != 1) {
885 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
886 return False;
889 if (pid == 0) {
890 fprintf(stderr, "Can only send to a specific PID\n");
891 return false;
894 messaging_send_iov(
895 msg_ctx,
896 dst,
897 MSG_REQ_POOL_USAGE,
898 NULL,
900 &stdout_fd,
903 return true;
906 static bool do_rpc_dump_status(
907 struct tevent_context *ev_ctx,
908 struct messaging_context *msg_ctx,
909 const struct server_id dst,
910 const int argc,
911 const char **argv)
913 pid_t pid = procid_to_pid(&dst);
914 int stdout_fd = 1;
916 if (argc != 1) {
917 fprintf(stderr,
918 "Usage: smbcontrol <dest> rpc-dump-status\n");
919 return False;
922 if (pid == 0) {
923 fprintf(stderr, "Can only send to a specific PID\n");
924 return false;
927 messaging_send_iov(
928 msg_ctx,
929 dst,
930 MSG_RPC_DUMP_STATUS,
931 NULL,
933 &stdout_fd,
936 return true;
939 /* Fetch and print the ringbuf log */
941 static void print_ringbuf_log_cb(struct messaging_context *msg,
942 void *private_data,
943 uint32_t msg_type,
944 struct server_id pid,
945 DATA_BLOB *data)
947 printf("%s", (const char *)data->data);
948 num_replies++;
951 static bool do_ringbuflog(struct tevent_context *ev_ctx,
952 struct messaging_context *msg_ctx,
953 const struct server_id pid,
954 const int argc, const char **argv)
956 if (argc != 1) {
957 fprintf(stderr, "Usage: smbcontrol <dest> ringbuf-log\n");
958 return false;
961 messaging_register(msg_ctx, NULL, MSG_RINGBUF_LOG,
962 print_ringbuf_log_cb);
964 /* Send a message and register our interest in a reply */
966 if (!send_message(msg_ctx, pid, MSG_REQ_RINGBUF_LOG, NULL, 0)) {
967 return false;
970 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
972 /* No replies were received within the timeout period */
974 if (num_replies == 0) {
975 printf("No replies received\n");
978 messaging_deregister(msg_ctx, MSG_RINGBUF_LOG, NULL);
980 return num_replies != 0;
983 /* Perform a dmalloc mark */
985 static bool do_dmalloc_mark(struct tevent_context *ev_ctx,
986 struct messaging_context *msg_ctx,
987 const struct server_id pid,
988 const int argc, const char **argv)
990 if (argc != 1) {
991 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
992 return False;
995 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
998 /* Perform a dmalloc changed */
1000 static bool do_dmalloc_changed(struct tevent_context *ev_ctx,
1001 struct messaging_context *msg_ctx,
1002 const struct server_id pid,
1003 const int argc, const char **argv)
1005 if (argc != 1) {
1006 fprintf(stderr, "Usage: smbcontrol <dest> "
1007 "dmalloc-log-changed\n");
1008 return False;
1011 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
1012 NULL, 0);
1015 static void print_uint32_cb(struct messaging_context *msg, void *private_data,
1016 uint32_t msg_type, struct server_id pid,
1017 DATA_BLOB *data)
1019 uint32_t num_children;
1021 if (data->length != sizeof(uint32_t)) {
1022 printf("Invalid response: %d bytes long\n",
1023 (int)data->length);
1024 goto done;
1026 num_children = IVAL(data->data, 0);
1027 printf("%u children\n", (unsigned)num_children);
1028 done:
1029 num_replies++;
1032 static bool do_num_children(struct tevent_context *ev_ctx,
1033 struct messaging_context *msg_ctx,
1034 const struct server_id pid,
1035 const int argc, const char **argv)
1037 if (argc != 1) {
1038 fprintf(stderr, "Usage: smbcontrol <dest> num-children\n");
1039 return False;
1042 messaging_register(msg_ctx, NULL, MSG_SMB_NUM_CHILDREN,
1043 print_uint32_cb);
1045 /* Send a message and register our interest in a reply */
1047 if (!send_message(msg_ctx, pid, MSG_SMB_TELL_NUM_CHILDREN, NULL, 0))
1048 return false;
1050 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1052 /* No replies were received within the timeout period */
1054 if (num_replies == 0)
1055 printf("No replies received\n");
1057 messaging_deregister(msg_ctx, MSG_SMB_NUM_CHILDREN, NULL);
1059 return num_replies;
1062 static bool do_msg_cleanup(struct tevent_context *ev_ctx,
1063 struct messaging_context *msg_ctx,
1064 const struct server_id pid,
1065 const int argc, const char **argv)
1067 int ret;
1069 ret = messaging_cleanup(msg_ctx, pid.pid);
1071 printf("cleanup(%u) returned %s\n", (unsigned)pid.pid,
1072 ret ? strerror(ret) : "ok");
1074 return (ret == 0);
1077 /* Shutdown a server process */
1079 static bool do_shutdown(struct tevent_context *ev_ctx,
1080 struct messaging_context *msg_ctx,
1081 const struct server_id pid,
1082 const int argc, const char **argv)
1084 if (argc != 1) {
1085 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
1086 return False;
1089 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
1092 /* Notify a driver upgrade */
1094 static bool do_drvupgrade(struct tevent_context *ev_ctx,
1095 struct messaging_context *msg_ctx,
1096 const struct server_id pid,
1097 const int argc, const char **argv)
1099 if (argc != 2) {
1100 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
1101 "<driver-name>\n");
1102 return False;
1105 return send_message(msg_ctx, pid, MSG_PRINTER_DRVUPGRADE, argv[1],
1106 strlen(argv[1]) + 1);
1109 static bool do_winbind_online(struct tevent_context *ev_ctx,
1110 struct messaging_context *msg_ctx,
1111 const struct server_id pid,
1112 const int argc, const char **argv)
1114 TDB_CONTEXT *tdb;
1115 char *db_path;
1117 if (argc != 1) {
1118 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
1119 return False;
1122 db_path = state_path(talloc_tos(), "winbindd_cache.tdb");
1123 if (db_path == NULL) {
1124 return false;
1127 /* Remove the entry in the winbindd_cache tdb to tell a later
1128 starting winbindd that we're online. */
1130 tdb = tdb_open_log(db_path, 0, TDB_DEFAULT, O_RDWR, 0600);
1131 if (!tdb) {
1132 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
1133 db_path);
1134 TALLOC_FREE(db_path);
1135 return False;
1138 TALLOC_FREE(db_path);
1139 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
1140 tdb_close(tdb);
1142 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
1145 static bool do_winbind_offline(struct tevent_context *ev_ctx,
1146 struct messaging_context *msg_ctx,
1147 const struct server_id pid,
1148 const int argc, const char **argv)
1150 TDB_CONTEXT *tdb;
1151 bool ret = False;
1152 int retry = 0;
1153 char *db_path;
1155 if (argc != 1) {
1156 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
1157 return False;
1160 db_path = state_path(talloc_tos(), "winbindd_cache.tdb");
1161 if (db_path == NULL) {
1162 return false;
1165 /* Create an entry in the winbindd_cache tdb to tell a later
1166 starting winbindd that we're offline. We may actually create
1167 it here... */
1169 tdb = tdb_open_log(db_path,
1170 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
1171 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
1172 O_RDWR|O_CREAT, 0600);
1174 if (!tdb) {
1175 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
1176 db_path);
1177 TALLOC_FREE(db_path);
1178 return False;
1180 TALLOC_FREE(db_path);
1182 /* There's a potential race condition that if a child
1183 winbindd detects a domain is online at the same time
1184 we're trying to tell it to go offline that it might
1185 delete the record we add between us adding it and
1186 sending the message. Minimize this by retrying up to
1187 5 times. */
1189 for (retry = 0; retry < 5; retry++) {
1190 uint8_t buf[4];
1191 TDB_DATA d = { .dptr = buf, .dsize = sizeof(buf) };
1193 SIVAL(buf, 0, time(NULL));
1195 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1197 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1198 NULL, 0);
1200 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1201 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1202 if (d.dptr != NULL && d.dsize == 4) {
1203 SAFE_FREE(d.dptr);
1204 break;
1207 SAFE_FREE(d.dptr);
1208 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1211 tdb_close(tdb);
1212 return ret;
1215 static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx,
1216 struct messaging_context *msg_ctx,
1217 const struct server_id pid,
1218 const int argc, const char **argv)
1220 if (argc != 1) {
1221 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1222 return False;
1225 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1226 print_pid_string_cb);
1228 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, NULL, 0)) {
1229 return False;
1232 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1234 /* No replies were received within the timeout period */
1236 if (num_replies == 0)
1237 printf("No replies received\n");
1239 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1241 return num_replies;
1244 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1245 struct messaging_context *msg_ctx,
1246 const struct server_id pid,
1247 const int argc, const char **argv)
1249 const char *domain = NULL;
1250 int domain_len = 0;
1252 if (argc < 1 || argc > 2) {
1253 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1254 "<domain>\n");
1255 return false;
1258 if (argc == 2) {
1259 domain = argv[1];
1260 domain_len = strlen(argv[1]) + 1;
1263 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1264 print_pid_string_cb);
1266 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1267 domain, domain_len))
1269 return false;
1272 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1274 /* No replies were received within the timeout period */
1276 if (num_replies == 0) {
1277 printf("No replies received\n");
1280 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1282 return num_replies;
1285 static bool do_msg_disconnect_dc(struct tevent_context *ev_ctx,
1286 struct messaging_context *msg_ctx,
1287 const struct server_id pid,
1288 const int argc, const char **argv)
1290 if (argc != 1) {
1291 fprintf(stderr, "Usage: smbcontrol <dest> disconnect-dc\n");
1292 return False;
1295 return send_message(msg_ctx, pid, MSG_WINBIND_DISCONNECT_DC, NULL, 0);
1298 static void winbind_validate_cache_cb(struct messaging_context *msg,
1299 void *private_data,
1300 uint32_t msg_type,
1301 struct server_id pid,
1302 DATA_BLOB *data)
1304 struct server_id_buf src_string;
1305 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1306 (*(data->data) == 0 ? "" : "NOT "),
1307 server_id_str_buf(pid, &src_string));
1308 num_replies++;
1311 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1312 struct messaging_context *msg_ctx,
1313 const struct server_id pid,
1314 const int argc, const char **argv)
1316 struct server_id myid;
1318 myid = messaging_server_id(msg_ctx);
1320 if (argc != 1) {
1321 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1322 return False;
1325 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1326 winbind_validate_cache_cb);
1328 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1329 sizeof(myid))) {
1330 return False;
1333 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1335 if (num_replies == 0) {
1336 printf("No replies received\n");
1339 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1341 return num_replies;
1344 static bool do_reload_config(struct tevent_context *ev_ctx,
1345 struct messaging_context *msg_ctx,
1346 const struct server_id pid,
1347 const int argc, const char **argv)
1349 if (argc != 1) {
1350 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1351 return False;
1354 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1357 static bool do_reload_printers(struct tevent_context *ev_ctx,
1358 struct messaging_context *msg_ctx,
1359 const struct server_id pid,
1360 const int argc, const char **argv)
1362 if (argc != 1) {
1363 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1364 return False;
1367 return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1370 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1372 fstring unix_name;
1373 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1374 fstrcpy(unix_name, name);
1375 (void)strupper_m(unix_name);
1376 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1377 n->name_type = (unsigned int)type & 0xFF;
1378 push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
1381 static bool do_nodestatus(struct tevent_context *ev_ctx,
1382 struct messaging_context *msg_ctx,
1383 const struct server_id pid,
1384 const int argc, const char **argv)
1386 struct packet_struct p;
1388 if (argc != 2) {
1389 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1390 return False;
1393 ZERO_STRUCT(p);
1395 p.ip = interpret_addr2(argv[1]);
1396 p.port = 137;
1397 p.packet_type = NMB_PACKET;
1399 p.packet.nmb.header.name_trn_id = 10;
1400 p.packet.nmb.header.opcode = 0;
1401 p.packet.nmb.header.response = False;
1402 p.packet.nmb.header.nm_flags.bcast = False;
1403 p.packet.nmb.header.nm_flags.recursion_available = False;
1404 p.packet.nmb.header.nm_flags.recursion_desired = False;
1405 p.packet.nmb.header.nm_flags.trunc = False;
1406 p.packet.nmb.header.nm_flags.authoritative = False;
1407 p.packet.nmb.header.rcode = 0;
1408 p.packet.nmb.header.qdcount = 1;
1409 p.packet.nmb.header.ancount = 0;
1410 p.packet.nmb.header.nscount = 0;
1411 p.packet.nmb.header.arcount = 0;
1412 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1413 p.packet.nmb.question.question_type = 0x21;
1414 p.packet.nmb.question.question_class = 0x1;
1416 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1419 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1420 struct messaging_context *msg_ctx,
1421 const struct server_id pid,
1422 const int argc, const char **argv)
1424 if (argc != 1) {
1425 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1426 return false;
1428 return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1431 /* A list of message type supported */
1433 static const struct {
1434 const char *name; /* Option name */
1435 bool (*fn)(struct tevent_context *ev_ctx,
1436 struct messaging_context *msg_ctx,
1437 const struct server_id pid,
1438 const int argc, const char **argv);
1439 const char *help; /* Short help text */
1440 } msg_types[] = {
1442 .name = "debug",
1443 .fn = do_debug,
1444 .help = "Set debuglevel",
1447 .name = "idmap",
1448 .fn = do_idmap,
1449 .help = "Manipulate idmap cache",
1452 .name = "force-election",
1453 .fn = do_election,
1454 .help = "Force a browse election",
1457 .name = "ping",
1458 .fn = do_ping,
1459 .help = "Elicit a response",
1462 .name = "profile",
1463 .fn = do_profile,
1464 .help = "",
1467 .name = "inject",
1468 .fn = do_inject_fault,
1469 .help = "Inject a fatal signal into a running smbd"},
1471 .name = "stacktrace",
1472 .fn = do_daemon_stack_trace,
1473 .help = "Display a stack trace of a daemon",
1476 .name = "profilelevel",
1477 .fn = do_profilelevel,
1478 .help = "",
1481 .name = "debuglevel",
1482 .fn = do_debuglevel,
1483 .help = "Display current debuglevels",
1486 .name = "printnotify",
1487 .fn = do_printnotify,
1488 .help = "Send a print notify message",
1491 .name = "close-share",
1492 .fn = do_closeshare,
1493 .help = "Forcibly disconnect a share",
1496 .name = "close-denied-share",
1497 .fn = do_close_denied_share,
1498 .help = "Forcibly disconnect users from shares disallowed now",
1501 .name = "kill-client-ip",
1502 .fn = do_kill_client_by_ip,
1503 .help = "Forcibly disconnect a client with a specific IP address",
1506 .name = "ip-dropped",
1507 .fn = do_ip_dropped,
1508 .help = "Tell winbind that an IP got dropped",
1511 .name = "pool-usage",
1512 .fn = do_poolusage,
1513 .help = "Display talloc memory usage",
1516 .name = "rpc-dump-status",
1517 .fn = do_rpc_dump_status,
1518 .help = "Display rpc status",
1521 .name = "ringbuf-log",
1522 .fn = do_ringbuflog,
1523 .help = "Display ringbuf log",
1526 .name = "dmalloc-mark",
1527 .fn = do_dmalloc_mark,
1528 .help = "",
1531 .name = "dmalloc-log-changed",
1532 .fn = do_dmalloc_changed,
1533 .help = "",
1536 .name = "shutdown",
1537 .fn = do_shutdown,
1538 .help = "Shut down daemon",
1541 .name = "drvupgrade",
1542 .fn = do_drvupgrade,
1543 .help = "Notify a printer driver has changed",
1546 .name = "reload-config",
1547 .fn = do_reload_config,
1548 .help = "Force smbd or winbindd to reload config file"},
1550 .name = "reload-printers",
1551 .fn = do_reload_printers,
1552 .help = "Force smbd to reload printers"},
1554 .name = "nodestatus",
1555 .fn = do_nodestatus,
1556 .help = "Ask nmbd to do a node status request"},
1558 .name = "online",
1559 .fn = do_winbind_online,
1560 .help = "Ask winbind to go into online state"},
1562 .name = "offline",
1563 .fn = do_winbind_offline,
1564 .help = "Ask winbind to go into offline state"},
1566 .name = "onlinestatus",
1567 .fn = do_winbind_onlinestatus,
1568 .help = "Request winbind online status"},
1570 .name = "validate-cache" ,
1571 .fn = do_winbind_validate_cache,
1572 .help = "Validate winbind's credential cache",
1575 .name = "dump-domain-list",
1576 .fn = do_winbind_dump_domain_list,
1577 .help = "Dump winbind domain list"},
1579 .name = "disconnect-dc",
1580 .fn = do_msg_disconnect_dc,
1583 .name = "notify-cleanup",
1584 .fn = do_notify_cleanup,
1587 .name = "num-children",
1588 .fn = do_num_children,
1589 .help = "Print number of smbd child processes",
1592 .name = "msg-cleanup",
1593 .fn = do_msg_cleanup,
1596 .name = "noop",
1597 .fn = do_noop,
1598 .help = "Do nothing",
1601 .name = "sleep",
1602 .fn = do_sleep,
1603 .help = "Cause the target process to sleep",
1605 { .name = NULL, },
1608 /* Display usage information */
1610 static void usage(poptContext pc)
1612 int i;
1614 poptPrintHelp(pc, stderr, 0);
1616 fprintf(stderr, "\n");
1617 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1618 "process ID\n");
1620 fprintf(stderr, "\n");
1621 fprintf(stderr, "<message-type> is one of:\n");
1623 for (i = 0; msg_types[i].name; i++) {
1624 const char *help = msg_types[i].help;
1625 if (help == NULL) {
1626 help = "";
1628 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, help);
1631 fprintf(stderr, "\n");
1633 exit(1);
1636 /* Return the pid number for a string destination */
1638 static struct server_id parse_dest(struct messaging_context *msg,
1639 const char *dest)
1641 struct server_id result = {
1642 .pid = (uint64_t)-1,
1644 pid_t pid;
1646 /* Zero is a special return value for broadcast to all processes */
1648 if (strequal(dest, "all")) {
1649 return interpret_pid(MSG_BROADCAST_PID_STR);
1652 /* Try self - useful for testing */
1654 if (strequal(dest, "self")) {
1655 return messaging_server_id(msg);
1658 /* Fix winbind typo. */
1659 if (strequal(dest, "winbind")) {
1660 dest = "winbindd";
1663 /* Check for numeric pid number */
1664 result = interpret_pid(dest);
1666 /* Zero isn't valid if not "all". */
1667 if (result.pid && procid_valid(&result)) {
1668 return result;
1671 /* Look up other destinations in pidfile directory */
1673 if ((pid = pidfile_pid(lp_pid_directory(), dest)) != 0) {
1674 return pid_to_procid(pid);
1677 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1679 return result;
1682 /* Execute smbcontrol command */
1684 static bool do_command(struct tevent_context *ev_ctx,
1685 struct messaging_context *msg_ctx,
1686 int argc, const char **argv)
1688 const char *dest = argv[0], *command = argv[1];
1689 struct server_id pid;
1690 int i;
1692 /* Check destination */
1694 pid = parse_dest(msg_ctx, dest);
1695 if (!procid_valid(&pid)) {
1696 return False;
1699 /* Check command */
1701 for (i = 0; msg_types[i].name; i++) {
1702 if (strequal(command, msg_types[i].name))
1703 return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1704 argc - 1, argv + 1);
1707 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1709 return False;
1712 static void smbcontrol_help(poptContext pc,
1713 enum poptCallbackReason preason,
1714 struct poptOption * poption,
1715 const char * parg,
1716 void * pdata)
1718 if (poption->shortName != '?') {
1719 poptPrintUsage(pc, stdout, 0);
1720 } else {
1721 usage(pc);
1724 exit(0);
1727 struct poptOption help_options[] = {
1728 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1729 NULL, NULL },
1730 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1731 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1735 /* Main program */
1737 int main(int argc, const char **argv)
1739 poptContext pc;
1740 int opt;
1741 struct tevent_context *evt_ctx;
1742 struct messaging_context *msg_ctx;
1744 struct poptOption long_options[] = {
1745 /* POPT_AUTOHELP */
1746 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1747 0, "Help options:", NULL },
1748 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1749 "Set timeout value in seconds", "TIMEOUT" },
1751 POPT_COMMON_SAMBA
1752 POPT_COMMON_VERSION
1753 POPT_TABLEEND
1755 TALLOC_CTX *frame = talloc_stackframe();
1756 int ret = 0;
1757 bool ok;
1759 smb_init_locale();
1761 ok = samba_cmdline_init(frame,
1762 SAMBA_CMDLINE_CONFIG_CLIENT,
1763 false /* require_smbconf */);
1764 if (!ok) {
1765 DBG_ERR("Failed to init cmdline parser!\n");
1766 TALLOC_FREE(frame);
1767 exit(1);
1769 lp_set_cmdline("log level", "0");
1771 /* Parse command line arguments using popt */
1773 pc = samba_popt_get_context(getprogname(),
1774 argc,
1775 argv,
1776 long_options,
1778 if (pc == NULL) {
1779 DBG_ERR("Failed to setup popt context!\n");
1780 TALLOC_FREE(frame);
1781 exit(1);
1784 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1785 "<parameters>");
1787 if (argc == 1)
1788 usage(pc);
1790 while ((opt = poptGetNextOpt(pc)) != -1) {
1791 switch(opt) {
1792 case 't': /* --timeout */
1793 break;
1794 default:
1795 fprintf(stderr, "Invalid option\n");
1796 poptPrintHelp(pc, stderr, 0);
1797 break;
1801 /* We should now have the remaining command line arguments in
1802 argv. The argc parameter should have been decremented to the
1803 correct value in the above switch statement. */
1805 argv = (const char **)poptGetArgs(pc);
1806 argc = 0;
1807 if (argv != NULL) {
1808 while (argv[argc] != NULL) {
1809 argc++;
1813 if (argc <= 1)
1814 usage(pc);
1816 msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE());
1817 if (msg_ctx == NULL) {
1818 fprintf(stderr,
1819 "Could not init messaging context, not root?\n");
1820 TALLOC_FREE(frame);
1821 exit(1);
1824 evt_ctx = global_event_context();
1826 /* Need to invert sense of return code -- samba
1827 * routines mostly return True==1 for success, but
1828 * shell needs 0. */
1830 ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1832 cmdline_messaging_context_free();
1833 poptFreeContext(pc);
1834 TALLOC_FREE(frame);
1835 return ret;