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>
26 static int prog_argc = 0;
27 static char **prog_argv = NULL;
28 static char *orig_env_pythonpath = NULL;
31 get_argv(PyObject *self, PyObject *args)
33 if (!PyArg_ParseTuple(args, ""))
36 PyObject *result = PyList_New(prog_argc);
37 for (int i = 0; i < prog_argc; i++) {
38 PyObject *s = PyBytes_FromString(prog_argv[i]);
40 die(2, "cannot convert argument to bytes: %s\n", prog_argv[i]);
41 PyList_SET_ITEM(result, i, s);
46 static PyMethodDef bup_main_methods[] = {
47 {"argv", get_argv, METH_VARARGS,
48 "Return the program's current argv array as a list of byte strings." },
52 static int setup_module(PyObject *mod)
54 if (!orig_env_pythonpath) {
55 PyObject_SetAttrString(mod, "env_pythonpath", Py_None);
57 PyObject *py_p = PyBytes_FromString(orig_env_pythonpath);
59 die(2, "cannot convert PYTHONPATH to bytes: %s\n",
61 PyObject_SetAttrString(mod, "env_pythonpath", py_p);
67 #if PY_MAJOR_VERSION >= 3
69 static struct PyModuleDef bup_main_module_def = {
70 .m_base = PyModuleDef_HEAD_INIT,
72 .m_doc = "Built-in bup module providing direct access to argv.",
74 .m_methods = bup_main_methods
78 PyInit_bup_main(void) {
79 PyObject *mod = PyModule_Create(&bup_main_module_def);
80 if (!setup_module(mod))
88 #else // PY_MAJOR_VERSION < 3
90 void PyInit_bup_main(void)
92 PyObject *mod = Py_InitModule("bup_main", bup_main_methods);
94 PyErr_SetString(PyExc_RuntimeError, "bup._helpers init failed");
97 if (!setup_module(mod))
99 PyErr_SetString(PyExc_RuntimeError, "bup._helpers set up failed");
105 #endif // PY_MAJOR_VERSION < 3
108 setup_bup_main_module(void) {
110 char *path = getenv("PYTHONPATH");
112 orig_env_pythonpath = strdup(path);
114 if (PyImport_AppendInittab("bup_main", PyInit_bup_main) == -1)
115 die(2, "unable to register bup_main module\n");
118 #if defined(__APPLE__) && defined(__MACH__)
120 static char *exe_parent_dir(const char * const argv_0) {
121 char path[4096]; // FIXME
122 uint32_t size = sizeof(path);
123 if(_NSGetExecutablePath(path, &size) !=0)
124 die(2, "unable to find executable path\n");
125 char * abs_exe = realpath(path, NULL);
127 die(2, "cannot resolve path (%s): %s\n", strerror(errno), path);
128 char * const abs_parent = strdup(dirname(abs_exe));
134 #elif defined(__FreeBSD__) || defined(__NetBSD__)
136 static char *exe_path ()
138 const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
140 int rc = sysctl (mib, 4, NULL, &path_len, NULL, 0);
141 if (rc != 0) die(2, "unable to determine executable path length\n");
142 char *path = malloc (path_len);
143 if (!path) die(2, "unable to allocate memory for executable path\n");
144 rc = sysctl (mib, 4, path, &path_len, NULL, 0);
145 if (rc != 0) die(2, "unable to determine executable path via sysctl\n");
149 static char *exe_parent_dir(const char * const argv_0)
151 char * const exe = exe_path();
152 if (!exe) die(2, "unable to determine executable path\n");
153 char * const parent = strdup(dirname(exe));
154 if (!parent) die(2, "unable to determine parent directory of executable\n");
159 #else // not defined(__FreeBSD__) || defined(__NetBSD__)
161 /// Use /proc if possible, and if all else fails, search in the PATH
163 #if defined(__linux__)
164 # define PROC_SELF_EXE "/proc/self/exe"
165 #elif defined(__sun) || defined (sun)
166 # define PROC_SELF_EXE "/proc/self/path/a.out"
168 # define PROC_SELF_EXE NULL
171 static char *find_in_path(const char * const name, const char * const path)
174 char *tmp_path = strdup(path);
177 char *tok_path = tmp_path;
178 while ((elt = strtok(tok_path, ":")) != NULL) {
181 int rc = asprintf(&candidate, "%s/%s", elt, name);
184 rc = stat(candidate, &st);
187 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
191 die(2, "cannot stat %s: %s\n", candidate, strerror(errno));
194 } else if (S_ISREG(st.st_mode)) {
195 if (access(candidate, X_OK) == 0) {
200 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
204 die(2, "cannot determine executability of %s: %s\n",
205 candidate, strerror(errno));
215 static char *find_exe_parent(const char * const argv_0)
217 char *candidate = NULL;
218 const char * const slash = index(argv_0, '/');
220 candidate = strdup(argv_0);
223 const char * const env_path = getenv("PATH");
225 die(2, "no PATH and executable isn't relative or absolute: %s\n",
227 char *path_exe = find_in_path(argv_0, env_path);
229 char * abs_exe = realpath(path_exe, NULL);
231 die(2, "cannot resolve path (%s): %s\n",
232 strerror(errno), path_exe);
240 char * const abs_exe = realpath(candidate, NULL);
242 die(2, "cannot resolve path (%s): %s\n", strerror(errno), candidate);
244 char * const abs_parent = strdup(dirname(abs_exe));
250 static char *exe_parent_dir(const char * const argv_0)
252 if (PROC_SELF_EXE != NULL) {
253 char path[4096]; // FIXME
254 int len = readlink(PROC_SELF_EXE, path, sizeof(path));
255 if (len == sizeof(path))
256 die(2, "unable to resolve symlink %s: %s\n",
257 PROC_SELF_EXE, strerror(errno));
260 return strdup(dirname(path));
263 case ENOENT: case EACCES: case EINVAL: case ELOOP: case ENOTDIR:
267 die(2, "cannot resolve %s: %s\n", path, strerror(errno));
271 return find_exe_parent(argv_0);
274 #endif // use /proc if possible, and if all else fails, search in the PATh
277 setenv_or_die(const char *name, const char *value)
279 int rc = setenv(name, value, 1);
281 die(2, "setenv %s=%s failed (%s)\n", name, value, strerror(errno));
285 prepend_lib_to_pythonpath(const char * const exec_path,
286 const char * const relative_path)
288 char *parent = exe_parent_dir(exec_path);
291 int rc = asprintf(&bupmodpath, "%s/%s", parent, relative_path);
294 rc = stat(bupmodpath, &st);
296 die(2, "unable find lib dir (%s): %s\n", strerror(errno), bupmodpath);
297 if (!S_ISDIR(st.st_mode))
298 die(2, "lib path is not dir: %s\n", bupmodpath);
299 char *curpypath = getenv("PYTHONPATH");
302 int rc = asprintf(&path, "%s:%s", bupmodpath, curpypath);
304 setenv_or_die("PYTHONPATH", path);
307 setenv_or_die("PYTHONPATH", bupmodpath);
314 #if PY_MAJOR_VERSION > 2
315 #define bup_py_main Py_BytesMain
317 #define bup_py_main Py_Main
320 #if defined(BUP_DEV_BUP_PYTHON) && defined(BUP_DEV_BUP_EXEC)
321 # error "Both BUP_DEV_BUP_PYTHON and BUP_DEV_BUP_EXEC are defined"
324 #ifdef BUP_DEV_BUP_PYTHON
326 int main(int argc, char **argv)
330 setup_bup_main_module();
331 prepend_lib_to_pythonpath(argv[0], "../lib");
332 return bup_py_main (argc, argv);
335 #elif defined(BUP_DEV_BUP_EXEC)
337 int main(int argc, char **argv)
339 prog_argc = argc - 1;
340 prog_argv = argv + 1;
341 setup_bup_main_module();
342 prepend_lib_to_pythonpath(argv[0], "../lib");
344 return bup_py_main (1, argv);
345 // This can't handle a script with a name like "-c", but that's
346 // python's problem, not ours.
347 return bup_py_main (2, argv);
350 #else // normal bup command
352 int main(int argc, char **argv)
356 setup_bup_main_module();
357 prepend_lib_to_pythonpath(argv[0], "..");
358 char *bup_argv[] = { argv[0], "-m", "bup.main" };
359 return bup_py_main (3, bup_argv);
362 #endif // normal bup command