xref: /dragonfly/sbin/rconfig/client.c (revision 9f7604d7)
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.4 2005/04/02 22:15:20 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 	    tagName = strdup(tagName);
81 	} else {
82 	    tagName = strdup("auto");
83 	}
84 	if (inet_aton(host, &sain.sin_addr) == 0) {
85 	    struct hostent *hp;
86 	    if ((hp = gethostbyname2(host, AF_INET)) == NULL) {
87 		fprintf(stderr, "Unable to resolve %s\n", host);
88 		exit(1);
89 	    }
90 	    bcopy(hp->h_addr_list[0], &sain.sin_addr, hp->h_length);
91 	    free(host);
92 	    host = strdup(hp->h_name);
93 	    endhostent();
94 	}
95 	sain.sin_port = htons(257);
96 	sain.sin_len = sizeof(sain);
97 	sain.sin_family = AF_INET;
98 
99 	/*
100 	 * Do a couple of UDP transactions to locate the tag on the server.
101 	 */
102 	printf("%s:%s - ", host, tagName);
103 	fflush(stdout);
104 	rc = udp_transact(&sain, &rsin, &ufd, &res, &len, "TAG %s\r\n", tagName);
105 	if (rc != 101 || res == NULL) {
106 	    printf("NO LUCK %s\n", (res ? res : ""));
107 	} else {
108 	    printf("%s -", res);
109 	    fflush(stdout);
110 	    rc = tcp_transact(&rsin, &fi, &fo, &buf, &len, "TAG %s\r\n", tagName);
111 	    if (rc == 201 && buf) {
112 		int ffd;
113 		char *path;
114 
115 		asprintf(&path, "%s/%s.sh", WorkDir, tagName);
116 		ffd = open(path, O_CREAT|O_TRUNC|O_RDWR, 0755);
117 		if (ffd >= 0 && write(ffd, buf, len) == len) {
118 		    printf("running %s [%d] in", path, len);
119 		    close(ffd);
120 		    ffd = -1;
121 		    for (rc = 5; rc > 0; --rc) {
122 			printf(" %d", rc);
123 			fflush(stdout);
124 			sleep(1);
125 		    }
126 		    printf(" 0\n");
127 		    fflush(stdout);
128 		    rc = system(path);
129 		    if (rc)
130 			printf("rconfig script exit code %d\n", rc);
131 		    done = 1;
132 		} else {
133 		    if (ffd >= 0) {
134 			remove(path);
135 			close(ffd);
136 			ffd = -1;
137 		    }
138 		    printf(" unable to create %s [%d] - DOWNLOAD FAILED\n",
139 			    path, len);
140 		}
141 	    } else {
142 		printf(" DOWNLOAD FAILED\n");
143 	    }
144 	}
145 	if (ufd >= 0) {
146 	    close(ufd);
147 	    ufd = -1;
148 	}
149 	if (fi != NULL) {
150 	    fclose(fi);
151 	    fi = NULL;
152 	}
153 	if (fo != NULL) {
154 	    fclose(fo);
155 	    fo = NULL;
156 	}
157 	if (buf)
158 	    free(buf);
159 	if (res)
160 	    free(res);
161 	free(host);
162 	free(tagName);
163     }
164 }
165 
166 static
167 void
168 load_client_broadcast_tags(tag_t tag, const char *tagName)
169 {
170     struct sockaddr_dl *sdl;
171     struct if_msghdr *ifm;
172     int mib[6];
173     char *buf;
174     size_t bytes;
175     int i;
176 
177     mib[0] = CTL_NET;
178     mib[1] = PF_ROUTE;
179     mib[2] = 0;
180     mib[3] = AF_INET;
181     mib[4] = NET_RT_IFLIST;
182     mib[5] = 0;
183 
184     if (sysctl(mib, 6, NULL, &bytes, NULL, 0) < 0) {
185 	printf("no interfaces!\n");
186 	exit(1);
187     }
188     buf = malloc(bytes);
189     if (sysctl(mib, 6, buf, &bytes, NULL, 0) < 0) {
190 	printf("no interfaces!\n");
191 	exit(1);
192     }
193     ifm = (void *)buf;
194     sdl = NULL;
195     while ((char *)ifm < buf + bytes && ifm->ifm_msglen) {
196 	switch(ifm->ifm_type) {
197 	case RTM_IFINFO:
198 	    if (ifm->ifm_flags & IFF_UP) {
199 		sdl = (void *)(ifm + 1);
200 	    } else {
201 		sdl = NULL;
202 	    }
203 	    break;
204 	case RTM_NEWADDR:
205 	    if (sdl) {
206 		struct sockaddr_in *sain;
207 		struct ifa_msghdr *ifam;
208 		char *scan;
209 		char *name;
210 		tag_t ntag;
211 
212 		ifam = (void *)ifm;
213 		scan = (char *)(ifam + 1);
214 		for (i = 0; i < RTAX_MAX; ++i) {
215 		    if ((1 << i) & ifam->ifam_addrs) {
216 			sain = (void *)scan;
217 			if (i == RTAX_BRD) {
218 			    asprintf(&name, "%s:%s",
219 				    inet_ntoa(sain->sin_addr), tagName);
220 			    ntag = calloc(sizeof(struct tag), 1);
221 			    ntag->name = name;
222 			    ntag->flags = 0;
223 			    ntag->next = tag->next;
224 			    tag->next = ntag;
225 			    tag = ntag;
226 			    if (VerboseOpt)
227 				printf("add: %s (%s)\n", sdl->sdl_data, tag->name);
228 			}
229 			scan = scan + LONG_ALIGN(sain->sin_len);
230 		    }
231 		}
232 	    }
233 	    break;
234 	}
235 	ifm = (void *)((char *)ifm + ifm->ifm_msglen);
236     }
237 }
238 
239