1 /* $Cambridge: exim/src/src/buildconfig.c,v 1.8 2005/06/16 14:10:13 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 variables, and generates macro code to
19 define OFF_T_FMT as a suitable format, if it is not already defined in the
20 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;
107 int last_initial = 'A';
110 int in_local_makefile = 0;
111 int use_which_db = 0;
112 int use_which_db_in_local_makefile = 0;
113 int support_crypteq = 0;
118 printf("*** Buildconfig: called with incorrect arguments\n");
122 new = fopen("config.h", "wb");
125 printf("*** Buildconfig: failed to open config.h for output\n");
129 printf("Building configuration file config.h\n");
131 fprintf(new, "/*************************************************\n");
132 fprintf(new, "* Configuration header for Exim *\n");
133 fprintf(new, "*************************************************/\n\n");
135 fprintf(new, "/* This file was automatically generated from Makefile and "
136 "config.h.defaults,\n");
137 fprintf(new, "using values specified in the configuration file Local/Makefile.\n");
138 fprintf(new, "Do not edit it. Instead, edit Local/Makefile and "
139 "rerun make. */\n\n");
141 /* First, deal with the printing format for off_t variables. We assume that if
142 the size of off_t is greater than 4, "%lld" will be available as a format for
143 printing long long variables, and there will be support for the long long type.
144 This assumption is known to be OK for the common operating systems. */
146 fprintf(new, "#ifndef OFF_T_FMT\n");
147 if (sizeof(test_off_t) > 4)
149 fprintf(new, "#define OFF_T_FMT \"%%lld\"\n");
150 fprintf(new, "#define ASSUME_LONG_LONG_SUPPORT\n");
154 fprintf(new, "#define OFF_T_FMT \"%%ld\"\n");
156 fprintf(new, "#endif\n\n");
158 /* Now search the makefile for certain settings */
160 base = fopen("Makefile", "rb");
163 printf("*** Buildconfig: failed to open Makefile\n");
168 errno_quota[0] = 0; /* no over-riding value set */
169 ostype[0] = 0; /* just in case */
172 while (fgets(buffer, sizeof(buffer), base) != NULL)
177 char *p = buffer + (int)strlen(buffer);
179 while (p > buffer && isspace((unsigned char)p[-1])) p--;
182 while (isspace((unsigned char)*p)) p++;
184 /* Notice when we hit the user's makefile */
186 if (strcmp(p, "# From Local/Makefile") == 0)
188 in_local_makefile = 1;
192 /* Remember the last DB option setting. If we hit two in the user's
193 Makefile, complain. */
195 for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
197 int len = (int)strlen(db_opts[i]);
198 if (strncmp(p, db_opts[i], len) == 0 && (p[len] == ' ' || p[len] == '='))
200 if (in_local_makefile)
202 if (use_which_db_in_local_makefile)
204 printf("*** Only one of USE_DB, USE_GDBM, or USE_TDB should be "
205 "defined in Local/Makefile\n");
208 use_which_db_in_local_makefile = 1;
214 if (i < sizeof(db_opts)/sizeof(char *)) continue;
216 /* Items where we just save a boolean */
218 for (h = have_list; h->name != NULL; h++)
220 int len = (int)strlen(h->name);
221 if (strncmp(p, h->name, len) == 0)
224 while (isspace((unsigned char)*p)) p++;
227 printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
230 while (isspace((unsigned char)*p)) p++;
231 if (strcmp(p, "YES") == 0 || strcmp(p, "yes") == 0) *(h->flag) = 1;
232 else *(h->flag) = 0; /* Must reset in case multiple instances */
237 if (h->name != NULL) continue;
239 /* Items where we save the complete string */
241 for (s = save_list; s->name != NULL; s++)
243 int len = (int)strlen(s->name);
244 if (strncmp(p, s->name, len) == 0)
247 while (isspace((unsigned char)*p)) p++;
250 printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount);
253 while (isspace((unsigned char)*p)) p++;
259 fprintf(new, "#define HAVE_IPV6 %s\n",
260 have_ipv6? "TRUE" : "FALSE");
262 fprintf(new, "#define HAVE_ICONV %s\n",
263 have_iconv? "TRUE" : "FALSE");
265 if (errno_quota[0] != 0)
266 fprintf(new, "\n#define ERRNO_QUOTA %s\n", errno_quota);
268 if (strcmp(cc, "gcc") == 0 && strstr(ostype, "IRIX") != NULL)
270 fprintf(new, "\n/* This switch includes the code to fix the inet_ntoa() */");
271 fprintf(new, "\n/* bug when using gcc on an IRIX system. */");
272 fprintf(new, "\n#define USE_INET_NTOA_FIX");
279 /* Now handle the macros listed in the defaults */
281 base = fopen("../src/config.h.defaults", "rb");
284 printf("*** Buildconfig: failed to open ../src/config.h.defaults\n");
289 while (fgets(buffer, sizeof(buffer), base) != NULL)
297 while (*p == ' ' || *p == '\t') p++;
299 if (strncmp(p, "#define ", 8) != 0) continue;
302 while (*p == ' ' || *p == '\t') p++;
304 if (*p < last_initial) fprintf(new, "\n");
307 while (*p && (isalnum((unsigned char)*p) || *p == '_')) *q++ = *p++;
310 /* USE_DB, USE_GDBM, and USE_TDB are special cases. We want to have only
311 one of them set. The scan of the Makefile has saved which was the last one
314 for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
316 if (strcmp(name, db_opts[i]) == 0)
318 if (use_which_db == i)
319 fprintf(new, "#define %s %.*syes\n", db_opts[i],
320 21 - (int)strlen(db_opts[i]), " ");
322 fprintf(new, "/* %s not set */\n", name);
326 if (i < sizeof(db_opts)/sizeof(char *)) continue;
328 /* EXIM_USER is a special case. We look in the environment for EXIM_USER or
329 EXIM_UID (the latter for backward compatibility with Exim 3). If the value is
330 not numeric, we look up the user, and default the GID if found. Otherwise,
331 EXIM_GROUP or EXIM_GID must be in the environment. */
333 if (strcmp(name, "EXIM_UID") == 0)
338 char *username = NULL;
339 char *groupname = NULL;
341 char *user = getenv("EXIM_USER");
342 char *group = getenv("EXIM_GROUP");
344 if (user == NULL) user = getenv("EXIM_UID");
345 if (group == NULL) group = getenv("EXIM_GID");
349 printf("\n*** EXIM_USER has not been defined in any of the Makefiles in "
350 "the\n \"Local\" directory. Please review your build-time "
351 "configuration.\n\n");
355 while (isspace((unsigned char)(*user))) user++;
358 printf("\n*** EXIM_USER is defined as an empty string in one of the "
359 "files\n in the \"Local\" directory. Please review your build-time"
360 "\n configuration.\n\n");
364 for (s = user; *s != 0; s++)
366 if (iscntrl((unsigned char)(*s)))
368 printf("\n*** EXIM_USER contains the control character 0x%02X in one "
369 "of the files\n in the \"Local\" directory. Please review your "
370 "build-time\n configuration.\n\n", *s);
375 /* Numeric uid given */
377 if (user[strspn(user, "0123456789")] == 0)
379 uid = (uid_t)atoi(user);
382 /* User name given. Normally, we look up the uid right away. However,
383 people building binary distributions sometimes want to retain the name till
384 runtime. This is supported if the name begins "ref:". */
386 else if (strncmp(user, "ref:", 4) == 0)
389 while (isspace(*user)) user++;
396 struct passwd *pw = getpwnam(user);
399 printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
400 "exist.\n Please review your build-time configuration.\n\n",
410 /* Use explicit group if set. */
414 while (isspace((unsigned char)(*group))) group++;
417 printf("\n*** EXIM_GROUP is defined as an empty string in one of "
418 "the files in the\n \"Local\" directory. ");
421 printf("If you want the Exim group to be taken from the\n "
422 "password data for the Exim user, just remove the EXIM_GROUP "
423 "setting.\n Otherwise, p");
425 else printf("EXIM_USER is defined numerically, so there is no"
426 "\n default for EXIM_GROUP and you must set it explicitly.\n P");
427 printf("lease review your build-time configuration.\n\n");
431 for (s = group; *s != 0; s++)
433 if (iscntrl((unsigned char)(*s)))
435 printf("\n*** EXIM_GROUP contains the control character 0x%02X in one "
436 "of the files\n in the \"Local\" directory. Please review your "
437 "build-time\n configuration.\n\n", *s);
442 /* Group name given. This may be by reference or to be looked up now,
445 if (strncmp(group, "ref:", 4) == 0)
448 while (isspace(*group)) group++;
452 else if (username != NULL)
457 else if (group[strspn(group, "0123456789")] == 0)
459 gid = (gid_t)atoi(group);
464 struct group *gr = getgrnam(group);
467 printf("\n*** Group \"%s\" (specified in one of the Makefiles) does "
468 "not exist.\n Please review your build-time configuration.\n\n",
476 /* Else trouble unless found in passwd file with user */
480 printf("\n*** No group set for Exim. Please review your build-time "
481 "configuration.\n\n");
485 /* Output user and group names or uid/gid. When names are set, uid/gid
486 are set to zero but will be replaced at runtime. */
488 if (username != NULL)
489 fprintf(new, "#define EXIM_USERNAME \"%s\"\n", username);
490 if (groupname != NULL)
491 fprintf(new, "#define EXIM_GROUPNAME \"%s\"\n", groupname);
493 fprintf(new, "#define EXIM_UID %d\n", (int)uid);
494 fprintf(new, "#define EXIM_GID %d\n", (int)gid);
498 /* CONFIGURE_OWNER and CONFIGURE_GROUP are special cases. We look in the
499 environment for first. If the value is not numeric, we look up the user or
500 group. A lot of this code is similar to that for EXIM_USER, but it's easier
501 to keep it separate. */
503 if (strcmp(name, "CONFIGURE_OWNER") == 0 ||
504 strcmp(name, "CONFIGURE_GROUP") == 0)
506 int isgroup = name[10] == 'G';
510 char *username = NULL;
511 char *user = getenv(name);
513 if (user == NULL) user = "";
514 while (isspace((unsigned char)(*user))) user++;
517 fprintf(new, "/* %s not set */\n", name);
521 for (s = user; *s != 0; s++)
523 if (iscntrl((unsigned char)(*s)))
525 printf("\n*** %s contains the control character 0x%02X in "
526 "one of the files\n in the \"Local\" directory. Please review "
527 "your build-time\n configuration.\n\n", name, *s);
532 /* Numeric uid given */
534 if (user[strspn(user, "0123456789")] == 0)
537 gid = (gid_t)atoi(user);
539 uid = (uid_t)atoi(user);
542 /* Name given. Normally, we look up the uid or gid right away. However,
543 people building binary distributions sometimes want to retain the name till
544 runtime. This is supported if the name begins "ref:". */
546 else if (strncmp(user, "ref:", 4) == 0)
549 while (isspace(*user)) user++;
555 struct group *gr = getgrnam(user);
558 printf("\n*** Group \"%s\" (specified in one of the Makefiles) does not "
559 "exist.\n Please review your build-time configuration.\n\n",
568 struct passwd *pw = getpwnam(user);
571 printf("\n*** User \"%s\" (specified in one of the Makefiles) does not "
572 "exist.\n Please review your build-time configuration.\n\n",
579 /* Output user and group names or uid/gid. When names are set, uid/gid
580 are set to zero but will be replaced at runtime. */
582 if (username != NULL)
585 fprintf(new, "#define CONFIGURE_GROUPNAME \"%s\"\n", username);
587 fprintf(new, "#define CONFIGURE_OWNERNAME \"%s\"\n", username);
591 fprintf(new, "#define CONFIGURE_GROUP %d\n", (int)gid);
593 fprintf(new, "#define CONFIGURE_OWNER %d\n", (int)uid);
597 /* FIXED_NEVER_USERS is another special case. Look up the uid values and
598 create suitable initialization data for a vector. */
600 if (strcmp(name, "FIXED_NEVER_USERS") == 0)
602 char *list = getenv("FIXED_NEVER_USERS");
605 fprintf(new, "#define FIXED_NEVER_USERS 0\n");
613 while (*p != 0) if (*p++ == ':') count++;
615 vector = malloc((count+1) * sizeof(uid_t));
616 vector[0] = (uid_t)count;
618 for (i = 1, j = 0; i <= count; list++, i++)
623 while (*list != 0 && *list != ':') list++;
624 strncpy(name, p, list-p);
631 else if (name[strspn(name, "0123456789")] == 0)
633 vector[j++] = (uid_t)atoi(name);
637 struct passwd *pw = getpwnam(name);
640 printf("\n*** User \"%s\" (specified for FIXED_NEVER_USERS in one of the Makefiles) does not "
641 "exist.\n Please review your build-time configuration.\n\n",
645 vector[j++] = pw->pw_uid;
648 fprintf(new, "#define FIXED_NEVER_USERS %d", j);
649 for (i = 0; i < j; i++) fprintf(new, ", %d", (unsigned int)vector[i]);
655 /* WITH_CONTENT_SCAN is another special case: it must be set if either it or
656 WITH_OLD_DEMIME is set. */
658 if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
660 char *wcs = getenv("WITH_CONTENT_SCAN");
661 char *wod = getenv("WITH_OLD_DEMIME");
662 if (wcs != NULL || wod != NULL)
663 fprintf(new, "#define WITH_CONTENT_SCAN yes\n");
664 else fprintf(new, "/* WITH_CONTENT_SCAN not set */\n");
668 /* Otherwise, check whether a value exists in the environment. Remember if
669 it is an AUTH setting or SUPPORT_CRYPTEQ. */
671 if ((value = getenv(name)) != NULL)
674 len = 21 - (int)strlen(name);
676 if (strncmp(name, "AUTH_", 5) == 0) have_auth = 1;
677 if (strncmp(name, "SUPPORT_CRYPTEQ", 15) == 0) support_crypteq = 1;
679 /* The text value of LDAP_LIB_TYPE refers to a macro that gets set. */
681 if (strcmp(name, "LDAP_LIB_TYPE") == 0)
683 if (strcmp(value, "NETSCAPE") == 0 ||
684 strcmp(value, "UMICHIGAN") == 0 ||
685 strcmp(value, "OPENLDAP1") == 0 ||
686 strcmp(value, "OPENLDAP2") == 0 ||
687 strcmp(value, "SOLARIS") == 0 ||
688 strcmp(value, "SOLARIS7") == 0) /* Compatibility */
690 fprintf(new, "#define LDAP_LIB_%s\n", value);
694 printf("\n*** LDAP_LIB_TYPE=%s is not a recognized LDAP library type."
695 "\n*** Please review your build-time configuration.\n\n", value);
700 else if (strcmp(name, "RADIUS_LIB_TYPE") == 0)
702 if (strcmp(value, "RADIUSCLIENT") == 0 ||
703 strcmp(value, "RADIUSCLIENTNEW") == 0 ||
704 strcmp(value, "RADLIB") == 0)
706 fprintf(new, "#define RADIUS_LIB_%s\n", value);
710 printf("\n*** RADIUS_LIB_TYPE=%s is not a recognized RADIUS library type."
711 "\n*** Please review your build-time configuration.\n\n", value);
716 /* Other macros get set to the environment value. */
720 fprintf(new, "#define %s ", name);
721 while(len-- > 0) fputc(' ', new);
723 /* LOG_FILE_PATH is now messy because it can be a path containing %s or
724 it can be "syslog" or ":syslog" or "syslog:path" or even "path:syslog". */
726 if (strcmp(name, "LOG_FILE_PATH") == 0)
732 char *sss = strchr(ss, ':');
735 strncpy(buffer, ss, sss-ss);
736 buffer[sss-ss] = 0; /* For empty case */
738 else strcpy(buffer, ss);
739 pp = buffer + (int)strlen(buffer);
740 while (pp > buffer && isspace((unsigned char)pp[-1])) pp--;
742 if (buffer[0] != 0 && strcmp(buffer, "syslog") != 0)
743 check_percent_ess(buffer, name);
744 if (sss == NULL) break;
746 while (isspace((unsigned char)*ss)) ss++;
748 fprintf(new, "\"%s\"\n", value);
751 /* Timezone values and HEADERS_CHARSET get quoted */
753 else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
754 strcmp(name, "HEADERS_CHARSET") == 0)
755 fprintf(new, "\"%s\"\n", value);
757 /* For others, quote any paths and don't quote anything else */
761 if (value[0] == '/') fprintf(new, "\"%s\"\n", value);
762 else fprintf(new, "%s\n", value);
767 /* Value not defined in the environment; use the default */
772 while (*p == ' ' || *p == '\t') p++;
773 if (*p != '\n') fputs(buffer, new); else
776 if (strcmp(name, "BIN_DIRECTORY") == 0 ||
777 strcmp(name, "CONFIGURE_FILE") == 0)
779 printf("\n*** %s has not been defined in any of the Makefiles in the\n"
780 " \"Local\" directory. "
781 "Please review your build-time configuration.\n\n", name);
785 if (strcmp(name, "TIMEZONE_DEFAULT") == 0)
787 char *tz = getenv("TZ");
788 fprintf(new, "#define TIMEZONE_DEFAULT ");
789 if (tz == NULL) fprintf(new, "NULL\n"); else
790 fprintf(new, "\"%s\"\n", tz);
793 else fprintf(new, "/* %s not set */\n", name);
800 /* If any AUTH macros were defined, ensure that SUPPORT_CRYPTEQ is also
805 if (!support_crypteq) fprintf(new, "/* Force SUPPORT_CRYPTEQ for AUTH */\n"
806 "#define SUPPORT_CRYPTEQ\n");
811 fprintf(new, "\n/* End of config.h */\n");
816 /* End of buildconfig.c */