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