[print notify fixes from APP_HEAD]
[garming/samba-autobuild/.git] / source3 / utils / smbcontrol.c
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
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24
25 extern BOOL AllowDebugChange;
26
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         {"drvupgrade", MSG_PRINTER_DRVUPGRADE},
46         {NULL, -1}
47 };
48
49 time_t timeout_start;
50
51 #define MAX_WAIT        10
52
53 /* we need these because we link to printing*.o */
54
55 void become_root(void) {}
56 void unbecome_root(void) {}
57
58
59 static void usage(BOOL doexit)
60 {
61         int i;
62         if (doexit) {
63                 printf("Usage: smbcontrol -i -s configfile\n");
64                 printf("       smbcontrol <destination> <message-type> <parameters>\n\n");
65         } else {
66                 printf("<destination> <message-type> <parameters>\n\n");
67         }
68         printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n");
69         printf("\t<message-type> is one of: ");
70         for (i=0; msg_types[i].name; i++) 
71             printf("%s%s", i?", ":"",msg_types[i].name);
72         printf("\n");
73         if (doexit) exit(1);
74 }
75
76 static int pong_count;
77 static BOOL got_level;
78 static BOOL pong_registered = False;
79 static BOOL debuglevel_registered = False;
80 static BOOL profilelevel_registered = False;
81
82
83 /**
84  * Wait for replies for up to @p *max_secs seconds, or until @p
85  * max_replies are received.  max_replies may be NULL in which case it
86  * is ignored.
87  *
88  * @note This is a pretty lame timeout; all it means is that after
89  * max_secs we won't look for any more messages.
90  **/
91 static void wait_for_replies(int max_secs, int *max_replies)
92 {
93         time_t timeout_end = time(NULL) + max_secs;
94
95         while ((!max_replies || (*max_replies)-- > 0)
96                &&  (time(NULL) < timeout_end)) {
97                 message_dispatch();
98         }
99 }
100
101
102 /****************************************************************************
103 a useful function for testing the message system
104 ****************************************************************************/
105 void pong_function(int msg_type, pid_t src, void *buf, size_t len)
106 {
107         pong_count++;
108         printf("PONG from PID %u\n",(unsigned int)src);
109 }
110
111 /****************************************************************************
112 Prints out the current Debug level returned by MSG_DEBUGLEVEL
113 ****************************************************************************/
114 void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len)
115 {
116         const char *levels = (char *)buf;
117         pstring dbgcl;
118
119         printf("Current debug levels of PID %u are:\n",(unsigned int)src);
120         
121         while(next_token(&levels, dbgcl, " ", sizeof(pstring)))
122                 printf("%s\n", dbgcl);
123         
124         got_level = True;
125 }
126
127 /****************************************************************************
128 Prints out the current Profile level returned by MSG_PROFILELEVEL
129 ****************************************************************************/
130 void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
131 {
132         int level;
133         char *s=NULL;
134         memcpy(&level, buf, sizeof(int));
135
136         if (level) {
137             switch (level) {
138             case 1:
139                 s = "off";
140                 break;
141             case 3:
142                 s = "count only";
143                 break;
144             case 7:
145                 s = "count and time";
146                 break;
147             default:
148                     s = "BOGUS";
149                     break;
150             }
151             printf("Profiling %s on PID %u\n",s,(unsigned int)src);
152         } else {
153             printf("Profiling not available on PID %u\n",(unsigned int)src);
154         }
155         got_level = True;
156 }
157
158 /**
159  * Handle reply from POOL_USAGE.
160  **/
161 static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len)
162 {
163         printf("Got POOL_USAGE reply from pid%u:\n%.*s",
164                (unsigned int) src_pid, (int) len, (const char *) buf);
165 }
166
167
168 /**
169  * Send a message to a named destination
170  *
171  * @return False if an error occurred.
172  **/
173 static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates)
174 {
175         pid_t pid;
176         /* "smbd" is the only broadcast operation */
177         if (strequal(dest,"smbd")) {
178                 TDB_CONTEXT *tdb;
179                 BOOL ret;
180                 int n_sent = 0;
181
182                 tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0);
183                 if (!tdb) {
184                         fprintf(stderr,"Failed to open connections database in send_message.\n");
185                         return False;
186                 }
187
188                 ret = message_send_all(tdb,msg_type, buf, len, duplicates,
189                                        &n_sent);
190                 DEBUG(10,("smbcontrol/send_message: broadcast message to "
191                           "%d processes\n", n_sent));
192                 tdb_close(tdb);
193
194                 return ret;
195         } else if (strequal(dest,"nmbd")) {
196                 pid = pidfile_pid(dest);
197                 if (pid == 0) {
198                         fprintf(stderr,"Can't find pid for nmbd\n");
199                         return False;
200                 }
201         } else if (strequal(dest,"self")) {
202                 pid = sys_getpid();
203         } else {
204                 pid = atoi(dest);
205                 if (pid == 0) {
206                         fprintf(stderr,"Not a valid pid\n");
207                         return False;
208                 }               
209         } 
210
211         DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid));
212         return message_send_pid(pid, msg_type, buf, len, duplicates);
213 }
214
215 /****************************************************************************
216 evaluate a message type string
217 ****************************************************************************/
218 static int parse_type(char *mtype)
219 {
220         int i;
221         for (i=0;msg_types[i].name;i++) {
222                 if (strequal(mtype, msg_types[i].name)) return msg_types[i].value;
223         }
224         return -1;
225 }
226
227
228 static void register_all(void)
229 {
230         message_register(MSG_POOL_USAGE, pool_usage_cb);
231 }
232
233 /* This guy is here so we can link printing/notify.c to the smbcontrol
234    binary without having to pull in tons of other crap. */
235
236 TDB_CONTEXT *conn_tdb_ctx(void)
237 {
238         static TDB_CONTEXT *tdb;
239
240         if (tdb)
241                 return tdb;
242
243         tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
244
245         if (!tdb)
246                 DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
247
248         return tdb;
249 }
250
251 /****************************************************************************
252 do command
253 ****************************************************************************/
254 static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
255 {
256         int i, n, v;
257         int mtype;
258         BOOL retval=False;
259         BOOL check_notify_msgs = False;
260
261         mtype = parse_type(msg_name);
262         if (mtype == -1) {
263                 fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name);
264                 return(False);
265         }
266
267         switch (mtype) {
268         case MSG_DEBUG: {
269                 char *buf, *b;
270                 char **p;
271                 int dim = 0;
272
273                 if (!params || !params[0]) {
274                         fprintf(stderr,"MSG_DEBUG needs a parameter\n");
275                         return(False);
276                 }
277
278                 /* first pass retrieve total lenght */
279                 for (p = params; p && *p ; p++)
280                         dim += (strnlen(*p, 1024) +1); /* lenght + space */
281                 b = buf = malloc(dim);
282                 if (!buf) {
283                         fprintf(stderr, "Out of memory!");
284                         return(False);
285                 }
286                 /* now build a single string with all parameters */
287                 for(p = params; p && *p; p++) {
288                         int l = strnlen(*p, 1024);
289                         strncpy(b, *p, l);
290                         b[l] = ' ';
291                         b = b + l + 1;
292                 }
293                 b[-1] = '\0';
294
295                 send_message(dest, MSG_DEBUG, buf, dim, False);
296
297                 free(buf);
298   
299                 break;
300         }
301
302         case MSG_PROFILE:
303                 if (!params || !params[0]) {
304                         fprintf(stderr,"MSG_PROFILE needs a parameter\n");
305                         return(False);
306                 }
307                 if (strequal(params[0], "off")) {
308                         v = 0;
309                 } else if (strequal(params[0], "count")) {
310                         v = 1;
311                 } else if (strequal(params[0], "on")) {
312                         v = 2;
313                 } else if (strequal(params[0], "flush")) {
314                         v = 3;
315                 } else {
316                     fprintf(stderr,
317                         "MSG_PROFILE parameter must be off, count, on, or flush\n");
318                     return(False);
319                 }
320                 send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
321                 break;
322
323         case MSG_FORCE_ELECTION:
324                 if (!strequal(dest, "nmbd")) {
325                         fprintf(stderr,"force-election can only be sent to nmbd\n");
326                         return(False);
327                 }
328                 send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
329                 break;
330
331         case MSG_REQ_PROFILELEVEL:
332                 if (!profilelevel_registered) {
333                     message_register(MSG_PROFILELEVEL, profilelevel_function);
334                     profilelevel_registered = True;
335                 }
336                 got_level = False;
337                 retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
338                 if (retval) {
339                         timeout_start = time(NULL);
340                         while (!got_level) {
341                                 message_dispatch();
342                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
343                                         fprintf(stderr,"profilelevel timeout\n");
344                                         break;
345                                 }
346                         }
347                 }
348                 break;
349
350         case MSG_REQ_DEBUGLEVEL:
351                 if (!debuglevel_registered) {
352                     message_register(MSG_DEBUGLEVEL, debuglevel_function);
353                     debuglevel_registered = True;
354                 }
355                 got_level = False;
356                 retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
357                 if (retval) {
358                         timeout_start = time(NULL);
359                         while (!got_level) {
360                                 message_dispatch();
361                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
362                                         fprintf(stderr,"debuglevel timeout\n");
363                                         break;
364                                 }
365                         }
366                 }
367                 break;
368
369                 /* Send a notification message to a printer */
370
371         case MSG_PRINTER_NOTIFY2: {
372                 char *cmd;
373
374                 /* Read subcommand */
375
376                 if (!params || !params[0]) {
377                         fprintf(stderr, "Must specify subcommand:\n");
378                         fprintf(stderr, "\tqueuepause <printername>\n");
379                         fprintf(stderr, "\tqueueresume <printername>\n");
380                         fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
381                         fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
382                         fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
383                         return False;
384                 }
385
386                 cmd = params[0];
387
388                 check_notify_msgs = True;
389
390                 /* Pause a print queue */
391
392                 if (strequal(cmd, "queuepause")) {
393
394                         if (!params[1]) {
395                                 fprintf(stderr, "queuepause command requires a printer name\n");
396                                 return False;
397                         }
398
399                         notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED);
400                         break;
401                 }
402
403                 /* Resume a print queue */
404
405                 if (strequal(cmd, "queueresume")) {
406
407                         if (!params[1]) {
408                                 fprintf(stderr, "queueresume command requires a printer name\n");
409                                 return False;
410                         }
411
412                         notify_printer_status_byname(params[1], PRINTER_STATUS_OK);
413                         break;
414                 }
415
416                 /* Pause a print job */
417
418                 if (strequal(cmd, "jobpause")) {
419                         int jobid;
420
421                         if (!params[1] || !params[2]) {
422                                 fprintf(stderr, "jobpause command requires a printer name and a jobid\n");
423                                 return False;
424                         }
425
426                         jobid = atoi(params[2]);
427
428                         notify_job_status_byname(
429                                 params[1], jobid, JOB_STATUS_PAUSED, 
430                                 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
431                         break;
432                 }
433
434                 /* Resume a print job */
435
436                 if (strequal(cmd, "jobresume")) {
437                         int jobid;
438
439                         if (!params[1] || !params[2]) {
440                                 fprintf(stderr, "jobresume command requires a printer name and a jobid\n");
441                                 return False;
442                         }
443
444                         jobid = atoi(params[2]);
445
446                         notify_job_status_byname(
447                                 params[1], jobid, JOB_STATUS_QUEUED,
448                                 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
449                         break;
450                 }
451
452                 /* Delete a print job */
453
454                 if (strequal(cmd, "jobdelete")) {
455                         int jobid;
456
457                         if (!params[1] || !params[2]) {
458                                 fprintf(stderr, "jobdelete command requires a printer name and a jobid\n");
459                                 return False;
460                         }
461
462                         jobid = atoi(params[2]);
463
464                         notify_job_status_byname(
465                                 params[1], jobid, JOB_STATUS_DELETING,
466                                 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
467
468                         notify_job_status_byname(
469                                 params[1], jobid, JOB_STATUS_DELETING|
470                                 JOB_STATUS_DELETED,
471                                 SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
472                 }
473
474                 /* printer change notify */
475                 
476                 if (strequal(cmd, "printer")) {
477                         int attribute = -1;
478                         
479                         if (!params[1] || !params[2] || !params[3]) {
480                                 fprintf(stderr, "printer command requires an and attribute name and value!\n");
481                                 fprintf(stderr, "supported attributes:\n");
482                                 fprintf(stderr, "\tcomment:\n");
483                                 fprintf(stderr, "\tport:\n");
484                                 fprintf(stderr, "\tdriver:\n");
485                                 return False;
486                         }
487                         if ( strequal(params[2], "comment") )
488                                 attribute = PRINTER_NOTIFY_COMMENT;
489                         else if ( strequal(params[2], "port") )
490                                 attribute = PRINTER_NOTIFY_PORT_NAME;
491                         else if ( strequal(params[2], "driver") )
492                                 attribute = PRINTER_NOTIFY_DRIVER_NAME;
493                         
494                         if ( attribute == -1 ) {
495                                 fprintf(stderr, "bad attribute!\n");
496                                 return False;
497                         }
498                         
499                         notify_printer_byname( params[1], attribute, params[3]);
500                         
501                         break;
502                 }
503                 
504                 break;
505           }
506
507
508         case MSG_SMB_FORCE_TDIS:
509                 if (!strequal(dest, "smbd")) {
510                         fprintf(stderr,"close-share can only be sent to smbd\n");
511                         return(False);
512                 }
513                 if (!params || !params[0]) {
514                         fprintf(stderr, "close-share needs a share name or '*'\n");
515                         return (False);
516                 }
517                 retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0],
518                                       strlen(params[0]) + 1, False);
519                 break;
520
521         case MSG_SMB_SAM_SYNC:
522                 if (!strequal(dest, "smbd")) {
523                         fprintf(stderr, "samsync can only be sent to smbd\n");
524                         return False;
525                 }
526
527                 if (params) {
528                         fprintf(stderr, "samsync does not take any parameters\n");
529                         return False;
530                 }
531
532                 retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False);
533
534                 break;
535
536         case MSG_SMB_SAM_REPL: {
537                 uint32 seqnum;
538
539                 if (!strequal(dest, "smbd")) {
540                         fprintf(stderr, "sam repl can only be sent to smbd\n");
541                         return False;
542                 }
543
544                 if (!params || !params[0]) {
545                         fprintf(stderr, "SAM_REPL needs a parameter\n");
546                         return False;
547                 }
548
549                 seqnum = atoi(params[0]);
550
551                 retval = send_message(dest, MSG_SMB_SAM_SYNC, 
552                                       (char *)&seqnum, sizeof(uint32), False); 
553
554                 break;
555         }
556
557         case MSG_PING:
558                 if (!pong_registered) {
559                     message_register(MSG_PONG, pong_function);
560                     pong_registered = True;
561                 }
562                 if (!params || !params[0]) {
563                         fprintf(stderr,"MSG_PING needs a parameter\n");
564                         return(False);
565                 }
566                 n = atoi(params[0]);
567                 pong_count = 0;
568                 for (i=0;i<n;i++) {
569                         if (iparams > 1)
570                                 retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True);
571                         else
572                                 retval = send_message(dest, MSG_PING, NULL, 0, True);
573                         if (retval == False)
574                                 return False;
575                 }
576                 wait_for_replies(MAX_WAIT, &n);
577                 if (n > 0) {
578                         fprintf(stderr,"PING timeout\n");
579                 }
580                 break;
581
582         case MSG_REQ_POOL_USAGE:
583                 if (!send_message(dest, MSG_REQ_POOL_USAGE, NULL, 0, True))
584                         return False;
585                 wait_for_replies(MAX_WAIT, NULL);
586                 
587                 break;
588
589         case MSG_REQ_DMALLOC_LOG_CHANGED:
590         case MSG_REQ_DMALLOC_MARK:
591                 if (!send_message(dest, mtype, NULL, 0, False))
592                         return False;
593                 break;
594
595         case MSG_SHUTDOWN:
596                 if (!send_message(dest, MSG_SHUTDOWN, NULL, 0, False))
597                         return False;
598                 break;
599         case MSG_PRINTER_DRVUPGRADE:
600                 if (!send_message(dest, MSG_PRINTER_DRVUPGRADE, params[0], 0, False))
601                         return False;
602                 break;
603         }
604
605         /* check if we have any pending print notify messages */
606
607         if ( check_notify_msgs )
608                 print_notify_send_messages();
609                 
610         return (True);
611 }
612
613  int main(int argc, char *argv[])
614 {
615         int opt;
616         char temp[255];
617         extern int optind;
618         BOOL interactive = False;
619
620         AllowDebugChange = False;
621         DEBUGLEVEL = 0;
622
623         setup_logging(argv[0],True);
624         
625         if (argc < 2) usage(True);
626
627         while ((opt = getopt(argc, argv,"is:")) != EOF) {
628                 switch (opt) {
629                 case 'i':
630                         interactive = True;
631                         break;
632                 case 's':
633                         pstrcpy(dyn_CONFIGFILE, optarg);
634                         break;
635                 default:
636                         printf("Unknown option %c (%d)\n", (char)opt, opt);
637                         usage(True);
638                 }
639         }
640
641         lp_load(dyn_CONFIGFILE,False,False,False);
642
643         if (!message_init()) exit(1);
644
645         argc -= optind;
646         argv = &argv[optind];
647
648         register_all();
649
650         if (!interactive) {
651                 if (argc < 2) usage(True);
652                 /* Need to invert sense of return code -- samba
653                  * routines mostly return True==1 for success, but
654                  * shell needs 0. */ 
655                 return ! do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0);
656         }
657
658         while (True) {
659                 char *myargv[4];
660                 int myargc;
661
662                 printf("smbcontrol> ");
663                 if (!fgets(temp, sizeof(temp)-1, stdin)) break;
664                 myargc = 0;
665                 while ((myargc < 4) && 
666                        (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
667                         myargc++;
668                 }
669                 if (!myargc) break;
670                 if (strequal(myargv[0],"q")) break;
671                 if (myargc < 2)
672                         usage(False);
673                 else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0))
674                         usage(False);
675         }
676         return(0);
677 }
678