]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/usr.sbin/config/main.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / usr.sbin / config / main.c
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  * 4. 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
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1980, 1993\n\
33         The Regents of the University of California.  All rights reserved.\n";
34 #endif /* not lint */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)main.c      8.1 (Berkeley) 6/6/93";
39 #endif
40 static const char rcsid[] =
41   "$FreeBSD$";
42 #endif /* not lint */
43
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/file.h>
47 #include <sys/mman.h>
48 #include <sys/param.h>
49 #include <ctype.h>
50 #include <err.h>
51 #include <stdio.h>
52 #include <sysexits.h>
53 #include <unistd.h>
54 #include <dirent.h>
55 #include "y.tab.h"
56 #include "config.h"
57 #include "configvers.h"
58
59 #ifndef TRUE
60 #define TRUE    (1)
61 #endif
62
63 #ifndef FALSE
64 #define FALSE   (0)
65 #endif
66
67 #define CDIR    "../compile/"
68
69 char *  PREFIX;
70 char    destdir[MAXPATHLEN];
71 char    srcdir[MAXPATHLEN];
72
73 int     debugging;
74 int     profiling;
75 int     found_defaults;
76
77 static void configfile(void);
78 static void get_srcdir(void);
79 static void usage(void);
80 static void cleanheaders(char *);
81
82 struct hdr_list {
83         char *h_name;
84         struct hdr_list *h_next;
85 } *htab;
86
87 /*
88  * Config builds a set of files for building a UNIX
89  * system given a description of the desired system.
90  */
91 int
92 main(int argc, char **argv)
93 {
94
95         struct stat buf;
96         int ch, len;
97         char *p;
98         char xxx[MAXPATHLEN];
99
100         while ((ch = getopt(argc, argv, "d:gpV")) != -1)
101                 switch (ch) {
102                 case 'V':
103                         printf("%d\n", CONFIGVERS);
104                         exit(0);
105                 case 'd':
106                         if (*destdir == '\0')
107                                 strlcpy(destdir, optarg, sizeof(destdir));
108                         else
109                                 errx(2, "directory already set");
110                         break;
111                 case 'g':
112                         debugging++;
113                         break;
114                 case 'p':
115                         profiling++;
116                         break;
117                 case '?':
118                 default:
119                         usage();
120                 }
121         argc -= optind;
122         argv += optind;
123
124         if (argc != 1)
125                 usage();
126
127         PREFIX = *argv;
128         if (freopen("DEFAULTS", "r", stdin) != NULL) {
129                 found_defaults = 1;
130                 yyfile = "DEFAULTS";
131         } else {
132                 if (freopen(PREFIX, "r", stdin) == NULL)
133                         err(2, "%s", PREFIX);
134                 yyfile = PREFIX;
135         }
136
137         if (*destdir != '\0') {
138                 len = strlen(destdir);
139                 while (len > 1 && destdir[len - 1] == '/')
140                         destdir[--len] = '\0';
141                 get_srcdir();
142         } else {
143                 strlcpy(destdir, CDIR, sizeof(destdir));
144                 strlcat(destdir, PREFIX, sizeof(destdir));
145         }
146
147         p = path((char *)NULL);
148         if (stat(p, &buf)) {
149                 if (mkdir(p, 0777))
150                         err(2, "%s", p);
151         }
152         else if ((buf.st_mode & S_IFMT) != S_IFDIR)
153                 errx(2, "%s isn't a directory", p);
154
155         STAILQ_INIT(&dtab);
156         STAILQ_INIT(&fntab);
157         SLIST_INIT(&cputype);
158         STAILQ_INIT(&ftab);
159         if (yyparse())
160                 exit(3);
161         if (machinename == NULL) {
162                 printf("Specify machine type, e.g. ``machine i386''\n");
163                 exit(1);
164         }
165         /*
166          * make symbolic links in compilation directory
167          * for "sys" (to make genassym.c work along with #include <sys/xxx>)
168          * and similarly for "machine".
169          */
170         if (*srcdir == '\0')
171                 (void)snprintf(xxx, sizeof(xxx), "../../include");
172         else
173                 (void)snprintf(xxx, sizeof(xxx), "%s/%s/include",
174                     srcdir, machinename);
175         (void) unlink(path("machine"));
176         (void) symlink(xxx, path("machine"));
177         if (strcmp(machinename, machinearch) != 0) {
178                 /*
179                  * make symbolic links in compilation directory for
180                  * machinearch, if it is different than machinename.
181                  */
182                 if (*srcdir == '\0')
183                         (void)snprintf(xxx, sizeof(xxx), "../../../%s/include",
184                             machinearch);
185                 else
186                         (void)snprintf(xxx, sizeof(xxx), "%s/%s/include",
187                             srcdir, machinearch);
188                 (void) unlink(path(machinearch));
189                 (void) symlink(xxx, path(machinearch));
190         }
191         options();                      /* make options .h files */
192         makefile();                     /* build Makefile */
193         headers();                      /* make a lot of .h files */
194         configfile();                   /* put config file into kernel*/
195         cleanheaders(p);
196         printf("Kernel build directory is %s\n", p);
197         printf("Don't forget to do ``make cleandepend; make depend''\n");
198         exit(0);
199 }
200
201 /*
202  * get_srcdir
203  *      determine the root of the kernel source tree
204  *      and save that in srcdir.
205  */
206 static void
207 get_srcdir(void)
208 {
209         struct stat lg, phy;
210         char *p, *pwd;
211         int i;
212
213         if (realpath("../..", srcdir) == NULL)
214                 errx(2, "Unable to find root of source tree");
215         if ((pwd = getenv("PWD")) != NULL && *pwd == '/' &&
216             (pwd = strdup(pwd)) != NULL) {
217                 /* Remove the last two path components. */
218                 for (i = 0; i < 2; i++) {
219                         if ((p = strrchr(pwd, '/')) == NULL) {
220                                 free(pwd);
221                                 return;
222                         }
223                         *p = '\0';
224                 }
225                 if (stat(pwd, &lg) != -1 && stat(srcdir, &phy) != -1 &&
226                     lg.st_dev == phy.st_dev && lg.st_ino == phy.st_ino)
227                         strlcpy(srcdir, pwd, MAXPATHLEN);
228                 free(pwd);
229         }
230 }
231
232 static void
233 usage(void)
234 {
235
236         fprintf(stderr, "usage: config [-Vgp] [-d destdir] sysname\n");
237         exit(1);
238 }
239
240 /*
241  * get_word
242  *      returns EOF on end of file
243  *      NULL on end of line
244  *      pointer to the word otherwise
245  */
246 char *
247 get_word(FILE *fp)
248 {
249         static char line[80];
250         int ch;
251         char *cp;
252         int escaped_nl = 0;
253
254 begin:
255         while ((ch = getc(fp)) != EOF)
256                 if (ch != ' ' && ch != '\t')
257                         break;
258         if (ch == EOF)
259                 return ((char *)EOF);
260         if (ch == '\\'){
261                 escaped_nl = 1;
262                 goto begin;
263         }
264         if (ch == '\n') {
265                 if (escaped_nl){
266                         escaped_nl = 0;
267                         goto begin;
268                 }
269                 else
270                         return (NULL);
271         }
272         cp = line;
273         *cp++ = ch;
274         while ((ch = getc(fp)) != EOF) {
275                 if (isspace(ch))
276                         break;
277                 *cp++ = ch;
278         }
279         *cp = 0;
280         if (ch == EOF)
281                 return ((char *)EOF);
282         (void) ungetc(ch, fp);
283         return (line);
284 }
285
286 /*
287  * get_quoted_word
288  *      like get_word but will accept something in double or single quotes
289  *      (to allow embedded spaces).
290  */
291 char *
292 get_quoted_word(FILE *fp)
293 {
294         static char line[256];
295         int ch;
296         char *cp;
297         int escaped_nl = 0;
298
299 begin:
300         while ((ch = getc(fp)) != EOF)
301                 if (ch != ' ' && ch != '\t')
302                         break;
303         if (ch == EOF)
304                 return ((char *)EOF);
305         if (ch == '\\'){
306                 escaped_nl = 1;
307                 goto begin;
308         }
309         if (ch == '\n') {
310                 if (escaped_nl){
311                         escaped_nl = 0;
312                         goto begin;
313                 }
314                 else
315                         return (NULL);
316         }
317         cp = line;
318         if (ch == '"' || ch == '\'') {
319                 int quote = ch;
320
321                 while ((ch = getc(fp)) != EOF) {
322                         if (ch == quote)
323                                 break;
324                         if (ch == '\n') {
325                                 *cp = 0;
326                                 printf("config: missing quote reading `%s'\n",
327                                         line);
328                                 exit(2);
329                         }
330                         *cp++ = ch;
331                 }
332         } else {
333                 *cp++ = ch;
334                 while ((ch = getc(fp)) != EOF) {
335                         if (isspace(ch))
336                                 break;
337                         *cp++ = ch;
338                 }
339                 if (ch != EOF)
340                         (void) ungetc(ch, fp);
341         }
342         *cp = 0;
343         if (ch == EOF)
344                 return ((char *)EOF);
345         return (line);
346 }
347
348 /*
349  * prepend the path to a filename
350  */
351 char *
352 path(const char *file)
353 {
354         char *cp = NULL;
355
356         if (file)
357                 asprintf(&cp, "%s/%s", destdir, file);
358         else
359                 cp = strdup(destdir);
360         return (cp);
361 }
362
363 static void
364 configfile(void)
365 {
366         FILE *fi, *fo;
367         char *p;
368         int i;
369         
370         fi = fopen(PREFIX, "r");
371         if (!fi)
372                 err(2, "%s", PREFIX);
373         fo = fopen(p=path("config.c.new"), "w");
374         if (!fo)
375                 err(2, "%s", p);
376         fprintf(fo, "#include \"opt_config.h\"\n");
377         fprintf(fo, "#ifdef INCLUDE_CONFIG_FILE \n");
378         fprintf(fo, "const char config[] = \"\\\n");
379         fprintf(fo, "START CONFIG FILE %s\\n\\\n___", PREFIX);
380         while (EOF != (i=getc(fi))) {
381                 if (i == '\n') {
382                         fprintf(fo, "\\n\\\n___");
383                 } else if (i == '\"') {
384                         fprintf(fo, "\\\"");
385                 } else if (i == '\\') {
386                         fprintf(fo, "\\\\");
387                 } else {
388                         putc(i, fo);
389                 }
390         }
391         fprintf(fo, "\\n\\\nEND CONFIG FILE %s\\n\\\n", PREFIX);
392         fprintf(fo, "\";\n");
393         fprintf(fo, "\n#endif /* INCLUDE_CONFIG_FILE */\n");
394         fclose(fi);
395         fclose(fo);
396         moveifchanged(path("config.c.new"), path("config.c"));
397 }
398
399 /*
400  * moveifchanged --
401  *      compare two files; rename if changed.
402  */
403 void
404 moveifchanged(const char *from_name, const char *to_name)
405 {
406         char *p, *q;
407         int changed;
408         size_t tsize;
409         struct stat from_sb, to_sb;
410         int from_fd, to_fd;
411
412         changed = 0;
413
414         if ((from_fd = open(from_name, O_RDONLY)) < 0)
415                 err(EX_OSERR, "moveifchanged open(%s)", from_name);
416
417         if ((to_fd = open(to_name, O_RDONLY)) < 0)
418                 changed++;
419
420         if (!changed && fstat(from_fd, &from_sb) < 0)
421                 err(EX_OSERR, "moveifchanged fstat(%s)", from_name);
422
423         if (!changed && fstat(to_fd, &to_sb) < 0)
424                 err(EX_OSERR, "moveifchanged fstat(%s)", to_name);
425
426         if (!changed && from_sb.st_size != to_sb.st_size)
427                 changed++;
428
429         tsize = (size_t)from_sb.st_size;
430
431         if (!changed) {
432                 p = mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, (off_t)0);
433 #ifndef MAP_FAILED
434 #define MAP_FAILED ((caddr_t) -1)
435 #endif
436                 if (p == MAP_FAILED)
437                         err(EX_OSERR, "mmap %s", from_name);
438                 q = mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, (off_t)0);
439                 if (q == MAP_FAILED)
440                         err(EX_OSERR, "mmap %s", to_name);
441
442                 changed = memcmp(p, q, tsize);
443                 munmap(p, tsize);
444                 munmap(q, tsize);
445         }
446         if (changed) {
447                 if (rename(from_name, to_name) < 0)
448                         err(EX_OSERR, "rename(%s, %s)", from_name, to_name);
449         } else {
450                 if (unlink(from_name) < 0)
451                         err(EX_OSERR, "unlink(%s)", from_name);
452         }
453 }
454
455 static void
456 cleanheaders(char *p)
457 {
458         DIR *dirp;
459         struct dirent *dp;
460         struct file_list *fl;
461         struct hdr_list *hl;
462         int i;
463
464         remember("y.tab.h");
465         remember("setdefs.h");
466         STAILQ_FOREACH(fl, &ftab, f_next)
467                 remember(fl->f_fn);
468
469         /*
470          * Scan the build directory and clean out stuff that looks like
471          * it might have been a leftover NFOO header, etc.
472          */
473         if ((dirp = opendir(p)) == NULL)
474                 err(EX_OSERR, "opendir %s", p);
475         while ((dp = readdir(dirp)) != NULL) {
476                 i = dp->d_namlen - 2;
477                 /* Skip non-headers */
478                 if (dp->d_name[i] != '.' || dp->d_name[i + 1] != 'h')
479                         continue;
480                 /* Skip special stuff, eg: bus_if.h, but check opt_*.h */
481                 if (index(dp->d_name, '_') &&
482                     strncmp(dp->d_name, "opt_", 4) != 0)
483                         continue;
484                 /* Check if it is a target file */
485                 for (hl = htab; hl != NULL; hl = hl->h_next) {
486                         if (strcmp(dp->d_name, hl->h_name) == 0) {
487                                 break;
488                         }
489                 }
490                 if (hl)
491                         continue;
492                 printf("Removing stale header: %s\n", dp->d_name);
493                 if (unlink(path(dp->d_name)) == -1)
494                         warn("unlink %s", dp->d_name);
495         }
496         (void)closedir(dirp);
497 }
498
499 void
500 remember(const char *file)
501 {
502         char *s;
503         struct hdr_list *hl;
504
505         if ((s = strrchr(file, '/')) != NULL)
506                 s = ns(s + 1);
507         else
508                 s = ns(file);
509
510         if (index(s, '_') && strncmp(s, "opt_", 4) != 0) {
511                 free(s);
512                 return;
513         }
514         for (hl = htab; hl != NULL; hl = hl->h_next) {
515                 if (strcmp(s, hl->h_name) == 0) {
516                         free(s);
517                         return;
518                 }
519         }
520         hl = malloc(sizeof(*hl));
521         bzero(hl, sizeof(*hl));
522         hl->h_name = s;
523         hl->h_next = htab;
524         htab = hl;
525 }