27a3b611701186c21ac87b02a9d26781113d0552
[samba.git] / source / utils / smbcontrol.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    program to send control messages to Samba processes
5    Copyright (C) Andrew Tridgell 1994-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 static struct {
25         char *name;
26         int value;
27 } msg_types[] = {
28         {"debug", MSG_DEBUG},
29         {"force-election", MSG_FORCE_ELECTION},
30         {"ping", MSG_PING},
31         {"profile", MSG_PROFILE},
32         {"profilelevel", MSG_REQ_PROFILELEVEL},
33         {"debuglevel", MSG_REQ_DEBUGLEVEL},
34         {"printer-notify", MSG_PRINTER_NOTIFY},
35         {"close-share", MSG_SMB_FORCE_TDIS},
36         {NULL, -1}
37 };
38
39 time_t timeout_start;
40
41 #define MAX_WAIT        10
42
43 static void usage(BOOL doexit)
44 {
45         int i;
46         if (doexit) {
47                 printf("Usage: smbcontrol -i\n");
48                 printf("       smbcontrol <destination> <message-type> <parameters>\n\n");
49         } else {
50                 printf("<destination> <message-type> <parameters>\n\n");
51         }
52         printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n");
53         printf("\t<message-type> is one of: ");
54         for (i=0; msg_types[i].name; i++) 
55             printf("%s%s", i?", ":"",msg_types[i].name);
56         printf("\n");
57         if (doexit) exit(1);
58 }
59
60 static int pong_count;
61 static BOOL got_level;
62 static BOOL pong_registered = False;
63 static BOOL debuglevel_registered = False;
64 static BOOL profilelevel_registered = False;
65
66
67 /****************************************************************************
68 a useful function for testing the message system
69 ****************************************************************************/
70 void pong_function(int msg_type, pid_t src, void *buf, size_t len)
71 {
72         pong_count++;
73         printf("PONG from PID %u\n",(unsigned int)src);
74 }
75
76 /****************************************************************************
77 Prints out the current Debug level returned by MSG_DEBUGLEVEL
78 ****************************************************************************/
79 void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len)
80 {
81         int i;
82         int debuglevel_class[DBGC_LAST];
83
84         memcpy(debuglevel_class, buf, len);
85
86         printf("Current debug level of PID %u is %d ",(unsigned int)src, debuglevel_class[0]);
87         for (i=1;i<DBGC_LAST;i++)
88                 if (debuglevel_class[i])
89                         printf("%s:%d ", debug_classname_from_index(i), debuglevel_class[i]);
90         printf("\n");
91
92         got_level = True;
93 }
94
95 /****************************************************************************
96 Prints out the current Profile level returned by MSG_PROFILELEVEL
97 ****************************************************************************/
98 void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
99 {
100         int level;
101         char *s=NULL;
102         memcpy(&level, buf, sizeof(int));
103
104         if (level) {
105             switch (level) {
106             case 1:
107                 s = "off";
108                 break;
109             case 3:
110                 s = "count only";
111                 break;
112             case 7:
113                 s = "count and time";
114                 break;
115             }
116             printf("Profiling %s on PID %u\n",s,(unsigned int)src);
117         } else {
118             printf("Profiling not available on PID %u\n",(unsigned int)src);
119         }
120         got_level = True;
121 }
122
123 /****************************************************************************
124 send a message to a named destination
125 ****************************************************************************/
126 static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates)
127 {
128         pid_t pid;
129         /* "smbd" is the only broadcast operation */
130         if (strequal(dest,"smbd")) {
131                 TDB_CONTEXT *tdb;
132                 BOOL ret;
133
134                 tdb = tdb_open_log(lock_path("connections.tdb"), 0, 0, O_RDONLY, 0);
135                 if (!tdb) {
136                         fprintf(stderr,"Failed to open connections database in send_message.\n");
137                         return False;
138                 }
139
140                 ret = message_send_all(tdb,msg_type, buf, len, duplicates);
141                 tdb_close(tdb);
142
143                 return ret;
144         } else if (strequal(dest,"nmbd")) {
145                 pid = pidfile_pid(dest);
146                 if (pid == 0) {
147                         fprintf(stderr,"Can't find pid for nmbd\n");
148                         return False;
149                 }
150         } else if (strequal(dest,"self")) {
151                 pid = getpid();
152         } else {
153                 pid = atoi(dest);
154                 if (pid == 0) {
155                         fprintf(stderr,"Not a valid pid\n");
156                         return False;
157                 }               
158         } 
159
160         return message_send_pid(pid, msg_type, buf, len, duplicates);
161 }
162
163 /****************************************************************************
164 evaluate a message type string
165 ****************************************************************************/
166 static int parse_type(char *mtype)
167 {
168         int i;
169         for (i=0;msg_types[i].name;i++) {
170                 if (strequal(mtype, msg_types[i].name)) return msg_types[i].value;
171         }
172         return -1;
173 }
174
175
176 /****************************************************************************
177 do command
178 ****************************************************************************/
179 static BOOL do_command(char *dest, char *msg_name, char **params)
180 {
181         int i, n, v;
182         int mtype;
183         BOOL retval=False;
184
185         mtype = parse_type(msg_name);
186         if (mtype == -1) {
187                 fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name);
188                 return(False);
189         }
190
191         switch (mtype) {
192         case MSG_DEBUG: {
193                 struct debuglevel_message dm;
194
195                 if (!params || !params[0]) {
196                         fprintf(stderr,"MSG_DEBUG needs a parameter\n");
197                         return(False);
198                 }
199
200                 ZERO_STRUCT(dm);
201                 if (!debug_parse_params(params, dm.debuglevel_class, dm.debuglevel_class_isset)) {
202                         fprintf(stderr, "MSG_DEBUG error. Expected <class name>:level\n");
203                         return(False);
204                 } else
205                         send_message(dest, MSG_DEBUG, &dm, sizeof(dm), False);
206                 break;
207         }
208
209         case MSG_PROFILE:
210                 if (!params || !params[0]) {
211                         fprintf(stderr,"MSG_PROFILE needs a parameter\n");
212                         return(False);
213                 }
214                 if (strequal(params[0], "off")) {
215                         v = 0;
216                 } else if (strequal(params[0], "count")) {
217                         v = 1;
218                 } else if (strequal(params[0], "on")) {
219                         v = 2;
220                 } else if (strequal(params[0], "flush")) {
221                         v = 3;
222                 } else {
223                     fprintf(stderr,
224                         "MSG_PROFILE parameter must be off, count, on, or flush\n");
225                     return(False);
226                 }
227                 send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
228                 break;
229
230         case MSG_FORCE_ELECTION:
231                 if (!strequal(dest, "nmbd")) {
232                         fprintf(stderr,"force-election can only be sent to nmbd\n");
233                         return(False);
234                 }
235                 send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
236                 break;
237
238         case MSG_REQ_PROFILELEVEL:
239                 if (!profilelevel_registered) {
240                     message_register(MSG_PROFILELEVEL, profilelevel_function);
241                     profilelevel_registered = True;
242                 }
243                 got_level = False;
244                 retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
245                 if (retval) {
246                         timeout_start = time(NULL);
247                         while (!got_level) {
248                                 message_dispatch();
249                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
250                                         fprintf(stderr,"profilelevel timeout\n");
251                                         break;
252                                 }
253                         }
254                 }
255                 break;
256
257         case MSG_REQ_DEBUGLEVEL:
258                 if (!debuglevel_registered) {
259                     message_register(MSG_DEBUGLEVEL, debuglevel_function);
260                     debuglevel_registered = True;
261                 }
262                 got_level = False;
263                 retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
264                 if (retval) {
265                         timeout_start = time(NULL);
266                         while (!got_level) {
267                                 message_dispatch();
268                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
269                                         fprintf(stderr,"debuglevel timeout\n");
270                                         break;
271                                 }
272                         }
273                 }
274                 break;
275
276         case MSG_PRINTER_NOTIFY:
277                 if (!strequal(dest, "smbd")) {
278                         fprintf(stderr,"printer-notify can only be sent to smbd\n");
279                         return(False);
280                 }
281                 if (!params || !params[0]) {
282                         fprintf(stderr, "printer-notify needs a printer name\n");
283                         return (False);
284                 }
285                 retval = send_message(dest, MSG_PRINTER_NOTIFY, params[0],
286                                       strlen(params[0]) + 1, False);
287                 break;
288
289         case MSG_SMB_FORCE_TDIS:
290                 if (!strequal(dest, "smbd")) {
291                         fprintf(stderr,"close-share can only be sent to smbd\n");
292                         return(False);
293                 }
294                 if (!params || !params[0]) {
295                         fprintf(stderr, "close-share needs a share name or '*'\n");
296                         return (False);
297                 }
298                 retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0],
299                                       strlen(params[0]) + 1, False);
300                 break;
301
302         case MSG_PING:
303                 if (!pong_registered) {
304                     message_register(MSG_PONG, pong_function);
305                     pong_registered = True;
306                 }
307                 if (!params || !params[0]) {
308                         fprintf(stderr,"MSG_PING needs a parameter\n");
309                         return(False);
310                 }
311                 n = atoi(params[0]);
312                 pong_count = 0;
313                 for (i=0;i<n;i++) {
314                         retval = send_message(dest, MSG_PING, NULL, 0, True);
315                         if (retval == False) break;
316                 }
317                 if (retval) {
318                         timeout_start = time(NULL);
319                         while (pong_count < n) {
320                                 message_dispatch();
321                                 if ((time(NULL) - timeout_start) > MAX_WAIT) {
322                                         fprintf(stderr,"PING timeout\n");
323                                         break;
324                                 }
325                         }
326                 }
327                 break;
328
329         }
330         
331         return (True);
332 }
333
334  int main(int argc, char *argv[])
335 {
336         int opt;
337         char temp[255];
338         extern int optind;
339         pstring servicesf = CONFIGFILE;
340         BOOL interactive = False;
341
342         TimeInit();
343         setup_logging(argv[0],True);
344         
345         charset_initialise();
346         lp_load(servicesf,False,False,False);
347
348         if (!message_init()) exit(1);
349
350         if (argc < 2) usage(True);
351
352         while ((opt = getopt(argc, argv,"i")) != EOF) {
353                 switch (opt) {
354                 case 'i':
355                         interactive = True;
356                         break;
357                 default:
358                         printf("Unknown option %c (%d)\n", (char)opt, opt);
359                         usage(True);
360                 }
361         }
362
363         argc -= optind;
364         argv = &argv[optind];
365
366         if (!interactive) {
367                 if (argc < 2) usage(True);
368                 return (do_command(argv[0],argv[1],argc > 2 ? &argv[2] : 0));
369         }
370
371         while (True) {
372                 char *myargv[3];
373                 int myargc;
374
375                 printf("smbcontrol> ");
376                 if (!fgets(temp, sizeof(temp)-1, stdin)) break;
377                 myargc = 0;
378                 while ((myargc < 3) && 
379                        (myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
380                         myargc++;
381                 }
382                 if (!myargc) break;
383                 if (strequal(myargv[0],"q")) break;
384                 if (myargc < 2)
385                         usage(False);
386                 else if (!do_command(myargv[0],myargv[1],myargc > 2 ? &myargv[2] : 0))
387                         usage(False);
388         }
389         return(0);
390 }
391