Fairly large change to printing code.
[Samba.git] / source / utils / smbcontrol.c
blob2d78b21dcc8a8be234250d1756f825a91d7429e3
1 /*
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.
23 #include "includes.h"
25 extern BOOL AllowDebugChange;
27 static struct {
28 char *name;
29 int value;
30 } msg_types[] = {
31 {"debug", MSG_DEBUG},
32 {"force-election", MSG_FORCE_ELECTION},
33 {"ping", MSG_PING},
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 },
45 {NULL, -1}
48 time_t timeout_start;
50 #define MAX_WAIT 10
52 static void usage(BOOL doexit)
54 int i;
55 if (doexit) {
56 printf("Usage: smbcontrol -i -s configfile\n");
57 printf(" smbcontrol <destination> <message-type> <parameters>\n\n");
58 } else {
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);
65 printf("\n");
66 if (doexit) exit(1);
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;
76 /**
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
79 * is ignored.
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.
83 **/
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)) {
90 message_dispatch();
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)
100 pong_count++;
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;
110 pstring dbgcl;
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);
117 got_level = True;
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)
125 int level;
126 char *s=NULL;
127 memcpy(&level, buf, sizeof(int));
129 if (level) {
130 switch (level) {
131 case 1:
132 s = "off";
133 break;
134 case 3:
135 s = "count only";
136 break;
137 case 7:
138 s = "count and time";
139 break;
140 default:
141 s = "BOGUS";
142 break;
144 printf("Profiling %s on PID %u\n",s,(unsigned int)src);
145 } else {
146 printf("Profiling not available on PID %u\n",(unsigned int)src);
148 got_level = True;
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)
168 pid_t pid;
169 /* "smbd" is the only broadcast operation */
170 if (strequal(dest,"smbd")) {
171 TDB_CONTEXT *tdb;
172 BOOL ret;
173 int n_sent = 0;
175 tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0);
176 if (!tdb) {
177 fprintf(stderr,"Failed to open connections database in send_message.\n");
178 return False;
181 ret = message_send_all(tdb,msg_type, buf, len, duplicates,
182 &n_sent);
183 DEBUG(10,("smbcontrol/send_message: broadcast message to "
184 "%d processes\n", n_sent));
185 tdb_close(tdb);
187 return ret;
188 } else if (strequal(dest,"nmbd")) {
189 pid = pidfile_pid(dest);
190 if (pid == 0) {
191 fprintf(stderr,"Can't find pid for nmbd\n");
192 return False;
194 } else if (strequal(dest,"self")) {
195 pid = sys_getpid();
196 } else {
197 pid = atoi(dest);
198 if (pid == 0) {
199 fprintf(stderr,"Not a valid pid\n");
200 return False;
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)
213 int i;
214 for (i=0;msg_types[i].name;i++) {
215 if (strequal(mtype, msg_types[i].name)) return msg_types[i].value;
217 return -1;
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;
233 if (tdb)
234 return tdb;
236 tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
238 if (!tdb)
239 DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
241 return tdb;
244 /****************************************************************************
245 do command
246 ****************************************************************************/
247 static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
249 int i, n, v;
250 int mtype;
251 BOOL retval=False;
253 mtype = parse_type(msg_name);
254 if (mtype == -1) {
255 fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name);
256 return(False);
259 switch (mtype) {
260 case MSG_DEBUG: {
261 char *buf, *b;
262 char **p;
263 int dim = 0;
265 if (!params || !params[0]) {
266 fprintf(stderr,"MSG_DEBUG needs a parameter\n");
267 return(False);
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);
274 if (!buf) {
275 fprintf(stderr, "Out of memory!");
276 return(False);
278 /* now build a single string with all parameters */
279 for(p = params; p && *p; p++) {
280 int l = strnlen(*p, 1024);
281 strncpy(b, *p, l);
282 b[l] = ' ';
283 b = b + l + 1;
285 b[-1] = '\0';
287 send_message(dest, MSG_DEBUG, buf, dim, False);
289 free(buf);
291 break;
294 case MSG_PROFILE:
295 if (!params || !params[0]) {
296 fprintf(stderr,"MSG_PROFILE needs a parameter\n");
297 return(False);
299 if (strequal(params[0], "off")) {
300 v = 0;
301 } else if (strequal(params[0], "count")) {
302 v = 1;
303 } else if (strequal(params[0], "on")) {
304 v = 2;
305 } else if (strequal(params[0], "flush")) {
306 v = 3;
307 } else {
308 fprintf(stderr,
309 "MSG_PROFILE parameter must be off, count, on, or flush\n");
310 return(False);
312 send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
313 break;
315 case MSG_FORCE_ELECTION:
316 if (!strequal(dest, "nmbd")) {
317 fprintf(stderr,"force-election can only be sent to nmbd\n");
318 return(False);
320 send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
321 break;
323 case MSG_REQ_PROFILELEVEL:
324 if (!profilelevel_registered) {
325 message_register(MSG_PROFILELEVEL, profilelevel_function);
326 profilelevel_registered = True;
328 got_level = False;
329 retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
330 if (retval) {
331 timeout_start = time(NULL);
332 while (!got_level) {
333 message_dispatch();
334 if ((time(NULL) - timeout_start) > MAX_WAIT) {
335 fprintf(stderr,"profilelevel timeout\n");
336 break;
340 break;
342 case MSG_REQ_DEBUGLEVEL:
343 if (!debuglevel_registered) {
344 message_register(MSG_DEBUGLEVEL, debuglevel_function);
345 debuglevel_registered = True;
347 got_level = False;
348 retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
349 if (retval) {
350 timeout_start = time(NULL);
351 while (!got_level) {
352 message_dispatch();
353 if ((time(NULL) - timeout_start) > MAX_WAIT) {
354 fprintf(stderr,"debuglevel timeout\n");
355 break;
359 break;
361 /* Send a notification message to a printer */
363 case MSG_PRINTER_NOTIFY2: {
364 char *cmd;
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");
375 return False;
378 cmd = params[0];
380 /* Pause a print queue */
382 if (strequal(cmd, "queuepause")) {
384 if (!params[1]) {
385 fprintf(stderr, "queuepause command requires a printer name\n");
386 return False;
389 notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED);
390 break;
393 /* Resume a print queue */
395 if (strequal(cmd, "queueresume")) {
397 if (!params[1]) {
398 fprintf(stderr, "queueresume command requires a printer name\n");
399 return False;
402 notify_printer_status_byname(params[1], PRINTER_STATUS_OK);
403 break;
406 /* Pause a print job */
408 if (strequal(cmd, "jobpause")) {
409 int jobid;
411 if (!params[1] || !params[2]) {
412 fprintf(stderr, "jobpause command requires a printer name and a jobid\n");
413 return False;
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")) {
426 int jobid;
428 if (!params[1] || !params[2]) {
429 fprintf(stderr, "jobresume command requires a printer name and a jobid\n");
430 return False;
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")) {
443 int jobid;
445 if (!params[1] || !params[2]) {
446 fprintf(stderr, "jobdelete command requires a printer name and a jobid\n");
447 return False;
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|
458 JOB_STATUS_DELETED,
459 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
462 break;
465 case MSG_SMB_FORCE_TDIS:
466 if (!strequal(dest, "smbd")) {
467 fprintf(stderr,"close-share can only be sent to smbd\n");
468 return(False);
470 if (!params || !params[0]) {
471 fprintf(stderr, "close-share needs a share name or '*'\n");
472 return (False);
474 retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0],
475 strlen(params[0]) + 1, False);
476 break;
478 case MSG_SMB_SAM_SYNC:
479 if (!strequal(dest, "smbd")) {
480 fprintf(stderr, "samsync can only be sent to smbd\n");
481 return False;
484 if (params) {
485 fprintf(stderr, "samsync does not take any parameters\n");
486 return False;
489 retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False);
491 break;
493 case MSG_SMB_SAM_REPL: {
494 uint32 seqnum;
496 if (!strequal(dest, "smbd")) {
497 fprintf(stderr, "sam repl can only be sent to smbd\n");
498 return False;
501 if (!params || !params[0]) {
502 fprintf(stderr, "SAM_REPL needs a parameter\n");
503 return False;
506 seqnum = atoi(params[0]);
508 retval = send_message(dest, MSG_SMB_SAM_SYNC,
509 (char *)&seqnum, sizeof(uint32), False);
511 break;
514 case MSG_PING:
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");
521 return(False);
523 n = atoi(params[0]);
524 pong_count = 0;
525 for (i=0;i<n;i++) {
526 if (iparams > 1)
527 retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True);
528 else
529 retval = send_message(dest, MSG_PING, NULL, 0, True);
530 if (retval == False)
531 return False;
533 wait_for_replies(MAX_WAIT, &n);
534 if (n > 0) {
535 fprintf(stderr,"PING timeout\n");
537 break;
539 case MSG_REQ_POOL_USAGE:
540 if (!send_message(dest, MSG_REQ_POOL_USAGE, NULL, 0, True))
541 return False;
542 wait_for_replies(MAX_WAIT, NULL);
544 break;
546 case MSG_REQ_DMALLOC_LOG_CHANGED:
547 case MSG_REQ_DMALLOC_MARK:
548 if (!send_message(dest, mtype, NULL, 0, False))
549 return False;
550 break;
552 case MSG_SHUTDOWN:
553 if (!send_message(dest, MSG_SHUTDOWN, NULL, 0, False))
554 return False;
555 break;
558 return (True);
561 int main(int argc, char *argv[])
563 int opt;
564 char temp[255];
565 extern int optind;
566 BOOL interactive = False;
568 AllowDebugChange = False;
569 DEBUGLEVEL = 0;
571 setup_logging(argv[0],True);
573 if (argc < 2) usage(True);
575 while ((opt = getopt(argc, argv,"is:")) != EOF) {
576 switch (opt) {
577 case 'i':
578 interactive = True;
579 break;
580 case 's':
581 pstrcpy(dyn_CONFIGFILE, optarg);
582 break;
583 default:
584 printf("Unknown option %c (%d)\n", (char)opt, opt);
585 usage(True);
589 lp_load(dyn_CONFIGFILE,False,False,False);
591 if (!message_init()) exit(1);
593 argc -= optind;
594 argv = &argv[optind];
596 register_all();
598 if (!interactive) {
599 if (argc < 2) usage(True);
600 /* Need to invert sense of return code -- samba
601 * routines mostly return True==1 for success, but
602 * shell needs 0. */
603 return ! do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0);
606 while (True) {
607 char *myargv[4];
608 int myargc;
610 printf("smbcontrol> ");
611 if (!fgets(temp, sizeof(temp)-1, stdin)) break;
612 myargc = 0;
613 while ((myargc < 4) &&
614 (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
615 myargc++;
617 if (!myargc) break;
618 if (strequal(myargv[0],"q")) break;
619 if (myargc < 2)
620 usage(False);
621 else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0))
622 usage(False);
624 return(0);