]> git.neil.brown.name Git - metad.git/blob - sendcmd.c
68d30616e1c006aaf8f7822270f13348287ae2d3
[metad.git] / sendcmd.c
1
2 /* send a command to a metad somewhere
3  * if we use tcp, wait for reply and interpret it
4  */
5
6 #include        <sys/types.h>
7 #include        <sys/socket.h>
8 #include        <netinet/in.h>
9 #include        <netinet/tcp.h>
10 #include        <arpa/inet.h>
11 #include        <netdb.h>
12 #include        <stdio.h>
13 #include        <string.h>
14 #include        <time.h>
15 #include        "skip.h"
16
17 #include "metad.h"
18
19 char *get_str(void);
20 #ifdef ULTRIX
21 char *strdup(char*);
22 #endif
23 /* cache addresses */
24 typedef struct acache
25 {
26         char *host;
27         struct sockaddr_in addr;
28 } *acache;
29
30 extern char *progname;
31
32 static int acmp(acache a, acache b, char *host)
33 {
34         if (b) host=b->host;
35         return strcmp(a->host, host);
36 }
37 static void afree(acache a)
38 {
39         free(a->host);
40         free(a);
41 }
42
43
44 static void *addr_cache = NULL;
45
46 static void list_service(char *, int);
47
48 int send_cmd(char *cmd, int udp, char *host, int verbose)
49 {
50
51         acache *cp, c;
52         if (addr_cache == NULL)
53                 addr_cache = skip_new(acmp, afree, NULL);
54
55         cp = skip_search(addr_cache, host);
56         if (cp != NULL)
57                 c = *cp;
58         else
59         {
60                 c = (acache)malloc(sizeof(struct acache));
61                 c->host = strdup(host);
62                 c->addr.sin_port = udp ? udp_port() : tcp_port();
63                 c->addr.sin_addr.s_addr = inet_addr(host);
64                 if (c->addr.sin_addr.s_addr > 0 && c->addr.sin_addr.s_addr < 0xffffffff)
65                 {
66                         c->addr.sin_family = AF_INET;
67                 }
68                 else
69                 {
70                         struct hostent *he;
71                         he = gethostbyname(host);
72                         if (he == NULL)
73                         {
74                                 c->addr.sin_family = -1;
75                                 fprintf(stderr, "%s: unknown host %s\n", progname, host);
76                         }
77                         else
78                         {
79                                 memcpy(&c->addr.sin_addr, he->h_addr_list[0], 4);
80                                 c->addr.sin_family = AF_INET;
81                         }
82                 }
83                 skip_insert(addr_cache, c);
84         }
85         if (c->addr.sin_family != AF_INET)
86                 return -1;
87         if (udp)
88         {
89                 static int sock = -1;
90
91                 if (sock == -1)
92                 {
93                         sock = socket(AF_INET, SOCK_DGRAM, 0);
94                         if (geteuid() == 0)
95                         {
96                                 int port;
97                                 struct sockaddr_in myaddr;
98                                 port = 600 + time(0)%400;
99
100                                 memset(&myaddr, 0, sizeof(myaddr));
101                                 myaddr.sin_family = AF_INET;
102                                 while (port > 500)
103                                 {
104                                         myaddr.sin_port = htons(port);
105                                         if (bind(sock, (struct sockaddr *)&myaddr, sizeof(myaddr))== 0)
106                                                 break;
107                                         port --;
108                                 }
109                                 if (port == 500)
110                                 {
111                                         fprintf(stderr, "%s: cannot bind priv udp port...\n", progname);
112                                 }
113                         }
114                 }
115                 sendto(sock, cmd, strlen(cmd)+1, 0, (struct sockaddr *)&c->addr, sizeof(c->addr));
116         }
117         else
118         {
119                 /* tcp - have to make a new connection each time */
120                 int sock;
121                 static int port = 0;
122                 char buf[8192]; /* FIXME autosize */
123                 int n;
124                 int have = 0;
125
126                 if (port == 0)
127                         port = 600 + time(0)%400;
128
129                 if (geteuid() == 0)
130                         sock = rresvport(&port);
131                 else
132                         sock = socket(AF_INET, SOCK_STREAM, 0);
133                 if (sock == -1)
134                 {
135                         fprintf(stderr, "%s: cannot bind socket!!\n", progname);
136                         return -1;
137                 }
138 #ifdef TCP_CONN_ABORT_THRESHOLD
139                 {
140                         int thresh;
141                         thresh = 10*1000;
142                         setsockopt(sock, IPPROTO_TCP, TCP_CONN_ABORT_THRESHOLD, (char*)&thresh, 4);
143                 }
144 #endif
145 /* */
146                 if (connect(sock, (struct sockaddr *)&c->addr, sizeof(c->addr))!= 0)
147                 {
148                         fprintf(stderr, "%s: cannot connect to %s\n", progname, c->host);
149                         close(sock);
150                         c->addr.sin_family = -1;
151                         return -1;
152                 }
153                 write(sock, cmd, strlen(cmd)+1);
154                 shutdown(sock, 1); /* don't want to write no more */
155                 do
156                 {
157                         n = read(sock, buf+have, sizeof(buf)-1 - have);
158                         if (n>0) have += n;
159                 } while (n>0 && have < sizeof(buf)-1);
160                 close(sock);
161                 if (have <= 0)
162                         return 0; /* probably OK, FIXME */
163                 buf[have] = 0;
164                 switch(buf[0])
165                 {
166                 case 0: return 0; /* definately ok */
167                 case 1: /* error message */
168                         fprintf(stderr, "%s: %s: %s\n", progname, c->host, buf+1);
169                         return 1;
170                 case 2: /* version number */
171                         fprintf(stdout, "%s: %s\n", c->host, buf+1);
172                         return 0;
173                 case 3: /* listing */
174                         init_recv(buf+1);
175                         list_service(c->host, verbose);
176                         /* FIXME */
177                         return 0;
178
179                 case 'm': /* old version number */
180                         fprintf(stdout, "%s\n", buf);
181                         return 0;
182                 default: /* old metad */
183                         /* FIXME */
184                         return 0;
185                 }
186         }
187         return 0;
188 }
189
190
191 static void list_service(char *host, int verbose)
192 {
193         int b;
194         b = get_byte();
195         while (b == 1 || b == 2)                /* a service */
196         {
197                 char *sname, *home, *user, *crash, *prog;
198                 char **args;
199                 int argc;
200                 int max, cnt, enabled;
201                 int i;
202                 int class;
203                 char *classname=NULL;
204                 char *pidfile = NULL;
205                 int watch_output = 0;
206                 int min=0, period=0, last;
207                 int proto, port=0, active=0, backlog=0;
208
209                 sname = get_str();
210                 max = get_int();
211                 home = get_str();
212                 user = get_str();
213                 crash = get_str();
214                 if (b == 2)
215                 {
216                         watch_output = get_int();
217                         pidfile = get_str();
218                 }
219                 cnt = get_int();
220                 enabled = get_int();
221                 prog = get_str();
222                 argc = get_int();
223                 args = (char**)malloc((argc+1)*sizeof(char*));
224                 for (i=0 ; i<argc ; i++)
225                         args[i] = get_str();
226                 args[i] = NULL;
227                 class = get_byte();
228                 switch(class)
229                 {
230                 case 1:                 /* daemon */
231                         classname = "daemon";
232                         min = get_int();
233                         period = get_int();
234                         last = get_int();
235                         break;
236                 case 2:                 /* stream */
237                         classname = "stream";
238                         proto = get_int();
239                         port = get_int();
240                         backlog = get_int();
241                         active = get_int();
242                         break;
243                 }
244 /*      printf("Host: %s\n", host); */
245                 if (sname == NULL) sname = "*unknown*";
246                 printf("%s:%s%*.0s %s %s (x%d)", host, sname, 18-(int)strlen(host) - (int)strlen(sname), "",
247                        classname, enabled?"enabled":"DISABLED", cnt);
248                 if (verbose)
249                 {
250                         printf("\n");
251                         printf("   Prog: %s\n", prog);
252                         printf("   Args:");
253                         for (i=0; i<argc ; i++)
254                                 printf(" %s", args[i]);
255                         printf("\n");
256                         printf("   Opts:");
257                         if (max) printf(" max=%d", max);
258                         if (home) printf(" dir=%s", home);
259                         if (user) printf(" user=%s", user);
260                         if (crash) printf(" crash=%s", crash);
261                         if (pidfile) printf(" pidfile=%s", pidfile);
262                         if (watch_output) printf(" watch_output");
263                         switch(class)
264                         {
265                         case 1:         /* daemon */
266                                 if (min) printf(" min=%d", min);
267                                 if (period) printf(" period=%d", period);
268                                 break;
269                         case 2:
270                                 printf(" port=%d", port);
271                                 printf(" backlog=%d", backlog);
272                                 if (!active) printf(" INACTIVE");
273                                 break;
274
275                         }
276                         printf("\n");
277                 }
278                 b = get_byte();
279                 while (b == 3 || b == 4) /* process */
280                 {
281                         int pid, hold, status;
282                         int forkedpid;
283                         time_t start, xit;
284                         pid = get_int();
285                         if (b==4)
286                         {
287                                 forkedpid = get_int();
288                                 get_int(); /* pipefd */
289                         }
290                         else forkedpid = 0;
291                         start = get_int();
292                         hold = get_int();
293                         xit = get_int();
294                         status = get_int();
295                         if (verbose)
296                         {
297                                 printf("     Proc: pid=%5d%s %s", (xit && forkedpid) ? forkedpid : pid,
298                                        (xit&&forkedpid)?"f":"", ctime(&start));
299                                 if (xit && forkedpid==0)
300                                 {
301                                         char *t,*t2;
302                                         time_t holdt;
303                                         holdt = hold - time(0);
304                                         t = prtime(holdt);
305                                         while(*t == ' ') t++;
306                                         t2=ctime(&xit)+4;
307                                         printf("        Exited %1.12s holding for %s\n", t2, t);
308                                 }
309                         }
310                         else
311                         {
312                                 char *t;
313                                 time_t age = time(0) - start;
314                                 t = (char*)prtime(age);
315                                 while(*t == ' ') t++;
316                                 printf(" %d%s(%s%s)",  (xit && forkedpid) ? forkedpid : pid,
317                                        (xit&&forkedpid)?"f":"",
318                                        (xit && forkedpid==0)?"exited:":"", t);
319                         }
320                         b = get_byte();
321                 }
322                 if (!verbose) printf("\n");
323         }
324 }