source: branches/samba-3.2.x/source/utils/smbcontrol.c@ 1001

Last change on this file since 1001 was 133, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.0pre3

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