xref: /freebsd/libexec/bootpd/tools/bootpef/bootpef.c (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
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) __dead2;
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(void)
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(int argc, char **argv)
120 {
121 	struct host *hp;
122 	char *stmp;
123 	int n;
124 
125 	progname = strrchr(argv[0], '/');
126 	if (progname) progname++;
127 	else progname = argv[0];
128 
129 	/* Get work space for making tag 18 files. */
130 	buffer = (byte *) malloc(BUFFERSIZE);
131 	if (!buffer) {
132 		report(LOG_ERR, "malloc failed");
133 		exit(1);
134 	}
135 	/*
136 	 * Set defaults that might be changed by option switches.
137 	 */
138 	stmp = NULL;
139 
140 	/*
141 	 * Read switches.
142 	 */
143 	for (argc--, argv++; argc > 0; argc--, argv++) {
144 		if (argv[0][0] != '-')
145 			break;
146 		switch (argv[0][1]) {
147 
148 		case 'c':				/* chdir_path */
149 			if (argv[0][2]) {
150 				stmp = &(argv[0][2]);
151 			} else {
152 				argc--;
153 				argv++;
154 				stmp = argv[0];
155 			}
156 			if (!stmp || (stmp[0] != '/')) {
157 				fprintf(stderr,
158 						"bootpd: invalid chdir specification\n");
159 				break;
160 			}
161 			chdir_path = stmp;
162 			break;
163 
164 		case 'd':				/* debug */
165 			if (argv[0][2]) {
166 				stmp = &(argv[0][2]);
167 			} else if (argv[1] && argv[1][0] == '-') {
168 				/*
169 				 * Backwards-compatible behavior:
170 				 * no parameter, so just increment the debug flag.
171 				 */
172 				debug++;
173 				break;
174 			} else {
175 				argc--;
176 				argv++;
177 				stmp = argv[0];
178 			}
179 			if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
180 				fprintf(stderr,
181 						"bootpd: invalid debug level\n");
182 				break;
183 			}
184 			debug = n;
185 			break;
186 
187 		case 'f':				/* config file */
188 			if (argv[0][2]) {
189 				stmp = &(argv[0][2]);
190 			} else {
191 				argc--;
192 				argv++;
193 				stmp = argv[0];
194 			}
195 			bootptab = stmp;
196 			break;
197 
198 		default:
199 			fprintf(stderr, "bootpd: unknown switch: -%c\n",
200 					argv[0][1]);
201 			usage();
202 			break;
203 		}
204 	}
205 
206 	/* Get the timezone. */
207 	tzone_init();
208 
209 	/* Allocate hash tables. */
210 	rdtab_init();
211 
212 	/*
213 	 * Read the bootptab file.
214 	 */
215 	readtab(1);					/* force read */
216 
217 	/* Set the cwd (i.e. to /tftpboot) */
218 	if (chdir_path) {
219 		if (chdir(chdir_path) < 0)
220 			report(LOG_ERR, "%s: chdir failed", chdir_path);
221 	}
222 	/* If there are host names on the command line, do only those. */
223 	if (argc > 0) {
224 		unsigned int tlen, hashcode;
225 
226 		while (argc) {
227 			tlen = strlen(argv[0]);
228 			hashcode = hash_HashFunction((u_char *)argv[0], tlen);
229 			hp = (struct host *) hash_Lookup(nmhashtable,
230 											 hashcode,
231 											 nmcmp, argv[0]);
232 			if (!hp) {
233 				printf("%s: no matching entry\n", argv[0]);
234 				exit(1);
235 			}
236 			if (!hp->flags.exten_file) {
237 				printf("%s: no extension file\n", argv[0]);
238 				exit(1);
239 			}
240 			mktagfile(hp);
241 			argv++;
242 			argc--;
243 		}
244 		exit(0);
245 	}
246 	/* No host names specified.  Do them all. */
247 	hp = (struct host *) hash_FirstEntry(nmhashtable);
248 	while (hp != NULL) {
249 		mktagfile(hp);
250 		hp = (struct host *) hash_NextEntry(nmhashtable);
251 	}
252 	return (0);
253 }
254 
255 
256 
257 /*
258  * Make a "TAG 18" file for this host.
259  * (Insert the RFC1497 options.)
260  */
261 
262 static void
263 mktagfile(struct host *hp)
264 {
265 	FILE *fp;
266 	int bytesleft, len;
267 	byte *vp;
268 
269 	if (!hp->flags.exten_file)
270 		return;
271 
272 	vp = buffer;
273 	bytesleft = BUFFERSIZE;
274 	bcopy(vm_rfc1048, vp, 4);	/* Copy in the magic cookie */
275 	vp += 4;
276 	bytesleft -= 4;
277 
278 	/*
279 	 * The "extension file" options are appended by the following
280 	 * function (which is shared with bootpd.c).
281 	 */
282 	len = dovend_rfc1497(hp, vp, bytesleft);
283 	vp += len;
284 	bytesleft -= len;
285 
286 	if (bytesleft < 1) {
287 		report(LOG_ERR, "%s: too much option data",
288 			   hp->exten_file->string);
289 		return;
290 	}
291 	*vp++ = TAG_END;
292 	bytesleft--;
293 
294 	/* Write the buffer to the extension file. */
295 	printf("Updating \"%s\"\n", hp->exten_file->string);
296 	if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
297 		report(LOG_ERR, "error opening \"%s\": %s",
298 			   hp->exten_file->string, get_errmsg());
299 		return;
300 	}
301 	len = vp - buffer;
302 	if (len != fwrite(buffer, 1, len, fp)) {
303 		report(LOG_ERR, "write failed on \"%s\" : %s",
304 			   hp->exten_file->string, get_errmsg());
305 	}
306 	fclose(fp);
307 
308 } /* mktagfile */
309 
310 /*
311  * Local Variables:
312  * tab-width: 4
313  * c-indent-level: 4
314  * c-argdecl-indent: 4
315  * c-continued-statement-offset: 4
316  * c-continued-brace-offset: -4
317  * c-label-offset: -4
318  * c-brace-offset: 0
319  * End:
320  */
321