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