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