Fix bug 7005 - mangle method = hash truncates files with dot '. ' character
[Samba.git] / source / utils / smbcontrol.c
blob962d1191727b6cc4369ff3182e69557dbc10a08d
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"
28 #if HAVE_LIBUNWIND_H
29 #include <libunwind.h>
30 #endif
32 #if HAVE_LIBUNWIND_PTRACE_H
33 #include <libunwind-ptrace.h>
34 #endif
36 #if HAVE_SYS_PTRACE_H
37 #include <sys/ptrace.h>
38 #endif
40 /* Default timeout value when waiting for replies (in seconds) */
42 #define DEFAULT_TIMEOUT 10
44 static int timeout = DEFAULT_TIMEOUT;
45 static int num_replies; /* Used by message callback fns */
47 /* Send a message to a destination pid. Zero means broadcast smbd. */
49 static bool send_message(struct messaging_context *msg_ctx,
50 struct server_id pid, int msg_type,
51 const void *buf, int len)
53 bool ret;
54 int n_sent = 0;
56 if (procid_to_pid(&pid) != 0)
57 return NT_STATUS_IS_OK(
58 messaging_send_buf(msg_ctx, pid, msg_type,
59 (uint8 *)buf, len));
61 ret = message_send_all(msg_ctx, msg_type, buf, len, &n_sent);
62 DEBUG(10,("smbcontrol/send_message: broadcast message to "
63 "%d processes\n", n_sent));
65 return ret;
68 static void smbcontrol_timeout(struct event_context *event_ctx,
69 struct timed_event *te,
70 struct timeval now,
71 void *private_data)
73 bool *timed_out = (bool *)private_data;
74 TALLOC_FREE(te);
75 *timed_out = True;
78 /* Wait for one or more reply messages */
80 static void wait_replies(struct messaging_context *msg_ctx,
81 bool multiple_replies)
83 struct timed_event *te;
84 bool timed_out = False;
86 if (!(te = event_add_timed(messaging_event_context(msg_ctx), NULL,
87 timeval_current_ofs(timeout, 0),
88 smbcontrol_timeout, (void *)&timed_out))) {
89 DEBUG(0, ("event_add_timed failed\n"));
90 return;
93 while (!timed_out) {
94 message_dispatch(msg_ctx);
95 if (num_replies > 0 && !multiple_replies)
96 break;
97 event_loop_once(messaging_event_context(msg_ctx));
101 /* Message handler callback that displays the PID and a string on stdout */
103 static void print_pid_string_cb(struct messaging_context *msg,
104 void *private_data,
105 uint32_t msg_type,
106 struct server_id pid,
107 DATA_BLOB *data)
109 printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
110 (int)data->length, (const char *)data->data);
111 num_replies++;
114 /* Message handler callback that displays a string on stdout */
116 static void print_string_cb(struct messaging_context *msg,
117 void *private_data,
118 uint32_t msg_type,
119 struct server_id pid,
120 DATA_BLOB *data)
122 printf("%.*s", (int)data->length, (const char *)data->data);
123 num_replies++;
126 /* Send no message. Useful for testing. */
128 static bool do_noop(struct messaging_context *msg_ctx,
129 const struct server_id pid,
130 const int argc, const char **argv)
132 if (argc != 1) {
133 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
134 return False;
137 /* Move along, nothing to see here */
139 return True;
142 /* Send a debug string */
144 static bool do_debug(struct messaging_context *msg_ctx,
145 const struct server_id pid,
146 const int argc, const char **argv)
148 if (argc != 2) {
149 fprintf(stderr, "Usage: smbcontrol <dest> debug "
150 "<debug-string>\n");
151 return False;
154 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
155 strlen(argv[1]) + 1);
158 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
160 /* Return the name of a process given it's PID. This will only work on Linux,
161 * but that's probably moot since this whole stack tracing implementatino is
162 * Linux-specific anyway.
164 static const char * procname(pid_t pid, char * buf, size_t bufsz)
166 char path[64];
167 FILE * fp;
169 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
170 (unsigned long long)pid);
171 if ((fp = fopen(path, "r")) == NULL) {
172 return NULL;
175 fgets(buf, bufsz, fp);
177 fclose(fp);
178 return buf;
181 static void print_stack_trace(pid_t pid, int * count)
183 void * pinfo = NULL;
184 unw_addr_space_t aspace = NULL;
185 unw_cursor_t cursor;
186 unw_word_t ip, sp;
188 char nbuf[256];
189 unw_word_t off;
191 int ret;
193 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
194 fprintf(stderr,
195 "Failed to attach to process %llu: %s\n",
196 (unsigned long long)pid, strerror(errno));
197 return;
200 /* Wait until the attach is complete. */
201 waitpid(pid, NULL, 0);
203 if (((pinfo = _UPT_create(pid)) == NULL) ||
204 ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
205 /* Probably out of memory. */
206 fprintf(stderr,
207 "Unable to initialize stack unwind for process %llu\n",
208 (unsigned long long)pid);
209 goto cleanup;
212 if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
213 fprintf(stderr,
214 "Unable to unwind stack for process %llu: %s\n",
215 (unsigned long long)pid, unw_strerror(ret));
216 goto cleanup;
219 if (*count > 0) {
220 printf("\n");
223 if (procname(pid, nbuf, sizeof(nbuf))) {
224 printf("Stack trace for process %llu (%s):\n",
225 (unsigned long long)pid, nbuf);
226 } else {
227 printf("Stack trace for process %llu:\n",
228 (unsigned long long)pid);
231 while (unw_step(&cursor) > 0) {
232 ip = sp = off = 0;
233 unw_get_reg(&cursor, UNW_REG_IP, &ip);
234 unw_get_reg(&cursor, UNW_REG_SP, &sp);
236 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
237 if (ret != 0 && ret != -UNW_ENOMEM) {
238 snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
240 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
241 nbuf, (long long)off, (long long)ip,
242 (long long)sp);
245 (*count)++;
247 cleanup:
248 if (aspace) {
249 unw_destroy_addr_space(aspace);
252 if (pinfo) {
253 _UPT_destroy(pinfo);
256 ptrace(PTRACE_DETACH, pid, NULL, NULL);
259 static int stack_trace_connection(struct db_record *rec,
260 const struct connections_key *key,
261 const struct connections_data *crec,
262 void *priv)
264 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
266 return 0;
269 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
270 const struct server_id pid,
271 const int argc, const char **argv)
273 pid_t dest;
274 int count = 0;
276 if (argc != 1) {
277 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
278 return False;
281 dest = procid_to_pid(&pid);
283 if (dest != 0) {
284 /* It would be nice to be able to make sure that this PID is
285 * the PID of a smbd/winbind/nmbd process, not some random PID
286 * the user liked the look of. It doesn't seem like it's worth
287 * the effort at the moment, however.
289 print_stack_trace(dest, &count);
290 } else {
291 connections_forall(stack_trace_connection, &count);
294 return True;
297 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
299 static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
300 const struct server_id pid,
301 const int argc, const char **argv)
303 fprintf(stderr,
304 "Daemon stack tracing is not supported on this platform\n");
305 return False;
308 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
310 /* Inject a fault (fatal signal) into a running smbd */
312 static bool do_inject_fault(struct messaging_context *msg_ctx,
313 const struct server_id pid,
314 const int argc, const char **argv)
316 if (argc != 2) {
317 fprintf(stderr, "Usage: smbcontrol <dest> inject "
318 "<bus|hup|term|internal|segv>\n");
319 return False;
322 #ifndef DEVELOPER
323 fprintf(stderr, "Fault injection is only available in "
324 "developer builds\n");
325 return False;
326 #else /* DEVELOPER */
328 int sig = 0;
330 if (strcmp(argv[1], "bus") == 0) {
331 sig = SIGBUS;
332 } else if (strcmp(argv[1], "hup") == 0) {
333 sig = SIGHUP;
334 } else if (strcmp(argv[1], "term") == 0) {
335 sig = SIGTERM;
336 } else if (strcmp(argv[1], "segv") == 0) {
337 sig = SIGSEGV;
338 } else if (strcmp(argv[1], "internal") == 0) {
339 /* Force an internal error, ie. an unclean exit. */
340 sig = -1;
341 } else {
342 fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
343 return False;
346 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
347 &sig, sizeof(int));
349 #endif /* DEVELOPER */
352 /* Force a browser election */
354 static bool do_election(struct messaging_context *msg_ctx,
355 const struct server_id pid,
356 const int argc, const char **argv)
358 if (argc != 1) {
359 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
360 return False;
363 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
366 /* Ping a samba daemon process */
368 static void pong_cb(struct messaging_context *msg,
369 void *private_data,
370 uint32_t msg_type,
371 struct server_id pid,
372 DATA_BLOB *data)
374 char *src_string = procid_str(NULL, &pid);
375 printf("PONG from pid %s\n", src_string);
376 TALLOC_FREE(src_string);
377 num_replies++;
380 static bool do_ping(struct messaging_context *msg_ctx,
381 const struct server_id pid,
382 const int argc, const char **argv)
384 if (argc != 1) {
385 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
386 return False;
389 /* Send a message and register our interest in a reply */
391 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
392 return False;
394 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
396 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
398 /* No replies were received within the timeout period */
400 if (num_replies == 0)
401 printf("No replies received\n");
403 messaging_deregister(msg_ctx, MSG_PONG, NULL);
405 return num_replies;
408 /* Set profiling options */
410 static bool do_profile(struct messaging_context *msg_ctx,
411 const struct server_id pid,
412 const int argc, const char **argv)
414 int v;
416 if (argc != 2) {
417 fprintf(stderr, "Usage: smbcontrol <dest> profile "
418 "<off|count|on|flush>\n");
419 return False;
422 if (strcmp(argv[1], "off") == 0) {
423 v = 0;
424 } else if (strcmp(argv[1], "count") == 0) {
425 v = 1;
426 } else if (strcmp(argv[1], "on") == 0) {
427 v = 2;
428 } else if (strcmp(argv[1], "flush") == 0) {
429 v = 3;
430 } else {
431 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
432 return False;
435 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
438 /* Return the profiling level */
440 static void profilelevel_cb(struct messaging_context *msg_ctx,
441 void *private_data,
442 uint32_t msg_type,
443 struct server_id pid,
444 DATA_BLOB *data)
446 int level;
447 const char *s;
449 num_replies++;
451 if (data->length != sizeof(int)) {
452 fprintf(stderr, "invalid message length %ld returned\n",
453 (unsigned long)data->length);
454 return;
457 memcpy(&level, data->data, sizeof(int));
459 switch (level) {
460 case 0:
461 s = "not enabled";
462 break;
463 case 1:
464 s = "off";
465 break;
466 case 3:
467 s = "count only";
468 break;
469 case 7:
470 s = "count and time";
471 break;
472 default:
473 s = "BOGUS";
474 break;
477 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
480 static void profilelevel_rqst(struct messaging_context *msg_ctx,
481 void *private_data,
482 uint32_t msg_type,
483 struct server_id pid,
484 DATA_BLOB *data)
486 int v = 0;
488 /* Send back a dummy reply */
490 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
493 static bool do_profilelevel(struct messaging_context *msg_ctx,
494 const struct server_id pid,
495 const int argc, const char **argv)
497 if (argc != 1) {
498 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
499 return False;
502 /* Send a message and register our interest in a reply */
504 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
505 return False;
507 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
508 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
509 profilelevel_rqst);
511 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
513 /* No replies were received within the timeout period */
515 if (num_replies == 0)
516 printf("No replies received\n");
518 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
520 return num_replies;
523 /* Display debug level settings */
525 static bool do_debuglevel(struct messaging_context *msg_ctx,
526 const struct server_id pid,
527 const int argc, const char **argv)
529 if (argc != 1) {
530 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
531 return False;
534 /* Send a message and register our interest in a reply */
536 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
537 return False;
539 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
541 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
543 /* No replies were received within the timeout period */
545 if (num_replies == 0)
546 printf("No replies received\n");
548 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
550 return num_replies;
553 /* Send a print notify message */
555 static bool do_printnotify(struct messaging_context *msg_ctx,
556 const struct server_id pid,
557 const int argc, const char **argv)
559 const char *cmd;
561 /* Check for subcommand */
563 if (argc == 1) {
564 fprintf(stderr, "Must specify subcommand:\n");
565 fprintf(stderr, "\tqueuepause <printername>\n");
566 fprintf(stderr, "\tqueueresume <printername>\n");
567 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
568 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
569 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
570 fprintf(stderr, "\tprinter <printername> <comment|port|"
571 "driver> <value>\n");
573 return False;
576 cmd = argv[1];
578 if (strcmp(cmd, "queuepause") == 0) {
580 if (argc != 3) {
581 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
582 " queuepause <printername>\n");
583 return False;
586 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
588 goto send;
590 } else if (strcmp(cmd, "queueresume") == 0) {
592 if (argc != 3) {
593 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
594 " queuereume <printername>\n");
595 return False;
598 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
600 goto send;
602 } else if (strcmp(cmd, "jobpause") == 0) {
603 int jobid;
605 if (argc != 4) {
606 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
607 " jobpause <printername> <unix-jobid>\n");
608 return False;
611 jobid = atoi(argv[3]);
613 notify_job_status_byname(
614 argv[2], jobid, JOB_STATUS_PAUSED,
615 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
617 goto send;
619 } else if (strcmp(cmd, "jobresume") == 0) {
620 int jobid;
622 if (argc != 4) {
623 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
624 " jobpause <printername> <unix-jobid>\n");
625 return False;
628 jobid = atoi(argv[3]);
630 notify_job_status_byname(
631 argv[2], jobid, JOB_STATUS_QUEUED,
632 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
634 goto send;
636 } else if (strcmp(cmd, "jobdelete") == 0) {
637 int jobid;
639 if (argc != 4) {
640 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
641 " jobpause <printername> <unix-jobid>\n");
642 return False;
645 jobid = atoi(argv[3]);
647 notify_job_status_byname(
648 argv[2], jobid, JOB_STATUS_DELETING,
649 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
651 notify_job_status_byname(
652 argv[2], jobid, JOB_STATUS_DELETING|
653 JOB_STATUS_DELETED,
654 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
656 goto send;
658 } else if (strcmp(cmd, "printer") == 0) {
659 uint32 attribute;
661 if (argc != 5) {
662 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
663 "printer <printername> <comment|port|driver> "
664 "<value>\n");
665 return False;
668 if (strcmp(argv[3], "comment") == 0) {
669 attribute = PRINTER_NOTIFY_COMMENT;
670 } else if (strcmp(argv[3], "port") == 0) {
671 attribute = PRINTER_NOTIFY_PORT_NAME;
672 } else if (strcmp(argv[3], "driver") == 0) {
673 attribute = PRINTER_NOTIFY_DRIVER_NAME;
674 } else {
675 fprintf(stderr, "Invalid printer command '%s'\n",
676 argv[3]);
677 return False;
680 notify_printer_byname(argv[2], attribute,
681 CONST_DISCARD(char *, argv[4]));
683 goto send;
686 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
687 return False;
689 send:
690 print_notify_send_messages(msg_ctx, 0);
691 return True;
694 /* Close a share */
696 static bool do_closeshare(struct messaging_context *msg_ctx,
697 const struct server_id pid,
698 const int argc, const char **argv)
700 if (argc != 2) {
701 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
702 "<sharename>\n");
703 return False;
706 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
707 strlen(argv[1]) + 1);
710 /* force a blocking lock retry */
712 static bool do_lockretry(struct messaging_context *msg_ctx,
713 const struct server_id pid,
714 const int argc, const char **argv)
716 if (argc != 1) {
717 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
718 return False;
721 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
724 /* force a validation of all brl entries, including re-sends. */
726 static bool do_brl_revalidate(struct messaging_context *msg_ctx,
727 const struct server_id pid,
728 const int argc, const char **argv)
730 if (argc != 1) {
731 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
732 return False;
735 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
738 /* Force a SAM synchronisation */
740 static bool do_samsync(struct messaging_context *msg_ctx,
741 const struct server_id pid,
742 const int argc, const char **argv)
744 if (argc != 1) {
745 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
746 return False;
749 return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
752 /* Force a SAM replication */
754 static bool do_samrepl(struct messaging_context *msg_ctx,
755 const struct server_id pid,
756 const int argc, const char **argv)
758 if (argc != 1) {
759 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
760 return False;
763 return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
766 /* Display talloc pool usage */
768 static bool do_poolusage(struct messaging_context *msg_ctx,
769 const struct server_id pid,
770 const int argc, const char **argv)
772 if (argc != 1) {
773 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
774 return False;
777 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
779 /* Send a message and register our interest in a reply */
781 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
782 return False;
784 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
786 /* No replies were received within the timeout period */
788 if (num_replies == 0)
789 printf("No replies received\n");
791 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
793 return num_replies;
796 /* Perform a dmalloc mark */
798 static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
799 const struct server_id pid,
800 const int argc, const char **argv)
802 if (argc != 1) {
803 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
804 return False;
807 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
810 /* Perform a dmalloc changed */
812 static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
813 const struct server_id pid,
814 const int argc, const char **argv)
816 if (argc != 1) {
817 fprintf(stderr, "Usage: smbcontrol <dest> "
818 "dmalloc-log-changed\n");
819 return False;
822 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
823 NULL, 0);
826 /* Shutdown a server process */
828 static bool do_shutdown(struct messaging_context *msg_ctx,
829 const struct server_id pid,
830 const int argc, const char **argv)
832 if (argc != 1) {
833 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
834 return False;
837 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
840 /* Notify a driver upgrade */
842 static bool do_drvupgrade(struct messaging_context *msg_ctx,
843 const struct server_id pid,
844 const int argc, const char **argv)
846 if (argc != 2) {
847 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
848 "<driver-name>\n");
849 return False;
852 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
853 strlen(argv[1]) + 1);
856 static bool do_winbind_online(struct messaging_context *msg_ctx,
857 const struct server_id pid,
858 const int argc, const char **argv)
860 TDB_CONTEXT *tdb;
862 if (argc != 1) {
863 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
864 return False;
867 /* Remove the entry in the winbindd_cache tdb to tell a later
868 starting winbindd that we're online. */
870 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
871 if (!tdb) {
872 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
873 lock_path("winbindd_cache.tdb"));
874 return False;
877 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
878 tdb_close(tdb);
880 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
883 static bool do_winbind_offline(struct messaging_context *msg_ctx,
884 const struct server_id pid,
885 const int argc, const char **argv)
887 TDB_CONTEXT *tdb;
888 bool ret = False;
889 int retry = 0;
891 if (argc != 1) {
892 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
893 return False;
896 /* Create an entry in the winbindd_cache tdb to tell a later
897 starting winbindd that we're offline. We may actually create
898 it here... */
900 tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
901 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
902 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
904 if (!tdb) {
905 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
906 lock_path("winbindd_cache.tdb"));
907 return False;
910 /* There's a potential race condition that if a child
911 winbindd detects a domain is online at the same time
912 we're trying to tell it to go offline that it might
913 delete the record we add between us adding it and
914 sending the message. Minimize this by retrying up to
915 5 times. */
917 for (retry = 0; retry < 5; retry++) {
918 TDB_DATA d;
919 uint8 buf[4];
921 ZERO_STRUCT(d);
923 SIVAL(buf, 0, time(NULL));
924 d.dptr = buf;
925 d.dsize = 4;
927 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
929 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
930 NULL, 0);
932 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
933 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
935 if (!d.dptr || d.dsize != 4) {
936 SAFE_FREE(d.dptr);
937 DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
938 } else {
939 SAFE_FREE(d.dptr);
940 break;
944 tdb_close(tdb);
945 return ret;
948 static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
949 const struct server_id pid,
950 const int argc, const char **argv)
952 struct server_id myid;
954 myid = pid_to_procid(sys_getpid());
956 if (argc != 1) {
957 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
958 return False;
961 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
962 print_pid_string_cb);
964 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
965 sizeof(myid)))
966 return False;
968 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
970 /* No replies were received within the timeout period */
972 if (num_replies == 0)
973 printf("No replies received\n");
975 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
977 return num_replies;
980 static bool do_dump_event_list(struct messaging_context *msg_ctx,
981 const struct server_id pid,
982 const int argc, const char **argv)
984 struct server_id myid;
986 myid = pid_to_procid(sys_getpid());
988 if (argc != 1) {
989 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
990 return False;
993 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
996 static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
997 const struct server_id pid,
998 const int argc, const char **argv)
1000 const char *domain = NULL;
1001 int domain_len = 0;
1002 struct server_id myid;
1003 uint8_t *buf = NULL;
1004 int buf_len = 0;
1006 myid = pid_to_procid(sys_getpid());
1008 if (argc < 1 || argc > 2) {
1009 fprintf(stderr, "Usage: smbcontrol <dest> dump_domain_list "
1010 "<domain>\n");
1011 return false;
1014 if (argc == 2) {
1015 domain = argv[1];
1016 domain_len = strlen(argv[1]) + 1;
1019 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1020 print_pid_string_cb);
1022 buf_len = sizeof(myid)+domain_len;
1023 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1024 if (!buf) {
1025 return false;
1028 memcpy(buf, &myid, sizeof(myid));
1029 memcpy(&buf[sizeof(myid)], domain, domain_len);
1031 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1032 buf, buf_len))
1034 SAFE_FREE(buf);
1035 return false;
1038 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1040 /* No replies were received within the timeout period */
1042 SAFE_FREE(buf);
1043 if (num_replies == 0) {
1044 printf("No replies received\n");
1047 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1049 return num_replies;
1052 static void winbind_validate_cache_cb(struct messaging_context *msg,
1053 void *private_data,
1054 uint32_t msg_type,
1055 struct server_id pid,
1056 DATA_BLOB *data)
1058 char *src_string = procid_str(NULL, &pid);
1059 printf("Winbindd cache is %svalid. (answer from pid %s)\n",
1060 (*(data->data) == 0 ? "" : "NOT "), src_string);
1061 TALLOC_FREE(src_string);
1062 num_replies++;
1065 static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1066 const struct server_id pid,
1067 const int argc, const char **argv)
1069 struct server_id myid = pid_to_procid(sys_getpid());
1071 if (argc != 1) {
1072 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1073 return False;
1076 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1077 winbind_validate_cache_cb);
1079 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1080 sizeof(myid))) {
1081 return False;
1084 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1086 if (num_replies == 0) {
1087 printf("No replies received\n");
1090 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1092 return num_replies;
1095 static bool do_reload_config(struct messaging_context *msg_ctx,
1096 const struct server_id pid,
1097 const int argc, const char **argv)
1099 if (argc != 1) {
1100 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1101 return False;
1104 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1107 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1109 fstring unix_name;
1110 memset( (char *)n, '\0', sizeof(struct nmb_name) );
1111 fstrcpy(unix_name, name);
1112 strupper_m(unix_name);
1113 push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
1114 n->name_type = (unsigned int)type & 0xFF;
1115 push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
1118 static bool do_nodestatus(struct messaging_context *msg_ctx,
1119 const struct server_id pid,
1120 const int argc, const char **argv)
1122 struct packet_struct p;
1124 if (argc != 2) {
1125 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1126 return False;
1129 ZERO_STRUCT(p);
1131 (void)interpret_addr2(&p.ip, argv[1]);
1132 p.port = 137;
1133 p.packet_type = NMB_PACKET;
1135 p.packet.nmb.header.name_trn_id = 10;
1136 p.packet.nmb.header.opcode = 0;
1137 p.packet.nmb.header.response = False;
1138 p.packet.nmb.header.nm_flags.bcast = False;
1139 p.packet.nmb.header.nm_flags.recursion_available = False;
1140 p.packet.nmb.header.nm_flags.recursion_desired = False;
1141 p.packet.nmb.header.nm_flags.trunc = False;
1142 p.packet.nmb.header.nm_flags.authoritative = False;
1143 p.packet.nmb.header.rcode = 0;
1144 p.packet.nmb.header.qdcount = 1;
1145 p.packet.nmb.header.ancount = 0;
1146 p.packet.nmb.header.nscount = 0;
1147 p.packet.nmb.header.arcount = 0;
1148 my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
1149 p.packet.nmb.question.question_type = 0x21;
1150 p.packet.nmb.question.question_class = 0x1;
1152 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1155 /* A list of message type supported */
1157 static const struct {
1158 const char *name; /* Option name */
1159 bool (*fn)(struct messaging_context *msg_ctx,
1160 const struct server_id pid,
1161 const int argc, const char **argv);
1162 const char *help; /* Short help text */
1163 } msg_types[] = {
1164 { "debug", do_debug, "Set debuglevel" },
1165 { "force-election", do_election,
1166 "Force a browse election" },
1167 { "ping", do_ping, "Elicit a response" },
1168 { "profile", do_profile, "" },
1169 { "inject", do_inject_fault,
1170 "Inject a fatal signal into a running smbd"},
1171 { "stacktrace", do_daemon_stack_trace,
1172 "Display a stack trace of a daemon" },
1173 { "profilelevel", do_profilelevel, "" },
1174 { "debuglevel", do_debuglevel, "Display current debuglevels" },
1175 { "printnotify", do_printnotify, "Send a print notify message" },
1176 { "close-share", do_closeshare, "Forcibly disconnect a share" },
1177 { "lockretry", do_lockretry, "Force a blocking lock retry" },
1178 { "brl-revalidate", do_brl_revalidate, "Revalidate all brl entries" },
1179 { "samsync", do_samsync, "Initiate SAM synchronisation" },
1180 { "samrepl", do_samrepl, "Initiate SAM replication" },
1181 { "pool-usage", do_poolusage, "Display talloc memory usage" },
1182 { "dmalloc-mark", do_dmalloc_mark, "" },
1183 { "dmalloc-log-changed", do_dmalloc_changed, "" },
1184 { "shutdown", do_shutdown, "Shut down daemon" },
1185 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
1186 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
1187 { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
1188 { "online", do_winbind_online, "Ask winbind to go into online state"},
1189 { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
1190 { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
1191 { "dump-event-list", do_dump_event_list, "Dump event list"},
1192 { "validate-cache" , do_winbind_validate_cache,
1193 "Validate winbind's credential cache" },
1194 { "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
1195 { "noop", do_noop, "Do nothing" },
1196 { NULL }
1199 /* Display usage information */
1201 static void usage(poptContext pc)
1203 int i;
1205 poptPrintHelp(pc, stderr, 0);
1207 fprintf(stderr, "\n");
1208 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1209 "process ID\n");
1211 fprintf(stderr, "\n");
1212 fprintf(stderr, "<message-type> is one of:\n");
1214 for (i = 0; msg_types[i].name; i++)
1215 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name,
1216 msg_types[i].help);
1218 fprintf(stderr, "\n");
1220 exit(1);
1223 /* Return the pid number for a string destination */
1225 static struct server_id parse_dest(const char *dest)
1227 struct server_id result = {-1};
1228 pid_t pid;
1230 /* Zero is a special return value for broadcast to all processes */
1232 if (strequal(dest, "all")) {
1233 return interpret_pid(MSG_BROADCAST_PID_STR);
1236 /* Try self - useful for testing */
1238 if (strequal(dest, "self")) {
1239 return pid_to_procid(sys_getpid());
1242 /* Fix winbind typo. */
1243 if (strequal(dest, "winbind")) {
1244 dest = "winbindd";
1247 if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
1248 /* Check for numeric pid number */
1250 result = interpret_pid(dest);
1252 /* Zero isn't valid if not smbd. */
1253 if (result.pid && procid_valid(&result)) {
1254 return result;
1258 /* Look up other destinations in pidfile directory */
1260 if ((pid = pidfile_pid(dest)) != 0) {
1261 return pid_to_procid(pid);
1264 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1266 return result;
1269 /* Execute smbcontrol command */
1271 static bool do_command(struct messaging_context *msg_ctx,
1272 int argc, const char **argv)
1274 const char *dest = argv[0], *command = argv[1];
1275 struct server_id pid;
1276 int i;
1278 /* Check destination */
1280 pid = parse_dest(dest);
1281 if (!procid_valid(&pid)) {
1282 return False;
1285 /* Check command */
1287 for (i = 0; msg_types[i].name; i++) {
1288 if (strequal(command, msg_types[i].name))
1289 return msg_types[i].fn(msg_ctx, pid,
1290 argc - 1, argv + 1);
1293 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1295 return False;
1298 static void smbcontrol_help(poptContext pc,
1299 enum poptCallbackReason preason,
1300 struct poptOption * poption,
1301 const char * parg,
1302 void * pdata)
1304 if (poption->shortName != '?') {
1305 poptPrintUsage(pc, stdout, 0);
1306 } else {
1307 usage(pc);
1310 exit(0);
1313 struct poptOption help_options[] = {
1314 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&smbcontrol_help, '\0',
1315 NULL, NULL },
1316 { "help", '?', 0, NULL, '?', "Show this help message", NULL },
1317 { "usage", '\0', 0, NULL, 'u', "Display brief usage message", NULL },
1318 { NULL }
1321 /* Main program */
1323 int main(int argc, const char **argv)
1325 poptContext pc;
1326 int opt;
1327 struct event_context *evt_ctx;
1328 struct messaging_context *msg_ctx;
1330 static struct poptOption long_options[] = {
1331 /* POPT_AUTOHELP */
1332 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, help_options,
1333 0, "Help options:", NULL },
1334 { "timeout", 't', POPT_ARG_INT, &timeout, 't',
1335 "Set timeout value in seconds", "TIMEOUT" },
1337 POPT_COMMON_SAMBA
1338 POPT_TABLEEND
1340 TALLOC_CTX *frame = talloc_stackframe();
1341 int ret = 0;
1343 load_case_tables();
1345 setup_logging(argv[0],True);
1347 /* Parse command line arguments using popt */
1349 pc = poptGetContext(
1350 "smbcontrol", argc, (const char **)argv, long_options, 0);
1352 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1353 "<parameters>");
1355 if (argc == 1)
1356 usage(pc);
1358 while ((opt = poptGetNextOpt(pc)) != -1) {
1359 switch(opt) {
1360 case 't': /* --timeout */
1361 break;
1362 default:
1363 fprintf(stderr, "Invalid option\n");
1364 poptPrintHelp(pc, stderr, 0);
1365 break;
1369 /* We should now have the remaining command line arguments in
1370 argv. The argc parameter should have been decremented to the
1371 correct value in the above switch statement. */
1373 argv = (const char **)poptGetArgs(pc);
1374 argc = 0;
1375 if (argv != NULL) {
1376 while (argv[argc] != NULL) {
1377 argc++;
1381 if (argc <= 1)
1382 usage(pc);
1384 lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1386 /* Need to invert sense of return code -- samba
1387 * routines mostly return True==1 for success, but
1388 * shell needs 0. */
1390 if (!(evt_ctx = event_context_init(NULL)) ||
1391 !(msg_ctx = messaging_init(NULL, server_id_self(), evt_ctx))) {
1392 fprintf(stderr, "could not init messaging context\n");
1393 TALLOC_FREE(frame);
1394 exit(1);
1397 ret = !do_command(msg_ctx, argc, argv);
1398 TALLOC_FREE(frame);
1399 return ret;