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