main.c revision 71866
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1980, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
3529451Scharnierstatic const char copyright[] =
361553Srgrimes"@(#) Copyright (c) 1980, 1993\n\
371553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381553Srgrimes#endif /* not lint */
391553Srgrimes
401553Srgrimes#ifndef lint
4129451Scharnier#if 0
421553Srgrimesstatic char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
4329451Scharnier#endif
4429451Scharnierstatic const char rcsid[] =
4550479Speter  "$FreeBSD: head/usr.sbin/config/main.c 71866 2001-01-31 08:42:35Z peter $";
461553Srgrimes#endif /* not lint */
471553Srgrimes
481553Srgrimes#include <sys/types.h>
491553Srgrimes#include <sys/stat.h>
501553Srgrimes#include <sys/file.h>
5113400Speter#include <sys/mman.h>
5252653Smarcel#include <sys/param.h>
531553Srgrimes#include <ctype.h>
5413400Speter#include <err.h>
5529451Scharnier#include <stdio.h>
5613400Speter#include <sysexits.h>
5729451Scharnier#include <unistd.h>
5871784Speter#include <dirent.h>
5916073Sphk#include "y.tab.h"
601553Srgrimes#include "config.h"
611553Srgrimes
626631Sjkh#ifndef TRUE
636631Sjkh#define TRUE	(1)
646631Sjkh#endif
656631Sjkh
666631Sjkh#ifndef FALSE
676631Sjkh#define FALSE	(0)
686631Sjkh#endif
696631Sjkh
7052653Smarcel#define	CDIR	"../../compile/"
7152653Smarcel
7245744Speterchar *	PREFIX;
7352653Smarcelchar 	destdir[MAXPATHLEN];
7452653Smarcelchar 	srcdir[MAXPATHLEN];
7552653Smarcel
7645744Speterint	debugging;
7745744Speterint	profiling;
781553Srgrimes
7961640Speterstatic void configfile(void);
8061640Speterstatic void get_srcdir(void);
8161640Speterstatic void usage(void);
8271866Speterstatic void cleanheaders(char *);
8329451Scharnier
8471866Speterstruct hdr_list {
8571866Speter	char *h_name;
8671866Speter	struct hdr_list *h_next;
8771866Speter} *htab;
8871866Speter
891553Srgrimes/*
901553Srgrimes * Config builds a set of files for building a UNIX
911553Srgrimes * system given a description of the desired system.
921553Srgrimes */
9329451Scharnierint
9461640Spetermain(int argc, char **argv)
951553Srgrimes{
961553Srgrimes
971553Srgrimes	struct stat buf;
9852653Smarcel	int ch, len;
991553Srgrimes	char *p;
1001553Srgrimes
10171363Speter	while ((ch = getopt(argc, argv, "d:gp")) != -1)
1021553Srgrimes		switch (ch) {
10352653Smarcel		case 'd':
10452653Smarcel			if (*destdir == '\0')
10569004Simp				strlcpy(destdir, optarg, sizeof(destdir));
10652653Smarcel			else
10752653Smarcel				errx(2, "directory already set");
10852653Smarcel			break;
1091553Srgrimes		case 'g':
11045579Sgrog			debugging++;
1111553Srgrimes			break;
1121553Srgrimes		case 'p':
1131553Srgrimes			profiling++;
1141553Srgrimes			break;
1151553Srgrimes		case '?':
1161553Srgrimes		default:
11729451Scharnier			usage();
1181553Srgrimes		}
1191553Srgrimes	argc -= optind;
1201553Srgrimes	argv += optind;
1211553Srgrimes
12229451Scharnier	if (argc != 1)
12329451Scharnier		usage();
1241553Srgrimes
12529451Scharnier	if (freopen(PREFIX = *argv, "r", stdin) == NULL)
12629451Scharnier		err(2, "%s", PREFIX);
1276631Sjkh
12852653Smarcel	if (*destdir != '\0') {
12952653Smarcel		len = strlen(destdir);
13052653Smarcel		while (len > 1 && destdir[len - 1] == '/')
13152653Smarcel			destdir[--len] = '\0';
13252653Smarcel		get_srcdir();
13352653Smarcel	} else {
13469004Simp		strlcpy(destdir, CDIR, sizeof(destdir));
13569004Simp		strlcat(destdir, PREFIX, sizeof(destdir));
13652653Smarcel	}
13752653Smarcel
1382483Sjkh	p = path((char *)NULL);
1392483Sjkh	if (stat(p, &buf)) {
14029451Scharnier		if (mkdir(p, 0777))
14129451Scharnier			err(2, "%s", p);
1421553Srgrimes	}
14371363Speter	else if ((buf.st_mode & S_IFMT) != S_IFDIR)
14429451Scharnier		errx(2, "%s isn't a directory", p);
1451553Srgrimes
1461553Srgrimes	dtab = NULL;
1471553Srgrimes	if (yyparse())
1481553Srgrimes		exit(3);
1491553Srgrimes	switch (machine) {
1501553Srgrimes
1511553Srgrimes	case MACHINE_I386:
15235609Skato	case MACHINE_PC98:
15336813Sdfr	case MACHINE_ALPHA:
15466457Sdfr	case MACHINE_IA64:
15571374Sbenno	case MACHINE_POWERPC:
15636813Sdfr		break;
15736813Sdfr
1581553Srgrimes	default:
15945775Speter		printf("Specify machine type, e.g. ``machine i386''\n");
1601553Srgrimes		exit(1);
1611553Srgrimes	}
1621553Srgrimes	/*
1631553Srgrimes	 * make symbolic links in compilation directory
1641553Srgrimes	 * for "sys" (to make genassym.c work along with #include <sys/xxx>)
1651553Srgrimes	 * and similarly for "machine".
1661553Srgrimes	 */
1671553Srgrimes	{
16869004Simp	char xxx[MAXPATHLEN];
16952653Smarcel	if (*srcdir == '\0')
17052653Smarcel		(void)snprintf(xxx, sizeof(xxx), "../../%s/include",
17152653Smarcel		    machinename);
17252653Smarcel	else
17352653Smarcel		(void)snprintf(xxx, sizeof(xxx), "%s/%s/include",
17452653Smarcel		    srcdir, machinename);
1751553Srgrimes	(void) symlink(xxx, path("machine"));
1761553Srgrimes	}
17712772Speter	options();			/* make options .h files */
1781553Srgrimes	makefile();			/* build Makefile */
1791553Srgrimes	headers();			/* make a lot of .h files */
18016239Sjkh	configfile();			/* put config file into kernel*/
18171866Speter	cleanheaders(p);
1828248Sjkh	printf("Kernel build directory is %s\n", p);
1831553Srgrimes	exit(0);
1841553Srgrimes}
1851553Srgrimes
18652653Smarcel/*
18752653Smarcel * get_srcdir
18852653Smarcel *	determine the root of the kernel source tree
18952653Smarcel *	and save that in srcdir.
19052653Smarcel */
19129451Scharnierstatic void
19261640Speterget_srcdir(void)
19352653Smarcel{
19452653Smarcel
19570673Speter	if (realpath("../..", srcdir) == NULL)
19670673Speter		errx(2, "Unable to find root of source tree");
19752653Smarcel}
19852653Smarcel
19952653Smarcelstatic void
20061640Speterusage(void)
20129451Scharnier{
20271363Speter		fprintf(stderr, "usage: config [-gp] [-d destdir] sysname\n");
20329451Scharnier		exit(1);
20429451Scharnier}
20529451Scharnier
2061553Srgrimes/*
2071553Srgrimes * get_word
2081553Srgrimes *	returns EOF on end of file
2091553Srgrimes *	NULL on end of line
2101553Srgrimes *	pointer to the word otherwise
2111553Srgrimes */
2121553Srgrimeschar *
21361640Speterget_word(FILE *fp)
2141553Srgrimes{
2151553Srgrimes	static char line[80];
21661640Speter	int ch;
21761640Speter	char *cp;
2184571Sgibbs	int escaped_nl = 0;
2191553Srgrimes
2204571Sgibbsbegin:
2211553Srgrimes	while ((ch = getc(fp)) != EOF)
2221553Srgrimes		if (ch != ' ' && ch != '\t')
2231553Srgrimes			break;
2241553Srgrimes	if (ch == EOF)
2251553Srgrimes		return ((char *)EOF);
2264571Sgibbs	if (ch == '\\'){
2274571Sgibbs		escaped_nl = 1;
2284571Sgibbs		goto begin;
2294571Sgibbs	}
23045775Speter	if (ch == '\n') {
2314571Sgibbs		if (escaped_nl){
2324571Sgibbs			escaped_nl = 0;
2334571Sgibbs			goto begin;
2344571Sgibbs		}
2354571Sgibbs		else
2364571Sgibbs			return (NULL);
23745775Speter	}
2381553Srgrimes	cp = line;
2391553Srgrimes	*cp++ = ch;
2401553Srgrimes	while ((ch = getc(fp)) != EOF) {
2411553Srgrimes		if (isspace(ch))
2421553Srgrimes			break;
2431553Srgrimes		*cp++ = ch;
2441553Srgrimes	}
2451553Srgrimes	*cp = 0;
2461553Srgrimes	if (ch == EOF)
2471553Srgrimes		return ((char *)EOF);
2481553Srgrimes	(void) ungetc(ch, fp);
2491553Srgrimes	return (line);
2501553Srgrimes}
2511553Srgrimes
2521553Srgrimes/*
2531553Srgrimes * get_quoted_word
2541553Srgrimes *	like get_word but will accept something in double or single quotes
2551553Srgrimes *	(to allow embedded spaces).
2561553Srgrimes */
2571553Srgrimeschar *
25861640Speterget_quoted_word(FILE *fp)
2591553Srgrimes{
2601553Srgrimes	static char line[256];
26161640Speter	int ch;
26261640Speter	char *cp;
2634571Sgibbs	int escaped_nl = 0;
2641553Srgrimes
2654571Sgibbsbegin:
2661553Srgrimes	while ((ch = getc(fp)) != EOF)
2671553Srgrimes		if (ch != ' ' && ch != '\t')
2681553Srgrimes			break;
2691553Srgrimes	if (ch == EOF)
2701553Srgrimes		return ((char *)EOF);
2714571Sgibbs	if (ch == '\\'){
2724571Sgibbs		escaped_nl = 1;
2734571Sgibbs		goto begin;
2744571Sgibbs	}
27545775Speter	if (ch == '\n') {
2764571Sgibbs		if (escaped_nl){
2774571Sgibbs			escaped_nl = 0;
2784571Sgibbs			goto begin;
2794571Sgibbs		}
2804571Sgibbs		else
2814571Sgibbs			return (NULL);
28245775Speter	}
2831553Srgrimes	cp = line;
2841553Srgrimes	if (ch == '"' || ch == '\'') {
28561640Speter		int quote = ch;
2861553Srgrimes
2871553Srgrimes		while ((ch = getc(fp)) != EOF) {
2881553Srgrimes			if (ch == quote)
2891553Srgrimes				break;
2901553Srgrimes			if (ch == '\n') {
2911553Srgrimes				*cp = 0;
2921553Srgrimes				printf("config: missing quote reading `%s'\n",
2931553Srgrimes					line);
2941553Srgrimes				exit(2);
2951553Srgrimes			}
2961553Srgrimes			*cp++ = ch;
2971553Srgrimes		}
2981553Srgrimes	} else {
2991553Srgrimes		*cp++ = ch;
3001553Srgrimes		while ((ch = getc(fp)) != EOF) {
3011553Srgrimes			if (isspace(ch))
3021553Srgrimes				break;
3031553Srgrimes			*cp++ = ch;
3041553Srgrimes		}
3051553Srgrimes		if (ch != EOF)
3061553Srgrimes			(void) ungetc(ch, fp);
3071553Srgrimes	}
3081553Srgrimes	*cp = 0;
3091553Srgrimes	if (ch == EOF)
3101553Srgrimes		return ((char *)EOF);
3111553Srgrimes	return (line);
3121553Srgrimes}
3131553Srgrimes
3141553Srgrimes/*
3151553Srgrimes * prepend the path to a filename
3161553Srgrimes */
3171553Srgrimeschar *
31861640Speterpath(char *file)
3191553Srgrimes{
32069004Simp	char *cp = NULL;
3211553Srgrimes
32269004Simp	if (file)
32369004Simp		asprintf(&cp, "%s/%s", destdir, file);
32469004Simp	else
32569004Simp		cp = strdup(destdir);
3261553Srgrimes	return (cp);
3271553Srgrimes}
32813400Speter
32945744Speterstatic void
33061640Speterconfigfile(void)
33116239Sjkh{
33216239Sjkh	FILE *fi, *fo;
33316239Sjkh	char *p;
33416239Sjkh	int i;
33516239Sjkh
33652098Speter	fi = fopen(PREFIX, "r");
33752098Speter	if (!fi)
33829451Scharnier		err(2, "%s", PREFIX);
33952098Speter	fo = fopen(p=path("config.c.new"), "w");
34052098Speter	if (!fo)
34129451Scharnier		err(2, "%s", p);
34252098Speter	fprintf(fo, "#include \"opt_config.h\"\n");
34352098Speter	fprintf(fo, "#ifdef INCLUDE_CONFIG_FILE \n");
34452098Speter	fprintf(fo, "static const char config[] = \"\\\n");
34552098Speter	fprintf(fo, "START CONFIG FILE %s\\n\\\n___", PREFIX);
34616239Sjkh	while (EOF != (i=getc(fi))) {
34752098Speter		if (i == '\n') {
34852098Speter			fprintf(fo, "\\n\\\n___");
34952098Speter		} else if (i == '\"') {
35052098Speter			fprintf(fo, "\\\"");
35152098Speter		} else if (i == '\\') {
35252098Speter			fprintf(fo, "\\\\");
35316239Sjkh		} else {
35452098Speter			putc(i, fo);
35516239Sjkh		}
35616239Sjkh	}
35752098Speter	fprintf(fo, "\\n\\\nEND CONFIG FILE %s\\n\\\n", PREFIX);
35852098Speter	fprintf(fo, "\";\n");
35952098Speter	fprintf(fo, "\n#endif /* INCLUDE_CONFIG_FILE */\n");
36016239Sjkh	fclose(fi);
36116239Sjkh	fclose(fo);
36220940Speter	moveifchanged(path("config.c.new"), path("config.c"));
36316239Sjkh}
36416239Sjkh
36513400Speter/*
36613400Speter * moveifchanged --
36713400Speter *	compare two files; rename if changed.
36813400Speter */
36913400Spetervoid
37013400Spetermoveifchanged(const char *from_name, const char *to_name)
37113400Speter{
37213400Speter	char *p, *q;
37313400Speter	int changed;
37413400Speter	size_t tsize;
37513400Speter	struct stat from_sb, to_sb;
37613400Speter	int from_fd, to_fd;
37713400Speter
37813400Speter	changed = 0;
37913400Speter
38013400Speter	if ((from_fd = open(from_name, O_RDONLY)) < 0)
38113400Speter		err(EX_OSERR, "moveifchanged open(%s)", from_name);
38213400Speter
38313400Speter	if ((to_fd = open(to_name, O_RDONLY)) < 0)
38413400Speter		changed++;
38513400Speter
38613400Speter	if (!changed && fstat(from_fd, &from_sb) < 0)
38713400Speter		err(EX_OSERR, "moveifchanged fstat(%s)", from_name);
38813400Speter
38913400Speter	if (!changed && fstat(to_fd, &to_sb) < 0)
39013400Speter		err(EX_OSERR, "moveifchanged fstat(%s)", to_name);
39113400Speter
39213400Speter	if (!changed && from_sb.st_size != to_sb.st_size)
39313400Speter		changed++;
39413400Speter
39513400Speter	tsize = (size_t)from_sb.st_size;
39613400Speter
39713400Speter	if (!changed) {
39821786Salex		p = mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, (off_t)0);
39936813Sdfr#ifndef MAP_FAILED
40036813Sdfr#define MAP_FAILED ((caddr_t) -1)
40136813Sdfr#endif
40221786Salex		if (p == MAP_FAILED)
40313400Speter			err(EX_OSERR, "mmap %s", from_name);
40421786Salex		q = mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, (off_t)0);
40521786Salex		if (q == MAP_FAILED)
40613400Speter			err(EX_OSERR, "mmap %s", to_name);
40713400Speter
40813400Speter		changed = memcmp(p, q, tsize);
40913400Speter		munmap(p, tsize);
41013400Speter		munmap(q, tsize);
41113400Speter	}
41213400Speter	if (changed) {
41313400Speter		if (rename(from_name, to_name) < 0)
41413400Speter			err(EX_OSERR, "rename(%s, %s)", from_name, to_name);
41513400Speter	} else {
41613400Speter		if (unlink(from_name) < 0)
41731216Sjdp			err(EX_OSERR, "unlink(%s)", from_name);
41813400Speter	}
41913400Speter}
42071784Speter
42171784Speterstatic void
42271866Spetercleanheaders(char *p)
42371784Speter{
42471784Speter	DIR *dirp;
42571784Speter	struct dirent *dp;
42671784Speter	struct file_list *fl;
42771866Speter	struct hdr_list *hl;
42871784Speter	int i;
42971784Speter
43071866Speter	remember("y.tab.h");
43171866Speter	remember("setdefs.h");
43271866Speter	for (fl = ftab; fl != NULL; fl = fl->f_next)
43371866Speter		remember(fl->f_fn);
43471784Speter
43571784Speter	/*
43671784Speter	 * Scan the build directory and clean out stuff that looks like
43771784Speter	 * it might have been a leftover NFOO header, etc.
43871784Speter	 */
43971784Speter	dirp = opendir(p);
44071784Speter	while ((dp = readdir(dirp)) != NULL) {
44171784Speter		i = dp->d_namlen - 2;
44271784Speter		/* Skip non-headers */
44371784Speter		if (dp->d_name[i] != '.' || dp->d_name[i + 1] != 'h')
44471784Speter			continue;
44571784Speter		/* Skip special stuff, eg: bus_if.h, but check opt_*.h */
44671784Speter		if (index(dp->d_name, '_') &&
44771784Speter		    strncmp(dp->d_name, "opt_", 4) != 0)
44871784Speter			continue;
44971784Speter		/* Check if it is a target file */
45071866Speter		for (hl = htab; hl != NULL; hl = hl->h_next) {
45171866Speter			if (strcmp(dp->d_name, hl->h_name) == 0) {
45271784Speter				break;
45371784Speter			}
45471784Speter		}
45571866Speter		if (hl)
45671784Speter			continue;
45771784Speter		printf("Removing stale header: %s\n", dp->d_name);
45871784Speter		unlink(path(dp->d_name));
45971784Speter	}
46071784Speter	(void)closedir(dirp);
46171866Speter}
46271784Speter
46371866Spetervoid
46471866Speterremember(char *file)
46571866Speter{
46671866Speter	char *s;
46771866Speter	struct hdr_list *hl;
46871866Speter
46971866Speter	if ((s = strrchr(file, '/')) != NULL)
47071866Speter		s++;
47171866Speter	else
47271866Speter		s = file;
47371866Speter	s = ns(s);
47471866Speter
47571866Speter	if (index(s, '_') && strncmp(s, "opt_", 4) != 0) {
47671866Speter		free(s);
47771866Speter		return;
47871866Speter	}
47971866Speter	for (hl = htab; hl != NULL; hl = hl->h_next) {
48071866Speter		if (strcmp(s, hl->h_name) == 0) {
48171866Speter			free(s);
48271866Speter			return;
48371866Speter		}
48471866Speter	}
48571866Speter	hl = malloc(sizeof(*hl));
48671866Speter	bzero(hl, sizeof(*hl));
48771866Speter	hl->h_name = s;
48871866Speter	hl->h_next = htab;
48971866Speter	htab = hl;
49071784Speter}
491