source: branches/samba-3.5.x/source3/utils/smbcontrol.c@ 773

Last change on this file since 773 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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