s4/torture: make --unclist active with smb2 testcases
[Samba.git] / source3 / utils / smbcontrol.c
blob4c4bfcb4e5b527c3626c1d4fcbb44fe764b5c853
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 "popt_common.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"
39 #if HAVE_LIBUNWIND_H
40 #include <libunwind.h>
41 #endif
43 #if HAVE_LIBUNWIND_PTRACE_H
44 #include <libunwind-ptrace.h>
45 #endif
47 #if HAVE_SYS_PTRACE_H
48 #include <sys/ptrace.h>
49 #endif
51 /* Default timeout value when waiting for replies (in seconds) */
53 #define DEFAULT_TIMEOUT 10
55 static int timeout = DEFAULT_TIMEOUT;
56 static int num_replies; /* Used by message callback fns */
58 /* Send a message to a destination pid. Zero means broadcast smbd. */
60 static bool send_message(struct messaging_context *msg_ctx,
61 struct server_id pid, int msg_type,
62 const void *buf, int len)
64 bool ret;
65 int n_sent = 0;
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 ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
73 DEBUG(10,("smbcontrol/send_message: broadcast message to "
74 "%d processes\n", n_sent));
76 return ret;
79 static void smbcontrol_timeout(struct tevent_context *event_ctx,
80 struct tevent_timer *te,
81 struct timeval now,
82 void *private_data)
84 bool *timed_out = (bool *)private_data;
85 TALLOC_FREE(te);
86 *timed_out = True;
89 /* Wait for one or more reply messages */
91 static void wait_replies(struct tevent_context *ev_ctx,
92 struct messaging_context *msg_ctx,
93 bool multiple_replies)
95 struct tevent_timer *te;
96 bool timed_out = False;
98 te = tevent_add_timer(ev_ctx, NULL,
99 timeval_current_ofs(timeout, 0),
100 smbcontrol_timeout, (void *)&timed_out);
101 if (te == NULL) {
102 DEBUG(0, ("tevent_add_timer failed\n"));
103 return;
106 while (!timed_out) {
107 int ret;
108 if (num_replies > 0 && !multiple_replies)
109 break;
110 ret = tevent_loop_once(ev_ctx);
111 if (ret != 0) {
112 break;
117 /* Message handler callback that displays the PID and a string on stdout */
119 static void print_pid_string_cb(struct messaging_context *msg,
120 void *private_data,
121 uint32_t msg_type,
122 struct server_id pid,
123 DATA_BLOB *data)
125 struct server_id_buf pidstr;
127 printf("PID %s: %.*s", server_id_str_buf(pid, &pidstr),
128 (int)data->length, (const char *)data->data);
129 num_replies++;
132 /* Message handler callback that displays a string on stdout */
134 static void print_string_cb(struct messaging_context *msg,
135 void *private_data,
136 uint32_t msg_type,
137 struct server_id pid,
138 DATA_BLOB *data)
140 printf("%*s", (int)data->length, (const char *)data->data);
141 num_replies++;
144 /* Send no message. Useful for testing. */
146 static bool do_noop(struct tevent_context *ev_ctx,
147 struct messaging_context *msg_ctx,
148 const struct server_id pid,
149 const int argc, const char **argv)
151 if (argc != 1) {
152 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
153 return False;
156 /* Move along, nothing to see here */
158 return True;
161 /* Send a debug string */
163 static bool do_debug(struct tevent_context *ev_ctx,
164 struct messaging_context *msg_ctx,
165 const struct server_id pid,
166 const int argc, const char **argv)
168 if (argc != 2) {
169 fprintf(stderr, "Usage: smbcontrol <dest> debug "
170 "<debug-string>\n");
171 return False;
174 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
175 strlen(argv[1]) + 1);
179 static bool do_idmap(struct tevent_context *ev,
180 struct messaging_context *msg_ctx,
181 const struct server_id pid,
182 const int argc, const char **argv)
184 static const char* usage = "Usage: "
185 "smbcontrol <dest> idmap <cmd> [arg]\n"
186 "\tcmd:"
187 "\tdelete \"UID <uid>\"|\"GID <gid>\"|<sid>\n"
188 "\t\tkill \"UID <uid>\"|\"GID <gid>\"|<sid>\n";
189 const char* arg = NULL;
190 int arglen = 0;
191 int msg_type;
193 switch (argc) {
194 case 2:
195 break;
196 case 3:
197 arg = argv[2];
198 arglen = strlen(arg) + 1;
199 break;
200 default:
201 fprintf(stderr, "%s", usage);
202 return false;
205 if (strcmp(argv[1], "delete") == 0) {
206 msg_type = ID_CACHE_DELETE;
208 else if (strcmp(argv[1], "kill") == 0) {
209 msg_type = ID_CACHE_KILL;
211 else if (strcmp(argv[1], "help") == 0) {
212 fprintf(stdout, "%s", usage);
213 return true;
215 else {
216 fprintf(stderr, "%s", usage);
217 return false;
220 return send_message(msg_ctx, pid, msg_type, arg, arglen);
224 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
226 /* Return the name of a process given it's PID. This will only work on Linux,
227 * but that's probably moot since this whole stack tracing implementation is
228 * Linux-specific anyway.
230 static const char * procname(pid_t pid, char * buf, size_t bufsz)
232 char path[64];
233 FILE * fp;
235 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
236 (unsigned long long)pid);
237 if ((fp = fopen(path, "r")) == NULL) {
238 return NULL;
241 fgets(buf, bufsz, fp);
243 fclose(fp);
244 return buf;
247 static void print_stack_trace(pid_t pid, int * count)
249 void * pinfo = NULL;
250 unw_addr_space_t aspace = NULL;
251 unw_cursor_t cursor;
252 unw_word_t ip, sp;
254 char nbuf[256];
255 unw_word_t off;
257 int ret;
259 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
260 fprintf(stderr,
261 "Failed to attach to process %llu: %s\n",
262 (unsigned long long)pid, strerror(errno));
263 return;
266 /* Wait until the attach is complete. */
267 waitpid(pid, NULL, 0);
269 if (((pinfo = _UPT_create(pid)) == NULL) ||
270 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
271 /* Probably out of memory. */
272 fprintf(stderr,
273 "Unable to initialize stack unwind for process %llu\n",
274 (unsigned long long)pid);
275 goto cleanup;
278 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
279 fprintf(stderr,
280 "Unable to unwind stack for process %llu: %s\n",
281 (unsigned long long)pid, unw_strerror(ret));
282 goto cleanup;
285 if (*count > 0) {
286 printf("\n");
289 if (procname(pid, nbuf, sizeof(nbuf))) {
290 printf("Stack trace for process %llu (%s):\n",
291 (unsigned long long)pid, nbuf);
292 } else {
293 printf("Stack trace for process %llu:\n",
294 (unsigned long long)pid);
297 while (unw_step(&cursor) > 0) {
298 ip = sp = off = 0;
299 unw_get_reg(&cursor, UNW_REG_IP, &ip);
300 unw_get_reg(&cursor, UNW_REG_SP, &sp);
302 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
303 if (ret != 0 && ret != -UNW_ENOMEM) {
304 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
306 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
307 nbuf, (long long)off, (long long)ip,
308 (long long)sp);
311 (*count)++;
313 cleanup:
314 if (aspace) {
315 unw_destroy_addr_space(aspace);
318 if (pinfo) {
319 _UPT_destroy(pinfo);
322 ptrace(PTRACE_DETACH, pid, NULL, NULL);
325 static int stack_trace_server(const struct server_id *id,
326 uint32_t msg_flags,
327 void *priv)
329 if (procid_is_local(id)) {
330 print_stack_trace(procid_to_pid(id), (int *)priv);
332 return 0;
335 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
336 struct messaging_context *msg_ctx,
337 const struct server_id pid,
338 const int argc, const char **argv)
340 pid_t dest;
341 int count = 0;
343 if (argc != 1) {
344 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
345 return False;
348 dest = procid_to_pid(&pid);
350 if (dest != 0) {
351 /* It would be nice to be able to make sure that this PID is
352 * the PID of a smbd/winbind/nmbd process, not some random PID
353 * the user liked the look of. It doesn't seem like it's worth
354 * the effort at the moment, however.
356 print_stack_trace(dest, &count);
357 } else {
358 serverid_traverse_read(stack_trace_server, &count);
361 return True;
364 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
366 static bool do_daemon_stack_trace(struct tevent_context *ev_ctx,
367 struct messaging_context *msg_ctx,
368 const struct server_id pid,
369 const int argc, const char **argv)
371 fprintf(stderr,
372 "Daemon stack tracing is not supported on this platform\n");
373 return False;
376 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
378 /* Inject a fault (fatal signal) into a running smbd */
380 static bool do_inject_fault(struct tevent_context *ev_ctx,
381 struct messaging_context *msg_ctx,
382 const struct server_id pid,
383 const int argc, const char **argv)
385 if (argc != 2) {
386 fprintf(stderr, "Usage: smbcontrol <dest> inject "
387 "<bus|hup|term|internal|segv>\n");
388 return False;
391 #ifndef DEVELOPER
392 fprintf(stderr, "Fault injection is only available in "
393 "developer builds\n");
394 return False;
395 #else /* DEVELOPER */
397 int sig = 0;
399 if (strcmp(argv[1], "bus") == 0) {
400 sig = SIGBUS;
401 } else if (strcmp(argv[1], "hup") == 0) {
402 sig = SIGHUP;
403 } else if (strcmp(argv[1], "term") == 0) {
404 sig = SIGTERM;
405 } else if (strcmp(argv[1], "segv") == 0) {
406 sig = SIGSEGV;
407 } else if (strcmp(argv[1], "internal") == 0) {
408 /* Force an internal error, ie. an unclean exit. */
409 sig = -1;
410 } else {
411 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
412 return False;
415 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
416 &sig, sizeof(int));
418 #endif /* DEVELOPER */
421 /* Force a browser election */
423 static bool do_election(struct tevent_context *ev_ctx,
424 struct messaging_context *msg_ctx,
425 const struct server_id pid,
426 const int argc, const char **argv)
428 if (argc != 1) {
429 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
430 return False;
433 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
436 /* Ping a samba daemon process */
438 static void pong_cb(struct messaging_context *msg,
439 void *private_data,
440 uint32_t msg_type,
441 struct server_id pid,
442 DATA_BLOB *data)
444 struct server_id_buf src_string;
445 printf("PONG from pid %s\n", server_id_str_buf(pid, &src_string));
446 num_replies++;
449 static bool do_ping(struct tevent_context *ev_ctx,
450 struct messaging_context *msg_ctx,
451 const struct server_id pid,
452 const int argc, const char **argv)
454 if (argc != 1) {
455 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
456 return False;
459 /* Send a message and register our interest in a reply */
461 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
462 return False;
464 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
466 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
468 /* No replies were received within the timeout period */
470 if (num_replies == 0)
471 printf("No replies received\n");
473 messaging_deregister(msg_ctx, MSG_PONG, NULL);
475 return num_replies;
478 /* Set profiling options */
480 static bool do_profile(struct tevent_context *ev_ctx,
481 struct messaging_context *msg_ctx,
482 const struct server_id pid,
483 const int argc, const char **argv)
485 int v;
487 if (argc != 2) {
488 fprintf(stderr, "Usage: smbcontrol <dest> profile "
489 "<off|count|on|flush>\n");
490 return False;
493 if (strcmp(argv[1], "off") == 0) {
494 v = 0;
495 } else if (strcmp(argv[1], "count") == 0) {
496 v = 1;
497 } else if (strcmp(argv[1], "on") == 0) {
498 v = 2;
499 } else if (strcmp(argv[1], "flush") == 0) {
500 v = 3;
501 } else {
502 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
503 return False;
506 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
509 /* Return the profiling level */
511 static void profilelevel_cb(struct messaging_context *msg_ctx,
512 void *private_data,
513 uint32_t msg_type,
514 struct server_id pid,
515 DATA_BLOB *data)
517 int level;
518 const char *s;
520 num_replies++;
522 if (data->length != sizeof(int)) {
523 fprintf(stderr, "invalid message length %ld returned\n",
524 (unsigned long)data->length);
525 return;
528 memcpy(&level, data->data, sizeof(int));
530 switch (level) {
531 case 0:
532 s = "not enabled";
533 break;
534 case 1:
535 s = "off";
536 break;
537 case 3:
538 s = "count only";
539 break;
540 case 7:
541 s = "count and time";
542 break;
543 default:
544 s = "BOGUS";
545 break;
548 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
551 static void profilelevel_rqst(struct messaging_context *msg_ctx,
552 void *private_data,
553 uint32_t msg_type,
554 struct server_id pid,
555 DATA_BLOB *data)
557 int v = 0;
559 /* Send back a dummy reply */
561 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
564 static bool do_profilelevel(struct tevent_context *ev_ctx,
565 struct messaging_context *msg_ctx,
566 const struct server_id pid,
567 const int argc, const char **argv)
569 if (argc != 1) {
570 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
571 return False;
574 /* Send a message and register our interest in a reply */
576 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
577 return False;
579 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
580 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
581 profilelevel_rqst);
583 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
585 /* No replies were received within the timeout period */
587 if (num_replies == 0)
588 printf("No replies received\n");
590 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
592 return num_replies;
595 /* Display debug level settings */
597 static bool do_debuglevel(struct tevent_context *ev_ctx,
598 struct messaging_context *msg_ctx,
599 const struct server_id pid,
600 const int argc, const char **argv)
602 if (argc != 1) {
603 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
604 return False;
607 /* Send a message and register our interest in a reply */
609 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
610 return False;
612 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
614 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
616 /* No replies were received within the timeout period */
618 if (num_replies == 0)
619 printf("No replies received\n");
621 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
623 return num_replies;
626 /* Send a print notify message */
628 static bool do_printnotify(struct tevent_context *ev_ctx,
629 struct messaging_context *msg_ctx,
630 const struct server_id pid,
631 const int argc, const char **argv)
633 const char *cmd;
635 /* Check for subcommand */
637 if (argc == 1) {
638 fprintf(stderr, "Must specify subcommand:\n");
639 fprintf(stderr, "\tqueuepause <printername>\n");
640 fprintf(stderr, "\tqueueresume <printername>\n");
641 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
642 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
643 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
644 fprintf(stderr, "\tprinter <printername> <comment|port|"
645 "driver> <value>\n");
647 return False;
650 cmd = argv[1];
652 if (strcmp(cmd, "queuepause") == 0) {
654 if (argc != 3) {
655 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
656 " queuepause <printername>\n");
657 return False;
660 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
661 PRINTER_STATUS_PAUSED);
663 goto send;
665 } else if (strcmp(cmd, "queueresume") == 0) {
667 if (argc != 3) {
668 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
669 " queuereume <printername>\n");
670 return False;
673 notify_printer_status_byname(ev_ctx, msg_ctx, argv[2],
674 PRINTER_STATUS_OK);
676 goto send;
678 } else if (strcmp(cmd, "jobpause") == 0) {
679 int jobid;
681 if (argc != 4) {
682 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
683 " jobpause <printername> <unix-jobid>\n");
684 return False;
687 jobid = atoi(argv[3]);
689 notify_job_status_byname(
690 ev_ctx, msg_ctx,
691 argv[2], jobid, JOB_STATUS_PAUSED,
692 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
694 goto send;
696 } else if (strcmp(cmd, "jobresume") == 0) {
697 int jobid;
699 if (argc != 4) {
700 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
701 " jobpause <printername> <unix-jobid>\n");
702 return False;
705 jobid = atoi(argv[3]);
707 notify_job_status_byname(
708 ev_ctx, msg_ctx,
709 argv[2], jobid, JOB_STATUS_QUEUED,
710 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
712 goto send;
714 } else if (strcmp(cmd, "jobdelete") == 0) {
715 int jobid;
717 if (argc != 4) {
718 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
719 " jobpause <printername> <unix-jobid>\n");
720 return False;
723 jobid = atoi(argv[3]);
725 notify_job_status_byname(
726 ev_ctx, msg_ctx,
727 argv[2], jobid, JOB_STATUS_DELETING,
728 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
730 notify_job_status_byname(
731 ev_ctx, msg_ctx,
732 argv[2], jobid, JOB_STATUS_DELETING|
733 JOB_STATUS_DELETED,
734 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
736 goto send;
738 } else if (strcmp(cmd, "printer") == 0) {
739 uint32_t attribute;
741 if (argc != 5) {
742 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
743 "printer <printername> <comment|port|driver> "
744 "<value>\n");
745 return False;
748 if (strcmp(argv[3], "comment") == 0) {
749 attribute = PRINTER_NOTIFY_FIELD_COMMENT;
750 } else if (strcmp(argv[3], "port") == 0) {
751 attribute = PRINTER_NOTIFY_FIELD_PORT_NAME;
752 } else if (strcmp(argv[3], "driver") == 0) {
753 attribute = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
754 } else {
755 fprintf(stderr, "Invalid printer command '%s'\n",
756 argv[3]);
757 return False;
760 notify_printer_byname(ev_ctx, msg_ctx, argv[2], attribute,
761 discard_const_p(char, argv[4]));
763 goto send;
766 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
767 return False;
769 send:
770 print_notify_send_messages(msg_ctx, 0);
771 return True;
774 /* Close a share */
776 static bool do_closeshare(struct tevent_context *ev_ctx,
777 struct messaging_context *msg_ctx,
778 const struct server_id pid,
779 const int argc, const char **argv)
781 if (argc != 2) {
782 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
783 "<sharename>\n");
784 return False;
787 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
788 strlen(argv[1]) + 1);
791 /* Kill a client by IP address */
792 static bool do_kill_client_by_ip(struct tevent_context *ev_ctx,
793 struct messaging_context *msg_ctx,
794 const struct server_id pid,
795 const int argc, const char **argv)
797 if (argc != 2) {
798 fprintf(stderr, "Usage: smbcontrol <dest> kill-client-ip "
799 "<IP address>\n");
800 return false;
803 if (!is_ipaddress_v4(argv[1]) && !is_ipaddress_v6(argv[1])) {
804 fprintf(stderr, "%s is not a valid IP address!\n", argv[1]);
805 return false;
808 return send_message(msg_ctx, pid, MSG_SMB_KILL_CLIENT_IP,
809 argv[1], strlen(argv[1]) + 1);
812 /* Tell winbindd an IP got dropped */
814 static bool do_ip_dropped(struct tevent_context *ev_ctx,
815 struct messaging_context *msg_ctx,
816 const struct server_id pid,
817 const int argc, const char **argv)
819 if (argc != 2) {
820 fprintf(stderr, "Usage: smbcontrol <dest> ip-dropped "
821 "<ip-address>\n");
822 return False;
825 return send_message(msg_ctx, pid, MSG_WINBIND_IP_DROPPED, argv[1],
826 strlen(argv[1]) + 1);
829 /* force a blocking lock retry */
831 static bool do_lockretry(struct tevent_context *ev_ctx,
832 struct messaging_context *msg_ctx,
833 const struct server_id pid,
834 const int argc, const char **argv)
836 if (argc != 1) {
837 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
838 return False;
841 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
844 /* force a validation of all brl entries, including re-sends. */
846 static bool do_brl_revalidate(struct tevent_context *ev_ctx,
847 struct messaging_context *msg_ctx,
848 const struct server_id pid,
849 const int argc, const char **argv)
851 if (argc != 1) {
852 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
853 return False;
856 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
859 /* Display talloc pool usage */
861 static bool do_poolusage(struct tevent_context *ev_ctx,
862 struct messaging_context *msg_ctx,
863 const struct server_id pid,
864 const int argc, const char **argv)
866 if (argc != 1) {
867 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
868 return False;
871 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
873 /* Send a message and register our interest in a reply */
875 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
876 return False;
878 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
880 /* No replies were received within the timeout period */
882 if (num_replies == 0)
883 printf("No replies received\n");
885 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
887 return num_replies;
890 /* Fetch and print the ringbuf log */
892 static void print_ringbuf_log_cb(struct messaging_context *msg,
893 void *private_data,
894 uint32_t msg_type,
895 struct server_id pid,
896 DATA_BLOB *data)
898 printf("%s", (const char *)data->data);
899 num_replies++;
902 static bool do_ringbuflog(struct tevent_context *ev_ctx,
903 struct messaging_context *msg_ctx,
904 const struct server_id pid,
905 const int argc, const char **argv)
907 if (argc != 1) {
908 fprintf(stderr, "Usage: smbcontrol <dest> ringbuf-log\n");
909 return false;
912 messaging_register(msg_ctx, NULL, MSG_RINGBUF_LOG,
913 print_ringbuf_log_cb);
915 /* Send a message and register our interest in a reply */
917 if (!send_message(msg_ctx, pid, MSG_REQ_RINGBUF_LOG, NULL, 0)) {
918 return false;
921 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
923 /* No replies were received within the timeout period */
925 if (num_replies == 0) {
926 printf("No replies received\n");
929 messaging_deregister(msg_ctx, MSG_RINGBUF_LOG, NULL);
931 return num_replies != 0;
934 /* Perform a dmalloc mark */
936 static bool do_dmalloc_mark(struct tevent_context *ev_ctx,
937 struct messaging_context *msg_ctx,
938 const struct server_id pid,
939 const int argc, const char **argv)
941 if (argc != 1) {
942 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
943 return False;
946 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
949 /* Perform a dmalloc changed */
951 static bool do_dmalloc_changed(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> "
958 "dmalloc-log-changed\n");
959 return False;
962 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
963 NULL, 0);
966 static void print_uint32_cb(struct messaging_context *msg, void *private_data,
967 uint32_t msg_type, struct server_id pid,
968 DATA_BLOB *data)
970 uint32_t num_children;
972 if (data->length != sizeof(uint32_t)) {
973 printf("Invalid response: %d bytes long\n",
974 (int)data->length);
975 goto done;
977 num_children = IVAL(data->data, 0);
978 printf("%u children\n", (unsigned)num_children);
979 done:
980 num_replies++;
983 static bool do_num_children(struct tevent_context *ev_ctx,
984 struct messaging_context *msg_ctx,
985 const struct server_id pid,
986 const int argc, const char **argv)
988 if (argc != 1) {
989 fprintf(stderr, "Usage: smbcontrol <dest> num-children\n");
990 return False;
993 messaging_register(msg_ctx, NULL, MSG_SMB_NUM_CHILDREN,
994 print_uint32_cb);
996 /* Send a message and register our interest in a reply */
998 if (!send_message(msg_ctx, pid, MSG_SMB_TELL_NUM_CHILDREN, NULL, 0))
999 return false;
1001 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1003 /* No replies were received within the timeout period */
1005 if (num_replies == 0)
1006 printf("No replies received\n");
1008 messaging_deregister(msg_ctx, MSG_SMB_NUM_CHILDREN, NULL);
1010 return num_replies;
1013 static bool do_msg_cleanup(struct tevent_context *ev_ctx,
1014 struct messaging_context *msg_ctx,
1015 const struct server_id pid,
1016 const int argc, const char **argv)
1018 int ret;
1020 ret = messaging_cleanup(msg_ctx, pid.pid);
1022 printf("cleanup(%u) returned %s\n", (unsigned)pid.pid,
1023 ret ? strerror(ret) : "ok");
1025 return (ret == 0);
1028 /* Shutdown a server process */
1030 static bool do_shutdown(struct tevent_context *ev_ctx,
1031 struct messaging_context *msg_ctx,
1032 const struct server_id pid,
1033 const int argc, const char **argv)
1035 if (argc != 1) {
1036 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
1037 return False;
1040 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
1043 /* Notify a driver upgrade */
1045 static bool do_drvupgrade(struct tevent_context *ev_ctx,
1046 struct messaging_context *msg_ctx,
1047 const struct server_id pid,
1048 const int argc, const char **argv)
1050 if (argc != 2) {
1051 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
1052 "<driver-name>\n");
1053 return False;
1056 return send_message(msg_ctx, pid, MSG_PRINTER_DRVUPGRADE, argv[1],
1057 strlen(argv[1]) + 1);
1060 static bool do_winbind_online(struct tevent_context *ev_ctx,
1061 struct messaging_context *msg_ctx,
1062 const struct server_id pid,
1063 const int argc, const char **argv)
1065 TDB_CONTEXT *tdb;
1066 char *db_path;
1068 if (argc != 1) {
1069 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
1070 return False;
1073 db_path = state_path("winbindd_cache.tdb");
1074 if (db_path == NULL) {
1075 return false;
1078 /* Remove the entry in the winbindd_cache tdb to tell a later
1079 starting winbindd that we're online. */
1081 tdb = tdb_open_log(db_path, 0, TDB_DEFAULT, O_RDWR, 0600);
1082 if (!tdb) {
1083 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
1084 db_path);
1085 TALLOC_FREE(db_path);
1086 return False;
1089 TALLOC_FREE(db_path);
1090 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
1091 tdb_close(tdb);
1093 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
1096 static bool do_winbind_offline(struct tevent_context *ev_ctx,
1097 struct messaging_context *msg_ctx,
1098 const struct server_id pid,
1099 const int argc, const char **argv)
1101 TDB_CONTEXT *tdb;
1102 bool ret = False;
1103 int retry = 0;
1104 char *db_path;
1106 if (argc != 1) {
1107 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
1108 return False;
1111 db_path = state_path("winbindd_cache.tdb");
1112 if (db_path == NULL) {
1113 return false;
1116 /* Create an entry in the winbindd_cache tdb to tell a later
1117 starting winbindd that we're offline. We may actually create
1118 it here... */
1120 tdb = tdb_open_log(db_path,
1121 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
1122 TDB_DEFAULT|TDB_INCOMPATIBLE_HASH /* TDB_CLEAR_IF_FIRST */,
1123 O_RDWR|O_CREAT, 0600);
1125 if (!tdb) {
1126 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
1127 db_path);
1128 TALLOC_FREE(db_path);
1129 return False;
1131 TALLOC_FREE(db_path);
1133 /* There's a potential race condition that if a child
1134 winbindd detects a domain is online at the same time
1135 we're trying to tell it to go offline that it might
1136 delete the record we add between us adding it and
1137 sending the message. Minimize this by retrying up to
1138 5 times. */
1140 for (retry = 0; retry < 5; retry++) {
1141 uint8_t buf[4];
1142 TDB_DATA d = { .dptr = buf, .dsize = sizeof(buf) };
1144 SIVAL(buf, 0, time(NULL));
1146 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
1148 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
1149 NULL, 0);
1151 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
1152 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
1154 if (!d.dptr || d.dsize != 4) {
1155 SAFE_FREE(d.dptr);
1156 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
1157 } else {
1158 SAFE_FREE(d.dptr);
1159 break;
1163 tdb_close(tdb);
1164 return ret;
1167 static bool do_winbind_onlinestatus(struct tevent_context *ev_ctx,
1168 struct messaging_context *msg_ctx,
1169 const struct server_id pid,
1170 const int argc, const char **argv)
1172 struct server_id myid;
1174 myid = messaging_server_id(msg_ctx);
1176 if (argc != 1) {
1177 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
1178 return False;
1181 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
1182 print_pid_string_cb);
1184 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
1185 sizeof(myid)))
1186 return False;
1188 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1190 /* No replies were received within the timeout period */
1192 if (num_replies == 0)
1193 printf("No replies received\n");
1195 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
1197 return num_replies;
1200 static bool do_dump_event_list(struct tevent_context *ev_ctx,
1201 struct messaging_context *msg_ctx,
1202 const struct server_id pid,
1203 const int argc, const char **argv)
1205 if (argc != 1) {
1206 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
1207 return False;
1210 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
1213 static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
1214 struct messaging_context *msg_ctx,
1215 const struct server_id pid,
1216 const int argc, const char **argv)
1218 const char *domain = NULL;
1219 int domain_len = 0;
1220 struct server_id myid;
1221 uint8_t *buf = NULL;
1222 int buf_len = 0;
1224 myid = messaging_server_id(msg_ctx);
1226 if (argc < 1 || argc > 2) {
1227 fprintf(stderr, "Usage: smbcontrol <dest> dump-domain-list "
1228 "<domain>\n");
1229 return false;
1232 if (argc == 2) {
1233 domain = argv[1];
1234 domain_len = strlen(argv[1]) + 1;
1237 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1238 print_pid_string_cb);
1240 buf_len = sizeof(myid)+domain_len;
1241 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1242 if (!buf) {
1243 return false;
1246 memcpy(buf, &myid, sizeof(myid));
1247 memcpy(&buf[sizeof(myid)], domain, domain_len);
1249 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1250 buf, buf_len))
1252 SAFE_FREE(buf);
1253 return false;
1256 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1258 /* No replies were received within the timeout period */
1260 SAFE_FREE(buf);
1261 if (num_replies == 0) {
1262 printf("No replies received\n");
1265 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1267 return num_replies;
1270 static void winbind_validate_cache_cb(struct messaging_context *msg,
1271 void *private_data,
1272 uint32_t msg_type,
1273 struct server_id pid,
1274 DATA_BLOB *data)
1276 struct server_id_buf src_string;
1277 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1278 (*(data->data) == 0 ? "" : "NOT "),
1279 server_id_str_buf(pid, &src_string));
1280 num_replies++;
1283 static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
1284 struct messaging_context *msg_ctx,
1285 const struct server_id pid,
1286 const int argc, const char **argv)
1288 struct server_id myid;
1290 myid = messaging_server_id(msg_ctx);
1292 if (argc != 1) {
1293 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1294 return False;
1297 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1298 winbind_validate_cache_cb);
1300 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1301 sizeof(myid))) {
1302 return False;
1305 wait_replies(ev_ctx, msg_ctx, procid_to_pid(&pid) == 0);
1307 if (num_replies == 0) {
1308 printf("No replies received\n");
1311 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1313 return num_replies;
1316 static bool do_reload_config(struct tevent_context *ev_ctx,
1317 struct messaging_context *msg_ctx,
1318 const struct server_id pid,
1319 const int argc, const char **argv)
1321 if (argc != 1) {
1322 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1323 return False;
1326 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1329 static bool do_reload_printers(struct tevent_context *ev_ctx,
1330 struct messaging_context *msg_ctx,
1331 const struct server_id pid,
1332 const int argc, const char **argv)
1334 if (argc != 1) {
1335 fprintf(stderr, "Usage: smbcontrol <dest> reload-printers\n");
1336 return False;
1339 return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
1342 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1344 fstring unix_name;
1345 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1346 fstrcpy(unix_name, name);
1347 (void)strupper_m(unix_name);
1348 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1349 n->name_type = (unsigned int)type & 0xFF;
1350 push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
1353 static bool do_nodestatus(struct tevent_context *ev_ctx,
1354 struct messaging_context *msg_ctx,
1355 const struct server_id pid,
1356 const int argc, const char **argv)
1358 struct packet_struct p;
1360 if (argc != 2) {
1361 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1362 return False;
1365 ZERO_STRUCT(p);
1367 p.ip = interpret_addr2(argv[1]);
1368 p.port = 137;
1369 p.packet_type = NMB_PACKET;
1371 p.packet.nmb.header.name_trn_id = 10;
1372 p.packet.nmb.header.opcode = 0;
1373 p.packet.nmb.header.response = False;
1374 p.packet.nmb.header.nm_flags.bcast = False;
1375 p.packet.nmb.header.nm_flags.recursion_available = False;
1376 p.packet.nmb.header.nm_flags.recursion_desired = False;
1377 p.packet.nmb.header.nm_flags.trunc = False;
1378 p.packet.nmb.header.nm_flags.authoritative = False;
1379 p.packet.nmb.header.rcode = 0;
1380 p.packet.nmb.header.qdcount = 1;
1381 p.packet.nmb.header.ancount = 0;
1382 p.packet.nmb.header.nscount = 0;
1383 p.packet.nmb.header.arcount = 0;
1384 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1385 p.packet.nmb.question.question_type = 0x21;
1386 p.packet.nmb.question.question_class = 0x1;
1388 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1391 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
1392 struct messaging_context *msg_ctx,
1393 const struct server_id pid,
1394 const int argc, const char **argv)
1396 if (argc != 1) {
1397 fprintf(stderr, "Usage: smbcontrol smbd notify-cleanup\n");
1398 return false;
1400 return send_message(msg_ctx, pid, MSG_SMB_NOTIFY_CLEANUP, NULL, 0);
1403 /* A list of message type supported */
1405 static const struct {
1406 const char *name; /* Option name */
1407 bool (*fn)(struct tevent_context *ev_ctx,
1408 struct messaging_context *msg_ctx,
1409 const struct server_id pid,
1410 const int argc, const char **argv);
1411 const char *help; /* Short help text */
1412 } msg_types[] = {
1413 { "debug", do_debug, "Set debuglevel" },
1414 { "idmap", do_idmap, "Manipulate idmap cache" },
1415 { "force-election", do_election,
1416 "Force a browse election" },
1417 { "ping", do_ping, "Elicit a response" },
1418 { "profile", do_profile, "" },
1419 { "inject", do_inject_fault,
1420 "Inject a fatal signal into a running smbd"},
1421 { "stacktrace", do_daemon_stack_trace,
1422 "Display a stack trace of a daemon" },
1423 { "profilelevel", do_profilelevel, "" },
1424 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1425 { "printnotify", do_printnotify, "Send a print notify message" },
1426 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1427 { "kill-client-ip", do_kill_client_by_ip,
1428 "Forcibly disconnect a client with a specific IP address" },
1429 { "ip-dropped", do_ip_dropped, "Tell winbind that an IP got dropped" },
1430 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1431 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1432 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1433 { "ringbuf-log", do_ringbuflog, "Display ringbuf log" },
1434 { "dmalloc-mark", do_dmalloc_mark, "" },
1435 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1436 { "shutdown", do_shutdown, "Shut down daemon" },
1437 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1438 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1439 { "reload-printers", do_reload_printers, "Force smbd to reload printers"},
1440 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1441 { "online", do_winbind_online, "Ask winbind to go into online state"},
1442 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1443 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1444 { "dump-event-list", do_dump_event_list, "Dump event list"},
1445 { "validate-cache" , do_winbind_validate_cache,
1446 "Validate winbind's credential cache" },
1447 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1448 { "notify-cleanup", do_notify_cleanup },
1449 { "num-children", do_num_children,
1450 "Print number of smbd child processes" },
1451 { "msg-cleanup", do_msg_cleanup },
1452 { "noop", do_noop, "Do nothing" },
1453 { NULL }
1456 /* Display usage information */
1458 static void usage(poptContext pc)
1460 int i;
1462 poptPrintHelp(pc, stderr, 0);
1464 fprintf(stderr, "\n");
1465 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1466 "process ID\n");
1468 fprintf(stderr, "\n");
1469 fprintf(stderr, "<message-type> is one of:\n");
1471 for (i = 0; msg_types[i].name; i++)
1472 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1473 msg_types[i].help);
1475 fprintf(stderr, "\n");
1477 exit(1);
1480 /* Return the pid number for a string destination */
1482 static struct server_id parse_dest(struct messaging_context *msg,
1483 const char *dest)
1485 struct server_id result = {-1};
1486 pid_t pid;
1488 /* Zero is a special return value for broadcast to all processes */
1490 if (strequal(dest, "all")) {
1491 return interpret_pid(MSG_BROADCAST_PID_STR);
1494 /* Try self - useful for testing */
1496 if (strequal(dest, "self")) {
1497 return messaging_server_id(msg);
1500 /* Fix winbind typo. */
1501 if (strequal(dest, "winbind")) {
1502 dest = "winbindd";
1505 /* Check for numeric pid number */
1506 result = interpret_pid(dest);
1508 /* Zero isn't valid if not "all". */
1509 if (result.pid && procid_valid(&result)) {
1510 return result;
1513 /* Look up other destinations in pidfile directory */
1515 if ((pid = pidfile_pid(lp_pid_directory(), dest)) != 0) {
1516 return pid_to_procid(pid);
1519 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1521 return result;
1524 /* Execute smbcontrol command */
1526 static bool do_command(struct tevent_context *ev_ctx,
1527 struct messaging_context *msg_ctx,
1528 int argc, const char **argv)
1530 const char *dest = argv[0], *command = argv[1];
1531 struct server_id pid;
1532 int i;
1534 /* Check destination */
1536 pid = parse_dest(msg_ctx, dest);
1537 if (!procid_valid(&pid)) {
1538 return False;
1541 /* Check command */
1543 for (i = 0; msg_types[i].name; i++) {
1544 if (strequal(command, msg_types[i].name))
1545 return msg_types[i].fn(ev_ctx, msg_ctx, pid,
1546 argc - 1, argv + 1);
1549 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1551 return False;
1554 static void smbcontrol_help(poptContext pc,
1555 enum poptCallbackReason preason,
1556 struct poptOption * poption,
1557 const char * parg,
1558 void * pdata)
1560 if (poption->shortName != '?') {
1561 poptPrintUsage(pc, stdout, 0);
1562 } else {
1563 usage(pc);
1566 exit(0);
1569 struct poptOption help_options[] = {
1570 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1571 NULL, NULL },
1572 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1573 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1574 { NULL }
1577 /* Main program */
1579 int main(int argc, const char **argv)
1581 poptContext pc;
1582 int opt;
1583 struct tevent_context *evt_ctx;
1584 struct messaging_context *msg_ctx;
1586 static struct poptOption long_options[] = {
1587 /* POPT_AUTOHELP */
1588 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1589 0, "Help options:", NULL },
1590 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1591 "Set timeout value in seconds", "TIMEOUT" },
1593 POPT_COMMON_SAMBA
1594 POPT_TABLEEND
1596 TALLOC_CTX *frame = talloc_stackframe();
1597 int ret = 0;
1599 smb_init_locale();
1601 setup_logging(argv[0], DEBUG_STDOUT);
1602 lp_set_cmdline("log level", "0");
1604 /* Parse command line arguments using popt */
1606 pc = poptGetContext(
1607 "smbcontrol", argc, (const char **)argv, long_options, 0);
1609 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1610 "<parameters>");
1612 if (argc == 1)
1613 usage(pc);
1615 while ((opt = poptGetNextOpt(pc)) != -1) {
1616 switch(opt) {
1617 case 't': /* --timeout */
1618 break;
1619 default:
1620 fprintf(stderr, "Invalid option\n");
1621 poptPrintHelp(pc, stderr, 0);
1622 break;
1626 /* We should now have the remaining command line arguments in
1627 argv. The argc parameter should have been decremented to the
1628 correct value in the above switch statement. */
1630 argv = (const char **)poptGetArgs(pc);
1631 argc = 0;
1632 if (argv != NULL) {
1633 while (argv[argc] != NULL) {
1634 argc++;
1638 if (argc <= 1)
1639 usage(pc);
1641 lp_load_global(get_dyn_CONFIGFILE());
1643 /* Need to invert sense of return code -- samba
1644 * routines mostly return True==1 for success, but
1645 * shell needs 0. */
1647 if (!(evt_ctx = samba_tevent_context_init(NULL)) ||
1648 !(msg_ctx = messaging_init(NULL, evt_ctx))) {
1649 fprintf(stderr, "could not init messaging context\n");
1650 TALLOC_FREE(frame);
1651 exit(1);
1654 ret = !do_command(evt_ctx, msg_ctx, argc, argv);
1655 TALLOC_FREE(msg_ctx);
1656 TALLOC_FREE(frame);
1657 return ret;