/*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2020 Baptiste Daroussin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #define NELEMS(a) (sizeof(a) / sizeof(a[0])) static const char * parse_config(const char *conffile, const char *cctype) { FILE *conf; char *line = NULL; size_t linecap = 0; ssize_t linelen; char *walk, *value; int confline = 0; char ccpathbuf[MAXPATHLEN]; const char *ccpath = NULL; if ((conf = fopen(conffile, "r")) == NULL) return (NULL); while ((linelen = getline(&line, &linecap, conf)) > 0) { confline++; walk = line; walk += strspn(walk, " \t\n\r"); if (*walk == '\0') continue; /* consider # as a comment line */ if (*walk == '#') continue; value = strchr(walk, '='); if (value == NULL) value = strchr(walk, ':'); if (value == NULL) errx(1, "Malformed line in the configuration file: %s line: %d", conffile, confline); *value = '\0'; value++; /* ignore lines not concernant if cctype we are looking for */ if (strncmp(walk, cctype, strlen(cctype)) != 0) continue; walk += strlen(cctype); /* * allow space and tabs after the key, if anything else if found, then * skip the line we consider the key not to be our cctype */ if (strspn(walk, " \t") != strlen(walk)) continue; value += strspn(value, " \t"); if (*value == '\0' || *value == '\n') errx(1, "Invalid value for %s, line %d in the configuration file %s", cctype, confline, conffile); /* trim space an the end of the value */ walk = value + strlen(value) - 1; while (walk > value && isspace(*walk)) { *walk = '\0'; walk--; } strlcpy(ccpathbuf, value, MAXPATHLEN); ccpath = ccpathbuf; break; } free(line); fclose(conf); return (ccpath); } static const char * get_cc_from_config(const char *cctype) { char confpath[MAXPATHLEN]; unsigned int i; const char *confpaths[] = { NULL, NULL, "/etc/compiler.conf", "/etc/defaults/compiler.conf", }; const char *ccpath; const char *localbase; /* * In order we first try to get the configuration from * LOCALBASE/etc/compiler.conf then from /etc/compiler.conf * only then we try to fallback on /etc/defaults/compiler.conf */ localbase = getenv("LOCALBASE"); if (localbase == NULL) localbase = "/usr/local"; snprintf(confpath, MAXPATHLEN, "%s/etc/compiler.conf", localbase); confpaths[1] = getenv("COMPILER_CONF"); confpaths[0] = confpath; for (i = 0; i < NELEMS(confpaths); i++) { if (confpaths[i] == NULL) continue; ccpath = parse_config(confpaths[i], cctype); if (ccpath != NULL) return (ccpath); } return (NULL); } int main(int argc __unused, char *argv[]) { const char *ccpath = NULL; const char *cctype = NULL; const char *progname = getprogname(); if (strcmp(progname, "cc") == 0) { cctype = "CC"; } else if (strcmp(progname, "cpp") == 0) { cctype = "CPP"; } else if (strcmp(progname, "c++") == 0) { cctype = "CXX"; } else { errx(1, "Invalid progname, this can only be used as cc, c++ or cpp"); } ccpath = get_cc_from_config(cctype); if (ccpath == NULL) errx(1, "Unable to determine the value of %s", getprogname()); execvp(ccpath, argv); err(1, "%s", ccpath); }