source: branches/samba-3.0/source/utils/smbcontrol.c

Last change on this file was 22, checked in by Yuri Dario, 18 years ago

Source code upgrade to 3.0.25pre2.

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