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