]> git.neil.brown.name Git - metad.git/blob - sendcmd.c
Create Makefile and get it to compile with -Wall
[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 }