1 /* $Cambridge: exim/src/src/buildconfig.c,v 1.21 2010/06/13 08:26:40 pdp Exp $ */
3 /*************************************************
4 * Exim - an Internet mail transport agent *
5 *************************************************/
7 /* Copyright (c) University of Cambridge 1995 - 2009 */
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 const 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;
106 #if ! (__STDC_VERSION__ >= 199901L)
107 size_t test_size_t = 0;
108 unsigned long test_ulong_t = 0L;
110 long test_long_t = 0;
113 int last_initial = 'A';
116 int in_local_makefile = 0;
117 int use_which_db = 0;
118 int use_which_db_in_local_makefile = 0;
119 int support_crypteq = 0;
124 printf("*** Buildconfig: called with incorrect arguments\n");
128 new = fopen("config.h", "wb");
131 printf("*** Buildconfig: failed to open config.h for output\n");
135 printf("Building configuration file config.h\n");
137 fprintf(new, "/*************************************************\n");
138 fprintf(new, "* Configuration header for Exim *\n");
139 fprintf(new, "*************************************************/\n\n");
141 fprintf(new, "/* This file was automatically generated from Makefile and "
142 "config.h.defaults,\n");
143 fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
144 fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
145 "rerun make. */\n\n");
147 /* First, deal with the printing format for off_t variables. We assume that if
148 the size of off_t is greater than 4, "%lld" will be available as a format for
149 printing long long variables, and there will be support for the long long type.
150 This assumption is known to be OK for the common operating systems. */
152 fprintf(new, "#ifndef OFF_T_FMT\n");
153 if (sizeof(test_off_t) > sizeof(test_long_t))
155 fprintf(new, "#define OFF_T_FMT \"%%lld\"\n");
156 fprintf(new, "#define LONGLONG_T long long int\n");
160 fprintf(new, "#define OFF_T_FMT \"%%ld\"\n");
161 fprintf(new, "#define LONGLONG_T long int\n");
163 fprintf(new, "#endif\n\n");
165 /* Now do the same thing for time_t variables. If the length is greater than
166 4, we want to assume long long support (even if off_t was less than 4). If the
167 length is 4 or less, we can leave LONGLONG_T to whatever was defined above for
170 fprintf(new, "#ifndef TIME_T_FMT\n");
171 if (sizeof(test_time_t) > sizeof(test_long_t))
173 fprintf(new, "#define TIME_T_FMT \"%%lld\"\n");
174 fprintf(new, "#undef LONGLONG_T\n");
175 fprintf(new, "#define LONGLONG_T long long int\n");
179 fprintf(new, "#define TIME_T_FMT \"%%ld\"\n");
181 fprintf(new, "#endif\n\n");
183 /* And for sizeof() results, size_t, which should with C99 be just %zu, deal
184 with C99 not being ubiquitous yet. Unfortunately. */
186 #if __STDC_VERSION__ >= 199901L
187 fprintf(new, "#define SIZE_T_FMT \"%%zu\"\n");
189 if (sizeof(test_size_t) > sizeof (test_ulong_t))
190 fprintf(new, "#define SIZE_T_FMT \"%%llu\"\n");
192 fprintf(new, "#define SIZE_T_FMT \"%%lu\"\n");
195 /* Now search the makefile for certain settings */
197 base = fopen("Makefile", "rb");
200 printf("*** Buildconfig: failed to open Makefile\n");
205 errno_quota[0] = 0; /* no over-riding value set */
206 ostype[0] = 0; /* just in case */
209 while (fgets(buffer, sizeof(buffer), base) != NULL)
214 char *p = buffer + (int)strlen(buffer);
216 while (p > buffer && isspace((unsigned char)p[-1])) p--;
219 while (isspace((unsigned char)*p)) p++;
221 /* Notice when we hit the user's makefile */
223 if (strcmp(p, "# From Local/Makefile") == 0)
225 in_local_makefile = 1;
229 /* Remember the last DB option setting. If we hit two in the user's
230 Makefile, complain. */
232 for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
234 int len = (int)strlen(db_opts[i]);
235 if (strncmp(p, db_opts[i], len) == 0 && (p[len] == ' ' || p[len] == '='))
237 if (in_local_makefile)
239 if (use_which_db_in_local_makefile)
241 printf("*** Only one of USE_DB, USE_GDBM, or USE_TDB should be "
242 "defined in Local/Makefile\n");
245 use_which_db_in_local_makefile = 1;
251 if (i < sizeof(db_opts)/sizeof(char *)) continue;
253 /* Items where we just save a boolean */
255 for (h = have_list; h->name != NULL; h++)
257 int len = (int)strlen(h->name);
258 if (strncmp(p, h->name, len) == 0)
261 while (isspace((unsigned char)*p)) p++;
264 printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
267 while (isspace((unsigned char)*p)) p++;
268 if (strcmp(p, "YES") == 0 || strcmp(p, "yes") == 0) *(h->flag) = 1;
269 else *(h->flag) = 0; /* Must reset in case multiple instances */
274 if (h->name != NULL) continue;
276 /* Items where we save the complete string */
278 for (s = save_list; s->name != NULL; s++)
280 int len = (int)strlen(s->name);
281 if (strncmp(p, s->name, len) == 0)
284 while (isspace((unsigned char)*p)) p++;
287 printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
290 while (isspace((unsigned char)*p)) p++;
296 fprintf(new, "#define HAVE_IPV6 %s\n",
297 have_ipv6? "TRUE" : "FALSE");
299 fprintf(new, "#define HAVE_ICONV %s\n",
300 have_iconv? "TRUE" : "FALSE");
302 if (errno_quota[0] != 0)
303 fprintf(new, "\n#define ERRNO_QUOTA %s\n", errno_quota);
305 if (strcmp(cc, "gcc") == 0 &&
306 (strstr(ostype, "IRIX") != NULL || strstr(ostype, "AIX") != NULL))
308 fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
309 fprintf(new, "\n/* bug when using gcc on an IRIX or AIX system. */");
310 fprintf(new, "\n#define USE_INET_NTOA_FIX");
317 /* Now handle the macros listed in the defaults */
319 base = fopen("../src/config.h.defaults", "rb");
322 printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
327 while (fgets(buffer, sizeof(buffer), base) != NULL)
335 while (*p == ' ' || *p == '\t') p++;
337 if (strncmp(p, "#define ", 8) != 0) continue;
340 while (*p == ' ' || *p == '\t') p++;
342 if (*p < last_initial) fprintf(new, "\n");
345 while (*p && (isalnum((unsigned char)*p) || *p == '_')) *q++ = *p++;
348 /* USE_DB, USE_GDBM, and USE_TDB are special cases. We want to have only
349 one of them set. The scan of the Makefile has saved which was the last one
352 for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
354 if (strcmp(name, db_opts[i]) == 0)
356 if (use_which_db == i)
357 fprintf(new, "#define %s %.*syes\n", db_opts[i],
358 21 - (int)strlen(db_opts[i]), " ");
360 fprintf(new, "/* %s not set */\n", name);
364 if (i < sizeof(db_opts)/sizeof(char *)) continue;
366 /* EXIM_USER is a special case. We look in the environment for EXIM_USER or
367 EXIM_UID (the latter for backward compatibility with Exim 3). If the value is
368 not numeric, we look up the user, and default the GID if found. Otherwise,
369 EXIM_GROUP or EXIM_GID must be in the environment. */
371 if (strcmp(name, "EXIM_UID") == 0)
377 char *username = NULL;
378 char *groupname = NULL;
380 char *user = getenv("EXIM_USER");
381 char *group = getenv("EXIM_GROUP");
383 if (user == NULL) user = getenv("EXIM_UID");
384 if (group == NULL) group = getenv("EXIM_GID");
388 printf("\n*** EXIM_USER has not been defined in any of the Makefiles in "
389 "the\n \"Local\" directory. Please review your build-time "
390 "configuration.\n\n");
394 while (isspace((unsigned char)(*user))) user++;
397 printf("\n*** EXIM_USER is defined as an empty string in one of the "
398 "files\n in the \"Local\" directory. Please review your build-time"
399 "\n configuration.\n\n");
403 for (s = user; *s != 0; s++)
405 if (iscntrl((unsigned char)(*s)))
407 printf("\n*** EXIM_USER contains the control character 0x%02X in one "
408 "of the files\n in the \"Local\" directory. Please review your "
409 "build-time\n configuration.\n\n", *s);
414 /* Numeric uid given */
416 if (user[strspn(user, "0123456789")] == 0)
418 uid = (uid_t)atoi(user);
421 /* User name given. Normally, we look up the uid right away. However,
422 people building binary distributions sometimes want to retain the name till
423 runtime. This is supported if the name begins "ref:". */
425 else if (strncmp(user, "ref:", 4) == 0)
428 while (isspace(*user)) user++;
436 struct passwd *pw = getpwnam(user);
439 printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
440 "exist.\n Please review your build-time configuration.\n\n",
450 /* Use explicit group if set. */
454 while (isspace((unsigned char)(*group))) group++;
457 printf("\n*** EXIM_GROUP is defined as an empty string in one of "
458 "the files in the\n \"Local\" directory. ");
461 printf("If you want the Exim group to be taken from the\n "
462 "password data for the Exim user, just remove the EXIM_GROUP "
463 "setting.\n Otherwise, p");
465 else printf("EXIM_USER is defined numerically, so there is no"
466 "\n default for EXIM_GROUP and you must set it explicitly.\n P");
467 printf("lease review your build-time configuration.\n\n");
471 for (s = group; *s != 0; s++)
473 if (iscntrl((unsigned char)(*s)))
475 printf("\n*** EXIM_GROUP contains the control character 0x%02X in one "
476 "of the files\n in the \"Local\" directory. Please review your "
477 "build-time\n configuration.\n\n", *s);
482 /* Group name given. This may be by reference or to be looked up now,
485 if (strncmp(group, "ref:", 4) == 0)
488 while (isspace(*group)) group++;
492 else if (username != NULL)
497 else if (group[strspn(group, "0123456789")] == 0)
499 gid = (gid_t)atoi(group);
504 struct group *gr = getgrnam(group);
507 printf("\n*** Group \"%s\" (specified in one of the Makefiles) does "
508 "not exist.\n Please review your build-time configuration.\n\n",
516 /* Else trouble unless found in passwd file with user */
520 printf("\n*** No group set for Exim. Please review your build-time "
521 "configuration.\n\n");
525 /* security sanity checks
526 if ref: is being used, we can never be sure, but we can take reasonable
527 steps to filter out the most obvious ones. */
529 if ((!uid_not_set && uid == 0) ||
530 ((username != NULL) && (
531 (strcmp(username, "root") == 0) ||
532 (strcmp(username, "toor") == 0) )))
534 printf("\n*** Exim's internal user must not be root.\n\n");
538 /* Output user and group names or uid/gid. When names are set, uid/gid
539 are set to zero but will be replaced at runtime. */
541 if (username != NULL)
542 fprintf(new, "#define EXIM_USERNAME \"%s\"\n", username);
543 if (groupname != NULL)
544 fprintf(new, "#define EXIM_GROUPNAME \"%s\"\n", groupname);
546 fprintf(new, "#define EXIM_UID %d\n", (int)uid);
547 fprintf(new, "#define EXIM_GID %d\n", (int)gid);
551 /* CONFIGURE_OWNER and CONFIGURE_GROUP are special cases. We look in the
552 environment for first. If the value is not numeric, we look up the user or
553 group. A lot of this code is similar to that for EXIM_USER, but it's easier
554 to keep it separate. */
556 if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
557 strcmp(name, "CONFIGURE_GROUP") == 0)
559 int isgroup = name[10] == 'G';
563 const char *username = NULL;
564 const char *user = getenv(name);
566 if (user == NULL) user = "";
567 while (isspace((unsigned char)(*user))) user++;
570 fprintf(new, "/* %s not set */\n", name);
574 for (s = user; *s != 0; s++)
576 if (iscntrl((unsigned char)(*s)))
578 printf("\n*** %s contains the control character 0x%02X in "
579 "one of the files\n in the \"Local\" directory. Please review "
580 "your build-time\n configuration.\n\n", name, *s);
585 /* Numeric uid given */
587 if (user[strspn(user, "0123456789")] == 0)
590 gid = (gid_t)atoi(user);
592 uid = (uid_t)atoi(user);
595 /* Name given. Normally, we look up the uid or gid right away. However,
596 people building binary distributions sometimes want to retain the name till
597 runtime. This is supported if the name begins "ref:". */
599 else if (strncmp(user, "ref:", 4) == 0)
602 while (isspace(*user)) user++;
607 struct group *gr = getgrnam(user);
610 printf("\n*** Group \"%s\" (specified in one of the Makefiles) does not "
611 "exist.\n Please review your build-time configuration.\n\n",
620 struct passwd *pw = getpwnam(user);
623 printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
624 "exist.\n Please review your build-time configuration.\n\n",
631 /* Output user and group names or uid/gid. When names are set, uid/gid
632 are set to zero but will be replaced at runtime. */
634 if (username != NULL)
637 fprintf(new, "#define CONFIGURE_GROUPNAME \"%s\"\n", username);
639 fprintf(new, "#define CONFIGURE_OWNERNAME \"%s\"\n", username);
643 fprintf(new, "#define CONFIGURE_GROUP %d\n", (int)gid);
645 fprintf(new, "#define CONFIGURE_OWNER %d\n", (int)uid);
649 /* FIXED_NEVER_USERS is another special case. Look up the uid values and
650 create suitable initialization data for a vector. */
652 if (strcmp(name, "FIXED_NEVER_USERS") == 0)
654 char *list = getenv("FIXED_NEVER_USERS");
657 fprintf(new, "#define FIXED_NEVER_USERS 0\n");
665 while (*p != 0) if (*p++ == ':') count++;
667 vector = malloc((count+1) * sizeof(uid_t));
668 vector[0] = (uid_t)count;
670 for (i = 1, j = 0; i <= count; list++, i++)
675 while (*list != 0 && *list != ':') list++;
676 strncpy(name, p, list-p);
683 else if (name[strspn(name, "0123456789")] == 0)
685 vector[j++] = (uid_t)atoi(name);
689 struct passwd *pw = getpwnam(name);
692 printf("\n*** User \"%s\" (specified for FIXED_NEVER_USERS in one of the Makefiles) does not "
693 "exist.\n Please review your build-time configuration.\n\n",
697 vector[j++] = pw->pw_uid;
700 fprintf(new, "#define FIXED_NEVER_USERS %d", j);
701 for (i = 0; i < j; i++) fprintf(new, ", %d", (unsigned int)vector[i]);
707 /* WITH_CONTENT_SCAN is another special case: it must be set if either it or
708 WITH_OLD_DEMIME is set. */
710 if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
712 char *wcs = getenv("WITH_CONTENT_SCAN");
713 char *wod = getenv("WITH_OLD_DEMIME");
714 char *dcc = getenv("EXPERIMENTAL_DCC");
715 if (wcs != NULL || wod != NULL || dcc != NULL)
716 fprintf(new, "#define WITH_CONTENT_SCAN yes\n");
717 else fprintf(new, "/* WITH_CONTENT_SCAN not set */\n");
721 /* Otherwise, check whether a value exists in the environment. Remember if
722 it is an AUTH setting or SUPPORT_CRYPTEQ. */
724 if ((value = getenv(name)) != NULL)
727 len = 21 - (int)strlen(name);
729 if (strncmp(name, "AUTH_", 5) == 0) have_auth = 1;
730 if (strncmp(name, "SUPPORT_CRYPTEQ", 15) == 0) support_crypteq = 1;
732 /* The text value of LDAP_LIB_TYPE refers to a macro that gets set. */
734 if (strcmp(name, "LDAP_LIB_TYPE") == 0)
736 if (strcmp(value, "NETSCAPE") == 0 ||
737 strcmp(value, "UMICHIGAN") == 0 ||
738 strcmp(value, "OPENLDAP1") == 0 ||
739 strcmp(value, "OPENLDAP2") == 0 ||
740 strcmp(value, "SOLARIS") == 0 ||
741 strcmp(value, "SOLARIS7") == 0) /* Compatibility */
743 fprintf(new, "#define LDAP_LIB_%s\n", value);
747 printf("\n*** LDAP_LIB_TYPE=%s is not a recognized LDAP library type."
748 "\n*** Please review your build-time configuration.\n\n", value);
753 else if (strcmp(name, "RADIUS_LIB_TYPE") == 0)
755 if (strcmp(value, "RADIUSCLIENT") == 0 ||
756 strcmp(value, "RADIUSCLIENTNEW") == 0 ||
757 strcmp(value, "RADLIB") == 0)
759 fprintf(new, "#define RADIUS_LIB_%s\n", value);
763 printf("\n*** RADIUS_LIB_TYPE=%s is not a recognized RADIUS library type."
764 "\n*** Please review your build-time configuration.\n\n", value);
769 /* Other macros get set to the environment value. */
773 fprintf(new, "#define %s ", name);
774 while(len-- > 0) fputc(' ', new);
776 /* LOG_FILE_PATH is now messy because it can be a path containing %s or
777 it can be "syslog" or ":syslog" or "syslog:path" or even "path:syslog". */
779 if (strcmp(name, "LOG_FILE_PATH") == 0)
785 char *sss = strchr(ss, ':');
788 strncpy(buffer, ss, sss-ss);
789 buffer[sss-ss] = 0; /* For empty case */
791 else strcpy(buffer, ss);
792 pp = buffer + (int)strlen(buffer);
793 while (pp > buffer && isspace((unsigned char)pp[-1])) pp--;
795 if (buffer[0] != 0 && strcmp(buffer, "syslog") != 0)
796 check_percent_ess(buffer, name);
797 if (sss == NULL) break;
799 while (isspace((unsigned char)*ss)) ss++;
801 fprintf(new, "\"%s\"\n", value);
804 /* Timezone values HEADERS_CHARSET, TCP_WRAPPERS_DAEMON_NAME and
805 WHITELIST_D_MACROS get quoted */
807 else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
808 strcmp(name, "TCP_WRAPPERS_DAEMON_NAME") == 0||
809 strcmp(name, "HEADERS_CHARSET") == 0||
810 strcmp(name, "WHITELIST_D_MACROS") == 0)
811 fprintf(new, "\"%s\"\n", value);
813 /* For others, quote any paths and don't quote anything else */
817 if (value[0] == '/') fprintf(new, "\"%s\"\n", value);
818 else fprintf(new, "%s\n", value);
823 /* Value not defined in the environment; use the default */
828 while (*p == ' ' || *p == '\t') p++;
829 if (*p != '\n') fputs(buffer, new); else
832 if (strcmp(name, "BIN_DIRECTORY") == 0 ||
833 strcmp(name, "CONFIGURE_FILE") == 0)
835 printf("\n*** %s has not been defined in any of the Makefiles in the\n"
836 " \"Local\" directory. "
837 "Please review your build-time configuration.\n\n", name);
841 if (strcmp(name, "TIMEZONE_DEFAULT") == 0)
843 char *tz = getenv("TZ");
844 fprintf(new, "#define TIMEZONE_DEFAULT ");
845 if (tz == NULL) fprintf(new, "NULL\n"); else
846 fprintf(new, "\"%s\"\n", tz);
849 else fprintf(new, "/* %s not set */\n", name);
856 /* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
861 if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
862 "#define SUPPORT_CRYPTEQ\n");
867 fprintf(new, "\n/* End of config.h */\n");
872 /* End of buildconfig.c */