diff options
Diffstat (limited to 'sys-devel/gcc-config/files/wrapper-1.4.7.c')
-rw-r--r-- | sys-devel/gcc-config/files/wrapper-1.4.7.c | 377 |
1 files changed, 0 insertions, 377 deletions
diff --git a/sys-devel/gcc-config/files/wrapper-1.4.7.c b/sys-devel/gcc-config/files/wrapper-1.4.7.c deleted file mode 100644 index 9c2d0cba3214..000000000000 --- a/sys-devel/gcc-config/files/wrapper-1.4.7.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright 1999-2005 Gentoo Foundation - * Distributed under the terms of the GNU General Public License v2 - * $Header: /var/cvsroot/gentoo-x86/sys-devel/gcc-config/files/wrapper-1.4.7.c,v 1.1 2005/08/04 03:40:05 vapier Exp $ - * Author: Martin Schlemmer <azarah@gentoo.org> - * az's lackey: Mike Frysinger <vapier@gentoo.org> - */ - -#define _REENTRANT -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/param.h> -#include <unistd.h> -#include <sys/wait.h> -#include <libgen.h> -#include <string.h> -#include <stdarg.h> -#include <errno.h> - -#define GCC_CONFIG "/usr/bin/gcc-config" -#define ENVD_BASE "/etc/env.d/05gcc" - -struct wrapper_data { - char name[MAXPATHLEN + 1]; - char fullname[MAXPATHLEN + 1]; - char bin[MAXPATHLEN + 1]; - char tmp[MAXPATHLEN + 1]; - char *path; -}; - -static struct { - char *alias; - char *target; -} wrapper_aliases[] = { - { "cc", "gcc" }, - { "f77", "g77" }, - { NULL, NULL } -}; - -static const char *wrapper_strerror(int err, struct wrapper_data *data) -{ - /* this app doesn't use threads and strerror - * is more portable than strerror_r */ - strncpy(data->tmp, strerror(err), sizeof(data->tmp)); - return data->tmp; -} - -static void wrapper_exit(char *msg, ...) -{ - va_list args; - fprintf(stderr, "gcc-config error: "); - va_start(args, msg); - vfprintf(stderr, msg, args); - va_end(args); - exit(1); -} - -/* check_for_target checks in path for the file we are seeking - * it returns 1 if found (with data->bin setup), 0 if not and - * negative on error - */ -static int check_for_target(char *path, struct wrapper_data *data) -{ - struct stat sbuf; - int result; - char str[MAXPATHLEN + 1]; - size_t len = strlen(path) + strlen(data->name) + 2; - - snprintf(str, len, "%s/%s", path, data->name); - - /* Stat possible file to check that - * 1) it exist and is a regular file, and - * 2) it is not the wrapper itself, and - * 3) it is in a /gcc-bin/ directory tree - */ - result = stat(str, &sbuf); - if ((result == 0) && \ - ((sbuf.st_mode & S_IFREG) || (sbuf.st_mode & S_IFLNK)) && \ - (strcmp(str, data->fullname) != 0) && \ - (strstr(str, "/gcc-bin/") != 0)) { - - strncpy(data->bin, str, MAXPATHLEN); - data->bin[MAXPATHLEN] = 0; - result = 1; - } else - result = 0; - - return result; -} - -static int find_target_in_path(struct wrapper_data *data) -{ - char *token = NULL, *state; - char str[MAXPATHLEN + 1]; - - if (data->path == NULL) return 0; - - /* Make a copy since strtok_r will modify path */ - snprintf(str, MAXPATHLEN + 1, "%s", data->path); - - token = strtok_r(str, ":", &state); - - /* Find the first file with suitable name in PATH. The idea here is - * that we do not want to bind ourselfs to something static like the - * default profile, or some odd environment variable, but want to be - * able to build something with a non default gcc by just tweaking - * the PATH ... */ - while ((token != NULL) && strlen(token)) { - if (check_for_target(token, data)) - return 1; - token = strtok_r(NULL, ":", &state); - } - - return 0; -} - -/* find_target_in_envd parses /etc/env.d/05gcc, and tries to - * extract PATH, which is set to the current profile's bin - * directory ... - */ -static int find_target_in_envd(struct wrapper_data *data, int cross_compile) -{ - FILE *envfile = NULL; - char *token = NULL, *state; - char str[MAXPATHLEN + 1]; - char *strp = str; - char envd_file[MAXPATHLEN + 1]; - - if (!cross_compile) { - snprintf(envd_file, MAXPATHLEN, "%s", ENVD_BASE); - } else { - char *ctarget, *end = strrchr(data->name, '-'); - if (end == NULL) - return 0; - ctarget = strdup(data->name); - ctarget[end - data->name] = '\0'; - snprintf(envd_file, MAXPATHLEN, "%s-%s", ENVD_BASE, ctarget); - free(ctarget); - } - envfile = fopen(envd_file, "r"); - if (envfile == NULL) - return 0; - - while (0 != fgets(strp, MAXPATHLEN, envfile)) { - /* Keep reading ENVD_FILE until we get a line that - * starts with 'PATH=' - */ - if (((strp) && (strlen(strp) > strlen("PATH=")) && - !strncmp("PATH=", strp, strlen("PATH=")))) { - - token = strtok_r(strp, "=", &state); - if ((token != NULL) && strlen(token)) - /* The second token should be the value of PATH .. */ - token = strtok_r(NULL, "=", &state); - else - goto bail; - - if ((token != NULL) && strlen(token)) { - strp = token; - /* A bash variable may be unquoted, quoted with " or - * quoted with ', so extract the value without those .. - */ - token = strtok(strp, "\n\"\'"); - - while (token != NULL) { - if (check_for_target(token, data)) { - fclose(envfile); - return 1; - } - - token = strtok(NULL, "\n\"\'"); - } - } - } - strp = str; - } - -bail: - fclose(envfile); - return (cross_compile ? 0 : find_target_in_envd(data, 1)); -} - -static void find_wrapper_target(struct wrapper_data *data) -{ - FILE *inpipe = NULL; - char str[MAXPATHLEN + 1]; - - if (find_target_in_path(data)) - return; - - if (find_target_in_envd(data, 0)) - return; - - /* Only our wrapper is in PATH, so - get the CC path using gcc-config and - execute the real binary in there... */ - inpipe = popen(GCC_CONFIG " --get-bin-path", "r"); - if (inpipe == NULL) - wrapper_exit( - "Could not open pipe: %s\n", - wrapper_strerror(errno, data)); - - if (fgets(str, MAXPATHLEN, inpipe) == 0) - wrapper_exit( - "Could not get compiler binary path: %s\n", - wrapper_strerror(errno, data)); - - strncpy(data->bin, str, sizeof(data->bin) - 1); - data->bin[strlen(data->bin) - 1] = '/'; - strncat(data->bin, data->name, sizeof(data->bin) - 1); - data->bin[MAXPATHLEN] = 0; - - pclose(inpipe); -} - -/* This function modifies PATH to have gcc's bin path appended */ -static void modify_path(struct wrapper_data *data) -{ - char *newpath = NULL, *token = NULL, *state; - char dname_data[MAXPATHLEN + 1], str[MAXPATHLEN + 1]; - char *str2 = dname_data, *dname = dname_data; - size_t len = 0; - - if (data->bin == NULL) - return; - - snprintf(str2, MAXPATHLEN + 1, "%s", data->bin); - - if ((dname = dirname(str2)) == NULL) - return; - - if (data->path == NULL) - return; - - /* Make a copy since strtok_r will modify path */ - snprintf(str, MAXPATHLEN + 1, "%s", data->path); - - token = strtok_r(str, ":", &state); - - /* Check if we already appended our bin location to PATH */ - if ((token != NULL) && strlen(token)) { - if (!strcmp(token, dname)) - return; - } - - len = strlen(dname) + strlen(data->path) + 2 + strlen("PATH") + 1; - - newpath = (char *)malloc(len); - if (newpath == NULL) - wrapper_exit("out of memory\n"); - memset(newpath, 0, len); - - snprintf(newpath, len, "PATH=%s:%s", dname, data->path); - putenv(newpath); -} - -static char *abi_flags[] = { - "-m32", "-m64", "-mabi", NULL -}; -static char **build_new_argv(char **argv, const char *newflags_str) -{ -#define MAX_NEWFLAGS 32 - char *newflags[MAX_NEWFLAGS]; - char **retargv; - unsigned int argc, i; - char *state, *flags_tokenized; - - retargv = argv; - - /* make sure user hasn't specified any ABI flags already ... - * if they have, lets just get out of here */ - for (argc = 0; argv[argc]; ++argc) - for (i = 0; abi_flags[i]; ++i) - if (!strncmp(argv[argc], abi_flags[i], strlen(abi_flags[i]))) - return retargv; - - /* Tokenize the flag list and put it into newflags array */ - flags_tokenized = strdup(newflags_str); - if (flags_tokenized == NULL) - return retargv; - i = 0; - newflags[i] = strtok_r(flags_tokenized, " \t\n", &state); - while (newflags[i] != NULL && i < MAX_NEWFLAGS-1) - newflags[++i] = strtok_r(NULL, " \t\n", &state); - - /* allocate memory for our spiffy new argv */ - retargv = (char**)calloc(argc + i + 1, sizeof(char*)); - /* start building retargv */ - retargv[0] = argv[0]; - /* insert the ABI flags first so cmdline always overrides ABI flags */ - memcpy(retargv+1, newflags, i * sizeof(char*)); - /* copy over the old argv */ - if (argc > 1) - memcpy(retargv+1+i, argv+1, (argc-1) * sizeof(char*)); - - return retargv; -} - -int main(int argc, char *argv[]) -{ - struct wrapper_data *data; - size_t size; - int i; - char **newargv = argv; - - data = alloca(sizeof(*data)); - if (data == NULL) - wrapper_exit("%s wrapper: out of memory\n", argv[0]); - memset(data, 0, sizeof(*data)); - - if (getenv("PATH")) { - data->path = strdup(getenv("PATH")); - if (data->path == NULL) - wrapper_exit("%s wrapper: out of memory\n", argv[0]); - } - - /* What should we find ? */ - strcpy(data->name, basename(argv[0])); - - /* Allow for common compiler names like cc->gcc */ - for (i = 0; wrapper_aliases[i].alias; ++i) - if (!strcmp(data->name, wrapper_aliases[i].alias)) - strcpy(data->name, wrapper_aliases[i].target); - - /* What is the full name of our wrapper? */ - size = sizeof(data->fullname); - i = snprintf(data->fullname, size, "/usr/bin/%s", data->name); - if ((i == -1) || (i > (int)size)) - wrapper_exit("invalid wrapper name: \"%s\"\n", data->name); - - find_wrapper_target(data); - - modify_path(data); - - if (data->path) - free(data->path); - data->path = NULL; - - /* Set argv[0] to the correct binary, else gcc can't find internal headers - * http://bugs.gentoo.org/show_bug.cgi?id=8132 */ - argv[0] = data->bin; - - /* If this is g{cc,++}{32,64}, we need to add -m{32,64} - * otherwise we need to add ${CFLAGS_${ABI}} - */ - size = strlen(data->bin) - 2; - if(!strcmp(data->bin + size, "32") ) { - *(data->bin + size) = '\0'; - newargv = build_new_argv(argv, "-m32"); - } else if (!strcmp(data->bin + size, "64") ) { - *(data->bin + size) = '\0'; - newargv = build_new_argv(argv, "-m64"); - } else if(getenv("ABI")) { - char envvar[50]; - - /* We use CFLAGS_${ABI} for gcc, g++, g77, etc as they are - * the same no matter which compiler we are using. - */ - snprintf(envvar, sizeof(envvar), "CFLAGS_%s", getenv("ABI")); - - if (getenv(envvar)) { - newargv = build_new_argv(argv, getenv(envvar)); - if(!newargv) - wrapper_exit("%s wrapper: out of memory\n", argv[0]); - } - } - - /* Ok, lets do it one more time ... */ - if (execv(data->bin, newargv) < 0) - wrapper_exit("Could not run/locate \"%s\"\n", data->name); - - return 0; -} |