]> andersk Git - moira.git/blame - update/client.c
Initial revision
[moira.git] / update / client.c
CommitLineData
de56407f 1/*
2 * $Source$
3 * $Header$
4 */
5
6#ifndef lint
7static char *rcsid_client2_c = "$Header$";
8#endif lint
9
10/*
11 * MODULE IDENTIFICATION:
12 * $Header$
13 * Copyright 1987 MIT Project Athena.
14 * DESCRIPTION:
15 * This code handles the actual distribution of data files
16 * to servers in the SMS server-update program.
17 * AUTHOR:
18 * Ken Raeburn (spook@athena.MIT.EDU),
19 * MIT Project Athena/MIT Information Systems.
20 * DEFINED VALUES:
21 * conn
22 * update_info
23 * sms_update_server
24 * VERSION HISTORY:
25 * $Log$
26 * Revision 1.1 1987-08-22 17:53:46 wesommer
27 * Initial revision
28 *
29 */
30
31#include <stdio.h>
32#include <strings.h>
33#include "gdb.h"
34#include <sys/stat.h>
35#include <sys/file.h>
36#include <sys/param.h>
37#include "update.h"
38#include <errno.h>
39#include "sms_update_int.h"
40#include "smsu_int.h"
41#include <krb.h>
42
43extern char *malloc(), *error_message();
44extern int errno;
45
46/* XXX */
47#include "kludge.h"
48/* XXX */
49
50static char buf[BUFSIZ];
51
52CONNECTION conn;
53struct update_desc *info;
54
55static int code;
56
57/*
58 * FUNCTION:
59 * initialize()
60 * DESCRIPTION:
61 * Insures that various libraries have a chance to get
62 * initialized.
63 * INPUT:
64 * OUTPUT:
65 * RETURN VALUE:
66 * void
67 * SIDE EFFECTS:
68 * Initializes GDB library and SMSU error table.
69 * PROBLEMS:
70 *
71 */
72static
73void
74initialize()
75{
76 static int initialized = 0;
77 if (!initialized) {
78 gdb_init();
79 init_smsU_err_tbl();
80 initialized++;
81 }
82}
83
84/*
85 * FUNCTION:
86 * sms_update_server(info)
87 * DESCRIPTION:
88 * Attempts to perform an update based on the information
89 * contained in the data structure pointed to by "info".
90 * Errors in performing the update are logged with the
91 * sms_log* routines; the 'override' field may be updated
92 * to cause updates to occur other than on the regular
93 * schedule (generally to force an earlier retry).
94 * INPUT:
95 * info->service_name
96 * Name of service to be updated; used to find
97 * the source data file in the SMS data directory.
98 * info->host_name
99 * info->target_path
100 * Location to install the file.
101 * info->enable
102 * Must be non-zero.
103 * info->instructions
104 * Sequence of commands to execute on remote
105 * machine to effect the installation.
106 * OUTPUT:
107 * info->last_time
108 * Set to the current time if the update was
109 * attempted.
110 * info->success
111 * Set to non-zero if the update succeeded, set
112 * to zero otherwise.
113 * info->override
114 * Set to -1 if the update succeeds, to (possibly)
115 * some other value otherwise.
116 * RETURN VALUE:
117 * int:
118 * Error code, or zero if no error was detected
119 * in the data supplied to this routine.
120 * SIDE EFFECTS:
121 * May write information to logs.
122 * PROBLEMS:
123 *
124 */
125
126int
127sms_update_server(update_info, pathname)
128 struct update_desc *update_info;
129 char *pathname;
130{
131#define ASSERT(condition,amsg) \
132 if (!(condition)) { msg = amsg; code = 0; goto local_error; }
133#define NONNULL(str) \
134 (((str) != (char *)NULL) && ((size = strlen(str)) != 0))
135#define IO_ERROR(msg) \
136 {log_priority=log_ERROR;com_err(whoami,connection_errno(conn),msg);goto io_error;}
137
138 char *service_address;
139 char *service_updated;
140 char *msg;
141 register char *cp;
142 STRING string_data, string2;
143 int size, num;
144 int fd = -1;
145 struct stat statb;
146
147 /* variable initializations */
148 code = 0;
149 info = update_info;
150 service_updated = (char *)NULL;
151 STRING_DATA(string_data) = (char *)NULL;
152
153 /* pessimism */
154 info->success = 0;
155
156 /* some sanity checking of arguments while we build data */
157 strcpy(buf, "???:???");
158 ASSERT(NONNULL(info->host_name), "null host name");
159 /* XXX -- check length here */
160 strcpy(buf, info->host_name);
161 for (cp = buf; *cp; cp++)
162 ;
163 strcpy(cp, ":???");
164 ASSERT(NONNULL(info->service_name), "null service name");
165 /* XXX -- check length here */
166 strcpy(++cp, info->service_name);
167 service_updated = malloc(strlen(buf)+1);
168 /* XXX -- check allocation succeeded */
169 strcpy(service_updated, buf);
170 service_address = malloc(strlen(SERVICE_NAME)+strlen(info->host_name)+1);
171 if (!service_address) {
172 code = errno;
173 info->override = -1;
174 return(code);
175 }
176 strcpy(service_address, info->host_name);
177 strcat(service_address, ":");
178 strcat(service_address, SERVICE_NAME);
179 ASSERT(info->enable, "server is disabled");
180 ASSERT(NONNULL(info->target_path), "null target pathname");
181 ASSERT(size < MAXPATHLEN, "target pathname too long");
182 ASSERT(info->target_path[0] == '/', "non-absolute pathname supplied");
183
184 initialize();
185
186 string_alloc(&string2, BUFSIZ);
187
188 sprintf(buf, "starting update for %s", service_updated);
189 sms_log_info(buf);
190
191 fd = open(pathname, O_RDONLY, 0);
192 if (fd < 0) {
193 code = errno;
194 msg = pathname;
195 goto local_error;
196 }
197 if (fstat(fd, &statb)) {
198 code = errno;
199 close(fd); fd = -1;
200 strcat(buf, ": can't fstat:");
201 strcat(buf, error_message(code));
202 sms_log_error(buf);
203 goto error_exit;
204 }
205 size = statb.st_size;
206
207 /* open connection */
208 conn = start_server_connection(service_address, 0);
209 if (!conn) {
210 com_err(whoami, 0, "can't connect to update %s", service_address);
211 connect_failed:
212 if (info->override<0 || info->override>INTERVAL_connection_failed)
213 info->override = INTERVAL_connection_failed;
214 return(0);
215 }
216 else if (connection_status(conn) == CON_STOPPED) {
217 com_err(whoami, connection_errno(conn), ": can't connect to update %s",
218 service_address);
219 goto connect_failed;
220 }
221
222
223 /* send authenticators */
224 code = send_auth();
225 if (code) {
226 sprintf(buf, "authorization attempt to %s failed: %s\n",
227 service_updated, error_message(code));
228 goto update_failed;
229 }
230
231 /* send file over */
232 fd = open(pathname, O_RDONLY, 0);
233 if (fd < 0) {
234 code = errno;
235 msg = pathname;
236 goto local_error;
237 }
238 sprintf(STRING_DATA(string2), "XFER_002 %d %d %s",
239 size, checksum_fd(fd), info->target_path);
240 code = send_object(conn, (char *)&string2, STRING_T);
241 if (code)
242 IO_ERROR("%s: sending XFER_002 request");
243 code = receive_object(conn, (char *)&num, INTEGER_T);
244 if (code)
245 IO_ERROR("%s: getting reply from XFER_002 request");
246 if (num) {
247 sprintf(buf, "transfer request to %s (XFER_002) rejected: %s",
248 service_updated, error_message(num));
249 update_failed:
250 sms_log_error(buf);
251 /*
252 * * if the update fails, something is probably wrong on
253 * * the remote side; we'll have to let a maintainer
254 * * take care of it. don't bother trying again any sooner
255 * * than INTERVAL_update_failed minutes
256 * */
257 update_failed_1:
258 if (info->override < INTERVAL_update_failed && info->override != -1)
259 info->override = INTERVAL_update_failed;
260 goto do_quit;
261 }
262 /* send actual data */
263 code = send_file(pathname, size);
264 if (code)
265 goto update_failed_1;
266 string_free(&string_data);
267 close(fd);
268
269 /* send instructions for installation */
270 strcpy(buf, "/tmp/sms-update.XXXXXX");
271 mktemp(buf);
272 fd = open(info->instructions, O_RDONLY, 0);
273 if (fd < 0) {
274 code = errno;
275 log_priority = log_ERROR;
276 com_err(whoami, code, ": can't open %s", info->instructions);
277 send_quit();
278 info->override = INTERVAL_local_error;
279 goto error_exit;
280 }
281 if (fstat(fd, &statb)) {
282 code = errno;
283 close(fd);
284 fd = -1;
285 log_priority = log_ERROR;
286 com_err(whoami, code, ": can't fstat %s", info->instructions);
287 goto error_exit;
288 }
289 sprintf(STRING_DATA(string2), "XFER_002 %d %d %s",
290 statb.st_size, checksum_fd(fd), buf);
291 code = send_object(conn, (char *)&string2, STRING_T);
292 if (code)
293 IO_ERROR("%s: sending request for transfer of instructions");
294 code = receive_object(conn, (char *)&num, INTEGER_T);
295 if (code)
296 IO_ERROR("%s: lost reply from installation script request");
297 if (num) {
298 com_err(whoami, num, ": transfer request rejected for %s", buf);
299 goto update_failed_1;
300 }
301 code = send_file(info->instructions, statb.st_size);
302 if (code)
303 goto update_failed_1;
304
305 /* perform installation */
306 code = execute(buf);
307 if (code) {
308 sprintf(buf, "installation of %s failed: %s", service_updated,
309 error_message(code));
310 sms_log_error(buf);
311 }
312
313 /* clear override timer and indicate success */
314 info->override = -1;
315 info->success = 1;
316
317 /* finished updates */
318do_quit:
319 send_quit();
320
321 /* fall through */
322EGRESS:
323 code = 0;
324error_exit:
325 info->last_time = time((long *)0);
326 if (STRING_DATA(string2))
327 string_free(&string2);
328 if (STRING_DATA(string_data))
329 string_free(&string_data);
330 conn = sever_connection(conn);
331 return(code);
332
333local_error:
334 log_priority = log_ERROR;
335 com_err(whoami, code, code ? ": %s" : "%s", msg);
336 return(SMSU_INTERNAL_ERROR);
337
338io_error:
339 sms_log_error(buf);
340 if (info->override== -1 || info->override > INTERVAL_connection_lost)
341 info->override = INTERVAL_connection_lost;
342 goto EGRESS;
343
344#undef IO_ERROR
345#undef NONNULL
346#undef ASSERT
347}
348
349static
350send_auth()
351{
352 KTEXT_ST ticket_st;
353 KTEXT ticket = &ticket_st;
354 STRING data;
355 register int code;
356 int response;
357
358 code = get_sms_update_ticket(info->host_name, ticket);
359 if (code) {
360 return(code);
361 }
362 STRING_DATA(data) = "AUTH_001";
363 MAX_STRING_SIZE(data) = 9;
364 code = send_object(conn, (char *)&data, STRING_T);
365 if (code) {
366 return(connection_errno(conn));
367 }
368 code = receive_object(conn, (char *)&response, INTEGER_T);
369 if (code) {
370 return(connection_errno(conn));
371 }
372 if (response) {
373 return(response);
374 }
375 STRING_DATA(data) = (char *)ticket->dat;
376 MAX_STRING_SIZE(data) = ticket->length;
377 code = send_object(conn, (char *)&data, STRING_T);
378 if (code) {
379 return(connection_errno(conn));
380 }
381 code = receive_object(conn, (char *)&response, INTEGER_T);
382 if (code) {
383 return(connection_errno(conn));
384 }
385 if (response) {
386 return(response);
387 }
388 return(0);
389}
390
391static
392execute(path)
393 char *path;
394{
395 int response;
396 STRING data;
397 register int code;
398
399 string_alloc(&data, BUFSIZ);
400 sprintf(STRING_DATA(data), "EXEC_002 %s", path);
401 code = send_object(conn, (char *)&data, STRING_T);
402 if (code)
403 return(connection_errno(conn));
404 code = receive_object(conn, (char *)&response, INTEGER_T);
405 if (code)
406 return(connection_errno(conn));
407 if (response)
408 return(response);
409 return(0);
410}
411
412send_quit()
413{
414 STRING str;
415 if (!conn)
416 return;
417 string_alloc(&str, 5);
418 (void) strcpy(STRING_DATA(str), "quit");
419 (void) send_object(conn, (char *)&str, STRING_T);
420 string_free(&str);
421}
This page took 0.150897 seconds and 5 git commands to generate.