bootpef.c revision 1.4 1 /************************************************************************
2 Copyright 1988, 1991 by Carnegie Mellon University
3
4 All Rights Reserved
5
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted, provided
8 that the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation, and that the name of Carnegie Mellon University not be used
11 in advertising or publicity pertaining to distribution of the software
12 without specific, written prior permission.
13
14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 ************************************************************************/
22
23 #include <sys/cdefs.h>
24 #ifndef lint
25 __RCSID("$NetBSD: bootpef.c,v 1.4 1998/03/14 04:39:53 lukem Exp $");
26 #endif
27
28
29 /*
30 * bootpef - BOOTP Extension File generator
31 * Makes an "Extension File" for each host entry that
32 * defines an and Extension File. (See RFC1497, tag 18.)
33 *
34 * HISTORY
35 * See ./Changes
36 *
37 * BUGS
38 * See ./ToDo
39 */
40
41
43
44 #ifdef __STDC__
45 #include <stdarg.h>
46 #else
47 #include <varargs.h>
48 #endif
49
50 #include <sys/types.h>
51 #include <sys/time.h>
52
53 #include <netinet/in.h>
54 #include <arpa/inet.h> /* inet_ntoa */
55
56 #ifndef NO_UNISTD
57 #include <unistd.h>
58 #endif
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <string.h>
62 #include <errno.h>
63 #include <ctype.h>
64 #include <syslog.h>
65
66 #ifndef USE_BFUNCS
67 #include <memory.h>
68 /* Yes, memcpy is OK here (no overlapped copies). */
69 #define bcopy(a,b,c) memcpy(b,a,c)
70 #define bzero(p,l) memset(p,0,l)
71 #define bcmp(a,b,c) memcmp(a,b,c)
72 #endif
73
74 #include "bootp.h"
75 #include "hash.h"
76 #include "hwaddr.h"
77 #include "bootpd.h"
78 #include "dovend.h"
79 #include "readfile.h"
80 #include "report.h"
81 #include "tzone.h"
82 #include "patchlevel.h"
83
84 #define BUFFERSIZE 0x4000
85
86 #ifndef CONFIG_FILE
87 #define CONFIG_FILE "/etc/bootptab"
88 #endif
89
90
92
93 /*
94 * Externals, forward declarations, and global variables
95 */
96
97 #ifdef __STDC__
98 #define P(args) args
99 #else
100 #define P(args) ()
101 #endif
102
103 static void mktagfile P((struct host *));
104 static void usage P((void));
105 int main P((int, char **));
106
107 #undef P
108
109
110 /*
111 * General
112 */
113
114 char *progname;
115 char *chdir_path;
116 int debug = 0; /* Debugging flag (level) */
117 byte *buffer;
118
119 /*
120 * Globals below are associated with the bootp database file (bootptab).
121 */
122
123 char *bootptab = CONFIG_FILE;
124
125
127 /*
128 * Print "usage" message and exit
129 */
130 static void
131 usage()
132 {
133 fprintf(stderr,
134 "usage: $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
135 fprintf(stderr, "\t -c n\tset current directory\n");
136 fprintf(stderr, "\t -d n\tset debug level\n");
137 fprintf(stderr, "\t -f n\tconfig file name\n");
138 exit(1);
139 }
140
141
142 /*
143 * Initialization such as command-line processing is done and then the
144 * main server loop is started.
145 */
146 int
147 main(argc, argv)
148 int argc;
149 char **argv;
150 {
151 struct host *hp;
152 char *stmp;
153 int n;
154
155 progname = strrchr(argv[0], '/');
156 if (progname) progname++;
157 else progname = argv[0];
158
159 /* Get work space for making tag 18 files. */
160 buffer = (byte *) malloc(BUFFERSIZE);
161 if (!buffer) {
162 report(LOG_ERR, "malloc failed");
163 exit(1);
164 }
165 /*
166 * Set defaults that might be changed by option switches.
167 */
168 stmp = NULL;
169
170 /*
171 * Read switches.
172 */
173 for (argc--, argv++; argc > 0; argc--, argv++) {
174 if (argv[0][0] != '-')
175 break;
176 switch (argv[0][1]) {
177
178 case 'c': /* chdir_path */
179 if (argv[0][2]) {
180 stmp = &(argv[0][2]);
181 } else {
182 argc--;
183 argv++;
184 stmp = argv[0];
185 }
186 if (!stmp || (stmp[0] != '/')) {
187 fprintf(stderr,
188 "bootpd: invalid chdir specification\n");
189 break;
190 }
191 chdir_path = stmp;
192 break;
193
194 case 'd': /* debug */
195 if (argv[0][2]) {
196 stmp = &(argv[0][2]);
197 } else if (argv[1] && argv[1][0] == '-') {
198 /*
199 * Backwards-compatible behavior:
200 * no parameter, so just increment the debug flag.
201 */
202 debug++;
203 break;
204 } else {
205 argc--;
206 argv++;
207 stmp = argv[0];
208 }
209 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
210 fprintf(stderr,
211 "bootpd: invalid debug level\n");
212 break;
213 }
214 debug = n;
215 break;
216
217 case 'f': /* config file */
218 if (argv[0][2]) {
219 stmp = &(argv[0][2]);
220 } else {
221 argc--;
222 argv++;
223 stmp = argv[0];
224 }
225 bootptab = stmp;
226 break;
227
228 default:
229 fprintf(stderr, "bootpd: unknown switch: -%c\n",
230 argv[0][1]);
231 usage();
232 break;
233 }
234 }
235
236 /* Get the timezone. */
237 tzone_init();
238
239 /* Allocate hash tables. */
240 rdtab_init();
241
242 /*
243 * Read the bootptab file.
244 */
245 readtab(1); /* force read */
246
247 /* Set the cwd (i.e. to /tftpboot) */
248 if (chdir_path) {
249 if (chdir(chdir_path) < 0)
250 report(LOG_ERR, "%s: chdir failed", chdir_path);
251 }
252 /* If there are host names on the command line, do only those. */
253 if (argc > 0) {
254 unsigned int tlen, hashcode;
255
256 while (argc) {
257 tlen = strlen(argv[0]);
258 hashcode = hash_HashFunction((u_char *)argv[0], tlen);
259 hp = (struct host *) hash_Lookup(nmhashtable,
260 hashcode,
261 nmcmp, argv[0]);
262 if (!hp) {
263 printf("%s: no matching entry\n", argv[0]);
264 exit(1);
265 }
266 if (!hp->flags.exten_file) {
267 printf("%s: no extension file\n", argv[0]);
268 exit(1);
269 }
270 mktagfile(hp);
271 argv++;
272 argc--;
273 }
274 exit(0);
275 }
276 /* No host names specified. Do them all. */
277 hp = (struct host *) hash_FirstEntry(nmhashtable);
278 while (hp != NULL) {
279 mktagfile(hp);
280 hp = (struct host *) hash_NextEntry(nmhashtable);
281 }
282 exit(0);
283 }
284
285
287
288 /*
289 * Make a "TAG 18" file for this host.
290 * (Insert the RFC1497 options.)
291 */
292
293 static void
294 mktagfile(hp)
295 struct host *hp;
296 {
297 FILE *fp;
298 int bytesleft, len;
299 byte *vp;
300
301 if (!hp->flags.exten_file)
302 return;
303
304 vp = buffer;
305 bytesleft = BUFFERSIZE;
306 bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
307 vp += 4;
308 bytesleft -= 4;
309
310 /*
311 * The "extension file" options are appended by the following
312 * function (which is shared with bootpd.c).
313 */
314 len = dovend_rfc1497(hp, vp, bytesleft);
315 vp += len;
316 bytesleft -= len;
317
318 if (bytesleft < 1) {
319 report(LOG_ERR, "%s: too much option data",
320 hp->exten_file->string);
321 return;
322 }
323 *vp++ = TAG_END;
324 bytesleft--;
325
326 /* Write the buffer to the extension file. */
327 printf("Updating \"%s\"\n", hp->exten_file->string);
328 if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
329 report(LOG_ERR, "error opening \"%s\": %s",
330 hp->exten_file->string, get_errmsg());
331 return;
332 }
333 len = vp - buffer;
334 if (len != fwrite(buffer, 1, len, fp)) {
335 report(LOG_ERR, "write failed on \"%s\" : %s",
336 hp->exten_file->string, get_errmsg());
337 }
338 fclose(fp);
339
340 } /* mktagfile */
341
342 /*
343 * Local Variables:
344 * tab-width: 4
345 * c-indent-level: 4
346 * c-argdecl-indent: 4
347 * c-continued-statement-offset: 4
348 * c-continued-brace-offset: -4
349 * c-label-offset: -4
350 * c-brace-offset: 0
351 * End:
352 */
353