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