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