1 /* $Cambridge: exim/src/src/buildconfig.c,v 1.9 2005/06/17 13:52:15 ph10 Exp $ */
3 /*************************************************
4 * Exim - an Internet mail transport agent *
5 *************************************************/
7 /* Copyright (c) University of Cambridge 1995 - 2005 */
8 /* See the file NOTICE for conditions of use and distribution. */
11 /*************************************************
12 * Build configuration header for Exim *
13 *************************************************/
15 /* This auxiliary program builds the file config.h by the following
18 First, it determines the size of off_t and time_t variables, and generates
19 macro code to define OFF_T_FMT and TIME_T_FMT as suitable formats, if they are
20 not already defined in the system-specific header file.
22 Then it reads Makefile, looking for certain OS-specific definitions which it
23 uses to define some specific macros. Finally, it reads the defaults file
26 The defaults file contains normal C #define statements for various macros; if
27 the name of a macro is found in the environment, the environment value replaces
28 the default. If the default #define does not contain any value, then that macro
29 is not copied to the created file unless there is some value in the
32 This program is compiled and run as part of the Make process and is not
33 normally called independently. */
40 #include <sys/types.h>
54 static char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB" };
56 static int have_ipv6 = 0;
57 static int have_iconv = 0;
59 static char errno_quota[256];
60 static char ostype[256];
63 /* If any entry is an initial substring of another, the longer one must
66 static have_item have_list[] = {
67 { "HAVE_IPV6", &have_ipv6 },
68 { "HAVE_ICONV", &have_iconv },
72 static save_item save_list[] = {
73 { "ERRNO_QUOTA", errno_quota },
80 /* Subroutine to check a string for precisely one instance of "%s". If not,
84 check_percent_ess(char *value, char *name)
87 char *p = strstr(value, "%s");
88 if (p != NULL) OK = strstr(p+2, "%s") == NULL;
91 printf("\n*** \"%s\" (%s) must contain precisely one occurrence of\n"
92 "*** \"%%s\". Please review your build-time configuration.\n\n/", value,
102 main(int argc, char **argv)
104 off_t test_off_t = 0;
105 time_t test_time_t = 0;
108 int last_initial = 'A';
111 int in_local_makefile = 0;
112 int use_which_db = 0;
113 int use_which_db_in_local_makefile = 0;
114 int support_crypteq = 0;
119 printf("*** Buildconfig: called with incorrect arguments\n");
123 new = fopen("config.h", "wb");
126 printf("*** Buildconfig: failed to open config.h for output\n");
130 printf("Building configuration file config.h\n");
132 fprintf(new, "/*************************************************\n");
133 fprintf(new, "* Configuration header for Exim *\n");
134 fprintf(new, "*************************************************/\n\n");
136 fprintf(new, "/* This file was automatically generated from Makefile and "
137 "config.h.defaults,\n");
138 fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
139 fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
140 "rerun make. */\n\n");
142 /* First, deal with the printing format for off_t variables. We assume that if
143 the size of off_t is greater than 4, "%lld" will be available as a format for
144 printing long long variables, and there will be support for the long long type.
145 This assumption is known to be OK for the common operating systems. */
147 fprintf(new, "#ifndef OFF_T_FMT\n");
148 if (sizeof(test_off_t) > 4)
150 fprintf(new, "#define OFF_T_FMT \"%%lld\"\n");
151 fprintf(new, "#define LONGLONG_T long long int\n");
155 fprintf(new, "#define OFF_T_FMT \"%%ld\"\n");
156 fprintf(new, "#define LONGLONG_T long int\n");
158 fprintf(new, "#endif\n\n");
160 /* Now do the same thing for time_t variables. If the length is greater than
161 4, we want to assume long long support (even if off_t was less than 4). If the
162 length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
165 fprintf(new, "#ifndef TIME_T_FMT\n");
166 if (sizeof(test_time_t) > 4)
168 fprintf(new, "#define TIME_T_FMT \"%%lld\"\n");
169 fprintf(new, "#undef LONGLONG_T\n");
170 fprintf(new, "#define LONGLONG_T long long int\n");
174 fprintf(new, "#define TIME_T_FMT \"%%ld\"\n");
176 fprintf(new, "#endif\n\n");
178 /* Now search the makefile for certain settings */
180 base = fopen("Makefile", "rb");
183 printf("*** Buildconfig: failed to open Makefile\n");
188 errno_quota[0] = 0; /* no over-riding value set */
189 ostype[0] = 0; /* just in case */
192 while (fgets(buffer, sizeof(buffer), base) != NULL)
197 char *p = buffer + (int)strlen(buffer);
199 while (p > buffer && isspace((unsigned char)p[-1])) p--;
202 while (isspace((unsigned char)*p)) p++;
204 /* Notice when we hit the user's makefile */
206 if (strcmp(p, "# From Local/Makefile") == 0)
208 in_local_makefile = 1;
212 /* Remember the last DB option setting. If we hit two in the user's
213 Makefile, complain. */
215 for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
217 int len = (int)strlen(db_opts[i]);
218 if (strncmp(p, db_opts[i], len) == 0 && (p[len] == ' ' || p[len] == '='))
220 if (in_local_makefile)
222 if (use_which_db_in_local_makefile)
224 printf("*** Only one of USE_DB, USE_GDBM, or USE_TDB should be "
225 "defined in Local/Makefile\n");
228 use_which_db_in_local_makefile = 1;
234 if (i < sizeof(db_opts)/sizeof(char *)) continue;
236 /* Items where we just save a boolean */
238 for (h = have_list; h->name != NULL; h++)
240 int len = (int)strlen(h->name);
241 if (strncmp(p, h->name, len) == 0)
244 while (isspace((unsigned char)*p)) p++;
247 printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
250 while (isspace((unsigned char)*p)) p++;
251 if (strcmp(p, "YES") == 0 || strcmp(p, "yes") == 0) *(h->flag) = 1;
252 else *(h->flag) = 0; /* Must reset in case multiple instances */
257 if (h->name != NULL) continue;
259 /* Items where we save the complete string */
261 for (s = save_list; s->name != NULL; s++)
263 int len = (int)strlen(s->name);
264 if (strncmp(p, s->name, len) == 0)
267 while (isspace((unsigned char)*p)) p++;
270 printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
273 while (isspace((unsigned char)*p)) p++;
279 fprintf(new, "#define HAVE_IPV6 %s\n",
280 have_ipv6? "TRUE" : "FALSE");
282 fprintf(new, "#define HAVE_ICONV %s\n",
283 have_iconv? "TRUE" : "FALSE");
285 if (errno_quota[0] != 0)
286 fprintf(new, "\n#define ERRNO_QUOTA %s\n", errno_quota);
288 if (strcmp(cc, "gcc") == 0 && strstr(ostype, "IRIX") != NULL)
290 fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
291 fprintf(new, "\n/* bug when using gcc on an IRIX system. */");
292 fprintf(new, "\n#define USE_INET_NTOA_FIX");
299 /* Now handle the macros listed in the defaults */
301 base = fopen("../src/config.h.defaults", "rb");
304 printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
309 while (fgets(buffer, sizeof(buffer), base) != NULL)
317 while (*p == ' ' || *p == '\t') p++;
319 if (strncmp(p, "#define ", 8) != 0) continue;
322 while (*p == ' ' || *p == '\t') p++;
324 if (*p < last_initial) fprintf(new, "\n");
327 while (*p && (isalnum((unsigned char)*p) || *p == '_')) *q++ = *p++;
330 /* USE_DB, USE_GDBM, and USE_TDB are special cases. We want to have only
331 one of them set. The scan of the Makefile has saved which was the last one
334 for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
336 if (strcmp(name, db_opts[i]) == 0)
338 if (use_which_db == i)
339 fprintf(new, "#define %s %.*syes\n", db_opts[i],
340 21 - (int)strlen(db_opts[i]), " ");
342 fprintf(new, "/* %s not set */\n", name);
346 if (i < sizeof(db_opts)/sizeof(char *)) continue;
348 /* EXIM_USER is a special case. We look in the environment for EXIM_USER or
349 EXIM_UID (the latter for backward compatibility with Exim 3). If the value is
350 not numeric, we look up the user, and default the GID if found. Otherwise,
351 EXIM_GROUP or EXIM_GID must be in the environment. */
353 if (strcmp(name, "EXIM_UID") == 0)
358 char *username = NULL;
359 char *groupname = NULL;
361 char *user = getenv("EXIM_USER");
362 char *group = getenv("EXIM_GROUP");
364 if (user == NULL) user = getenv("EXIM_UID");
365 if (group == NULL) group = getenv("EXIM_GID");
369 printf("\n*** EXIM_USER has not been defined in any of the Makefiles in "
370 "the\n \"Local\" directory. Please review your build-time "
371 "configuration.\n\n");
375 while (isspace((unsigned char)(*user))) user++;
378 printf("\n*** EXIM_USER is defined as an empty string in one of the "
379 "files\n in the \"Local\" directory. Please review your build-time"
380 "\n configuration.\n\n");
384 for (s = user; *s != 0; s++)
386 if (iscntrl((unsigned char)(*s)))
388 printf("\n*** EXIM_USER contains the control character 0x%02X in one "
389 "of the files\n in the \"Local\" directory. Please review your "
390 "build-time\n configuration.\n\n", *s);
395 /* Numeric uid given */
397 if (user[strspn(user, "0123456789")] == 0)
399 uid = (uid_t)atoi(user);
402 /* User name given. Normally, we look up the uid right away. However,
403 people building binary distributions sometimes want to retain the name till
404 runtime. This is supported if the name begins "ref:". */
406 else if (strncmp(user, "ref:", 4) == 0)
409 while (isspace(*user)) user++;
416 struct passwd *pw = getpwnam(user);
419 printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
420 "exist.\n Please review your build-time configuration.\n\n",
430 /* Use explicit group if set. */
434 while (isspace((unsigned char)(*group))) group++;
437 printf("\n*** EXIM_GROUP is defined as an empty string in one of "
438 "the files in the\n \"Local\" directory. ");
441 printf("If you want the Exim group to be taken from the\n "
442 "password data for the Exim user, just remove the EXIM_GROUP "
443 "setting.\n Otherwise, p");
445 else printf("EXIM_USER is defined numerically, so there is no"
446 "\n default for EXIM_GROUP and you must set it explicitly.\n P");
447 printf("lease review your build-time configuration.\n\n");
451 for (s = group; *s != 0; s++)
453 if (iscntrl((unsigned char)(*s)))
455 printf("\n*** EXIM_GROUP contains the control character 0x%02X in one "
456 "of the files\n in the \"Local\" directory. Please review your "
457 "build-time\n configuration.\n\n", *s);
462 /* Group name given. This may be by reference or to be looked up now,
465 if (strncmp(group, "ref:", 4) == 0)
468 while (isspace(*group)) group++;
472 else if (username != NULL)
477 else if (group[strspn(group, "0123456789")] == 0)
479 gid = (gid_t)atoi(group);
484 struct group *gr = getgrnam(group);
487 printf("\n*** Group \"%s\" (specified in one of the Makefiles) does "
488 "not exist.\n Please review your build-time configuration.\n\n",
496 /* Else trouble unless found in passwd file with user */
500 printf("\n*** No group set for Exim. Please review your build-time "
501 "configuration.\n\n");
505 /* Output user and group names or uid/gid. When names are set, uid/gid
506 are set to zero but will be replaced at runtime. */
508 if (username != NULL)
509 fprintf(new, "#define EXIM_USERNAME \"%s\"\n", username);
510 if (groupname != NULL)
511 fprintf(new, "#define EXIM_GROUPNAME \"%s\"\n", groupname);
513 fprintf(new, "#define EXIM_UID %d\n", (int)uid);
514 fprintf(new, "#define EXIM_GID %d\n", (int)gid);
518 /* CONFIGURE_OWNER and CONFIGURE_GROUP are special cases. We look in the
519 environment for first. If the value is not numeric, we look up the user or
520 group. A lot of this code is similar to that for EXIM_USER, but it's easier
521 to keep it separate. */
523 if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
524 strcmp(name, "CONFIGURE_GROUP") == 0)
526 int isgroup = name[10] == 'G';
530 char *username = NULL;
531 char *user = getenv(name);
533 if (user == NULL) user = "";
534 while (isspace((unsigned char)(*user))) user++;
537 fprintf(new, "/* %s not set */\n", name);
541 for (s = user; *s != 0; s++)
543 if (iscntrl((unsigned char)(*s)))
545 printf("\n*** %s contains the control character 0x%02X in "
546 "one of the files\n in the \"Local\" directory. Please review "
547 "your build-time\n configuration.\n\n", name, *s);
552 /* Numeric uid given */
554 if (user[strspn(user, "0123456789")] == 0)
557 gid = (gid_t)atoi(user);
559 uid = (uid_t)atoi(user);
562 /* Name given. Normally, we look up the uid or gid right away. However,
563 people building binary distributions sometimes want to retain the name till
564 runtime. This is supported if the name begins "ref:". */
566 else if (strncmp(user, "ref:", 4) == 0)
569 while (isspace(*user)) user++;
575 struct group *gr = getgrnam(user);
578 printf("\n*** Group \"%s\" (specified in one of the Makefiles) does not "
579 "exist.\n Please review your build-time configuration.\n\n",
588 struct passwd *pw = getpwnam(user);
591 printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
592 "exist.\n Please review your build-time configuration.\n\n",
599 /* Output user and group names or uid/gid. When names are set, uid/gid
600 are set to zero but will be replaced at runtime. */
602 if (username != NULL)
605 fprintf(new, "#define CONFIGURE_GROUPNAME \"%s\"\n", username);
607 fprintf(new, "#define CONFIGURE_OWNERNAME \"%s\"\n", username);
611 fprintf(new, "#define CONFIGURE_GROUP %d\n", (int)gid);
613 fprintf(new, "#define CONFIGURE_OWNER %d\n", (int)uid);
617 /* FIXED_NEVER_USERS is another special case. Look up the uid values and
618 create suitable initialization data for a vector. */
620 if (strcmp(name, "FIXED_NEVER_USERS") == 0)
622 char *list = getenv("FIXED_NEVER_USERS");
625 fprintf(new, "#define FIXED_NEVER_USERS 0\n");
633 while (*p != 0) if (*p++ == ':') count++;
635 vector = malloc((count+1) * sizeof(uid_t));
636 vector[0] = (uid_t)count;
638 for (i = 1, j = 0; i <= count; list++, i++)
643 while (*list != 0 && *list != ':') list++;
644 strncpy(name, p, list-p);
651 else if (name[strspn(name, "0123456789")] == 0)
653 vector[j++] = (uid_t)atoi(name);
657 struct passwd *pw = getpwnam(name);
660 printf("\n*** User \"%s\" (specified for FIXED_NEVER_USERS in one of the Makefiles) does not "
661 "exist.\n Please review your build-time configuration.\n\n",
665 vector[j++] = pw->pw_uid;
668 fprintf(new, "#define FIXED_NEVER_USERS %d", j);
669 for (i = 0; i < j; i++) fprintf(new, ", %d", (unsigned int)vector[i]);
675 /* WITH_CONTENT_SCAN is another special case: it must be set if either it or
676 WITH_OLD_DEMIME is set. */
678 if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
680 char *wcs = getenv("WITH_CONTENT_SCAN");
681 char *wod = getenv("WITH_OLD_DEMIME");
682 if (wcs != NULL || wod != NULL)
683 fprintf(new, "#define WITH_CONTENT_SCAN yes\n");
684 else fprintf(new, "/* WITH_CONTENT_SCAN not set */\n");
688 /* Otherwise, check whether a value exists in the environment. Remember if
689 it is an AUTH setting or SUPPORT_CRYPTEQ. */
691 if ((value = getenv(name)) != NULL)
694 len = 21 - (int)strlen(name);
696 if (strncmp(name, "AUTH_", 5) == 0) have_auth = 1;
697 if (strncmp(name, "SUPPORT_CRYPTEQ", 15) == 0) support_crypteq = 1;
699 /* The text value of LDAP_LIB_TYPE refers to a macro that gets set. */
701 if (strcmp(name, "LDAP_LIB_TYPE") == 0)
703 if (strcmp(value, "NETSCAPE") == 0 ||
704 strcmp(value, "UMICHIGAN") == 0 ||
705 strcmp(value, "OPENLDAP1") == 0 ||
706 strcmp(value, "OPENLDAP2") == 0 ||
707 strcmp(value, "SOLARIS") == 0 ||
708 strcmp(value, "SOLARIS7") == 0) /* Compatibility */
710 fprintf(new, "#define LDAP_LIB_%s\n", value);
714 printf("\n*** LDAP_LIB_TYPE=%s is not a recognized LDAP library type."
715 "\n*** Please review your build-time configuration.\n\n", value);
720 else if (strcmp(name, "RADIUS_LIB_TYPE") == 0)
722 if (strcmp(value, "RADIUSCLIENT") == 0 ||
723 strcmp(value, "RADIUSCLIENTNEW") == 0 ||
724 strcmp(value, "RADLIB") == 0)
726 fprintf(new, "#define RADIUS_LIB_%s\n", value);
730 printf("\n*** RADIUS_LIB_TYPE=%s is not a recognized RADIUS library type."
731 "\n*** Please review your build-time configuration.\n\n", value);
736 /* Other macros get set to the environment value. */
740 fprintf(new, "#define %s ", name);
741 while(len-- > 0) fputc(' ', new);
743 /* LOG_FILE_PATH is now messy because it can be a path containing %s or
744 it can be "syslog" or ":syslog" or "syslog:path" or even "path:syslog". */
746 if (strcmp(name, "LOG_FILE_PATH") == 0)
752 char *sss = strchr(ss, ':');
755 strncpy(buffer, ss, sss-ss);
756 buffer[sss-ss] = 0; /* For empty case */
758 else strcpy(buffer, ss);
759 pp = buffer + (int)strlen(buffer);
760 while (pp > buffer && isspace((unsigned char)pp[-1])) pp--;
762 if (buffer[0] != 0 && strcmp(buffer, "syslog") != 0)
763 check_percent_ess(buffer, name);
764 if (sss == NULL) break;
766 while (isspace((unsigned char)*ss)) ss++;
768 fprintf(new, "\"%s\"\n", value);
771 /* Timezone values and HEADERS_CHARSET get quoted */
773 else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
774 strcmp(name, "HEADERS_CHARSET") == 0)
775 fprintf(new, "\"%s\"\n", value);
777 /* For others, quote any paths and don't quote anything else */
781 if (value[0] == '/') fprintf(new, "\"%s\"\n", value);
782 else fprintf(new, "%s\n", value);
787 /* Value not defined in the environment; use the default */
792 while (*p == ' ' || *p == '\t') p++;
793 if (*p != '\n') fputs(buffer, new); else
796 if (strcmp(name, "BIN_DIRECTORY") == 0 ||
797 strcmp(name, "CONFIGURE_FILE") == 0)
799 printf("\n*** %s has not been defined in any of the Makefiles in the\n"
800 " \"Local\" directory. "
801 "Please review your build-time configuration.\n\n", name);
805 if (strcmp(name, "TIMEZONE_DEFAULT") == 0)
807 char *tz = getenv("TZ");
808 fprintf(new, "#define TIMEZONE_DEFAULT ");
809 if (tz == NULL) fprintf(new, "NULL\n"); else
810 fprintf(new, "\"%s\"\n", tz);
813 else fprintf(new, "/* %s not set */\n", name);
820 /* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
825 if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
826 "#define SUPPORT_CRYPTEQ\n");
831 fprintf(new, "\n/* End of config.h */\n");
836 /* End of buildconfig.c */