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