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