Source

python-exec / src / python-exec-c.c

/* python-exec -- a Gentoo tool to choose the correct Python script
 * variant for currently selected Python implementation.
 * (c) 2012 Michał Górny
 * Licensed under the terms of the 2-clause BSD license.
 */

#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

const char* const python_impls[] = { PYTHON_IMPLS };
const size_t max_epython_len = 30;

static int try_env(char* bufp, const char* variable)
{
	const char* epython = getenv(variable);

	if (epython)
	{
		if (strlen(epython) <= max_epython_len)
		{
			strcpy(bufp, epython);
			return 1;
		}
		else
			fprintf(stderr, "EPYTHON value invalid (too long).\n");
	}

	return 0;
}

static int try_file(char* bufp, const char* path)
{
	FILE* f = fopen(path, "r");

	if (f)
	{
		size_t rd = fread(bufp, 1, max_epython_len, f);

		if (rd > 0 && feof(f))
		{
			bufp[rd] = 0;
			if (bufp[rd-1] == '\n')
				bufp[rd-1] = 0;
		}

		fclose(f);
	}

	return !!f;
}

static int try_symlink(char* bufp, const char* path)
{
	size_t rd = readlink(path, bufp, max_epython_len);

	/* [max_epython_len] could mean that the name is too long */
	if (rd > 0 && rd < max_epython_len)
	{
		bufp[rd] = 0;
		return 1;
	}

	return 0;
}

static void shift_argv(char* argv[])
{
	char** i;

	for (i = argv; *i; ++i)
		i[0] = i[1];
}

int main(int argc, char* argv[])
{
	const char* const* i;
	char buf[BUFSIZ];
	char* bufp = buf;
	char* bufpy;

	const char* script = argv[1];

	if (!script)
	{
		fprintf(stderr, "Usage: %s <script>\n", argv[0]);
		return EXIT_FAILURE;
	}

	{
		size_t len = strlen(script);

		/* 2 for the hyphen and the null terminator */
		if (len + max_epython_len + 2 >= BUFSIZ)
		{
			bufp = malloc(len + max_epython_len + 2);
			if (!bufp)
			{
				fprintf(stderr, "%s: memory allocation failed (program name too long).\n",
						script);
				return 1;
			}
		}
		memcpy(bufp, script, len);
		bufp[len] = '-';

		shift_argv(argv);

		bufpy = &bufp[len+1];

		if (try_env(bufpy, "EPYTHON"))
			execvp(bufp, argv);
		if (try_file(bufpy, EPREFIX "/etc/env.d/python/config"))
			execvp(bufp, argv);
		if (try_symlink(bufpy, EPREFIX "/usr/bin/python2"))
			execvp(bufp, argv);
		if (try_symlink(bufpy, EPREFIX "/usr/bin/python3"))
			execvp(bufp, argv);

		for (i = python_impls; *i; ++i)
		{
			strcpy(&bufp[len+1], *i);
			execvp(bufp, argv);
		}
	}

	if (bufp != buf)
		free(bufp);
	fprintf(stderr, "%s: no supported Python implementation variant found!\n",
			script);
	return 127;
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.