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