2 Unix SMB/CIFS implementation.
3 program to send control messages to Samba processes
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) 2001, 2002 by Martin Pool
6 Copyright (C) Simo Sorce 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 extern BOOL AllowDebugChange
;
32 {"force-election", MSG_FORCE_ELECTION
},
34 {"profile", MSG_PROFILE
},
35 {"profilelevel", MSG_REQ_PROFILELEVEL
},
36 {"debuglevel", MSG_REQ_DEBUGLEVEL
},
37 {"printnotify", MSG_PRINTER_NOTIFY2
},
38 {"close-share", MSG_SMB_FORCE_TDIS
},
39 {"samsync", MSG_SMB_SAM_SYNC
},
40 {"samrepl", MSG_SMB_SAM_REPL
},
41 {"pool-usage", MSG_REQ_POOL_USAGE
},
42 {"dmalloc-mark", MSG_REQ_DMALLOC_MARK
},
43 {"dmalloc-log-changed", MSG_REQ_DMALLOC_LOG_CHANGED
},
44 {"shutdown", MSG_SHUTDOWN
},
52 static void usage(BOOL doexit
)
56 printf("Usage: smbcontrol -i -s configfile\n");
57 printf(" smbcontrol <destination> <message-type> <parameters>\n\n");
59 printf("<destination> <message-type> <parameters>\n\n");
61 printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n");
62 printf("\t<message-type> is one of: ");
63 for (i
=0; msg_types
[i
].name
; i
++)
64 printf("%s%s", i
?", ":"",msg_types
[i
].name
);
69 static int pong_count
;
70 static BOOL got_level
;
71 static BOOL pong_registered
= False
;
72 static BOOL debuglevel_registered
= False
;
73 static BOOL profilelevel_registered
= False
;
77 * Wait for replies for up to @p *max_secs seconds, or until @p
78 * max_replies are received. max_replies may be NULL in which case it
81 * @note This is a pretty lame timeout; all it means is that after
82 * max_secs we won't look for any more messages.
84 static void wait_for_replies(int max_secs
, int *max_replies
)
86 time_t timeout_end
= time(NULL
) + max_secs
;
88 while ((!max_replies
|| (*max_replies
)-- > 0)
89 && (time(NULL
) < timeout_end
)) {
95 /****************************************************************************
96 a useful function for testing the message system
97 ****************************************************************************/
98 void pong_function(int msg_type
, pid_t src
, void *buf
, size_t len
)
101 printf("PONG from PID %u\n",(unsigned int)src
);
104 /****************************************************************************
105 Prints out the current Debug level returned by MSG_DEBUGLEVEL
106 ****************************************************************************/
107 void debuglevel_function(int msg_type
, pid_t src
, void *buf
, size_t len
)
109 char *levels
= (char *)buf
;
112 printf("Current debug levels of PID %u are:\n",(unsigned int)src
);
114 while(next_token(&levels
, dbgcl
, " ", sizeof(pstring
)))
115 printf("%s\n", dbgcl
);
120 /****************************************************************************
121 Prints out the current Profile level returned by MSG_PROFILELEVEL
122 ****************************************************************************/
123 void profilelevel_function(int msg_type
, pid_t src
, void *buf
, size_t len
)
127 memcpy(&level
, buf
, sizeof(int));
138 s
= "count and time";
144 printf("Profiling %s on PID %u\n",s
,(unsigned int)src
);
146 printf("Profiling not available on PID %u\n",(unsigned int)src
);
152 * Handle reply from POOL_USAGE.
154 static void pool_usage_cb(int msg_type
, pid_t src_pid
, void *buf
, size_t len
)
156 printf("Got POOL_USAGE reply from pid%u:\n%.*s",
157 (unsigned int) src_pid
, (int) len
, (const char *) buf
);
162 * Send a message to a named destination
164 * @return False if an error occurred.
166 static BOOL
send_message(char *dest
, int msg_type
, void *buf
, int len
, BOOL duplicates
)
169 /* "smbd" is the only broadcast operation */
170 if (strequal(dest
,"smbd")) {
175 tdb
= tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT
, O_RDWR
, 0);
177 fprintf(stderr
,"Failed to open connections database in send_message.\n");
181 ret
= message_send_all(tdb
,msg_type
, buf
, len
, duplicates
,
183 DEBUG(10,("smbcontrol/send_message: broadcast message to "
184 "%d processes\n", n_sent
));
188 } else if (strequal(dest
,"nmbd")) {
189 pid
= pidfile_pid(dest
);
191 fprintf(stderr
,"Can't find pid for nmbd\n");
194 } else if (strequal(dest
,"self")) {
199 fprintf(stderr
,"Not a valid pid\n");
204 DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid
));
205 return message_send_pid(pid
, msg_type
, buf
, len
, duplicates
);
208 /****************************************************************************
209 evaluate a message type string
210 ****************************************************************************/
211 static int parse_type(char *mtype
)
214 for (i
=0;msg_types
[i
].name
;i
++) {
215 if (strequal(mtype
, msg_types
[i
].name
)) return msg_types
[i
].value
;
221 static void register_all(void)
223 message_register(MSG_POOL_USAGE
, pool_usage_cb
);
226 /* This guy is here so we can link printing/notify.c to the smbcontrol
227 binary without having to pull in tons of other crap. */
229 TDB_CONTEXT
*conn_tdb_ctx(void)
231 static TDB_CONTEXT
*tdb
;
236 tdb
= tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT
, O_RDONLY
, 0);
239 DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
244 /****************************************************************************
246 ****************************************************************************/
247 static BOOL
do_command(char *dest
, char *msg_name
, int iparams
, char **params
)
253 mtype
= parse_type(msg_name
);
255 fprintf(stderr
,"Couldn't resolve message type: %s\n", msg_name
);
265 if (!params
|| !params
[0]) {
266 fprintf(stderr
,"MSG_DEBUG needs a parameter\n");
270 /* first pass retrieve total lenght */
271 for (p
= params
; p
&& *p
; p
++)
272 dim
+= (strnlen(*p
, 1024) +1); /* lenght + space */
273 b
= buf
= malloc(dim
);
275 fprintf(stderr
, "Out of memory!");
278 /* now build a single string with all parameters */
279 for(p
= params
; p
&& *p
; p
++) {
280 int l
= strnlen(*p
, 1024);
287 send_message(dest
, MSG_DEBUG
, buf
, dim
, False
);
295 if (!params
|| !params
[0]) {
296 fprintf(stderr
,"MSG_PROFILE needs a parameter\n");
299 if (strequal(params
[0], "off")) {
301 } else if (strequal(params
[0], "count")) {
303 } else if (strequal(params
[0], "on")) {
305 } else if (strequal(params
[0], "flush")) {
309 "MSG_PROFILE parameter must be off, count, on, or flush\n");
312 send_message(dest
, MSG_PROFILE
, &v
, sizeof(int), False
);
315 case MSG_FORCE_ELECTION
:
316 if (!strequal(dest
, "nmbd")) {
317 fprintf(stderr
,"force-election can only be sent to nmbd\n");
320 send_message(dest
, MSG_FORCE_ELECTION
, NULL
, 0, False
);
323 case MSG_REQ_PROFILELEVEL
:
324 if (!profilelevel_registered
) {
325 message_register(MSG_PROFILELEVEL
, profilelevel_function
);
326 profilelevel_registered
= True
;
329 retval
= send_message(dest
, MSG_REQ_PROFILELEVEL
, NULL
, 0, True
);
331 timeout_start
= time(NULL
);
334 if ((time(NULL
) - timeout_start
) > MAX_WAIT
) {
335 fprintf(stderr
,"profilelevel timeout\n");
342 case MSG_REQ_DEBUGLEVEL
:
343 if (!debuglevel_registered
) {
344 message_register(MSG_DEBUGLEVEL
, debuglevel_function
);
345 debuglevel_registered
= True
;
348 retval
= send_message(dest
, MSG_REQ_DEBUGLEVEL
, NULL
, 0, True
);
350 timeout_start
= time(NULL
);
353 if ((time(NULL
) - timeout_start
) > MAX_WAIT
) {
354 fprintf(stderr
,"debuglevel timeout\n");
361 /* Send a notification message to a printer */
363 case MSG_PRINTER_NOTIFY2
: {
366 /* Read subcommand */
368 if (!params
|| !params
[0]) {
369 fprintf(stderr
, "Must specify subcommand:\n");
370 fprintf(stderr
, "\tqueuepause <printername>\n");
371 fprintf(stderr
, "\tqueueresume <printername>\n");
372 fprintf(stderr
, "\tjobpause <printername> <unix jobid>\n");
373 fprintf(stderr
, "\tjobresume <printername> <unix jobid>\n");
374 fprintf(stderr
, "\tjobdelete <printername> <unix jobid>\n");
380 /* Pause a print queue */
382 if (strequal(cmd
, "queuepause")) {
385 fprintf(stderr
, "queuepause command requires a printer name\n");
389 notify_printer_status_byname(params
[1], PRINTER_STATUS_PAUSED
);
393 /* Resume a print queue */
395 if (strequal(cmd
, "queueresume")) {
398 fprintf(stderr
, "queueresume command requires a printer name\n");
402 notify_printer_status_byname(params
[1], PRINTER_STATUS_OK
);
406 /* Pause a print job */
408 if (strequal(cmd
, "jobpause")) {
411 if (!params
[1] || !params
[2]) {
412 fprintf(stderr
, "jobpause command requires a printer name and a jobid\n");
416 jobid
= atoi(params
[2]);
418 notify_job_status_byname(
419 params
[1], jobid
, JOB_STATUS_PAUSED
,
420 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
423 /* Resume a print job */
425 if (strequal(cmd
, "jobresume")) {
428 if (!params
[1] || !params
[2]) {
429 fprintf(stderr
, "jobresume command requires a printer name and a jobid\n");
433 jobid
= atoi(params
[2]);
435 notify_job_status_byname(
436 params
[1], jobid
, JOB_STATUS_QUEUED
,
437 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
440 /* Delete a print job */
442 if (strequal(cmd
, "jobdelete")) {
445 if (!params
[1] || !params
[2]) {
446 fprintf(stderr
, "jobdelete command requires a printer name and a jobid\n");
450 jobid
= atoi(params
[2]);
452 notify_job_status_byname(
453 params
[1], jobid
, JOB_STATUS_DELETING
,
454 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
456 notify_job_status_byname(
457 params
[1], jobid
, JOB_STATUS_DELETING
|
459 SPOOLSS_NOTIFY_MSG_UNIX_JOBID
);
465 case MSG_SMB_FORCE_TDIS
:
466 if (!strequal(dest
, "smbd")) {
467 fprintf(stderr
,"close-share can only be sent to smbd\n");
470 if (!params
|| !params
[0]) {
471 fprintf(stderr
, "close-share needs a share name or '*'\n");
474 retval
= send_message(dest
, MSG_SMB_FORCE_TDIS
, params
[0],
475 strlen(params
[0]) + 1, False
);
478 case MSG_SMB_SAM_SYNC
:
479 if (!strequal(dest
, "smbd")) {
480 fprintf(stderr
, "samsync can only be sent to smbd\n");
485 fprintf(stderr
, "samsync does not take any parameters\n");
489 retval
= send_message(dest
, MSG_SMB_SAM_SYNC
, NULL
, 0, False
);
493 case MSG_SMB_SAM_REPL
: {
496 if (!strequal(dest
, "smbd")) {
497 fprintf(stderr
, "sam repl can only be sent to smbd\n");
501 if (!params
|| !params
[0]) {
502 fprintf(stderr
, "SAM_REPL needs a parameter\n");
506 seqnum
= atoi(params
[0]);
508 retval
= send_message(dest
, MSG_SMB_SAM_SYNC
,
509 (char *)&seqnum
, sizeof(uint32
), False
);
515 if (!pong_registered
) {
516 message_register(MSG_PONG
, pong_function
);
517 pong_registered
= True
;
519 if (!params
|| !params
[0]) {
520 fprintf(stderr
,"MSG_PING needs a parameter\n");
527 retval
= send_message(dest
, MSG_PING
, params
[1], strlen(params
[1]) + 1, True
);
529 retval
= send_message(dest
, MSG_PING
, NULL
, 0, True
);
533 wait_for_replies(MAX_WAIT
, &n
);
535 fprintf(stderr
,"PING timeout\n");
539 case MSG_REQ_POOL_USAGE
:
540 if (!send_message(dest
, MSG_REQ_POOL_USAGE
, NULL
, 0, True
))
542 wait_for_replies(MAX_WAIT
, NULL
);
546 case MSG_REQ_DMALLOC_LOG_CHANGED
:
547 case MSG_REQ_DMALLOC_MARK
:
548 if (!send_message(dest
, mtype
, NULL
, 0, False
))
553 if (!send_message(dest
, MSG_SHUTDOWN
, NULL
, 0, False
))
561 int main(int argc
, char *argv
[])
566 BOOL interactive
= False
;
568 AllowDebugChange
= False
;
571 setup_logging(argv
[0],True
);
573 if (argc
< 2) usage(True
);
575 while ((opt
= getopt(argc
, argv
,"is:")) != EOF
) {
581 pstrcpy(dyn_CONFIGFILE
, optarg
);
584 printf("Unknown option %c (%d)\n", (char)opt
, opt
);
589 lp_load(dyn_CONFIGFILE
,False
,False
,False
);
591 if (!message_init()) exit(1);
594 argv
= &argv
[optind
];
599 if (argc
< 2) usage(True
);
600 /* Need to invert sense of return code -- samba
601 * routines mostly return True==1 for success, but
603 return ! do_command(argv
[0],argv
[1], argc
-2, argc
> 2 ? &argv
[2] : 0);
610 printf("smbcontrol> ");
611 if (!fgets(temp
, sizeof(temp
)-1, stdin
)) break;
613 while ((myargc
< 4) &&
614 (myargv
[myargc
] = strtok(myargc
?NULL
:temp
," \t\n"))) {
618 if (strequal(myargv
[0],"q")) break;
621 else if (!do_command(myargv
[0],myargv
[1],myargc
-2,myargc
> 2 ? &myargv
[2] : 0))