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