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 * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved. 34 * @(#)main.c 8.1 (Berkeley) 6/6/93 35 * $FreeBSD: src/usr.sbin/config/main.c,v 1.37.2.3 2001/06/13 00:25:53 cg Exp $ 36 */ 37 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <sys/file.h> 41 #include <sys/mman.h> 42 #include <sys/param.h> 43 #include <ctype.h> 44 #include <err.h> 45 #include <stdio.h> 46 #include <dirent.h> 47 #include <sysexits.h> 48 #include <unistd.h> 49 #include "y.tab.h" 50 #include "config.h" 51 52 #ifndef TRUE 53 #define TRUE (1) 54 #endif 55 56 #ifndef FALSE 57 #define FALSE (0) 58 #endif 59 60 #define CDIR "../compile/" 61 62 char * PREFIX; 63 char destdir[MAXPATHLEN]; 64 char srcdir[MAXPATHLEN]; 65 66 static int no_config_clobber = TRUE; 67 int debugging; 68 int profiling; 69 70 extern int yyparse(void); 71 static void configfile(void); 72 static void get_srcdir(void); 73 static void usage(void); 74 75 /* 76 * Config builds a set of files for building a UNIX 77 * system given a description of the desired system. 78 */ 79 int 80 main(int argc, char *argv[]) 81 { 82 struct stat buf; 83 int ch, len; 84 unsigned int i; 85 char *p; 86 char linksrc[64], linkdest[MAXPATHLEN]; 87 static const char *emus[] = { "linux" }; 88 89 while ((ch = getopt(argc, argv, "d:gpr")) != -1) 90 switch (ch) { 91 case 'd': 92 if (*destdir == '\0') 93 strlcpy(destdir, optarg, sizeof(destdir)); 94 else 95 errx(2, "directory already set"); 96 break; 97 case 'g': 98 debugging++; 99 break; 100 case 'p': 101 profiling++; 102 break; 103 case 'r': 104 no_config_clobber = FALSE; 105 break; 106 case '?': 107 default: 108 usage(); 109 } 110 argc -= optind; 111 argv += optind; 112 113 if (argc != 1) 114 usage(); 115 116 if (freopen(PREFIX = *argv, "r", stdin) == NULL) 117 err(2, "%s", PREFIX); 118 119 if (*destdir != '\0') { 120 len = strlen(destdir); 121 while (len > 1 && destdir[len - 1] == '/') 122 destdir[--len] = '\0'; 123 get_srcdir(); 124 } else { 125 strlcpy(destdir, CDIR, sizeof(destdir)); 126 strlcat(destdir, PREFIX, sizeof(destdir)); 127 } 128 129 p = path(NULL); 130 if (stat(p, &buf)) { 131 if (mkdir(p, 0777)) 132 err(2, "%s", p); 133 } 134 else if ((buf.st_mode & S_IFMT) != S_IFDIR) { 135 errx(2, "%s isn't a directory", p); 136 } 137 else if (!no_config_clobber) { 138 char tmp[strlen(p) + 8]; 139 140 fprintf(stderr, "Removing old directory %s: ", p); 141 fflush(stderr); 142 snprintf(tmp, sizeof(tmp), "rm -rf %s", p); 143 if (system(tmp)) { 144 fprintf(stderr, "Failed!\n"); 145 err(2, "%s", tmp); 146 } 147 fprintf(stderr, "Done.\n"); 148 if (mkdir(p, 0777)) 149 err(2, "%s", p); 150 } 151 152 dtab = NULL; 153 if (yyparse()) 154 exit(3); 155 if (platformname == NULL) { 156 printf("Specify platform architecture, e.g. 'platform pc32'\n"); 157 exit(1); 158 } 159 if (machinename == NULL) { 160 printf("Specify machine architecture, e.g. 'machine i386'\n"); 161 exit(1); 162 } 163 if (machinearchname == NULL) { 164 printf("Specify cpu architecture, e.g. 'machine_arch i386'\n"); 165 exit(1); 166 } 167 newbus_ioconf(); 168 169 /* 170 * "machine" points into platform/<PLATFORM>/include 171 */ 172 if (*srcdir == '\0') 173 snprintf(linkdest, sizeof(linkdest), "../../platform/%s/include", 174 platformname); 175 else 176 snprintf(linkdest, sizeof(linkdest), "%s/platform/%s/include", 177 srcdir, platformname); 178 symlink(linkdest, path("machine")); 179 180 /* 181 * "machine_base" points into platform/<PLATFORM> 182 */ 183 if (*srcdir == '\0') 184 snprintf(linkdest, sizeof(linkdest), "../../platform/%s", 185 platformname); 186 else 187 snprintf(linkdest, sizeof(linkdest), "%s/platform/%s", 188 srcdir, platformname); 189 symlink(linkdest, path("machine_base")); 190 191 /* 192 * "cpu" points to cpu/<MACHINE_ARCH>/include 193 */ 194 if (*srcdir == '\0') 195 snprintf(linkdest, sizeof(linkdest), 196 "../../cpu/%s/include", machinearchname); 197 else 198 snprintf(linkdest, sizeof(linkdest), 199 "%s/cpu/%s/include", srcdir, machinearchname); 200 symlink(linkdest, path("cpu")); 201 202 /* 203 * "cpu_base" points to cpu/<MACHINE_ARCH> 204 */ 205 if (*srcdir == '\0') 206 snprintf(linkdest, sizeof(linkdest), "../../cpu/%s", 207 machinearchname); 208 else 209 snprintf(linkdest, sizeof(linkdest), "%s/cpu/%s", 210 srcdir, machinearchname); 211 symlink(linkdest, path("cpu_base")); 212 213 /* 214 * XXX check directory structure for architecture subdirectories and 215 * create the symlinks automatically XXX 216 */ 217 for (i = 0; i < sizeof(emus) / sizeof(emus[0]); ++i) { 218 if (*srcdir == 0) { 219 snprintf(linkdest, sizeof(linkdest), 220 "../../emulation/%s/%s", 221 emus[i], machinearchname); 222 } else { 223 snprintf(linkdest, sizeof(linkdest), 224 "%s/emulation/%s/%s", 225 srcdir, emus[i], machinearchname); 226 } 227 snprintf(linksrc, sizeof(linksrc), "arch_%s", emus[i]); 228 symlink(linkdest, path(linksrc)); 229 } 230 231 options(); /* make options .h files */ 232 makefile(); /* build Makefile */ 233 headers(); /* make a lot of .h files */ 234 configfile(); /* put config file into kernel*/ 235 printf("Kernel build directory is %s\n", p); 236 exit(EX_OK); 237 } 238 239 /* 240 * get_srcdir 241 * determine the root of the kernel source tree 242 * and save that in srcdir. 243 */ 244 static void 245 get_srcdir(void) 246 { 247 248 if (realpath("..", srcdir) == NULL) 249 errx(2, "Unable to find root of source tree"); 250 } 251 252 static void 253 usage(void) 254 { 255 256 fprintf(stderr, "usage: config [-gpr] [-d destdir] sysname\n"); 257 exit(1); 258 } 259 260 /* 261 * get_word 262 * returns EOF on end of file 263 * NULL on end of line 264 * pointer to the word otherwise 265 */ 266 char * 267 get_word(FILE *fp) 268 { 269 static char line[80]; 270 int ch; 271 char *cp; 272 int escaped_nl = 0; 273 274 begin: 275 while ((ch = getc(fp)) != EOF) 276 if (ch != ' ' && ch != '\t') 277 break; 278 if (ch == EOF) 279 return((char *)EOF); 280 if (ch == '\\') { 281 escaped_nl = 1; 282 goto begin; 283 } 284 if (ch == '\n') { 285 if (escaped_nl) { 286 escaped_nl = 0; 287 goto begin; 288 } 289 else 290 return(NULL); 291 } 292 cp = line; 293 *cp++ = ch; 294 while ((ch = getc(fp)) != EOF) { 295 if (isspace(ch)) 296 break; 297 *cp++ = ch; 298 } 299 *cp = 0; 300 if (ch == EOF) 301 return((char *)EOF); 302 ungetc(ch, fp); 303 return(line); 304 } 305 306 /* 307 * get_quoted_word 308 * like get_word but will accept something in double or single quotes 309 * (to allow embedded spaces). 310 */ 311 char * 312 get_quoted_word(FILE *fp) 313 { 314 static char line[256]; 315 int ch; 316 char *cp; 317 int escaped_nl = 0; 318 319 begin: 320 while ((ch = getc(fp)) != EOF) 321 if (ch != ' ' && ch != '\t') 322 break; 323 if (ch == EOF) 324 return((char *)EOF); 325 if (ch == '\\') { 326 escaped_nl = 1; 327 goto begin; 328 } 329 if (ch == '\n') { 330 if (escaped_nl) { 331 escaped_nl = 0; 332 goto begin; 333 } 334 else 335 return(NULL); 336 } 337 cp = line; 338 if (ch == '"' || ch == '\'') { 339 int quote = ch; 340 341 while ((ch = getc(fp)) != EOF) { 342 if (ch == quote) 343 break; 344 if (ch == '\n') { 345 *cp = 0; 346 printf("config: missing quote reading `%s'\n", 347 line); 348 exit(2); 349 } 350 *cp++ = ch; 351 } 352 } else { 353 *cp++ = ch; 354 while ((ch = getc(fp)) != EOF) { 355 if (isspace(ch)) 356 break; 357 *cp++ = ch; 358 } 359 if (ch != EOF) 360 ungetc(ch, fp); 361 } 362 *cp = 0; 363 if (ch == EOF) 364 return((char *)EOF); 365 return(line); 366 } 367 368 /* 369 * prepend the path to a filename 370 */ 371 char * 372 path(const char *file) 373 { 374 char *cp; 375 376 cp = malloc((size_t)(strlen(destdir) + (file ? strlen(file) : 0) + 2)); 377 strcpy(cp, destdir); 378 if (file != NULL) { 379 strcat(cp, "/"); 380 strcat(cp, file); 381 } 382 return(cp); 383 } 384 385 static void 386 configfile(void) 387 { 388 FILE *fi, *fo; 389 char *p; 390 int i; 391 392 fi = fopen(PREFIX, "r"); 393 if (fi == NULL) 394 err(2, "%s", PREFIX); 395 fo = fopen(p = path("config.c.new"), "w"); 396 if (fo == NULL) 397 err(2, "%s", p); 398 fprintf(fo, "#include \"opt_config.h\"\n"); 399 fprintf(fo, "#ifdef INCLUDE_CONFIG_FILE \n"); 400 fprintf(fo, "/* Mark config as used, so gcc doesn't optimize it away. */\n"); 401 fprintf(fo, "#include <sys/types.h>\n"); 402 fprintf(fo, "__used\n"); 403 fprintf(fo, "static const char config[] = \"\\\n"); 404 fprintf(fo, "START CONFIG FILE %s\\n\\\n___", PREFIX); 405 while (EOF != (i = getc(fi))) { 406 if (i == '\n') { 407 fprintf(fo, "\\n\\\n___"); 408 } else if (i == '\"') { 409 fprintf(fo, "\\\""); 410 } else if (i == '\\') { 411 fprintf(fo, "\\\\"); 412 } else { 413 putc(i, fo); 414 } 415 } 416 fprintf(fo, "\\n\\\nEND CONFIG FILE %s\\n\\\n", PREFIX); 417 fprintf(fo, "\";\n"); 418 fprintf(fo, "\n#endif /* INCLUDE_CONFIG_FILE */\n"); 419 fclose(fi); 420 fclose(fo); 421 moveifchanged(path("config.c.new"), path("config.c")); 422 } 423 424 /* 425 * moveifchanged -- 426 * compare two files; rename if changed. 427 */ 428 void 429 moveifchanged(const char *from_name, const char *to_name) 430 { 431 char *p, *q; 432 int changed; 433 size_t tsize; 434 struct stat from_sb, to_sb; 435 int from_fd, to_fd; 436 437 changed = 0; 438 439 if ((from_fd = open(from_name, O_RDONLY)) < 0) 440 err(EX_OSERR, "moveifchanged open(%s)", from_name); 441 442 if ((to_fd = open(to_name, O_RDONLY)) < 0) 443 changed++; 444 445 if (!changed && fstat(from_fd, &from_sb) < 0) 446 err(EX_OSERR, "moveifchanged fstat(%s)", from_name); 447 448 if (!changed && fstat(to_fd, &to_sb) < 0) 449 err(EX_OSERR, "moveifchanged fstat(%s)", to_name); 450 451 if (!changed && from_sb.st_size != to_sb.st_size) 452 changed++; 453 454 tsize = (size_t)from_sb.st_size; 455 456 if (!changed) { 457 p = mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, (off_t)0); 458 #ifndef MAP_FAILED 459 #define MAP_FAILED ((caddr_t)-1) 460 #endif 461 if (p == MAP_FAILED) 462 err(EX_OSERR, "mmap %s", from_name); 463 q = mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, (off_t)0); 464 if (q == MAP_FAILED) 465 err(EX_OSERR, "mmap %s", to_name); 466 467 changed = memcmp(p, q, tsize); 468 munmap(p, tsize); 469 munmap(q, tsize); 470 } 471 if (changed) { 472 if (rename(from_name, to_name) < 0) 473 err(EX_OSERR, "rename(%s, %s)", from_name, to_name); 474 } else { 475 if (unlink(from_name) < 0) 476 err(EX_OSERR, "unlink(%s)", from_name); 477 } 478 } 479