source: vendor/current/source3/utils/smbcontrol.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

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