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/3/c-api/intro.html#include-files
17 #if defined(__FreeBSD__) || defined(__NetBSD__)
18 # include <sys/sysctl.h>
20 #include <sys/types.h>
23 #include "bup/compat.h"
24 #include "bup/intprops.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);
39 for (i = 0; i < prog_argc; i++) {
40 PyObject *s = PyBytes_FromString(prog_argv[i]);
42 die(2, "cannot convert argument to bytes: %s\n", prog_argv[i]);
43 PyList_SET_ITEM(result, i, s);
48 static PyMethodDef bup_main_methods[] = {
49 {"argv", get_argv, METH_VARARGS,
50 "Return the program's current argv array as a list of byte strings." },
54 static int setup_module(PyObject *mod)
56 if (!orig_env_pythonpath) {
57 PyObject_SetAttrString(mod, "env_pythonpath", Py_None);
59 PyObject *py_p = PyBytes_FromString(orig_env_pythonpath);
61 die(2, "cannot convert PYTHONPATH to bytes: %s\n",
63 PyObject_SetAttrString(mod, "env_pythonpath", py_p);
69 #if PY_MAJOR_VERSION >= 3
71 static struct PyModuleDef bup_main_module_def = {
72 .m_base = PyModuleDef_HEAD_INIT,
74 .m_doc = "Built-in bup module providing direct access to argv.",
76 .m_methods = bup_main_methods
80 PyInit_bup_main(void) {
81 PyObject *mod = PyModule_Create(&bup_main_module_def);
82 if (!setup_module(mod))
90 #else // PY_MAJOR_VERSION < 3
92 void PyInit_bup_main(void)
94 PyObject *mod = Py_InitModule("bup_main", bup_main_methods);
96 PyErr_SetString(PyExc_RuntimeError, "bup._helpers init failed");
99 if (!setup_module(mod))
101 PyErr_SetString(PyExc_RuntimeError, "bup._helpers set up failed");
107 #endif // PY_MAJOR_VERSION < 3
110 setup_bup_main_module(void) {
112 char *path = getenv("PYTHONPATH");
114 orig_env_pythonpath = strdup(path);
116 if (PyImport_AppendInittab("bup_main", PyInit_bup_main) == -1)
117 die(2, "unable to register bup_main module\n");
120 #if defined(__APPLE__) && defined(__MACH__)
122 static char *exe_parent_dir(const char * const argv_0) {
125 uint32_t size = sizeof(spath);
126 int rc = _NSGetExecutablePath(spath, &size);
128 mpath = malloc(size);
129 if (!mpath) die(2, "unable to allocate memory for executable path\n");
130 rc = _NSGetExecutablePath(mpath, &size);
132 if(rc != 0) die(2, "unable to find executable path\n");
133 char *path = mpath ? mpath : spath;
134 char *abs_exe = realpath(path, NULL);
136 die(2, "cannot resolve path (%s): %s\n", strerror(errno), path);
137 char * const abs_parent = strdup(dirname(abs_exe));
139 if (mpath) free(mpath);
144 #elif defined(__FreeBSD__) || defined(__NetBSD__)
146 static char *exe_path ()
148 const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
150 int rc = sysctl (mib, 4, NULL, &path_len, NULL, 0);
151 if (rc != 0) die(2, "unable to determine executable path length\n");
152 char *path = malloc (path_len);
153 if (!path) die(2, "unable to allocate memory for executable path\n");
154 rc = sysctl (mib, 4, path, &path_len, NULL, 0);
155 if (rc != 0) die(2, "unable to determine executable path via sysctl\n");
159 static char *exe_parent_dir(const char * const argv_0)
161 char * const exe = exe_path();
162 if (!exe) die(2, "unable to determine executable path\n");
163 char * const parent = strdup(dirname(exe));
164 if (!parent) die(2, "unable to determine parent directory of executable\n");
169 #else // not defined(__FreeBSD__) || defined(__NetBSD__)
171 /// Use /proc if possible, and if all else fails, search in the PATH
173 #if defined(__linux__)
174 # define PROC_SELF_EXE "/proc/self/exe"
175 #elif defined(__sun) || defined (sun)
176 # define PROC_SELF_EXE "/proc/self/path/a.out"
178 # define PROC_SELF_EXE NULL
181 static char *find_in_path(const char * const name, const char * const path)
184 char *tmp_path = strdup(path);
187 char *tok_path = tmp_path;
188 while ((elt = strtok(tok_path, ":")) != NULL) {
191 int rc = asprintf(&candidate, "%s/%s", elt, name);
194 rc = stat(candidate, &st);
197 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
201 die(2, "cannot stat %s: %s\n", candidate, strerror(errno));
204 } else if (S_ISREG(st.st_mode)) {
205 if (access(candidate, X_OK) == 0) {
210 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
214 die(2, "cannot determine executability of %s: %s\n",
215 candidate, strerror(errno));
225 static char *find_exe_parent(const char * const argv_0)
227 char *candidate = NULL;
228 const char * const slash = strchr(argv_0, '/');
230 candidate = strdup(argv_0);
233 const char * const env_path = getenv("PATH");
235 die(2, "no PATH and executable isn't relative or absolute: %s\n",
237 char *path_exe = find_in_path(argv_0, env_path);
239 char * abs_exe = realpath(path_exe, NULL);
241 die(2, "cannot resolve path (%s): %s\n",
242 strerror(errno), path_exe);
250 char * const abs_exe = realpath(candidate, NULL);
252 die(2, "cannot resolve path (%s): %s\n", strerror(errno), candidate);
254 char * const abs_parent = strdup(dirname(abs_exe));
260 static char *exe_parent_dir(const char * const argv_0)
262 if (PROC_SELF_EXE != NULL) {
265 size_t path_n = sizeof(sbuf);
268 len = readlink(PROC_SELF_EXE, path, path_n);
269 if (len == -1 || (size_t) len != path_n)
271 if (!INT_MULTIPLY_OK(path_n, 2, &path_n))
272 die(2, "memory buffer for executable path would be too big\n");
273 if (path != sbuf) free(path);
274 path = malloc(path_n);
276 die(2, "unable to allocate memory for executable path\n");
280 char *result = strdup(dirname(path));
286 case ENOENT: case EACCES: case EINVAL: case ELOOP: case ENOTDIR:
290 die(2, "cannot resolve %s: %s\n", path, strerror(errno));
296 return find_exe_parent(argv_0);
299 #endif // use /proc if possible, and if all else fails, search in the PATh
302 setenv_or_die(const char *name, const char *value)
304 int rc = setenv(name, value, 1);
306 die(2, "setenv %s=%s failed (%s)\n", name, value, strerror(errno));
310 prepend_lib_to_pythonpath(const char * const exec_path,
311 const char * const relative_path)
313 char *parent = exe_parent_dir(exec_path);
316 int rc = asprintf(&bupmodpath, "%s/%s", parent, relative_path);
319 rc = stat(bupmodpath, &st);
321 die(2, "unable find lib dir (%s): %s\n", strerror(errno), bupmodpath);
322 if (!S_ISDIR(st.st_mode))
323 die(2, "lib path is not dir: %s\n", bupmodpath);
324 char *curpypath = getenv("PYTHONPATH");
327 int rc = asprintf(&path, "%s:%s", bupmodpath, curpypath);
329 setenv_or_die("PYTHONPATH", path);
332 setenv_or_die("PYTHONPATH", bupmodpath);
339 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 8
340 # define bup_py_main bup_py_bytes_main
341 #elif PY_MAJOR_VERSION > 2
342 # define bup_py_main Py_BytesMain
344 # define bup_py_main Py_Main
347 #if defined(BUP_DEV_BUP_PYTHON) && defined(BUP_DEV_BUP_EXEC)
348 # error "Both BUP_DEV_BUP_PYTHON and BUP_DEV_BUP_EXEC are defined"
351 #ifdef BUP_DEV_BUP_PYTHON
353 int main(int argc, char **argv)
357 setup_bup_main_module();
358 prepend_lib_to_pythonpath(argv[0], "../lib");
359 return bup_py_main (argc, argv);
362 #elif defined(BUP_DEV_BUP_EXEC)
364 int main(int argc, char **argv)
367 prog_argc = argc - 1;
368 prog_argv = argv + 1;
369 setup_bup_main_module();
370 prepend_lib_to_pythonpath(argv[0], "../lib");
372 return bup_py_main (1, argv);
373 // This can't handle a script with a name like "-c", but that's
374 // python's problem, not ours.
375 return bup_py_main (2, argv);
378 #else // normal bup command
380 int main(int argc, char **argv)
384 setup_bup_main_module();
385 prepend_lib_to_pythonpath(argv[0], "..");
386 char *bup_argv[] = { argv[0], "-m", "bup.main" };
387 return bup_py_main (3, bup_argv);
390 #endif // normal bup command