main.c revision 144352
1/* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#ifndef lint 31static const char copyright[] = 32"@(#) Copyright (c) 1980, 1993\n\ 33 The Regents of the University of California. All rights reserved.\n"; 34#endif /* not lint */ 35 36#ifndef lint 37#if 0 38static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 39#endif 40static const char rcsid[] = 41 "$FreeBSD: head/usr.sbin/config/main.c 144352 2005-03-30 21:45:08Z imp $"; 42#endif /* not lint */ 43 44#include <sys/types.h> 45#include <sys/stat.h> 46#include <sys/file.h> 47#include <sys/mman.h> 48#include <sys/param.h> 49#include <ctype.h> 50#include <err.h> 51#include <stdio.h> 52#include <sysexits.h> 53#include <unistd.h> 54#include <dirent.h> 55#include "y.tab.h" 56#include "config.h" 57 58#ifndef TRUE 59#define TRUE (1) 60#endif 61 62#ifndef FALSE 63#define FALSE (0) 64#endif 65 66#define CDIR "../compile/" 67 68char * PREFIX; 69char destdir[MAXPATHLEN]; 70char srcdir[MAXPATHLEN]; 71 72int debugging; 73int profiling; 74 75static void configfile(void); 76static void get_srcdir(void); 77static void usage(void); 78static void cleanheaders(char *); 79 80struct hdr_list { 81 char *h_name; 82 struct hdr_list *h_next; 83} *htab; 84 85/* 86 * Config builds a set of files for building a UNIX 87 * system given a description of the desired system. 88 */ 89int 90main(int argc, char **argv) 91{ 92 93 struct stat buf; 94 int ch, len; 95 char *p; 96 char xxx[MAXPATHLEN]; 97 98 while ((ch = getopt(argc, argv, "d:gp")) != -1) 99 switch (ch) { 100 case 'd': 101 if (*destdir == '\0') 102 strlcpy(destdir, optarg, sizeof(destdir)); 103 else 104 errx(2, "directory already set"); 105 break; 106 case 'g': 107 debugging++; 108 break; 109 case 'p': 110 profiling++; 111 break; 112 case '?': 113 default: 114 usage(); 115 } 116 argc -= optind; 117 argv += optind; 118 119 if (argc != 1) 120 usage(); 121 122 if (freopen(PREFIX = *argv, "r", stdin) == NULL) 123 err(2, "%s", PREFIX); 124 125 if (*destdir != '\0') { 126 len = strlen(destdir); 127 while (len > 1 && destdir[len - 1] == '/') 128 destdir[--len] = '\0'; 129 get_srcdir(); 130 } else { 131 strlcpy(destdir, CDIR, sizeof(destdir)); 132 strlcat(destdir, PREFIX, sizeof(destdir)); 133 } 134 135 p = path((char *)NULL); 136 if (stat(p, &buf)) { 137 if (mkdir(p, 0777)) 138 err(2, "%s", p); 139 } 140 else if ((buf.st_mode & S_IFMT) != S_IFDIR) 141 errx(2, "%s isn't a directory", p); 142 143 STAILQ_INIT(&dtab); 144 STAILQ_INIT(&fntab); 145 SLIST_INIT(&cputype); 146 STAILQ_INIT(&ftab); 147 yyfile = *argv; 148 if (yyparse()) 149 exit(3); 150 if (machinename == NULL) { 151 printf("Specify machine type, e.g. ``machine i386''\n"); 152 exit(1); 153 } 154 /* 155 * make symbolic links in compilation directory 156 * for "sys" (to make genassym.c work along with #include <sys/xxx>) 157 * and similarly for "machine". 158 */ 159 if (*srcdir == '\0') 160 (void)snprintf(xxx, sizeof(xxx), "../../include"); 161 else 162 (void)snprintf(xxx, sizeof(xxx), "%s/%s/include", 163 srcdir, machinename); 164 (void) unlink(path("machine")); 165 (void) symlink(xxx, path("machine")); 166 options(); /* make options .h files */ 167 makefile(); /* build Makefile */ 168 headers(); /* make a lot of .h files */ 169 configfile(); /* put config file into kernel*/ 170 cleanheaders(p); 171 printf("Kernel build directory is %s\n", p); 172 printf("Don't forget to do a ``make depend''\n"); 173 exit(0); 174} 175 176/* 177 * get_srcdir 178 * determine the root of the kernel source tree 179 * and save that in srcdir. 180 */ 181static void 182get_srcdir(void) 183{ 184 185 if (realpath("../..", srcdir) == NULL) 186 errx(2, "Unable to find root of source tree"); 187} 188 189static void 190usage(void) 191{ 192 193 fprintf(stderr, "usage: config [-gp] [-d destdir] sysname\n"); 194 exit(1); 195} 196 197/* 198 * get_word 199 * returns EOF on end of file 200 * NULL on end of line 201 * pointer to the word otherwise 202 */ 203char * 204get_word(FILE *fp) 205{ 206 static char line[80]; 207 int ch; 208 char *cp; 209 int escaped_nl = 0; 210 211begin: 212 while ((ch = getc(fp)) != EOF) 213 if (ch != ' ' && ch != '\t') 214 break; 215 if (ch == EOF) 216 return ((char *)EOF); 217 if (ch == '\\'){ 218 escaped_nl = 1; 219 goto begin; 220 } 221 if (ch == '\n') { 222 if (escaped_nl){ 223 escaped_nl = 0; 224 goto begin; 225 } 226 else 227 return (NULL); 228 } 229 cp = line; 230 *cp++ = ch; 231 while ((ch = getc(fp)) != EOF) { 232 if (isspace(ch)) 233 break; 234 *cp++ = ch; 235 } 236 *cp = 0; 237 if (ch == EOF) 238 return ((char *)EOF); 239 (void) ungetc(ch, fp); 240 return (line); 241} 242 243/* 244 * get_quoted_word 245 * like get_word but will accept something in double or single quotes 246 * (to allow embedded spaces). 247 */ 248char * 249get_quoted_word(FILE *fp) 250{ 251 static char line[256]; 252 int ch; 253 char *cp; 254 int escaped_nl = 0; 255 256begin: 257 while ((ch = getc(fp)) != EOF) 258 if (ch != ' ' && ch != '\t') 259 break; 260 if (ch == EOF) 261 return ((char *)EOF); 262 if (ch == '\\'){ 263 escaped_nl = 1; 264 goto begin; 265 } 266 if (ch == '\n') { 267 if (escaped_nl){ 268 escaped_nl = 0; 269 goto begin; 270 } 271 else 272 return (NULL); 273 } 274 cp = line; 275 if (ch == '"' || ch == '\'') { 276 int quote = ch; 277 278 while ((ch = getc(fp)) != EOF) { 279 if (ch == quote) 280 break; 281 if (ch == '\n') { 282 *cp = 0; 283 printf("config: missing quote reading `%s'\n", 284 line); 285 exit(2); 286 } 287 *cp++ = ch; 288 } 289 } else { 290 *cp++ = ch; 291 while ((ch = getc(fp)) != EOF) { 292 if (isspace(ch)) 293 break; 294 *cp++ = ch; 295 } 296 if (ch != EOF) 297 (void) ungetc(ch, fp); 298 } 299 *cp = 0; 300 if (ch == EOF) 301 return ((char *)EOF); 302 return (line); 303} 304 305/* 306 * prepend the path to a filename 307 */ 308char * 309path(const char *file) 310{ 311 char *cp = NULL; 312 313 if (file) 314 asprintf(&cp, "%s/%s", destdir, file); 315 else 316 cp = strdup(destdir); 317 return (cp); 318} 319 320static void 321configfile(void) 322{ 323 FILE *fi, *fo; 324 char *p; 325 int i; 326 327 fi = fopen(PREFIX, "r"); 328 if (!fi) 329 err(2, "%s", PREFIX); 330 fo = fopen(p=path("config.c.new"), "w"); 331 if (!fo) 332 err(2, "%s", p); 333 fprintf(fo, "#include \"opt_config.h\"\n"); 334 fprintf(fo, "#ifdef INCLUDE_CONFIG_FILE \n"); 335 fprintf(fo, "const char config[] = \"\\\n"); 336 fprintf(fo, "START CONFIG FILE %s\\n\\\n___", PREFIX); 337 while (EOF != (i=getc(fi))) { 338 if (i == '\n') { 339 fprintf(fo, "\\n\\\n___"); 340 } else if (i == '\"') { 341 fprintf(fo, "\\\""); 342 } else if (i == '\\') { 343 fprintf(fo, "\\\\"); 344 } else { 345 putc(i, fo); 346 } 347 } 348 fprintf(fo, "\\n\\\nEND CONFIG FILE %s\\n\\\n", PREFIX); 349 fprintf(fo, "\";\n"); 350 fprintf(fo, "\n#endif /* INCLUDE_CONFIG_FILE */\n"); 351 fclose(fi); 352 fclose(fo); 353 moveifchanged(path("config.c.new"), path("config.c")); 354} 355 356/* 357 * moveifchanged -- 358 * compare two files; rename if changed. 359 */ 360void 361moveifchanged(const char *from_name, const char *to_name) 362{ 363 char *p, *q; 364 int changed; 365 size_t tsize; 366 struct stat from_sb, to_sb; 367 int from_fd, to_fd; 368 369 changed = 0; 370 371 if ((from_fd = open(from_name, O_RDONLY)) < 0) 372 err(EX_OSERR, "moveifchanged open(%s)", from_name); 373 374 if ((to_fd = open(to_name, O_RDONLY)) < 0) 375 changed++; 376 377 if (!changed && fstat(from_fd, &from_sb) < 0) 378 err(EX_OSERR, "moveifchanged fstat(%s)", from_name); 379 380 if (!changed && fstat(to_fd, &to_sb) < 0) 381 err(EX_OSERR, "moveifchanged fstat(%s)", to_name); 382 383 if (!changed && from_sb.st_size != to_sb.st_size) 384 changed++; 385 386 tsize = (size_t)from_sb.st_size; 387 388 if (!changed) { 389 p = mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, (off_t)0); 390#ifndef MAP_FAILED 391#define MAP_FAILED ((caddr_t) -1) 392#endif 393 if (p == MAP_FAILED) 394 err(EX_OSERR, "mmap %s", from_name); 395 q = mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, (off_t)0); 396 if (q == MAP_FAILED) 397 err(EX_OSERR, "mmap %s", to_name); 398 399 changed = memcmp(p, q, tsize); 400 munmap(p, tsize); 401 munmap(q, tsize); 402 } 403 if (changed) { 404 if (rename(from_name, to_name) < 0) 405 err(EX_OSERR, "rename(%s, %s)", from_name, to_name); 406 } else { 407 if (unlink(from_name) < 0) 408 err(EX_OSERR, "unlink(%s)", from_name); 409 } 410} 411 412static void 413cleanheaders(char *p) 414{ 415 DIR *dirp; 416 struct dirent *dp; 417 struct file_list *fl; 418 struct hdr_list *hl; 419 int i; 420 421 remember("y.tab.h"); 422 remember("setdefs.h"); 423 STAILQ_FOREACH(fl, &ftab, f_next) 424 remember(fl->f_fn); 425 426 /* 427 * Scan the build directory and clean out stuff that looks like 428 * it might have been a leftover NFOO header, etc. 429 */ 430 if ((dirp = opendir(p)) == NULL) 431 err(EX_OSERR, "opendir %s", p); 432 while ((dp = readdir(dirp)) != NULL) { 433 i = dp->d_namlen - 2; 434 /* Skip non-headers */ 435 if (dp->d_name[i] != '.' || dp->d_name[i + 1] != 'h') 436 continue; 437 /* Skip special stuff, eg: bus_if.h, but check opt_*.h */ 438 if (index(dp->d_name, '_') && 439 strncmp(dp->d_name, "opt_", 4) != 0) 440 continue; 441 /* Check if it is a target file */ 442 for (hl = htab; hl != NULL; hl = hl->h_next) { 443 if (strcmp(dp->d_name, hl->h_name) == 0) { 444 break; 445 } 446 } 447 if (hl) 448 continue; 449 printf("Removing stale header: %s\n", dp->d_name); 450 if (unlink(path(dp->d_name)) == -1) 451 warn("unlink %s", dp->d_name); 452 } 453 (void)closedir(dirp); 454} 455 456void 457remember(const char *file) 458{ 459 char *s; 460 struct hdr_list *hl; 461 462 if ((s = strrchr(file, '/')) != NULL) 463 s = ns(s + 1); 464 else 465 s = ns(file); 466 467 if (index(s, '_') && strncmp(s, "opt_", 4) != 0) { 468 free(s); 469 return; 470 } 471 for (hl = htab; hl != NULL; hl = hl->h_next) { 472 if (strcmp(s, hl->h_name) == 0) { 473 free(s); 474 return; 475 } 476 } 477 hl = malloc(sizeof(*hl)); 478 bzero(hl, sizeof(*hl)); 479 hl->h_name = s; 480 hl->h_next = htab; 481 htab = hl; 482} 483