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