Merge from vendor branch DHCP:
[dragonfly.git] / sbin / rconfig / client.c
1 /*
2  * RCONFIG/CLIENT.C
3  *
4  * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
5  * 
6  * This code is derived from software contributed to The DragonFly Project
7  * by Matthew Dillon <dillon@backplane.com>
8  * 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  * 3. Neither the name of The DragonFly Project nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific, prior written permission.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  * 
36  * $DragonFly: src/sbin/rconfig/client.c,v 1.3 2004/08/19 23:57:02 dillon Exp $
37  */
38
39 #include "defs.h"
40
41 #define LONG_ALIGN(n)   (((n) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
42
43 static void load_client_broadcast_tags(tag_t tag, const char *tagName);
44
45 void
46 doClient(void)
47 {
48     int done = 0;
49     tag_t tag;
50
51     /*
52      * The server list is in the form host[:tag]
53      */
54     chdir(WorkDir);
55     for (tag = AddrBase; tag && !done; tag = tag->next) {
56         struct sockaddr_in sain;
57         struct sockaddr_in rsin;
58         char *tagName;
59         char *host = NULL;
60         char *res = NULL;
61         char *buf = NULL;
62         int len;
63         int ufd = -1;
64         FILE *fi = NULL;
65         FILE *fo = NULL;
66         int rc;
67
68         bzero(&sain, sizeof(sain));
69         if (tag->name == NULL) {
70             load_client_broadcast_tags(tag, "auto");
71             continue;
72         }
73         if (tag->name[0] == ':') {
74             load_client_broadcast_tags(tag, tag->name + 1);
75             continue;
76         }
77         host = strdup(tag->name);
78         if ((tagName = strchr(host, ':')) != NULL)
79             *tagName++ = 0;
80         else
81             tagName = "auto";
82         tagName = strdup(tagName);
83         if (inet_aton(host, &sain.sin_addr) == 0) {
84             struct hostent *hp;
85             if ((hp = gethostbyname2(host, AF_INET)) == NULL) {
86                 fprintf(stderr, "Unable to resolve %s\n", host);
87                 exit(1);
88             }
89             bcopy(hp->h_addr_list[0], &sain.sin_addr, hp->h_length);
90             free(host);
91             host = strdup(hp->h_name);
92             endhostent();
93         }
94         sain.sin_port = htons(257);
95         sain.sin_len = sizeof(sain);
96         sain.sin_family = AF_INET;
97
98         /*
99          * Do a couple of UDP transactions to locate the tag on the server.
100          */
101         printf("%s:%s - ", host, tagName);
102         fflush(stdout);
103         rc = udp_transact(&sain, &rsin, &ufd, &res, &len, "TAG %s\r\n", tagName);
104         if (rc != 101 || res == NULL) {
105             printf("NO LUCK %s\n", (res ? res : ""));
106         } else {
107             printf("%s -", res);
108             fflush(stdout);
109             rc = tcp_transact(&rsin, &fi, &fo, &buf, &len, "TAG %s\r\n", tagName);
110             if (rc == 201 && buf) {
111                 int ffd;
112                 char *path;
113
114                 asprintf(&path, "%s/%s.sh", WorkDir, tagName);
115                 ffd = open(path, O_CREAT|O_TRUNC|O_RDWR, 0755);
116                 if (ffd >= 0 && write(ffd, buf, len) == len) {
117                     printf("running %s [%d] in", path, len);
118                     close(ffd);
119                     ffd = -1;
120                     for (rc = 5; rc > 0; --rc) {
121                         printf(" %d", rc);
122                         fflush(stdout);
123                         sleep(1);
124                     }
125                     printf(" 0\n");
126                     fflush(stdout);
127                     rc = system(path);
128                     if (rc)
129                         printf("rconfig script exit code %d\n", rc);
130                     done = 1;
131                 } else {
132                     if (ffd >= 0) {
133                         remove(path);
134                         close(ffd);
135                         ffd = -1;
136                     }
137                     printf(" unable to create %s [%d] - DOWNLOAD FAILED\n",
138                             path, len);
139                 }
140             } else {
141                 printf(" DOWNLOAD FAILED\n");
142             }
143         }
144         if (ufd >= 0) {
145             close(ufd);
146             ufd = -1;
147         }
148         if (fi != NULL) {
149             fclose(fi);
150             fi = NULL;
151         }
152         if (fo != NULL) {
153             fclose(fo);
154             fo = NULL;
155         }
156         if (buf)
157             free(buf);
158         if (res)
159             free(res);
160         free(host);
161         free(tagName);
162     }
163 }
164
165 static
166 void
167 load_client_broadcast_tags(tag_t tag, const char *tagName)
168 {
169     struct sockaddr_dl *sdl;
170     struct if_msghdr *ifm;
171     int mib[6];
172     char *buf;
173     int bytes;
174     int i;
175
176     mib[0] = CTL_NET;
177     mib[1] = PF_ROUTE;
178     mib[2] = 0;
179     mib[3] = AF_INET;
180     mib[4] = NET_RT_IFLIST;
181     mib[5] = 0;
182
183     if (sysctl(mib, 6, NULL, &bytes, NULL, 0) < 0) {
184         printf("no interfaces!\n");
185         exit(1);
186     }
187     buf = malloc(bytes);
188     if (sysctl(mib, 6, buf, &bytes, NULL, 0) < 0) {
189         printf("no interfaces!\n");
190         exit(1);
191     }
192     ifm = (void *)buf;
193     sdl = NULL;
194     while ((char *)ifm < buf + bytes && ifm->ifm_msglen) {
195         switch(ifm->ifm_type) {
196         case RTM_IFINFO:
197             if (ifm->ifm_flags & IFF_UP) {
198                 sdl = (void *)(ifm + 1);
199             } else {
200                 sdl = NULL;
201             }
202             break;
203         case RTM_NEWADDR:
204             if (sdl) {
205                 struct sockaddr_in *sain;
206                 struct ifa_msghdr *ifam;
207                 char *scan;
208                 char *name;
209                 tag_t ntag;
210
211                 ifam = (void *)ifm;
212                 scan = (char *)(ifam + 1);
213                 for (i = 0; i < RTAX_MAX; ++i) {
214                     if ((1 << i) & ifam->ifam_addrs) {
215                         sain = (void *)scan;
216                         if (i == RTAX_BRD) {
217                             asprintf(&name, "%s:%s",
218                                     inet_ntoa(sain->sin_addr), tagName);
219                             ntag = calloc(sizeof(struct tag), 1);
220                             ntag->name = name;
221                             ntag->flags = 0;
222                             ntag->next = tag->next;
223                             tag->next = ntag;
224                             tag = ntag;
225                             if (VerboseOpt)
226                                 printf("add: %s (%s)\n", sdl->sdl_data, tag->name);
227                         }
228                         scan = scan + LONG_ALIGN(sain->sin_len);
229                     }
230                 }
231             }
232             break;
233         }
234         ifm = (void *)((char *)ifm + ifm->ifm_msglen);
235     }
236 }
237