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"
25 #include "bup/intprops.h"
28 static int prog_argc = 0;
29 static char **prog_argv = NULL;
30 static char *orig_env_pythonpath = NULL;
33 get_argv(PyObject *self, PyObject *args)
35 if (!PyArg_ParseTuple(args, ""))
38 PyObject *result = PyList_New(prog_argc);
40 for (i = 0; i < prog_argc; i++) {
41 PyObject *s = PyBytes_FromString(prog_argv[i]);
43 die(2, "cannot convert argument to bytes: %s\n", prog_argv[i]);
44 PyList_SET_ITEM(result, i, s);
49 static PyMethodDef bup_main_methods[] = {
50 {"argv", get_argv, METH_VARARGS,
51 "Return the program's current argv array as a list of byte strings." },
55 static int setup_module(PyObject *mod)
57 if (!orig_env_pythonpath) {
58 PyObject_SetAttrString(mod, "env_pythonpath", Py_None);
60 PyObject *py_p = PyBytes_FromString(orig_env_pythonpath);
62 die(2, "cannot convert PYTHONPATH to bytes: %s\n",
64 PyObject_SetAttrString(mod, "env_pythonpath", py_p);
70 #if PY_MAJOR_VERSION >= 3
72 static struct PyModuleDef bup_main_module_def = {
73 .m_base = PyModuleDef_HEAD_INIT,
75 .m_doc = "Built-in bup module providing direct access to argv.",
77 .m_methods = bup_main_methods
81 PyInit_bup_main(void) {
82 PyObject *mod = PyModule_Create(&bup_main_module_def);
83 if (!setup_module(mod))
91 #else // PY_MAJOR_VERSION < 3
93 void PyInit_bup_main(void)
95 PyObject *mod = Py_InitModule("bup_main", bup_main_methods);
97 PyErr_SetString(PyExc_RuntimeError, "bup._helpers init failed");
100 if (!setup_module(mod))
102 PyErr_SetString(PyExc_RuntimeError, "bup._helpers set up failed");
108 #endif // PY_MAJOR_VERSION < 3
111 setup_bup_main_module(void) {
113 char *path = getenv("PYTHONPATH");
115 orig_env_pythonpath = strdup(path);
117 if (PyImport_AppendInittab("bup_main", PyInit_bup_main) == -1)
118 die(2, "unable to register bup_main module\n");
121 #if defined(__APPLE__) && defined(__MACH__)
123 static char *exe_parent_dir(const char * const argv_0) {
126 uint32_t size = sizeof(spath);
127 int rc = _NSGetExecutablePath(spath, &size);
129 mpath = malloc(size);
130 if (!mpath) die(2, "unable to allocate memory for executable path\n");
131 rc = _NSGetExecutablePath(mpath, &size);
133 if(rc != 0) die(2, "unable to find executable path\n");
134 char *path = mpath ? mpath : spath;
135 char *abs_exe = realpath(path, NULL);
137 die(2, "cannot resolve path (%s): %s\n", strerror(errno), path);
138 char * const abs_parent = strdup(dirname(abs_exe));
140 if (mpath) free(mpath);
145 #elif defined(__FreeBSD__) || defined(__NetBSD__)
147 static char *exe_path ()
149 const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
151 int rc = sysctl (mib, 4, NULL, &path_len, NULL, 0);
152 if (rc != 0) die(2, "unable to determine executable path length\n");
153 char *path = malloc (path_len);
154 if (!path) die(2, "unable to allocate memory for executable path\n");
155 rc = sysctl (mib, 4, path, &path_len, NULL, 0);
156 if (rc != 0) die(2, "unable to determine executable path via sysctl\n");
160 static char *exe_parent_dir(const char * const argv_0)
162 char * const exe = exe_path();
163 if (!exe) die(2, "unable to determine executable path\n");
164 char * const parent = strdup(dirname(exe));
165 if (!parent) die(2, "unable to determine parent directory of executable\n");
170 #else // not defined(__FreeBSD__) || defined(__NetBSD__)
172 /// Use /proc if possible, and if all else fails, search in the PATH
174 #if defined(__linux__)
175 # define PROC_SELF_EXE "/proc/self/exe"
176 #elif defined(__sun) || defined (sun)
177 # define PROC_SELF_EXE "/proc/self/path/a.out"
179 # define PROC_SELF_EXE NULL
182 static char *find_in_path(const char * const name, const char * const path)
185 char *tmp_path = strdup(path);
188 char *tok_path = tmp_path;
189 while ((elt = strtok(tok_path, ":")) != NULL) {
192 int rc = asprintf(&candidate, "%s/%s", elt, name);
195 rc = stat(candidate, &st);
198 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
202 die(2, "cannot stat %s: %s\n", candidate, strerror(errno));
205 } else if (S_ISREG(st.st_mode)) {
206 if (access(candidate, X_OK) == 0) {
211 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
215 die(2, "cannot determine executability of %s: %s\n",
216 candidate, strerror(errno));
226 static char *find_exe_parent(const char * const argv_0)
228 char *candidate = NULL;
229 const char * const slash = index(argv_0, '/');
231 candidate = strdup(argv_0);
234 const char * const env_path = getenv("PATH");
236 die(2, "no PATH and executable isn't relative or absolute: %s\n",
238 char *path_exe = find_in_path(argv_0, env_path);
240 char * abs_exe = realpath(path_exe, NULL);
242 die(2, "cannot resolve path (%s): %s\n",
243 strerror(errno), path_exe);
251 char * const abs_exe = realpath(candidate, NULL);
253 die(2, "cannot resolve path (%s): %s\n", strerror(errno), candidate);
255 char * const abs_parent = strdup(dirname(abs_exe));
261 static char *exe_parent_dir(const char * const argv_0)
263 if (PROC_SELF_EXE != NULL) {
266 size_t path_n = sizeof(sbuf);
269 len = readlink(PROC_SELF_EXE, path, path_n);
270 if (len == -1 || (size_t) len != path_n)
272 if (!INT_MULTIPLY_OK(path_n, 2, &path_n))
273 die(2, "memory buffer for executable path would be too big\n");
275 if (path != sbuf) free(path);
276 path = malloc(path_n);
278 die(2, "unable to allocate memory for executable path\n");
282 char *result = strdup(dirname(path));
288 case ENOENT: case EACCES: case EINVAL: case ELOOP: case ENOTDIR:
292 die(2, "cannot resolve %s: %s\n", path, strerror(errno));
298 return find_exe_parent(argv_0);
301 #endif // use /proc if possible, and if all else fails, search in the PATh
304 setenv_or_die(const char *name, const char *value)
306 int rc = setenv(name, value, 1);
308 die(2, "setenv %s=%s failed (%s)\n", name, value, strerror(errno));
312 prepend_lib_to_pythonpath(const char * const exec_path,
313 const char * const relative_path)
315 char *parent = exe_parent_dir(exec_path);
318 int rc = asprintf(&bupmodpath, "%s/%s", parent, relative_path);
321 rc = stat(bupmodpath, &st);
323 die(2, "unable find lib dir (%s): %s\n", strerror(errno), bupmodpath);
324 if (!S_ISDIR(st.st_mode))
325 die(2, "lib path is not dir: %s\n", bupmodpath);
326 char *curpypath = getenv("PYTHONPATH");
329 int rc = asprintf(&path, "%s:%s", bupmodpath, curpypath);
331 setenv_or_die("PYTHONPATH", path);
334 setenv_or_die("PYTHONPATH", bupmodpath);
341 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 8
342 # define bup_py_main bup_py_bytes_main
343 #elif PY_MAJOR_VERSION > 2
344 # define bup_py_main Py_BytesMain
346 # define bup_py_main Py_Main
349 #if defined(BUP_DEV_BUP_PYTHON) && defined(BUP_DEV_BUP_EXEC)
350 # error "Both BUP_DEV_BUP_PYTHON and BUP_DEV_BUP_EXEC are defined"
353 #ifdef BUP_DEV_BUP_PYTHON
355 int main(int argc, char **argv)
359 setup_bup_main_module();
360 prepend_lib_to_pythonpath(argv[0], "../lib");
361 return bup_py_main (argc, argv);
364 #elif defined(BUP_DEV_BUP_EXEC)
366 int main(int argc, char **argv)
369 prog_argc = argc - 1;
370 prog_argv = argv + 1;
371 setup_bup_main_module();
372 prepend_lib_to_pythonpath(argv[0], "../lib");
374 return bup_py_main (1, argv);
375 // This can't handle a script with a name like "-c", but that's
376 // python's problem, not ours.
377 return bup_py_main (2, argv);
380 #else // normal bup command
382 int main(int argc, char **argv)
386 setup_bup_main_module();
387 prepend_lib_to_pythonpath(argv[0], "..");
388 char *bup_argv[] = { argv[0], "-m", "bup.main" };
389 return bup_py_main (3, bup_argv);
392 #endif // normal bup command