2 #define PY_SSIZE_T_CLEAN
3 #define _GNU_SOURCE 1 // asprintf
6 // According to Python, its header has to go first:
7 // http://docs.python.org/2/c-api/intro.html#include-files
8 // http://docs.python.org/3/c-api/intro.html#include-files
18 #if defined(__FreeBSD__) || defined(__NetBSD__)
19 # include <sys/sysctl.h>
21 #include <sys/types.h>
24 #include "bup/compat.h"
27 static int prog_argc = 0;
28 static char **prog_argv = NULL;
29 static char *orig_env_pythonpath = NULL;
32 get_argv(PyObject *self, PyObject *args)
34 if (!PyArg_ParseTuple(args, ""))
37 PyObject *result = PyList_New(prog_argc);
38 for (int i = 0; i < prog_argc; i++) {
39 PyObject *s = PyBytes_FromString(prog_argv[i]);
41 die(2, "cannot convert argument to bytes: %s\n", prog_argv[i]);
42 PyList_SET_ITEM(result, i, s);
47 static PyMethodDef bup_main_methods[] = {
48 {"argv", get_argv, METH_VARARGS,
49 "Return the program's current argv array as a list of byte strings." },
53 static int setup_module(PyObject *mod)
55 if (!orig_env_pythonpath) {
56 PyObject_SetAttrString(mod, "env_pythonpath", Py_None);
58 PyObject *py_p = PyBytes_FromString(orig_env_pythonpath);
60 die(2, "cannot convert PYTHONPATH to bytes: %s\n",
62 PyObject_SetAttrString(mod, "env_pythonpath", py_p);
68 #if PY_MAJOR_VERSION >= 3
70 static struct PyModuleDef bup_main_module_def = {
71 .m_base = PyModuleDef_HEAD_INIT,
73 .m_doc = "Built-in bup module providing direct access to argv.",
75 .m_methods = bup_main_methods
79 PyInit_bup_main(void) {
80 PyObject *mod = PyModule_Create(&bup_main_module_def);
81 if (!setup_module(mod))
89 #else // PY_MAJOR_VERSION < 3
91 void PyInit_bup_main(void)
93 PyObject *mod = Py_InitModule("bup_main", bup_main_methods);
95 PyErr_SetString(PyExc_RuntimeError, "bup._helpers init failed");
98 if (!setup_module(mod))
100 PyErr_SetString(PyExc_RuntimeError, "bup._helpers set up failed");
106 #endif // PY_MAJOR_VERSION < 3
109 setup_bup_main_module(void) {
111 char *path = getenv("PYTHONPATH");
113 orig_env_pythonpath = strdup(path);
115 if (PyImport_AppendInittab("bup_main", PyInit_bup_main) == -1)
116 die(2, "unable to register bup_main module\n");
119 #if defined(__APPLE__) && defined(__MACH__)
121 static char *exe_parent_dir(const char * const argv_0) {
124 uint32_t size = sizeof(spath);
125 int rc = _NSGetExecutablePath(spath, &size);
127 mpath = malloc(size);
128 if (!mpath) die(2, "unable to allocate memory for executable path\n");
129 rc = _NSGetExecutablePath(mpath, &size);
131 if(rc != 0) die(2, "unable to find executable path\n");
132 char *path = mpath ? mpath : spath;
133 char *abs_exe = realpath(path, NULL);
135 die(2, "cannot resolve path (%s): %s\n", strerror(errno), path);
136 char * const abs_parent = strdup(dirname(abs_exe));
138 if (mpath) free(mpath);
143 #elif defined(__FreeBSD__) || defined(__NetBSD__)
145 static char *exe_path ()
147 const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
149 int rc = sysctl (mib, 4, NULL, &path_len, NULL, 0);
150 if (rc != 0) die(2, "unable to determine executable path length\n");
151 char *path = malloc (path_len);
152 if (!path) die(2, "unable to allocate memory for executable path\n");
153 rc = sysctl (mib, 4, path, &path_len, NULL, 0);
154 if (rc != 0) die(2, "unable to determine executable path via sysctl\n");
158 static char *exe_parent_dir(const char * const argv_0)
160 char * const exe = exe_path();
161 if (!exe) die(2, "unable to determine executable path\n");
162 char * const parent = strdup(dirname(exe));
163 if (!parent) die(2, "unable to determine parent directory of executable\n");
168 #else // not defined(__FreeBSD__) || defined(__NetBSD__)
170 /// Use /proc if possible, and if all else fails, search in the PATH
172 #if defined(__linux__)
173 # define PROC_SELF_EXE "/proc/self/exe"
174 #elif defined(__sun) || defined (sun)
175 # define PROC_SELF_EXE "/proc/self/path/a.out"
177 # define PROC_SELF_EXE NULL
180 static char *find_in_path(const char * const name, const char * const path)
183 char *tmp_path = strdup(path);
186 char *tok_path = tmp_path;
187 while ((elt = strtok(tok_path, ":")) != NULL) {
190 int rc = asprintf(&candidate, "%s/%s", elt, name);
193 rc = stat(candidate, &st);
196 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
200 die(2, "cannot stat %s: %s\n", candidate, strerror(errno));
203 } else if (S_ISREG(st.st_mode)) {
204 if (access(candidate, X_OK) == 0) {
209 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
213 die(2, "cannot determine executability of %s: %s\n",
214 candidate, strerror(errno));
224 static char *find_exe_parent(const char * const argv_0)
226 char *candidate = NULL;
227 const char * const slash = index(argv_0, '/');
229 candidate = strdup(argv_0);
232 const char * const env_path = getenv("PATH");
234 die(2, "no PATH and executable isn't relative or absolute: %s\n",
236 char *path_exe = find_in_path(argv_0, env_path);
238 char * abs_exe = realpath(path_exe, NULL);
240 die(2, "cannot resolve path (%s): %s\n",
241 strerror(errno), path_exe);
249 char * const abs_exe = realpath(candidate, NULL);
251 die(2, "cannot resolve path (%s): %s\n", strerror(errno), candidate);
253 char * const abs_parent = strdup(dirname(abs_exe));
259 static char *exe_parent_dir(const char * const argv_0)
261 if (PROC_SELF_EXE != NULL) {
264 size_t path_n = sizeof(sbuf);
267 len = readlink(PROC_SELF_EXE, path, path_n);
268 if (len == -1 || (size_t) len != path_n)
271 if (path != sbuf) free(path);
272 path = malloc(path_n);
274 die(2, "unable to allocate memory for executable path\n");
278 char *result = strdup(dirname(path));
284 case ENOENT: case EACCES: case EINVAL: case ELOOP: case ENOTDIR:
288 die(2, "cannot resolve %s: %s\n", path, strerror(errno));
294 return find_exe_parent(argv_0);
297 #endif // use /proc if possible, and if all else fails, search in the PATh
300 setenv_or_die(const char *name, const char *value)
302 int rc = setenv(name, value, 1);
304 die(2, "setenv %s=%s failed (%s)\n", name, value, strerror(errno));
308 prepend_lib_to_pythonpath(const char * const exec_path,
309 const char * const relative_path)
311 char *parent = exe_parent_dir(exec_path);
314 int rc = asprintf(&bupmodpath, "%s/%s", parent, relative_path);
317 rc = stat(bupmodpath, &st);
319 die(2, "unable find lib dir (%s): %s\n", strerror(errno), bupmodpath);
320 if (!S_ISDIR(st.st_mode))
321 die(2, "lib path is not dir: %s\n", bupmodpath);
322 char *curpypath = getenv("PYTHONPATH");
325 int rc = asprintf(&path, "%s:%s", bupmodpath, curpypath);
327 setenv_or_die("PYTHONPATH", path);
330 setenv_or_die("PYTHONPATH", bupmodpath);
337 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 8
338 # define bup_py_main bup_py_bytes_main
339 #elif PY_MAJOR_VERSION > 2
340 # define bup_py_main Py_BytesMain
342 # define bup_py_main Py_Main
345 #if defined(BUP_DEV_BUP_PYTHON) && defined(BUP_DEV_BUP_EXEC)
346 # error "Both BUP_DEV_BUP_PYTHON and BUP_DEV_BUP_EXEC are defined"
349 #ifdef BUP_DEV_BUP_PYTHON
351 int main(int argc, char **argv)
355 setup_bup_main_module();
356 prepend_lib_to_pythonpath(argv[0], "../lib");
357 return bup_py_main (argc, argv);
360 #elif defined(BUP_DEV_BUP_EXEC)
362 int main(int argc, char **argv)
364 prog_argc = argc - 1;
365 prog_argv = argv + 1;
366 setup_bup_main_module();
367 prepend_lib_to_pythonpath(argv[0], "../lib");
369 return bup_py_main (1, argv);
370 // This can't handle a script with a name like "-c", but that's
371 // python's problem, not ours.
372 return bup_py_main (2, argv);
375 #else // normal bup command
377 int main(int argc, char **argv)
381 setup_bup_main_module();
382 prepend_lib_to_pythonpath(argv[0], "..");
383 char *bup_argv[] = { argv[0], "-m", "bup.main" };
384 return bup_py_main (3, bup_argv);
387 #endif // normal bup command