utils/smbcontrol.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    Send messages to other Samba daemons
00005 
00006    Copyright (C) Tim Potter 2003
00007    Copyright (C) Andrew Tridgell 1994-1998
00008    Copyright (C) Martin Pool 2001-2002
00009    Copyright (C) Simo Sorce 2002
00010    Copyright (C) James Peach 2006
00011    
00012    This program is free software; you can redistribute it and/or modify
00013    it under the terms of the GNU General Public License as published by
00014    the Free Software Foundation; either version 2 of the License, or
00015    (at your option) any later version.
00016    
00017    This program is distributed in the hope that it will be useful,
00018    but WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020    GNU General Public License for more details.
00021    
00022    You should have received a copy of the GNU General Public License
00023    along with this program; if not, write to the Free Software
00024    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 */
00026 
00027 #include "includes.h"
00028 
00029 #if HAVE_LIBUNWIND_H
00030 #include <libunwind.h>
00031 #endif
00032 
00033 #if HAVE_LIBUNWIND_PTRACE_H
00034 #include <libunwind-ptrace.h>
00035 #endif
00036 
00037 #if HAVE_SYS_PTRACE_H
00038 #include <sys/ptrace.h>
00039 #endif
00040 
00041 /* Default timeout value when waiting for replies (in seconds) */
00042 
00043 #define DEFAULT_TIMEOUT 10
00044 
00045 static int timeout = DEFAULT_TIMEOUT;
00046 static int num_replies;         /* Used by message callback fns */
00047 
00048 /* Send a message to a destination pid.  Zero means broadcast smbd. */
00049 
00050 static BOOL send_message(struct process_id pid, int msg_type,
00051                          const void *buf, int len,
00052                          BOOL duplicates)
00053 {
00054         TDB_CONTEXT *tdb;
00055         BOOL ret;
00056         int n_sent = 0;
00057 
00058         if (!message_init())
00059                 return False;
00060 
00061         if (procid_to_pid(&pid) != 0)
00062                 return NT_STATUS_IS_OK(message_send_pid(pid, msg_type, buf, len,
00063                                                         duplicates));
00064 
00065         tdb = tdb_open_log(lock_path("connections.tdb"), 0, 
00066                            TDB_DEFAULT, O_RDWR, 0);
00067         if (!tdb) {
00068                 fprintf(stderr,"Failed to open connections database"
00069                         ": %s\n", strerror(errno));
00070                 return False;
00071         }
00072         
00073         ret = message_send_all(tdb,msg_type, buf, len, duplicates,
00074                                &n_sent);
00075         DEBUG(10,("smbcontrol/send_message: broadcast message to "
00076                   "%d processes\n", n_sent));
00077         
00078         tdb_close(tdb);
00079         
00080         return ret;
00081 }
00082 
00083 /* Wait for one or more reply messages */
00084 
00085 static void wait_replies(BOOL multiple_replies)
00086 {
00087         time_t start_time = time(NULL);
00088 
00089         /* Wait around a bit.  This is pretty disgusting - we have to
00090            busy-wait here as there is no nicer way to do it. */
00091 
00092         do {
00093                 message_dispatch();
00094                 if (num_replies > 0 && !multiple_replies)
00095                         break;
00096                 sleep(1);
00097         } while (timeout - (time(NULL) - start_time) > 0);
00098 }
00099 
00100 /* Message handler callback that displays the PID and a string on stdout */
00101 
00102 static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf,
00103                                 size_t len, void *private_data)
00104 {
00105         printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
00106                (int)len, (const char *)buf);
00107         num_replies++;
00108 }
00109 
00110 /* Message handler callback that displays a string on stdout */
00111 
00112 static void print_string_cb(int msg_type, struct process_id pid,
00113                             void *buf, size_t len, void *private_data)
00114 {
00115         printf("%.*s", (int)len, (const char *)buf);
00116         num_replies++;
00117 }
00118 
00119 /* Send no message.  Useful for testing. */
00120 
00121 static BOOL do_noop(const struct process_id pid,
00122                     const int argc, const char **argv)
00123 {
00124         if (argc != 1) {
00125                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
00126                 return False;
00127         }
00128 
00129         /* Move along, nothing to see here */
00130 
00131         return True;
00132 }
00133 
00134 /* Send a debug string */
00135 
00136 static BOOL do_debug(const struct process_id pid,
00137                      const int argc, const char **argv)
00138 {
00139         if (argc != 2) {
00140                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
00141                         "<debug-string>\n");
00142                 return False;
00143         }
00144 
00145         return send_message(
00146                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
00147 }
00148 
00149 #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE)
00150 
00151 /* Return the name of a process given it's PID. This will only work on Linux,
00152  * but that's probably moot since this whole stack tracing implementatino is
00153  * Linux-specific anyway.
00154  */
00155 static const char * procname(pid_t pid, char * buf, size_t bufsz)
00156 {
00157         char path[64];
00158         FILE * fp;
00159 
00160         snprintf(path, sizeof(path), "/proc/%llu/cmdline",
00161                 (unsigned long long)pid);
00162         if ((fp = fopen(path, "r")) == NULL) {
00163                 return NULL;
00164         }
00165 
00166         fgets(buf, bufsz, fp);
00167 
00168         fclose(fp);
00169         return buf;
00170 }
00171 
00172 static void print_stack_trace(pid_t pid, int * count)
00173 {
00174         void *              pinfo = NULL;
00175         unw_addr_space_t    aspace = NULL;
00176         unw_cursor_t        cursor;
00177         unw_word_t          ip, sp;
00178 
00179         char                nbuf[256];
00180         unw_word_t          off;
00181 
00182         int ret;
00183 
00184         if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
00185                 fprintf(stderr,
00186                         "Failed to attach to process %llu: %s\n",
00187                         (unsigned long long)pid, strerror(errno));
00188                 return;
00189         }
00190 
00191         /* Wait until the attach is complete. */
00192         waitpid(pid, NULL, 0);
00193 
00194         if (((pinfo = _UPT_create(pid)) == NULL) ||
00195             ((aspace = unw_create_addr_space(&_UPT_accessors, 0)) == NULL)) {
00196                 /* Probably out of memory. */
00197                 fprintf(stderr,
00198                         "Unable to initialize stack unwind for process %llu\n",
00199                         (unsigned long long)pid);
00200                 goto cleanup;
00201         }
00202 
00203         if ((ret = unw_init_remote(&cursor, aspace, pinfo))) {
00204                 fprintf(stderr,
00205                         "Unable to unwind stack for process %llu: %s\n",
00206                         (unsigned long long)pid, unw_strerror(ret));
00207                 goto cleanup;
00208         }
00209 
00210         if (*count > 0) {
00211                 printf("\n");
00212         }
00213 
00214         if (procname(pid, nbuf, sizeof(nbuf))) {
00215                 printf("Stack trace for process %llu (%s):\n",
00216                         (unsigned long long)pid, nbuf);
00217         } else {
00218                 printf("Stack trace for process %llu:\n",
00219                         (unsigned long long)pid);
00220         }
00221 
00222         while (unw_step(&cursor) > 0) {
00223                 ip = sp = off = 0;
00224                 unw_get_reg(&cursor, UNW_REG_IP, &ip);
00225                 unw_get_reg(&cursor, UNW_REG_SP, &sp);
00226 
00227                 ret = unw_get_proc_name(&cursor, nbuf, sizeof(nbuf), &off);
00228                 if (ret != 0 && ret != -UNW_ENOMEM) {
00229                         snprintf(nbuf, sizeof(nbuf), "<unknown symbol>");
00230                 }
00231                 printf("    %s + %#llx [ip=%#llx] [sp=%#llx]\n",
00232                         nbuf, (long long)off, (long long)ip,
00233                         (long long)sp);
00234         }
00235 
00236         (*count)++;
00237 
00238 cleanup:
00239         if (aspace) {
00240                 unw_destroy_addr_space(aspace);
00241         }
00242 
00243         if (pinfo) {
00244                 _UPT_destroy(pinfo);
00245         }
00246 
00247         ptrace(PTRACE_DETACH, pid, NULL, NULL);
00248 }
00249 
00250 static int stack_trace_connection(TDB_CONTEXT * tdb, TDB_DATA key,
00251         TDB_DATA data, void * priv)
00252 {
00253         struct connections_data conn;
00254 
00255         if (data.dsize != sizeof(conn))
00256                 return 0;
00257 
00258         memcpy(&conn, data.dptr, sizeof(conn));
00259         print_stack_trace(procid_to_pid(&conn.pid), (int *)priv);
00260 
00261         return 0;
00262 }
00263 
00264 static BOOL do_daemon_stack_trace(const struct process_id pid,
00265                        const int argc, const char **argv)
00266 {
00267         fprintf(stderr,
00268                 "Daemon stack tracing is not supported on this platform\n");
00269         return False;
00270 
00271         pid_t   dest;
00272         int     count = 0;
00273 
00274         if (argc != 1) {
00275                 fprintf(stderr, "Usage: smbcontrol <dest> stacktrace\n");
00276                 return False;
00277         }
00278 
00279         dest = procid_to_pid(&pid);
00280 
00281         if (dest != 0) {
00282                 /* It would be nice to be able to make sure that this PID is
00283                  * the PID of a smbd/winbind/nmbd process, not some random PID
00284                  * the user liked the look of. It doesn't seem like it's worth
00285                  * the effort at the moment, however.
00286                  */
00287                 print_stack_trace(dest, &count);
00288         } else {
00289                 TDB_CONTEXT * tdb;
00290 
00291                 tdb = tdb_open_log(lock_path("connections.tdb"), 0, 
00292                                    TDB_DEFAULT, O_RDONLY, 0);
00293                 if (!tdb) {
00294                         fprintf(stderr,
00295                                 "Failed to open connections database: %s\n",
00296                                 strerror(errno));
00297                         return False;
00298                 }
00299 
00300                 tdb_traverse(tdb, stack_trace_connection, &count);
00301                 tdb_close(tdb);
00302         }
00303 
00304         return True;
00305 }
00306 
00307 #else /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
00308 
00309 static BOOL do_daemon_stack_trace(const struct process_id pid,
00310                        const int argc, const char **argv)
00311 {
00312         fprintf(stderr,
00313                 "Daemon stack tracing is not supported on this platform\n");
00314         return False;
00315 }
00316 
00317 #endif /* defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) */
00318 
00319 /* Inject a fault (fatal signal) into a running smbd */
00320 
00321 static BOOL do_inject_fault(const struct process_id pid,
00322                        const int argc, const char **argv)
00323 {
00324         if (argc != 2) {
00325                 fprintf(stderr, "Usage: smbcontrol <dest> inject "
00326                         "<bus|hup|term|internal|segv>\n");
00327                 return False;
00328         }
00329 
00330 #ifndef DEVELOPER
00331         fprintf(stderr, "Fault injection is only available in "
00332                 "developer builds\n");
00333         return False;
00334 #else /* DEVELOPER */
00335         {
00336                 int sig = 0;
00337 
00338                 if (strcmp(argv[1], "bus") == 0) {
00339                         sig = SIGBUS;
00340                 } else if (strcmp(argv[1], "hup") == 0) {
00341                         sig = SIGHUP;
00342                 } else if (strcmp(argv[1], "term") == 0) {
00343                         sig = SIGTERM;
00344                 } else if (strcmp(argv[1], "segv") == 0) {
00345                         sig = SIGSEGV;
00346                 } else if (strcmp(argv[1], "internal") == 0) {
00347                         /* Force an internal error, ie. an unclean exit. */
00348                         sig = -1;
00349                 } else {
00350                         fprintf(stderr, "Unknown signal name '%s'\n", argv[1]);
00351                         return False;
00352                 }
00353 
00354                 return send_message(pid, MSG_SMB_INJECT_FAULT,
00355                                     &sig, sizeof(int), False);
00356         }
00357 #endif /* DEVELOPER */
00358 }
00359 
00360 /* Force a browser election */
00361 
00362 static BOOL do_election(const struct process_id pid,
00363                         const int argc, const char **argv)
00364 {
00365         if (argc != 1) {
00366                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
00367                 return False;
00368         }
00369 
00370         return send_message(
00371                 pid, MSG_FORCE_ELECTION, NULL, 0, False);
00372 }
00373 
00374 /* Ping a samba daemon process */
00375 
00376 static void pong_cb(int msg_type, struct process_id pid, void *buf,
00377                     size_t len, void *private_data)
00378 {
00379         char *src_string = procid_str(NULL, &pid);
00380         printf("PONG from pid %s\n", src_string);
00381         TALLOC_FREE(src_string);
00382         num_replies++;
00383 }
00384 
00385 static BOOL do_ping(const struct process_id pid, const int argc, const char **argv)
00386 {
00387         if (argc != 1) {
00388                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
00389                 return False;
00390         }
00391 
00392         /* Send a message and register our interest in a reply */
00393 
00394         if (!send_message(pid, MSG_PING, NULL, 0, False))
00395                 return False;
00396 
00397         message_register(MSG_PONG, pong_cb, NULL);
00398 
00399         wait_replies(procid_to_pid(&pid) == 0);
00400 
00401         /* No replies were received within the timeout period */
00402 
00403         if (num_replies == 0)
00404                 printf("No replies received\n");
00405 
00406         message_deregister(MSG_PONG);
00407 
00408         return num_replies;
00409 }
00410 
00411 /* Set profiling options */
00412 
00413 static BOOL do_profile(const struct process_id pid,
00414                        const int argc, const char **argv)
00415 {
00416         int v;
00417 
00418         if (argc != 2) {
00419                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
00420                         "<off|count|on|flush>\n");
00421                 return False;
00422         }
00423 
00424         if (strcmp(argv[1], "off") == 0) {
00425                 v = 0;
00426         } else if (strcmp(argv[1], "count") == 0) {
00427                 v = 1;
00428         } else if (strcmp(argv[1], "on") == 0) {
00429                 v = 2;
00430         } else if (strcmp(argv[1], "flush") == 0) {
00431                 v = 3;
00432         } else {
00433                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
00434                 return False;
00435         }
00436 
00437         return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
00438 }
00439 
00440 /* Return the profiling level */
00441 
00442 static void profilelevel_cb(int msg_type, struct process_id pid, void *buf,
00443                             size_t len, void *private_data)
00444 {
00445         int level;
00446         const char *s;
00447 
00448         num_replies++;
00449 
00450         if (len != sizeof(int)) {
00451                 fprintf(stderr, "invalid message length %ld returned\n", 
00452                         (unsigned long)len);
00453                 return;
00454         }
00455 
00456         memcpy(&level, buf, sizeof(int));
00457 
00458         switch (level) {
00459         case 0:
00460                 s = "not enabled";
00461                 break;
00462         case 1:
00463                 s = "off";
00464                 break;
00465         case 3:
00466                 s = "count only";
00467                 break;
00468         case 7:
00469                 s = "count and time";
00470                 break;
00471         default:
00472                 s = "BOGUS";
00473                 break;
00474         }
00475         
00476         printf("Profiling %s on pid %u\n",s,(unsigned int)procid_to_pid(&pid));
00477 }
00478 
00479 static void profilelevel_rqst(int msg_type, struct process_id pid,
00480                               void *buf, size_t len, void *private_data)
00481 {
00482         int v = 0;
00483 
00484         /* Send back a dummy reply */
00485 
00486         send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
00487 }
00488 
00489 static BOOL do_profilelevel(const struct process_id pid,
00490                             const int argc, const char **argv)
00491 {
00492         if (argc != 1) {
00493                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
00494                 return False;
00495         }
00496 
00497         /* Send a message and register our interest in a reply */
00498 
00499         if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
00500                 return False;
00501 
00502         message_register(MSG_PROFILELEVEL, profilelevel_cb, NULL);
00503         message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst, NULL);
00504 
00505         wait_replies(procid_to_pid(&pid) == 0);
00506 
00507         /* No replies were received within the timeout period */
00508 
00509         if (num_replies == 0)
00510                 printf("No replies received\n");
00511 
00512         message_deregister(MSG_PROFILE);
00513 
00514         return num_replies;
00515 }
00516 
00517 /* Display debug level settings */
00518 
00519 static BOOL do_debuglevel(const struct process_id pid,
00520                           const int argc, const char **argv)
00521 {
00522         if (argc != 1) {
00523                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
00524                 return False;
00525         }
00526 
00527         /* Send a message and register our interest in a reply */
00528 
00529         if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
00530                 return False;
00531 
00532         message_register(MSG_DEBUGLEVEL, print_pid_string_cb, NULL);
00533 
00534         wait_replies(procid_to_pid(&pid) == 0);
00535 
00536         /* No replies were received within the timeout period */
00537 
00538         if (num_replies == 0)
00539                 printf("No replies received\n");
00540 
00541         message_deregister(MSG_DEBUGLEVEL);
00542 
00543         return num_replies;
00544 }
00545 
00546 /* Send a print notify message */
00547 
00548 static BOOL do_printnotify(const struct process_id pid,
00549                            const int argc, const char **argv)
00550 {
00551         const char *cmd;
00552 
00553         /* Check for subcommand */
00554 
00555         if (argc == 1) {
00556                 fprintf(stderr, "Must specify subcommand:\n");
00557                 fprintf(stderr, "\tqueuepause <printername>\n");
00558                 fprintf(stderr, "\tqueueresume <printername>\n");
00559                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
00560                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
00561                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
00562                 fprintf(stderr, "\tprinter <printername> <comment|port|"
00563                         "driver> <value>\n");
00564                 
00565                 return False;
00566         }
00567 
00568         cmd = argv[1];
00569 
00570         if (strcmp(cmd, "queuepause") == 0) {
00571 
00572                 if (argc != 3) {
00573                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
00574                                 " queuepause <printername>\n");
00575                         return False;
00576                 }
00577                 
00578                 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
00579 
00580                 goto send;
00581 
00582         } else if (strcmp(cmd, "queueresume") == 0) {
00583 
00584                 if (argc != 3) {
00585                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
00586                                 " queuereume <printername>\n");
00587                         return False;
00588                 }
00589                 
00590                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
00591 
00592                 goto send;
00593 
00594         } else if (strcmp(cmd, "jobpause") == 0) {
00595                 int jobid;
00596 
00597                 if (argc != 4) {
00598                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
00599                                 " jobpause <printername> <unix-jobid>\n");
00600                         return False;
00601                 }
00602 
00603                 jobid = atoi(argv[3]);
00604 
00605                 notify_job_status_byname(
00606                         argv[2], jobid, JOB_STATUS_PAUSED, 
00607                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
00608 
00609                 goto send;
00610 
00611         } else if (strcmp(cmd, "jobresume") == 0) {
00612                 int jobid;
00613 
00614                 if (argc != 4) {
00615                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
00616                                 " jobpause <printername> <unix-jobid>\n");
00617                         return False;
00618                 }
00619 
00620                 jobid = atoi(argv[3]);
00621 
00622                 notify_job_status_byname(
00623                         argv[2], jobid, JOB_STATUS_QUEUED, 
00624                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
00625 
00626                 goto send;
00627 
00628         } else if (strcmp(cmd, "jobdelete") == 0) {
00629                 int jobid;
00630 
00631                 if (argc != 4) {
00632                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
00633                                 " jobpause <printername> <unix-jobid>\n");
00634                         return False;
00635                 }
00636 
00637                 jobid = atoi(argv[3]);
00638 
00639                 notify_job_status_byname(
00640                         argv[2], jobid, JOB_STATUS_DELETING,
00641                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
00642                 
00643                 notify_job_status_byname(
00644                         argv[2], jobid, JOB_STATUS_DELETING|
00645                         JOB_STATUS_DELETED,
00646                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
00647 
00648                 goto send;
00649 
00650         } else if (strcmp(cmd, "printer") == 0) {
00651                 uint32 attribute;
00652                 
00653                 if (argc != 5) {
00654                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
00655                                 "printer <printername> <comment|port|driver> "
00656                                 "<value>\n");
00657                         return False;
00658                 }
00659 
00660                 if (strcmp(argv[3], "comment") == 0) {
00661                         attribute = PRINTER_NOTIFY_COMMENT;
00662                 } else if (strcmp(argv[3], "port") == 0) {
00663                         attribute = PRINTER_NOTIFY_PORT_NAME;
00664                 } else if (strcmp(argv[3], "driver") == 0) {
00665                         attribute = PRINTER_NOTIFY_DRIVER_NAME;
00666                 } else {
00667                         fprintf(stderr, "Invalid printer command '%s'\n",
00668                                 argv[3]);
00669                         return False;
00670                 }
00671 
00672                 notify_printer_byname(argv[2], attribute,
00673                                       CONST_DISCARD(char *, argv[4]));
00674 
00675                 goto send;
00676         }
00677 
00678         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
00679         return False;
00680 
00681 send:
00682         print_notify_send_messages(0);
00683         return True;
00684 }
00685 
00686 /* Close a share */
00687 
00688 static BOOL do_closeshare(const struct process_id pid,
00689                           const int argc, const char **argv)
00690 {
00691         if (argc != 2) {
00692                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
00693                         "<sharename>\n");
00694                 return False;
00695         }
00696 
00697         return send_message(
00698                 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
00699 }
00700 
00701 /* Force a SAM synchronisation */
00702 
00703 static BOOL do_samsync(const struct process_id pid,
00704                        const int argc, const char **argv)
00705 {
00706         if (argc != 1) {
00707                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
00708                 return False;
00709         }
00710 
00711         return send_message(
00712                 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
00713 }
00714 
00715 /* Force a SAM replication */
00716 
00717 static BOOL do_samrepl(const struct process_id pid,
00718                        const int argc, const char **argv)
00719 {
00720         if (argc != 1) {
00721                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
00722                 return False;
00723         }
00724 
00725         return send_message(
00726                 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
00727 }
00728 
00729 /* Display talloc pool usage */
00730 
00731 static BOOL do_poolusage(const struct process_id pid,
00732                          const int argc, const char **argv)
00733 {
00734         if (argc != 1) {
00735                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
00736                 return False;
00737         }
00738 
00739         message_register(MSG_POOL_USAGE, print_string_cb, NULL);
00740 
00741         /* Send a message and register our interest in a reply */
00742 
00743         if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
00744                 return False;
00745 
00746         wait_replies(procid_to_pid(&pid) == 0);
00747 
00748         /* No replies were received within the timeout period */
00749 
00750         if (num_replies == 0)
00751                 printf("No replies received\n");
00752 
00753         message_deregister(MSG_POOL_USAGE);
00754 
00755         return num_replies;
00756 }
00757 
00758 /* Perform a dmalloc mark */
00759 
00760 static BOOL do_dmalloc_mark(const struct process_id pid,
00761                             const int argc, const char **argv)
00762 {
00763         if (argc != 1) {
00764                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
00765                 return False;
00766         }
00767 
00768         return send_message(
00769                 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
00770 }
00771 
00772 /* Perform a dmalloc changed */
00773 
00774 static BOOL do_dmalloc_changed(const struct process_id pid,
00775                                const int argc, const char **argv)
00776 {
00777         if (argc != 1) {
00778                 fprintf(stderr, "Usage: smbcontrol <dest> "
00779                         "dmalloc-log-changed\n");
00780                 return False;
00781         }
00782 
00783         return send_message(
00784                 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
00785 }
00786 
00787 /* Shutdown a server process */
00788 
00789 static BOOL do_shutdown(const struct process_id pid,
00790                         const int argc, const char **argv)
00791 {
00792         if (argc != 1) {
00793                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
00794                 return False;
00795         }
00796 
00797         return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
00798 }
00799 
00800 /* Notify a driver upgrade */
00801 
00802 static BOOL do_drvupgrade(const struct process_id pid,
00803                           const int argc, const char **argv)
00804 {
00805         if (argc != 2) {
00806                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
00807                         "<driver-name>\n");
00808                 return False;
00809         }
00810 
00811         return send_message(
00812                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
00813 }
00814 
00815 static BOOL do_winbind_online(const struct process_id pid,
00816                              const int argc, const char **argv)
00817 {
00818         TDB_CONTEXT *tdb;
00819 
00820         if (argc != 1) {
00821                 fprintf(stderr, "Usage: smbcontrol winbindd online\n");
00822                 return False;
00823         }
00824 
00825         if (!lp_winbind_offline_logon()) {
00826                 fprintf(stderr, "The parameter \"winbind offline logon\" must "
00827                         "be set in the [global] section of smb.conf for this "
00828                         "command to be allowed.\n");
00829                 return False;
00830         }
00831 
00832         /* Remove the entry in the winbindd_cache tdb to tell a later
00833            starting winbindd that we're online. */
00834 
00835         tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
00836         if (!tdb) {
00837                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
00838                         lock_path("winbindd_cache.tdb"));
00839                 return False;
00840         }
00841 
00842         tdb_delete_bystring(tdb, "WINBINDD_OFFLINE");
00843         tdb_close(tdb);
00844 
00845         return send_message(pid, MSG_WINBIND_ONLINE, NULL, 0, False);
00846 }
00847 
00848 static BOOL do_winbind_offline(const struct process_id pid,
00849                              const int argc, const char **argv)
00850 {
00851         TDB_CONTEXT *tdb;
00852         BOOL ret = False;
00853         int retry = 0;
00854 
00855         if (argc != 1) {
00856                 fprintf(stderr, "Usage: smbcontrol winbindd offline\n");
00857                 return False;
00858         }
00859 
00860         if (!lp_winbind_offline_logon()) {
00861                 fprintf(stderr, "The parameter \"winbind offline logon\" must "
00862                         "be set in the [global] section of smb.conf for this "
00863                         "command to be allowed.\n");
00864                 return False;
00865         }
00866 
00867         /* Create an entry in the winbindd_cache tdb to tell a later
00868            starting winbindd that we're offline. We may actually create
00869            it here... */
00870 
00871         tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
00872                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
00873                                 TDB_DEFAULT /* TDB_CLEAR_IF_FIRST */, O_RDWR|O_CREAT, 0600);
00874 
00875         if (!tdb) {
00876                 fprintf(stderr, "Cannot open the tdb %s for writing.\n",
00877                         lock_path("winbindd_cache.tdb"));
00878                 return False;
00879         }
00880 
00881         /* There's a potential race condition that if a child
00882            winbindd detects a domain is online at the same time
00883            we're trying to tell it to go offline that it might 
00884            delete the record we add between us adding it and
00885            sending the message. Minimize this by retrying up to
00886            5 times. */
00887 
00888         for (retry = 0; retry < 5; retry++) {
00889                 TDB_DATA d;
00890                 char buf[4];
00891 
00892                 ZERO_STRUCT(d);
00893 
00894                 SIVAL(buf, 0, time(NULL));
00895                 d.dptr = buf;
00896                 d.dsize = 4;
00897 
00898                 tdb_store_bystring(tdb, "WINBINDD_OFFLINE", d, TDB_INSERT);
00899 
00900                 ret = send_message(pid, MSG_WINBIND_OFFLINE, NULL, 0, False);
00901 
00902                 /* Check that the entry "WINBINDD_OFFLINE" still exists. */
00903                 d = tdb_fetch_bystring( tdb, "WINBINDD_OFFLINE" );
00904         
00905                 if (!d.dptr || d.dsize != 4) {
00906                         SAFE_FREE(d.dptr);
00907                         DEBUG(10,("do_winbind_offline: offline state not set - retrying.\n"));
00908                 } else {
00909                         SAFE_FREE(d.dptr);
00910                         break;
00911                 }
00912         }
00913 
00914         tdb_close(tdb);
00915         return ret;
00916 }
00917 
00918 static BOOL do_winbind_onlinestatus(const struct process_id pid,
00919                                     const int argc, const char **argv)
00920 {
00921         struct process_id myid;
00922 
00923         myid = pid_to_procid(sys_getpid());
00924 
00925         if (argc != 1) {
00926                 fprintf(stderr, "Usage: smbcontrol winbindd onlinestatus\n");
00927                 return False;
00928         }
00929 
00930         message_register(MSG_WINBIND_ONLINESTATUS, print_pid_string_cb, NULL);
00931 
00932         if (!send_message(pid, MSG_WINBIND_ONLINESTATUS, &myid, sizeof(myid), False))
00933                 return False;
00934 
00935         wait_replies(procid_to_pid(&pid) == 0);
00936 
00937         /* No replies were received within the timeout period */
00938 
00939         if (num_replies == 0)
00940                 printf("No replies received\n");
00941 
00942         message_deregister(MSG_WINBIND_ONLINESTATUS);
00943 
00944         return num_replies;
00945 }
00946 
00947 
00948 static BOOL do_reload_config(const struct process_id pid,
00949                              const int argc, const char **argv)
00950 {
00951         if (argc != 1) {
00952                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
00953                 return False;
00954         }
00955 
00956         return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
00957 }
00958 
00959 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
00960 {
00961         fstring unix_name;
00962         memset( (char *)n, '\0', sizeof(struct nmb_name) );
00963         fstrcpy(unix_name, name);
00964         strupper_m(unix_name);
00965         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
00966         n->name_type = (unsigned int)type & 0xFF;
00967         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
00968 }
00969 
00970 static BOOL do_nodestatus(const struct process_id pid,
00971                           const int argc, const char **argv)
00972 {
00973         struct packet_struct p;
00974 
00975         if (argc != 2) {
00976                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
00977                 return False;
00978         }
00979 
00980         ZERO_STRUCT(p);
00981 
00982         p.ip = *interpret_addr2(argv[1]);
00983         p.port = 137;
00984         p.packet_type = NMB_PACKET;
00985 
00986         p.packet.nmb.header.name_trn_id = 10;
00987         p.packet.nmb.header.opcode = 0;
00988         p.packet.nmb.header.response = False;
00989         p.packet.nmb.header.nm_flags.bcast = False;
00990         p.packet.nmb.header.nm_flags.recursion_available = False;
00991         p.packet.nmb.header.nm_flags.recursion_desired = False;
00992         p.packet.nmb.header.nm_flags.trunc = False;
00993         p.packet.nmb.header.nm_flags.authoritative = False;
00994         p.packet.nmb.header.rcode = 0;
00995         p.packet.nmb.header.qdcount = 1;
00996         p.packet.nmb.header.ancount = 0;
00997         p.packet.nmb.header.nscount = 0;
00998         p.packet.nmb.header.arcount = 0;
00999         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
01000         p.packet.nmb.question.question_type = 0x21;
01001         p.packet.nmb.question.question_class = 0x1;
01002 
01003         return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
01004 }
01005 
01006 /* A list of message type supported */
01007 
01008 static const struct {
01009         const char *name;       /* Option name */
01010         BOOL (*fn)(const struct process_id pid,
01011                    const int argc, const char **argv);
01012         const char *help;       /* Short help text */
01013 } msg_types[] = {
01014         { "debug", do_debug, "Set debuglevel"  },
01015         { "force-election", do_election,
01016           "Force a browse election" },
01017         { "ping", do_ping, "Elicit a response" },
01018         { "profile", do_profile, "" },
01019         { "inject", do_inject_fault,
01020             "Inject a fatal signal into a running smbd"},
01021         { "stacktrace", do_daemon_stack_trace,
01022             "Display a stack trace of a daemon" },
01023         { "profilelevel", do_profilelevel, "" },
01024         { "debuglevel", do_debuglevel, "Display current debuglevels" },
01025         { "printnotify", do_printnotify, "Send a print notify message" },
01026         { "close-share", do_closeshare, "Forcibly disconnect a share" },
01027         { "samsync", do_samsync, "Initiate SAM synchronisation" },
01028         { "samrepl", do_samrepl, "Initiate SAM replication" },
01029         { "pool-usage", do_poolusage, "Display talloc memory usage" },
01030         { "dmalloc-mark", do_dmalloc_mark, "" },
01031         { "dmalloc-log-changed", do_dmalloc_changed, "" },
01032         { "shutdown", do_shutdown, "Shut down daemon" },
01033         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
01034         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
01035         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
01036         { "online", do_winbind_online, "Ask winbind to go into online state"},
01037         { "offline", do_winbind_offline, "Ask winbind to go into offline state"},
01038         { "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
01039         { "noop", do_noop, "Do nothing" },
01040         { NULL }
01041 };
01042 
01043 /* Display usage information */
01044 
01045 static void usage(poptContext *pc)
01046 {
01047         int i;
01048 
01049         poptPrintHelp(*pc, stderr, 0);
01050 
01051         fprintf(stderr, "\n");
01052         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
01053                 "process ID\n");
01054 
01055         fprintf(stderr, "\n");
01056         fprintf(stderr, "<message-type> is one of:\n");
01057 
01058         for (i = 0; msg_types[i].name; i++) 
01059             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
01060                     msg_types[i].help);
01061 
01062         fprintf(stderr, "\n");
01063 
01064         exit(1);
01065 }
01066 
01067 /* Return the pid number for a string destination */
01068 
01069 static struct process_id parse_dest(const char *dest)
01070 {
01071         struct process_id result = {-1};
01072         pid_t pid;
01073 
01074         /* Zero is a special return value for broadcast smbd */
01075 
01076         if (strequal(dest, "smbd")) {
01077                 return interpret_pid("0");
01078         }
01079 
01080         /* Try self - useful for testing */
01081 
01082         if (strequal(dest, "self")) {
01083                 return pid_to_procid(sys_getpid());
01084         }
01085 
01086         /* Fix winbind typo. */
01087         if (strequal(dest, "winbind")) {
01088                 dest = "winbindd";
01089         }
01090 
01091         
01092         if (!(strequal(dest, "winbindd") || strequal(dest, "nmbd"))) {
01093                 /* Check for numeric pid number */
01094 
01095                 result = interpret_pid(dest);
01096 
01097                 /* Zero isn't valid if not smbd. */
01098                 if (result.pid && procid_valid(&result)) {
01099                         return result;
01100                 }
01101         }
01102 
01103         /* Look up other destinations in pidfile directory */
01104 
01105         if ((pid = pidfile_pid(dest)) != 0) {
01106                 return pid_to_procid(pid);
01107         }
01108 
01109         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
01110 
01111         return result;
01112 }       
01113 
01114 /* Execute smbcontrol command */
01115 
01116 static BOOL do_command(int argc, const char **argv)
01117 {
01118         const char *dest = argv[0], *command = argv[1];
01119         struct process_id pid;
01120         int i;
01121 
01122         /* Check destination */
01123 
01124         pid = parse_dest(dest);
01125         if (!procid_valid(&pid)) {
01126                 return False;
01127         }
01128 
01129         /* Check command */
01130 
01131         for (i = 0; msg_types[i].name; i++) {
01132                 if (strequal(command, msg_types[i].name))
01133                         return msg_types[i].fn(pid, argc - 1, argv + 1);
01134         }
01135 
01136         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
01137 
01138         return False;
01139 }
01140 
01141 /* Main program */
01142 
01143 int main(int argc, const char **argv)
01144 {
01145         poptContext pc;
01146         int opt;
01147 
01148         static struct poptOption long_options[] = {
01149                 POPT_AUTOHELP
01150                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
01151                   "Set timeout value in seconds", "TIMEOUT" },
01152 
01153                 POPT_COMMON_SAMBA
01154                 POPT_TABLEEND
01155         };
01156 
01157         load_case_tables();
01158 
01159         setup_logging(argv[0],True);
01160         
01161         /* Parse command line arguments using popt */
01162 
01163         pc = poptGetContext(
01164                 "smbcontrol", argc, (const char **)argv, long_options, 0);
01165 
01166         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
01167                                "<parameters>");
01168 
01169         if (argc == 1)
01170                 usage(&pc);
01171 
01172         while ((opt = poptGetNextOpt(pc)) != -1) {
01173                 switch(opt) {
01174                 case 't':       /* --timeout */
01175                         break;
01176                 default:
01177                         fprintf(stderr, "Invalid option\n");
01178                         poptPrintHelp(pc, stderr, 0);
01179                         break;
01180                 }
01181         }
01182 
01183         /* We should now have the remaining command line arguments in
01184            argv.  The argc parameter should have been decremented to the
01185            correct value in the above switch statement. */
01186 
01187         argv = (const char **)poptGetArgs(pc);
01188         argc = 0;
01189         while (argv[argc] != NULL) {
01190                 argc++;
01191         }
01192 
01193         if (argc == 1)
01194                 usage(&pc);
01195 
01196         lp_load(dyn_CONFIGFILE,False,False,False,True);
01197 
01198         /* Need to invert sense of return code -- samba
01199          * routines mostly return True==1 for success, but
01200          * shell needs 0. */ 
01201         
01202         return !do_command(argc, argv);
01203 }

Sambaに対してSat Aug 29 21:23:30 2009に生成されました。  doxygen 1.4.7