/* Copyright 1999-2009 Gentoo Foundation * Distributed under the terms of the GNU General Public License v2 */ #ifndef _BSD_SOURCE #define _BSD_SOURCE #endif #include #include #include #include #include #include #include #define ENVD_CONFIG "/etc/env.d/python/config" void get_self_dir(char* buf, size_t size) { *buf = 0; if (readlink("/proc/self/exe", buf, size - 1) != -1) { char* last_path_sep = strrchr(buf, '/'); if (last_path_sep) *last_path_sep = 0; } } /* True if a valid file name, and not "python" */ int valid_interpreter(const char* name) { if (!name || ! *name || (strcmp(name, "python") == 0)) { return 0; } return 1; } int get_version(const char* name) { /* Only find files beginning with "python" - this is a fallback, * so we only want CPython */ if (!valid_interpreter(name) || strncmp(name, "python", 6) != 0) return -1; int pos = 6; int major = 0; int minor = 0; if (name[pos] < '0' || name[pos] > '9') return -1; do { major = major * 10 + name[pos] - '0'; if (!name[++pos]) return -1; } while (name[pos] >= '0' && name[pos] <= '9'); if (name[pos++] != '.') return -1; if (name[pos] < '0' || name[pos] > '9') return -1; do { minor = minor * 10 + name[pos] - '0'; if (!name[++pos]) return (major << 8) | minor; } while (name[pos] >= '0' && name[pos] <= '9'); return -1; } int filter_python(const struct dirent *file) { return get_version(file->d_name) != -1; } /* This implements a version sort, such that the following order applies: * (should never be seen) * python2.6 * python2.9 * python2.10 * python3.0 * python3.1 * python3.2 * python9.1 * python9.9 * python9.10 * python10.1 * python10.9 * python10.10 */ int sort_python(const struct dirent **f1, const struct dirent **f2) { int ver1 = get_version((*f1)->d_name); int ver2 = get_version((*f2)->d_name); return ver1 - ver2; } const char* find_latest() { int major = -1; int minor = -1; char buf[PATH_MAX + 1]; get_self_dir(buf, sizeof(buf)); if (! *buf) { strncpy(buf, "/usr/bin", 9); } struct dirent **namelist; int n = scandir(buf, &namelist, filter_python, sort_python); const char* ret = NULL; if (n < 0) { return NULL; } /* walk backwards through the list */ while (n--) { if (!ret) ret = strdup(namelist[n]->d_name); free(namelist[n]); } free(namelist); return ret; } int main(int argc, char** argv) { const char* EPYTHON = getenv("EPYTHON"); if (!valid_interpreter(EPYTHON)) { FILE* f = fopen(ENVD_CONFIG, "r"); if (f) { struct stat st; fstat(fileno(f), &st); size_t size = st.st_size; char* cont = malloc(size + 1); fgets(cont, size + 1, f); fclose(f); size_t len = strlen(cont); if (len && cont[len - 1] == '\n') cont[len - 1] = 0; EPYTHON = cont; } } if (!valid_interpreter(EPYTHON)) EPYTHON = find_latest(); if (!EPYTHON) return 127; if (strchr(EPYTHON, '/')) { execv(EPYTHON, argv); return 127; } char buf[PATH_MAX + 1]; get_self_dir(buf, sizeof(buf)); if (*buf) { char* absolute_python_path = strcat(strcat(buf, "/"), EPYTHON); execv(absolute_python_path, argv); } execvp(EPYTHON, argv); return 127; }