source: branches/samba-3.3.x/source/utils/smbcontrol.c@ 472

Last change on this file since 472 was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

File size: 33.7 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 smbcontrol_timeout(struct event_context *event_ctx,
69 struct timed_event *te,
70 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, (void *)&timed_out))) {
89 DEBUG(0, ("event_add_timed failed\n"));
90 return;
91 }
92
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));
98 }
99}
100
101/* Message handler callback that displays the PID and a string on stdout */
102
103static 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)
108{
109 printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
110 (int)data->length, (const char *)data->data);
111 num_replies++;
112}
113
114/* Message handler callback that displays a string on stdout */
115
116static 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)
121{
122 printf("%.*s", (int)data->length, (const char *)data->data);
123 num_replies++;
124}
125
126/* Send no message. Useful for testing. */
127
128static bool do_noop(struct messaging_context *msg_ctx,
129 const struct server_id pid,
130 const int argc, const char **argv)
131{
132 if (argc != 1) {
133 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
134 return False;
135 }
136
137 /* Move along, nothing to see here */
138
139 return True;
140}
141
142/* Send a debug string */
143
144static bool do_debug(struct messaging_context *msg_ctx,
145 const struct server_id pid,
146 const int argc, const char **argv)
147{
148 if (argc != 2) {
149 fprintf(stderr, "Usage: smbcontrol <dest> debug "
150 "<debug-string>\n");
151 return False;
152 }
153
154 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
155 strlen(argv[1]) + 1);
156}
157
158#if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
159
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.
163 */
164static const char * procname(pid_t pid, char * buf, size_t bufsz)
165{
166 char path[64];
167 FILE * fp;
168
169 snprintf(path, sizeof(path), "/proc/%llu/cmdline",
170 (unsigned long long)pid);
171 if ((fp = fopen(path, "r")) == NULL) {
172 return NULL;
173 }
174
175 fgets(buf, bufsz, fp);
176
177 fclose(fp);
178 return buf;
179}
180
181static void print_stack_trace(pid_t pid, int * count)
182{
183 void * pinfo = NULL;
184 unw_addr_space_t aspace = NULL;
185 unw_cursor_t cursor;
186 unw_word_t ip, sp;
187
188 char nbuf[256];
189 unw_word_t off;
190
191 int ret;
192
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;
198 }
199
200 /* Wait until the attach is complete. */
201 waitpid(pid, NULL, 0);
202
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;
210 }
211
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;
217 }
218
219 if (*count > 0) {
220 printf("\n");
221 }
222
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);
229 }
230
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);
235
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>");
239 }
240 printf(" %s + %#llx [ip=%#llx] [sp=%#llx]\n",
241 nbuf, (long long)off, (long long)ip,
242 (long long)sp);
243 }
244
245 (*count)++;
246
247cleanup:
248 if (aspace) {
249 unw_destroy_addr_space(aspace);
250 }
251
252 if (pinfo) {
253 _UPT_destroy(pinfo);
254 }
255
256 ptrace(PTRACE_DETACH, pid, NULL, NULL);
257}
258
259static int stack_trace_connection(struct db_record *rec,
260 const struct connections_key *key,
261 const struct connections_data *crec,
262 void *priv)
263{
264 print_stack_trace(procid_to_pid(&crec->pid), (int *)priv);
265
266 return 0;
267}
268
269static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
270 const struct server_id pid,
271 const int argc, const char **argv)
272{
273 pid_t dest;
274 int count = 0;
275
276 if (argc != 1) {
277 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
278 return False;
279 }
280
281 dest = procid_to_pid(&pid);
282
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.
288 */
289 print_stack_trace(dest, &count);
290 } else {
291 connections_forall(stack_trace_connection, &count);
292 }
293
294 return True;
295}
296
297#else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
298
299static bool do_daemon_stack_trace(struct messaging_context *msg_ctx,
300 const struct server_id pid,
301 const int argc, const char **argv)
302{
303 fprintf(stderr,
304 "Daemon stack tracing is not supported on this platform\n");
305 return False;
306}
307
308#endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
309
310/* Inject a fault (fatal signal) into a running smbd */
311
312static bool do_inject_fault(struct messaging_context *msg_ctx,
313 const struct server_id pid,
314 const int argc, const char **argv)
315{
316 if (argc != 2) {
317 fprintf(stderr, "Usage: smbcontrol <dest> inject "
318 "<bus|hup|term|internal|segv>\n");
319 return False;
320 }
321
322#ifndef DEVELOPER
323 fprintf(stderr, "Fault injection is only available in "
324 "developer builds\n");
325 return False;
326#else /* DEVELOPER */
327 {
328 int sig = 0;
329
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;
344 }
345
346 return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
347 &sig, sizeof(int));
348 }
349#endif /* DEVELOPER */
350}
351
352/* Force a browser election */
353
354static bool do_election(struct messaging_context *msg_ctx,
355 const struct server_id pid,
356 const int argc, const char **argv)
357{
358 if (argc != 1) {
359 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
360 return False;
361 }
362
363 return send_message(msg_ctx, pid, MSG_FORCE_ELECTION, NULL, 0);
364}
365
366/* Ping a samba daemon process */
367
368static 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)
373{
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++;
378}
379
380static bool do_ping(struct messaging_context *msg_ctx,
381 const struct server_id pid,
382 const int argc, const char **argv)
383{
384 if (argc != 1) {
385 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
386 return False;
387 }
388
389 /* Send a message and register our interest in a reply */
390
391 if (!send_message(msg_ctx, pid, MSG_PING, NULL, 0))
392 return False;
393
394 messaging_register(msg_ctx, NULL, MSG_PONG, pong_cb);
395
396 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
397
398 /* No replies were received within the timeout period */
399
400 if (num_replies == 0)
401 printf("No replies received\n");
402
403 messaging_deregister(msg_ctx, MSG_PONG, NULL);
404
405 return num_replies;
406}
407
408/* Set profiling options */
409
410static bool do_profile(struct messaging_context *msg_ctx,
411 const struct server_id pid,
412 const int argc, const char **argv)
413{
414 int v;
415
416 if (argc != 2) {
417 fprintf(stderr, "Usage: smbcontrol <dest> profile "
418 "<off|count|on|flush>\n");
419 return False;
420 }
421
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;
433 }
434
435 return send_message(msg_ctx, pid, MSG_PROFILE, &v, sizeof(int));
436}
437
438/* Return the profiling level */
439
440static 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)
445{
446 int level;
447 const char *s;
448
449 num_replies++;
450
451 if (data->length != sizeof(int)) {
452 fprintf(stderr, "invalid message length %ld returned\n",
453 (unsigned long)data->length);
454 return;
455 }
456
457 memcpy(&level, data->data, sizeof(int));
458
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;
475 }
476
477 printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
478}
479
480static 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)
485{
486 int v = 0;
487
488 /* Send back a dummy reply */
489
490 send_message(msg_ctx, pid, MSG_PROFILELEVEL, &v, sizeof(int));
491}
492
493static bool do_profilelevel(struct messaging_context *msg_ctx,
494 const struct server_id pid,
495 const int argc, const char **argv)
496{
497 if (argc != 1) {
498 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
499 return False;
500 }
501
502 /* Send a message and register our interest in a reply */
503
504 if (!send_message(msg_ctx, pid, MSG_REQ_PROFILELEVEL, NULL, 0))
505 return False;
506
507 messaging_register(msg_ctx, NULL, MSG_PROFILELEVEL, profilelevel_cb);
508 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
509 profilelevel_rqst);
510
511 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
512
513 /* No replies were received within the timeout period */
514
515 if (num_replies == 0)
516 printf("No replies received\n");
517
518 messaging_deregister(msg_ctx, MSG_PROFILE, NULL);
519
520 return num_replies;
521}
522
523/* Display debug level settings */
524
525static bool do_debuglevel(struct messaging_context *msg_ctx,
526 const struct server_id pid,
527 const int argc, const char **argv)
528{
529 if (argc != 1) {
530 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
531 return False;
532 }
533
534 /* Send a message and register our interest in a reply */
535
536 if (!send_message(msg_ctx, pid, MSG_REQ_DEBUGLEVEL, NULL, 0))
537 return False;
538
539 messaging_register(msg_ctx, NULL, MSG_DEBUGLEVEL, print_pid_string_cb);
540
541 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
542
543 /* No replies were received within the timeout period */
544
545 if (num_replies == 0)
546 printf("No replies received\n");
547
548 messaging_deregister(msg_ctx, MSG_DEBUGLEVEL, NULL);
549
550 return num_replies;
551}
552
553/* Send a print notify message */
554
555static bool do_printnotify(struct messaging_context *msg_ctx,
556 const struct server_id pid,
557 const int argc, const char **argv)
558{
559 const char *cmd;
560
561 /* Check for subcommand */
562
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");
572
573 return False;
574 }
575
576 cmd = argv[1];
577
578 if (strcmp(cmd, "queuepause") == 0) {
579
580 if (argc != 3) {
581 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
582 " queuepause <printername>\n");
583 return False;
584 }
585
586 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
587
588 goto send;
589
590 } else if (strcmp(cmd, "queueresume") == 0) {
591
592 if (argc != 3) {
593 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
594 " queuereume <printername>\n");
595 return False;
596 }
597
598 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
599
600 goto send;
601
602 } else if (strcmp(cmd, "jobpause") == 0) {
603 int jobid;
604
605 if (argc != 4) {
606 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
607 " jobpause <printername> <unix-jobid>\n");
608 return False;
609 }
610
611 jobid = atoi(argv[3]);
612
613 notify_job_status_byname(
614 argv[2], jobid, JOB_STATUS_PAUSED,
615 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
616
617 goto send;
618
619 } else if (strcmp(cmd, "jobresume") == 0) {
620 int jobid;
621
622 if (argc != 4) {
623 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
624 " jobpause <printername> <unix-jobid>\n");
625 return False;
626 }
627
628 jobid = atoi(argv[3]);
629
630 notify_job_status_byname(
631 argv[2], jobid, JOB_STATUS_QUEUED,
632 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
633
634 goto send;
635
636 } else if (strcmp(cmd, "jobdelete") == 0) {
637 int jobid;
638
639 if (argc != 4) {
640 fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
641 " jobpause <printername> <unix-jobid>\n");
642 return False;
643 }
644
645 jobid = atoi(argv[3]);
646
647 notify_job_status_byname(
648 argv[2], jobid, JOB_STATUS_DELETING,
649 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
650
651 notify_job_status_byname(
652 argv[2], jobid, JOB_STATUS_DELETING|
653 JOB_STATUS_DELETED,
654 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
655
656 goto send;
657
658 } else if (strcmp(cmd, "printer") == 0) {
659 uint32 attribute;
660
661 if (argc != 5) {
662 fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
663 "printer <printername> <comment|port|driver> "
664 "<value>\n");
665 return False;
666 }
667
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;
678 }
679
680 notify_printer_byname(argv[2], attribute,
681 CONST_DISCARD(char *, argv[4]));
682
683 goto send;
684 }
685
686 fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
687 return False;
688
689send:
690 print_notify_send_messages(msg_ctx, 0);
691 return True;
692}
693
694/* Close a share */
695
696static bool do_closeshare(struct messaging_context *msg_ctx,
697 const struct server_id pid,
698 const int argc, const char **argv)
699{
700 if (argc != 2) {
701 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
702 "<sharename>\n");
703 return False;
704 }
705
706 return send_message(msg_ctx, pid, MSG_SMB_FORCE_TDIS, argv[1],
707 strlen(argv[1]) + 1);
708}
709
710/* force a blocking lock retry */
711
712static bool do_lockretry(struct messaging_context *msg_ctx,
713 const struct server_id pid,
714 const int argc, const char **argv)
715{
716 if (argc != 1) {
717 fprintf(stderr, "Usage: smbcontrol <dest> lockretry\n");
718 return False;
719 }
720
721 return send_message(msg_ctx, pid, MSG_SMB_UNLOCK, NULL, 0);
722}
723
724/* force a validation of all brl entries, including re-sends. */
725
726static bool do_brl_revalidate(struct messaging_context *msg_ctx,
727 const struct server_id pid,
728 const int argc, const char **argv)
729{
730 if (argc != 1) {
731 fprintf(stderr, "Usage: smbcontrol <dest> brl-revalidate\n");
732 return False;
733 }
734
735 return send_message(msg_ctx, pid, MSG_SMB_BRL_VALIDATE, NULL, 0);
736}
737
738/* Force a SAM synchronisation */
739
740static bool do_samsync(struct messaging_context *msg_ctx,
741 const struct server_id pid,
742 const int argc, const char **argv)
743{
744 if (argc != 1) {
745 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
746 return False;
747 }
748
749 return send_message(msg_ctx, pid, MSG_SMB_SAM_SYNC, NULL, 0);
750}
751
752/* Force a SAM replication */
753
754static bool do_samrepl(struct messaging_context *msg_ctx,
755 const struct server_id pid,
756 const int argc, const char **argv)
757{
758 if (argc != 1) {
759 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
760 return False;
761 }
762
763 return send_message(msg_ctx, pid, MSG_SMB_SAM_REPL, NULL, 0);
764}
765
766/* Display talloc pool usage */
767
768static bool do_poolusage(struct messaging_context *msg_ctx,
769 const struct server_id pid,
770 const int argc, const char **argv)
771{
772 if (argc != 1) {
773 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
774 return False;
775 }
776
777 messaging_register(msg_ctx, NULL, MSG_POOL_USAGE, print_string_cb);
778
779 /* Send a message and register our interest in a reply */
780
781 if (!send_message(msg_ctx, pid, MSG_REQ_POOL_USAGE, NULL, 0))
782 return False;
783
784 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
785
786 /* No replies were received within the timeout period */
787
788 if (num_replies == 0)
789 printf("No replies received\n");
790
791 messaging_deregister(msg_ctx, MSG_POOL_USAGE, NULL);
792
793 return num_replies;
794}
795
796/* Perform a dmalloc mark */
797
798static bool do_dmalloc_mark(struct messaging_context *msg_ctx,
799 const struct server_id pid,
800 const int argc, const char **argv)
801{
802 if (argc != 1) {
803 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
804 return False;
805 }
806
807 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_MARK, NULL, 0);
808}
809
810/* Perform a dmalloc changed */
811
812static bool do_dmalloc_changed(struct messaging_context *msg_ctx,
813 const struct server_id pid,
814 const int argc, const char **argv)
815{
816 if (argc != 1) {
817 fprintf(stderr, "Usage: smbcontrol <dest> "
818 "dmalloc-log-changed\n");
819 return False;
820 }
821
822 return send_message(msg_ctx, pid, MSG_REQ_DMALLOC_LOG_CHANGED,
823 NULL, 0);
824}
825
826/* Shutdown a server process */
827
828static bool do_shutdown(struct messaging_context *msg_ctx,
829 const struct server_id pid,
830 const int argc, const char **argv)
831{
832 if (argc != 1) {
833 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
834 return False;
835 }
836
837 return send_message(msg_ctx, pid, MSG_SHUTDOWN, NULL, 0);
838}
839
840/* Notify a driver upgrade */
841
842static bool do_drvupgrade(struct messaging_context *msg_ctx,
843 const struct server_id pid,
844 const int argc, const char **argv)
845{
846 if (argc != 2) {
847 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
848 "<driver-name>\n");
849 return False;
850 }
851
852 return send_message(msg_ctx, pid, MSG_DEBUG, argv[1],
853 strlen(argv[1]) + 1);
854}
855
856static bool do_winbind_online(struct messaging_context *msg_ctx,
857 const struct server_id pid,
858 const int argc, const char **argv)
859{
860 TDB_CONTEXT *tdb;
861
862 if (argc != 1) {
863 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
864 return False;
865 }
866
867 /* Remove the entry in the winbindd_cache tdb to tell a later
868 starting winbindd that we're online. */
869
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;
875 }
876
877 tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
878 tdb_close(tdb);
879
880 return send_message(msg_ctx, pid, MSG_WINBIND_ONLINE, NULL, 0);
881}
882
883static bool do_winbind_offline(struct messaging_context *msg_ctx,
884 const struct server_id pid,
885 const int argc, const char **argv)
886{
887 TDB_CONTEXT *tdb;
888 bool ret = False;
889 int retry = 0;
890
891 if (argc != 1) {
892 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
893 return False;
894 }
895
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... */
899
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);
903
904 if (!tdb) {
905 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
906 lock_path("winbindd_cache.tdb"));
907 return False;
908 }
909
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. */
916
917 for (retry = 0; retry < 5; retry++) {
918 TDB_DATA d;
919 uint8 buf[4];
920
921 ZERO_STRUCT(d);
922
923 SIVAL(buf, 0, time(NULL));
924 d.dptr = buf;
925 d.dsize = 4;
926
927 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
928
929 ret = send_message(msg_ctx, pid, MSG_WINBIND_OFFLINE,
930 NULL, 0);
931
932 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
933 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
934
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;
941 }
942 }
943
944 tdb_close(tdb);
945 return ret;
946}
947
948static bool do_winbind_onlinestatus(struct messaging_context *msg_ctx,
949 const struct server_id pid,
950 const int argc, const char **argv)
951{
952 struct server_id myid;
953
954 myid = pid_to_procid(sys_getpid());
955
956 if (argc != 1) {
957 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
958 return False;
959 }
960
961 messaging_register(msg_ctx, NULL, MSG_WINBIND_ONLINESTATUS,
962 print_pid_string_cb);
963
964 if (!send_message(msg_ctx, pid, MSG_WINBIND_ONLINESTATUS, &myid,
965 sizeof(myid)))
966 return False;
967
968 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
969
970 /* No replies were received within the timeout period */
971
972 if (num_replies == 0)
973 printf("No replies received\n");
974
975 messaging_deregister(msg_ctx, MSG_WINBIND_ONLINESTATUS, NULL);
976
977 return num_replies;
978}
979
980static bool do_dump_event_list(struct messaging_context *msg_ctx,
981 const struct server_id pid,
982 const int argc, const char **argv)
983{
984 struct server_id myid;
985
986 myid = pid_to_procid(sys_getpid());
987
988 if (argc != 1) {
989 fprintf(stderr, "Usage: smbcontrol <dest> dump-event-list\n");
990 return False;
991 }
992
993 return send_message(msg_ctx, pid, MSG_DUMP_EVENT_LIST, NULL, 0);
994}
995
996static bool do_winbind_dump_domain_list(struct messaging_context *msg_ctx,
997 const struct server_id pid,
998 const int argc, const char **argv)
999{
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;
1005
1006 myid = pid_to_procid(sys_getpid());
1007
1008 if (argc < 1 || argc > 2) {
1009 fprintf(stderr, "Usage: smbcontrol <dest> dump_domain_list "
1010 "<domain>\n");
1011 return false;
1012 }
1013
1014 if (argc == 2) {
1015 domain = argv[1];
1016 domain_len = strlen(argv[1]) + 1;
1017 }
1018
1019 messaging_register(msg_ctx, NULL, MSG_WINBIND_DUMP_DOMAIN_LIST,
1020 print_pid_string_cb);
1021
1022 buf_len = sizeof(myid)+domain_len;
1023 buf = SMB_MALLOC_ARRAY(uint8_t, buf_len);
1024 if (!buf) {
1025 return false;
1026 }
1027
1028 memcpy(buf, &myid, sizeof(myid));
1029 memcpy(&buf[sizeof(myid)], domain, domain_len);
1030
1031 if (!send_message(msg_ctx, pid, MSG_WINBIND_DUMP_DOMAIN_LIST,
1032 buf, buf_len))
1033 {
1034 SAFE_FREE(buf);
1035 return false;
1036 }
1037
1038 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1039
1040 /* No replies were received within the timeout period */
1041
1042 SAFE_FREE(buf);
1043 if (num_replies == 0) {
1044 printf("No replies received\n");
1045 }
1046
1047 messaging_deregister(msg_ctx, MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1048
1049 return num_replies;
1050}
1051
1052static 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)
1057{
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++;
1063}
1064
1065static bool do_winbind_validate_cache(struct messaging_context *msg_ctx,
1066 const struct server_id pid,
1067 const int argc, const char **argv)
1068{
1069 struct server_id myid = pid_to_procid(sys_getpid());
1070
1071 if (argc != 1) {
1072 fprintf(stderr, "Usage: smbcontrol winbindd validate-cache\n");
1073 return False;
1074 }
1075
1076 messaging_register(msg_ctx, NULL, MSG_WINBIND_VALIDATE_CACHE,
1077 winbind_validate_cache_cb);
1078
1079 if (!send_message(msg_ctx, pid, MSG_WINBIND_VALIDATE_CACHE, &myid,
1080 sizeof(myid))) {
1081 return False;
1082 }
1083
1084 wait_replies(msg_ctx, procid_to_pid(&pid) == 0);
1085
1086 if (num_replies == 0) {
1087 printf("No replies received\n");
1088 }
1089
1090 messaging_deregister(msg_ctx, MSG_WINBIND_VALIDATE_CACHE, NULL);
1091
1092 return num_replies;
1093}
1094
1095static bool do_reload_config(struct messaging_context *msg_ctx,
1096 const struct server_id pid,
1097 const int argc, const char **argv)
1098{
1099 if (argc != 1) {
1100 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
1101 return False;
1102 }
1103
1104 return send_message(msg_ctx, pid, MSG_SMB_CONF_UPDATED, NULL, 0);
1105}
1106
1107static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
1108{
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);
1116}
1117
1118static bool do_nodestatus(struct messaging_context *msg_ctx,
1119 const struct server_id pid,
1120 const int argc, const char **argv)
1121{
1122 struct packet_struct p;
1123
1124 if (argc != 2) {
1125 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
1126 return False;
1127 }
1128
1129 ZERO_STRUCT(p);
1130
1131 (void)interpret_addr2(&p.ip, argv[1]);
1132 p.port = 137;
1133 p.packet_type = NMB_PACKET;
1134
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;
1151
1152 return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
1153}
1154
1155/* A list of message type supported */
1156
1157static 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 }
1197};
1198
1199/* Display usage information */
1200
1201static void usage(poptContext pc)
1202{
1203 int i;
1204
1205 poptPrintHelp(pc, stderr, 0);
1206
1207 fprintf(stderr, "\n");
1208 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
1209 "process ID\n");
1210
1211 fprintf(stderr, "\n");
1212 fprintf(stderr, "<message-type> is one of:\n");
1213
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);
1217
1218 fprintf(stderr, "\n");
1219
1220 exit(1);
1221}
1222
1223/* Return the pid number for a string destination */
1224
1225static struct server_id parse_dest(const char *dest)
1226{
1227 struct server_id result = {-1};
1228 pid_t pid;
1229
1230 /* Zero is a special return value for broadcast to all processes */
1231
1232 if (strequal(dest, "all")) {
1233 return interpret_pid(MSG_BROADCAST_PID_STR);
1234 }
1235
1236 /* Try self - useful for testing */
1237
1238 if (strequal(dest, "self")) {
1239 return pid_to_procid(sys_getpid());
1240 }
1241
1242 /* Fix winbind typo. */
1243 if (strequal(dest, "winbind")) {
1244 dest = "winbindd";
1245 }
1246
1247 if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
1248 /* Check for numeric pid number */
1249
1250 result = interpret_pid(dest);
1251
1252 /* Zero isn't valid if not smbd. */
1253 if (result.pid && procid_valid(&result)) {
1254 return result;
1255 }
1256 }
1257
1258 /* Look up other destinations in pidfile directory */
1259
1260 if ((pid = pidfile_pid(dest)) != 0) {
1261 return pid_to_procid(pid);
1262 }
1263
1264 fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
1265
1266 return result;
1267}
1268
1269/* Execute smbcontrol command */
1270
1271static bool do_command(struct messaging_context *msg_ctx,
1272 int argc, const char **argv)
1273{
1274 const char *dest = argv[0], *command = argv[1];
1275 struct server_id pid;
1276 int i;
1277
1278 /* Check destination */
1279
1280 pid = parse_dest(dest);
1281 if (!procid_valid(&pid)) {
1282 return False;
1283 }
1284
1285 /* Check command */
1286
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);
1291 }
1292
1293 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
1294
1295 return False;
1296}
1297
1298static void smbcontrol_help(poptContext pc,
1299 enum poptCallbackReason preason,
1300 struct poptOption * poption,
1301 const char * parg,
1302 void * pdata)
1303{
1304 if (poption->shortName != '?') {
1305 poptPrintUsage(pc, stdout, 0);
1306 } else {
1307 usage(pc);
1308 }
1309
1310 exit(0);
1311}
1312
1313struct 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 }
1319} ;
1320
1321/* Main program */
1322
1323int main(int argc, const char **argv)
1324{
1325 poptContext pc;
1326 int opt;
1327 struct event_context *evt_ctx;
1328 struct messaging_context *msg_ctx;
1329
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" },
1336
1337 POPT_COMMON_SAMBA
1338 POPT_TABLEEND
1339 };
1340 TALLOC_CTX *frame = talloc_stackframe();
1341 int ret = 0;
1342
1343 load_case_tables();
1344
1345 setup_logging(argv[0],True);
1346
1347 /* Parse command line arguments using popt */
1348
1349 pc = poptGetContext(
1350 "smbcontrol", argc, (const char **)argv, long_options, 0);
1351
1352 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
1353 "<parameters>");
1354
1355 if (argc == 1)
1356 usage(pc);
1357
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;
1366 }
1367 }
1368
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. */
1372
1373 argv = (const char **)poptGetArgs(pc);
1374 argc = 0;
1375 if (argv != NULL) {
1376 while (argv[argc] != NULL) {
1377 argc++;
1378 }
1379 }
1380
1381 if (argc <= 1)
1382 usage(pc);
1383
1384 lp_load(get_dyn_CONFIGFILE(),False,False,False,True);
1385
1386 /* Need to invert sense of return code -- samba
1387 * routines mostly return True==1 for success, but
1388 * shell needs 0. */
1389
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);
1395 }
1396
1397 ret = !do_command(msg_ctx, argc, argv);
1398 TALLOC_FREE(frame);
1399 return ret;
1400}
Note: See TracBrowser for help on using the repository browser.