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 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 2 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program; if not, write to the Free Software 23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24*/ 25 26#include "includes.h" 27 28/* Default timeout value when waiting for replies (in seconds) */ 29 30#define DEFAULT_TIMEOUT 10 31 32static int timeout = DEFAULT_TIMEOUT; 33static int num_replies; /* Used by message callback fns */ 34 35/* Send a message to a destination pid. Zero means broadcast smbd. */ 36 37static BOOL send_message(pid_t pid, int msg_type, const void *buf, int len, 38 BOOL duplicates) 39{ 40 TDB_CONTEXT *tdb; 41 BOOL ret; 42 int n_sent = 0; 43 44 if (!message_init()) 45 return False; 46 47 if (pid != 0) 48 return message_send_pid(pid, msg_type, buf, len, duplicates); 49 50 tdb = tdb_open_log(lock_path("connections.tdb"), 0, 51 TDB_DEFAULT, O_RDWR, 0); 52 if (!tdb) { 53 fprintf(stderr,"Failed to open connections database" 54 ": %s\n", strerror(errno)); 55 return False; 56 } 57 58 ret = message_send_all(tdb,msg_type, buf, len, duplicates, 59 &n_sent); 60 DEBUG(10,("smbcontrol/send_message: broadcast message to " 61 "%d processes\n", n_sent)); 62 63 tdb_close(tdb); 64 65 return ret; 66} 67 68/* Wait for one or more reply messages */ 69 70static void wait_replies(BOOL multiple_replies) 71{ 72 time_t start_time = time(NULL); 73 74 /* Wait around a bit. This is pretty disgusting - we have to 75 busy-wait here as there is no nicer way to do it. */ 76 77 do { 78 message_dispatch(); 79 if (num_replies > 0 && !multiple_replies) 80 break; 81 sleep(1); 82 } while (timeout - (time(NULL) - start_time) > 0); 83} 84 85/* Message handler callback that displays the PID and a string on stdout */ 86 87static void print_pid_string_cb(int msg_type, pid_t pid, void *buf, size_t len) 88{ 89 printf("PID %u: %.*s", (unsigned int)pid, (int)len, (const char *)buf); 90 num_replies++; 91} 92 93/* Message handler callback that displays a string on stdout */ 94 95static void print_string_cb(int msg_type, pid_t pid, void *buf, size_t len) 96{ 97 printf("%.*s", (int)len, (const char *)buf); 98 num_replies++; 99} 100 101/* Send no message. Useful for testing. */ 102 103static BOOL do_noop(const pid_t pid, const int argc, const char **argv) 104{ 105 if (argc != 1) { 106 fprintf(stderr, "Usage: smbcontrol <dest> noop\n"); 107 return False; 108 } 109 110 /* Move along, nothing to see here */ 111 112 return True; 113} 114 115/* Send a debug string */ 116 117static BOOL do_debug(const pid_t pid, const int argc, const char **argv) 118{ 119 if (argc != 2) { 120 fprintf(stderr, "Usage: smbcontrol <dest> debug " 121 "<debug-string>\n"); 122 return False; 123 } 124 125 return send_message( 126 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); 127} 128 129/* Force a browser election */ 130 131static BOOL do_election(const pid_t pid, const int argc, const char **argv) 132{ 133 if (argc != 1) { 134 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n"); 135 return False; 136 } 137 138 return send_message( 139 pid, MSG_FORCE_ELECTION, NULL, 0, False); 140} 141 142/* Ping a samba daemon process */ 143 144static void pong_cb(int msg_type, pid_t pid, void *buf, size_t len) 145{ 146 printf("PONG from pid %u\n", (unsigned int)pid); 147 num_replies++; 148} 149 150static BOOL do_ping(const pid_t pid, const int argc, const char **argv) 151{ 152 if (argc != 1) { 153 fprintf(stderr, "Usage: smbcontrol <dest> ping\n"); 154 return False; 155 } 156 157 /* Send a message and register our interest in a reply */ 158 159 if (!send_message(pid, MSG_PING, NULL, 0, False)) 160 return False; 161 162 message_register(MSG_PONG, pong_cb); 163 164 wait_replies(pid == 0); 165 166 /* No replies were received within the timeout period */ 167 168 if (num_replies == 0) 169 printf("No replies received\n"); 170 171 message_deregister(MSG_PONG); 172 173 return num_replies; 174} 175 176/* Set profiling options */ 177 178static BOOL do_profile(const pid_t pid, const int argc, const char **argv) 179{ 180 int v; 181 182 if (argc != 2) { 183 fprintf(stderr, "Usage: smbcontrol <dest> profile " 184 "<off|count|on|flush>\n"); 185 return False; 186 } 187 188 if (strcmp(argv[1], "off") == 0) { 189 v = 0; 190 } else if (strcmp(argv[1], "count") == 0) { 191 v = 1; 192 } else if (strcmp(argv[1], "on") == 0) { 193 v = 2; 194 } else if (strcmp(argv[1], "flush") == 0) { 195 v = 3; 196 } else { 197 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]); 198 return False; 199 } 200 201 return send_message(pid, MSG_PROFILE, &v, sizeof(int), False); 202} 203 204/* Return the profiling level */ 205 206static void profilelevel_cb(int msg_type, pid_t pid, void *buf, size_t len) 207{ 208 int level; 209 const char *s; 210 211 num_replies++; 212 213 if (len != sizeof(int)) { 214 fprintf(stderr, "invalid message length %ld returned\n", 215 (unsigned long)len); 216 return; 217 } 218 219 memcpy(&level, buf, sizeof(int)); 220 221 switch (level) { 222 case 0: 223 s = "not enabled"; 224 break; 225 case 1: 226 s = "off"; 227 break; 228 case 3: 229 s = "count only"; 230 break; 231 case 7: 232 s = "count and time"; 233 break; 234 default: 235 s = "BOGUS"; 236 break; 237 } 238 239 printf("Profiling %s on pid %u\n",s,(unsigned int)pid); 240} 241 242static void profilelevel_rqst(int msg_type, pid_t pid, void *buf, size_t len) 243{ 244 int v = 0; 245 246 /* Send back a dummy reply */ 247 248 send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False); 249} 250 251static BOOL do_profilelevel(const pid_t pid, const int argc, const char **argv) 252{ 253 if (argc != 1) { 254 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n"); 255 return False; 256 } 257 258 /* Send a message and register our interest in a reply */ 259 260 if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False)) 261 return False; 262 263 message_register(MSG_PROFILELEVEL, profilelevel_cb); 264 message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst); 265 266 wait_replies(pid == 0); 267 268 /* No replies were received within the timeout period */ 269 270 if (num_replies == 0) 271 printf("No replies received\n"); 272 273 message_deregister(MSG_PROFILE); 274 275 return num_replies; 276} 277 278/* Display debug level settings */ 279 280static BOOL do_debuglevel(const pid_t pid, const int argc, const char **argv) 281{ 282 if (argc != 1) { 283 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n"); 284 return False; 285 } 286 287 /* Send a message and register our interest in a reply */ 288 289 if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False)) 290 return False; 291 292 message_register(MSG_DEBUGLEVEL, print_pid_string_cb); 293 294 wait_replies(pid == 0); 295 296 /* No replies were received within the timeout period */ 297 298 if (num_replies == 0) 299 printf("No replies received\n"); 300 301 message_deregister(MSG_DEBUGLEVEL); 302 303 return num_replies; 304} 305 306/* Send a print notify message */ 307 308static BOOL do_printnotify(const pid_t pid, const int argc, const char **argv) 309{ 310 const char *cmd; 311 312 /* Check for subcommand */ 313 314 if (argc == 1) { 315 fprintf(stderr, "Must specify subcommand:\n"); 316 fprintf(stderr, "\tqueuepause <printername>\n"); 317 fprintf(stderr, "\tqueueresume <printername>\n"); 318 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n"); 319 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n"); 320 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n"); 321 fprintf(stderr, "\tprinter <printername> <comment|port|" 322 "driver> <value>\n"); 323 324 return False; 325 } 326 327 cmd = argv[1]; 328 329 if (strcmp(cmd, "queuepause") == 0) { 330 331 if (argc != 3) { 332 fprintf(stderr, "Usage: smbcontrol <dest> printnotify" 333 " queuepause <printername>\n"); 334 return False; 335 } 336 337 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED); 338 339 goto send; 340 341 } else if (strcmp(cmd, "queueresume") == 0) { 342 343 if (argc != 3) { 344 fprintf(stderr, "Usage: smbcontrol <dest> printnotify" 345 " queuereume <printername>\n"); 346 return False; 347 } 348 349 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK); 350 351 goto send; 352 353 } else if (strcmp(cmd, "jobpause") == 0) { 354 int jobid; 355 356 if (argc != 4) { 357 fprintf(stderr, "Usage: smbcontrol <dest> printnotify" 358 " jobpause <printername> <unix-jobid>\n"); 359 return False; 360 } 361 362 jobid = atoi(argv[3]); 363 364 notify_job_status_byname( 365 argv[2], jobid, JOB_STATUS_PAUSED, 366 SPOOLSS_NOTIFY_MSG_UNIX_JOBID); 367 368 goto send; 369 370 } else if (strcmp(cmd, "jobresume") == 0) { 371 int jobid; 372 373 if (argc != 4) { 374 fprintf(stderr, "Usage: smbcontrol <dest> printnotify" 375 " jobpause <printername> <unix-jobid>\n"); 376 return False; 377 } 378 379 jobid = atoi(argv[3]); 380 381 notify_job_status_byname( 382 argv[2], jobid, JOB_STATUS_QUEUED, 383 SPOOLSS_NOTIFY_MSG_UNIX_JOBID); 384 385 goto send; 386 387 } else if (strcmp(cmd, "jobdelete") == 0) { 388 int jobid; 389 390 if (argc != 4) { 391 fprintf(stderr, "Usage: smbcontrol <dest> printnotify" 392 " jobpause <printername> <unix-jobid>\n"); 393 return False; 394 } 395 396 jobid = atoi(argv[3]); 397 398 notify_job_status_byname( 399 argv[2], jobid, JOB_STATUS_DELETING, 400 SPOOLSS_NOTIFY_MSG_UNIX_JOBID); 401 402 notify_job_status_byname( 403 argv[2], jobid, JOB_STATUS_DELETING| 404 JOB_STATUS_DELETED, 405 SPOOLSS_NOTIFY_MSG_UNIX_JOBID); 406 407 goto send; 408 409 } else if (strcmp(cmd, "printer") == 0) { 410 uint32 attribute; 411 412 if (argc != 5) { 413 fprintf(stderr, "Usage: smbcontrol <dest> printnotify " 414 "printer <printername> <comment|port|driver> " 415 "<value>\n"); 416 return False; 417 } 418 419 if (strcmp(argv[3], "comment") == 0) { 420 attribute = PRINTER_NOTIFY_COMMENT; 421 } else if (strcmp(argv[3], "port") == 0) { 422 attribute = PRINTER_NOTIFY_PORT_NAME; 423 } else if (strcmp(argv[3], "driver") == 0) { 424 attribute = PRINTER_NOTIFY_DRIVER_NAME; 425 } else { 426 fprintf(stderr, "Invalid printer command '%s'\n", 427 argv[3]); 428 return False; 429 } 430 431 notify_printer_byname(argv[2], attribute, argv[4]); 432 433 goto send; 434 } 435 436 fprintf(stderr, "Invalid subcommand '%s'\n", cmd); 437 return False; 438 439send: 440 print_notify_send_messages(0); 441 return True; 442} 443 444/* Close a share */ 445 446static BOOL do_closeshare(const pid_t pid, const int argc, const char **argv) 447{ 448 if (argc != 2) { 449 fprintf(stderr, "Usage: smbcontrol <dest> close-share " 450 "<sharename>\n"); 451 return False; 452 } 453 454 return send_message( 455 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False); 456} 457 458/* Force a SAM synchronisation */ 459 460static BOOL do_samsync(const pid_t pid, const int argc, const char **argv) 461{ 462 if (argc != 1) { 463 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n"); 464 return False; 465 } 466 467 return send_message( 468 pid, MSG_SMB_SAM_SYNC, NULL, 0, False); 469} 470 471/* Force a SAM replication */ 472 473static BOOL do_samrepl(const pid_t pid, const int argc, const char **argv) 474{ 475 if (argc != 1) { 476 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n"); 477 return False; 478 } 479 480 return send_message( 481 pid, MSG_SMB_SAM_REPL, NULL, 0, False); 482} 483 484/* Display talloc pool usage */ 485 486static BOOL do_poolusage(const pid_t pid, const int argc, const char **argv) 487{ 488 if (argc != 1) { 489 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n"); 490 return False; 491 } 492 493 /* Send a message and register our interest in a reply */ 494 495 if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False)) 496 return False; 497 498 message_register(MSG_POOL_USAGE, print_string_cb); 499 500 wait_replies(pid == 0); 501 502 /* No replies were received within the timeout period */ 503 504 if (num_replies == 0) 505 printf("No replies received\n"); 506 507 message_deregister(MSG_POOL_USAGE); 508 509 return num_replies; 510} 511 512/* Perform a dmalloc mark */ 513 514static BOOL do_dmalloc_mark(const pid_t pid, const int argc, const char **argv) 515{ 516 if (argc != 1) { 517 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n"); 518 return False; 519 } 520 521 return send_message( 522 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False); 523} 524 525/* Perform a dmalloc changed */ 526 527static BOOL do_dmalloc_changed(const pid_t pid, const int argc, const char **argv) 528{ 529 if (argc != 1) { 530 fprintf(stderr, "Usage: smbcontrol <dest> " 531 "dmalloc-log-changed\n"); 532 return False; 533 } 534 535 return send_message( 536 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False); 537} 538 539/* Shutdown a server process */ 540 541static BOOL do_shutdown(const pid_t pid, const int argc, const char **argv) 542{ 543 if (argc != 1) { 544 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n"); 545 return False; 546 } 547 548 return send_message(pid, MSG_SHUTDOWN, NULL, 0, False); 549} 550 551/* Notify a driver upgrade */ 552 553static BOOL do_drvupgrade(const pid_t pid, const int argc, const char **argv) 554{ 555 if (argc != 2) { 556 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade " 557 "<driver-name>\n"); 558 return False; 559 } 560 561 return send_message( 562 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False); 563} 564 565static BOOL do_reload_config(const pid_t pid, const int argc, const char **argv) 566{ 567 if (argc != 1) { 568 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n"); 569 return False; 570 } 571 572 return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False); 573} 574 575/* A list of message type supported */ 576 577static const struct { 578 const char *name; /* Option name */ 579 BOOL (*fn)(const pid_t pid, const int argc, const char **argv); 580 const char *help; /* Short help text */ 581} msg_types[] = { 582 { "debug", do_debug, "Set debuglevel" }, 583 { "force-election", do_election, 584 "Force a browse election" }, 585 { "ping", do_ping, "Elicit a response" }, 586 { "profile", do_profile, "" }, 587 { "profilelevel", do_profilelevel, "" }, 588 { "debuglevel", do_debuglevel, "Display current debuglevels" }, 589 { "printnotify", do_printnotify, "Send a print notify message" }, 590 { "close-share", do_closeshare, "Forcibly disconnect a share" }, 591 { "samsync", do_samsync, "Initiate SAM synchronisation" }, 592 { "samrepl", do_samrepl, "Initiate SAM replication" }, 593 { "pool-usage", do_poolusage, "Display talloc memory usage" }, 594 { "dmalloc-mark", do_dmalloc_mark, "" }, 595 { "dmalloc-log-changed", do_dmalloc_changed, "" }, 596 { "shutdown", do_shutdown, "Shut down daemon" }, 597 { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" }, 598 { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"}, 599 { "noop", do_noop, "Do nothing" }, 600 { NULL } 601}; 602 603/* Display usage information */ 604 605static void usage(poptContext *pc) 606{ 607 int i; 608 609 poptPrintHelp(*pc, stderr, 0); 610 611 fprintf(stderr, "\n"); 612 fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a " 613 "process ID\n"); 614 615 fprintf(stderr, "\n"); 616 fprintf(stderr, "<message-type> is one of:\n"); 617 618 for (i = 0; msg_types[i].name; i++) 619 fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 620 msg_types[i].help); 621 622 fprintf(stderr, "\n"); 623 624 exit(1); 625} 626 627/* Return the pid number for a string destination */ 628 629static pid_t parse_dest(const char *dest) 630{ 631 pid_t pid; 632 633 /* Zero is a special return value for broadcast smbd */ 634 635 if (strequal(dest, "smbd")) 636 return 0; 637 638 /* Try self - useful for testing */ 639 640 if (strequal(dest, "self")) 641 return sys_getpid(); 642 643 /* Check for numeric pid number */ 644 645 if ((pid = atoi(dest)) != 0) 646 return pid; 647 648 /* Look up other destinations in pidfile directory */ 649 650 if ((pid = pidfile_pid(dest)) != 0) 651 return pid; 652 653 fprintf(stderr,"Can't find pid for destination '%s'\n", dest); 654 655 return -1; 656} 657 658/* Execute smbcontrol command */ 659 660static BOOL do_command(int argc, const char **argv) 661{ 662 const char *dest = argv[0], *command = argv[1]; 663 pid_t pid; 664 int i; 665 666 /* Check destination */ 667 668 if ((pid = parse_dest(dest)) == -1) 669 return False; 670 671 /* Check command */ 672 673 for (i = 0; msg_types[i].name; i++) { 674 if (strequal(command, msg_types[i].name)) 675 return msg_types[i].fn(pid, argc - 1, argv + 1); 676 } 677 678 fprintf(stderr, "smbcontrol: unknown command '%s'\n", command); 679 680 return False; 681} 682 683/* Main program */ 684 685int main(int argc, const char **argv) 686{ 687 poptContext pc; 688 int opt; 689 690 static struct poptOption wbinfo_options[] = { 691 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 692 "Set timeout value in seconds", "TIMEOUT" }, 693 694 { "configfile", 's', POPT_ARG_STRING, NULL, 's', 695 "Use alternative configuration file", "CONFIGFILE" }, 696 697 POPT_TABLEEND 698 }; 699 700 struct poptOption options[] = { 701 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, 702 "Options" }, 703 704 POPT_AUTOHELP 705 POPT_COMMON_VERSION 706 POPT_TABLEEND 707 }; 708 709 setup_logging(argv[0],True); 710 711 /* Parse command line arguments using popt */ 712 713 pc = poptGetContext( 714 "smbcontrol", argc, (const char **)argv, options, 0); 715 716 poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> " 717 "<parameters>"); 718 719 if (argc == 1) 720 usage(&pc); 721 722 while ((opt = poptGetNextOpt(pc)) != -1) { 723 switch(opt) { 724 case 't': /* --timeout */ 725 argc -= 2; 726 break; 727 case 's': /* --configfile */ 728 pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc)); 729 argc -= 2; 730 break; 731 default: 732 fprintf(stderr, "Invalid option\n"); 733 poptPrintHelp(pc, stderr, 0); 734 break; 735 } 736 } 737 738 /* We should now have the remaining command line arguments in 739 argv. The argc parameter should have been decremented to the 740 correct value in the above switch statement. */ 741 742 argv = (const char **)poptGetArgs(pc); 743 argc--; /* Don't forget about argv[0] */ 744 745 if (argc == 1) 746 usage(&pc); 747 748 lp_load(dyn_CONFIGFILE,False,False,False); 749 750 /* Need to invert sense of return code -- samba 751 * routines mostly return True==1 for success, but 752 * shell needs 0. */ 753 754 return !do_command(argc, argv); 755} 756