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 __attribute__ ((format(printf, 2, 3)))
26 die(int exit_status, const char * const msg, ...)
28 if (fputs("bup: ", stderr) == EOF)
32 if (vfprintf(stderr, msg, ap) < 0)
38 static int prog_argc = 0;
39 static char **prog_argv = NULL;
40 static char *orig_env_pythonpath = NULL;
43 get_argv(PyObject *self, PyObject *args)
45 if (!PyArg_ParseTuple(args, ""))
48 PyObject *result = PyList_New(prog_argc);
49 for (int i = 0; i < prog_argc; i++) {
50 PyObject *s = PyBytes_FromString(prog_argv[i]);
52 die(2, "cannot convert argument to bytes: %s\n", prog_argv[i]);
53 PyList_SET_ITEM(result, i, s);
58 static PyMethodDef bup_main_methods[] = {
59 {"argv", get_argv, METH_VARARGS,
60 "Return the program's current argv array as a list of byte strings." },
64 static int setup_module(PyObject *mod)
66 if (!orig_env_pythonpath) {
67 PyObject_SetAttrString(mod, "env_pythonpath", Py_None);
69 PyObject *py_p = PyBytes_FromString(orig_env_pythonpath);
71 die(2, "cannot convert PYTHONPATH to bytes: %s\n",
73 PyObject_SetAttrString(mod, "env_pythonpath", py_p);
79 #if PY_MAJOR_VERSION >= 3
81 static struct PyModuleDef bup_main_module_def = {
82 .m_base = PyModuleDef_HEAD_INIT,
84 .m_doc = "Built-in bup module providing direct access to argv.",
86 .m_methods = bup_main_methods
90 PyInit_bup_main(void) {
91 PyObject *mod = PyModule_Create(&bup_main_module_def);
92 if (!setup_module(mod))
100 #else // PY_MAJOR_VERSION < 3
102 void PyInit_bup_main(void)
104 PyObject *mod = Py_InitModule("bup_main", bup_main_methods);
106 PyErr_SetString(PyExc_RuntimeError, "bup._helpers init failed");
109 if (!setup_module(mod))
111 PyErr_SetString(PyExc_RuntimeError, "bup._helpers set up failed");
117 #endif // PY_MAJOR_VERSION < 3
120 setup_bup_main_module(void) {
122 char *path = getenv("PYTHONPATH");
124 orig_env_pythonpath = strdup(path);
126 if (PyImport_AppendInittab("bup_main", PyInit_bup_main) == -1)
127 die(2, "unable to register bup_main module\n");
130 #if defined(__APPLE__) && defined(__MACH__)
132 static char *exe_parent_dir(const char * const argv_0) {
133 char path[4096]; // FIXME
134 uint32_t size = sizeof(path);
135 if(_NSGetExecutablePath(path, &size) !=0)
136 die(2, "unable to find executable path\n");
137 char * abs_exe = realpath(path, NULL);
139 die(2, "cannot resolve path (%s): %s\n", strerror(errno), path);
140 char * const abs_parent = strdup(dirname(abs_exe));
146 #elif defined(__FreeBSD__) || defined(__NetBSD__)
148 static char *exe_path ()
150 const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
152 int rc = sysctl (mib, 4, NULL, &path_len, NULL, 0);
153 if (rc != 0) die(2, "unable to determine executable path length\n");
154 char *path = malloc (path_len);
155 if (!path) die(2, "unable to allocate memory for executable path\n");
156 rc = sysctl (mib, 4, path, &path_len, NULL, 0);
157 if (rc != 0) die(2, "unable to determine executable path via sysctl\n");
161 static char *exe_parent_dir(const char * const argv_0)
163 char * const exe = exe_path();
164 if (!exe) die(2, "unable to determine executable path\n");
165 char * const parent = strdup(dirname(exe));
166 if (!parent) die(2, "unable to determine parent directory of executable\n");
171 #else // not defined(__FreeBSD__) || defined(__NetBSD__)
173 /// Use /proc if possible, and if all else fails, search in the PATH
175 #if defined(__linux__)
176 # define PROC_SELF_EXE "/proc/self/exe"
177 #elif defined(__sun) || defined (sun)
178 # define PROC_SELF_EXE "/proc/self/path/a.out"
180 # define PROC_SELF_EXE NULL
183 static char *find_in_path(const char * const name, const char * const path)
186 char *tmp_path = strdup(path);
189 char *tok_path = tmp_path;
190 while ((elt = strtok(tok_path, ":")) != NULL) {
193 int rc = asprintf(&candidate, "%s/%s", elt, name);
196 rc = stat(candidate, &st);
199 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
203 die(2, "cannot stat %s: %s\n", candidate, strerror(errno));
206 } else if (S_ISREG(st.st_mode)) {
207 if (access(candidate, X_OK) == 0) {
212 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
216 die(2, "cannot determine executability of %s: %s\n",
217 candidate, strerror(errno));
227 static char *find_exe_parent(const char * const argv_0)
229 char *candidate = NULL;
230 const char * const slash = index(argv_0, '/');
232 candidate = strdup(argv_0);
235 const char * const env_path = getenv("PATH");
237 die(2, "no PATH and executable isn't relative or absolute: %s\n",
239 char *path_exe = find_in_path(argv_0, env_path);
241 char * abs_exe = realpath(path_exe, NULL);
243 die(2, "cannot resolve path (%s): %s\n",
244 strerror(errno), path_exe);
252 char * const abs_exe = realpath(candidate, NULL);
254 die(2, "cannot resolve path (%s): %s\n", strerror(errno), candidate);
256 char * const abs_parent = strdup(dirname(abs_exe));
262 static char *exe_parent_dir(const char * const argv_0)
264 if (PROC_SELF_EXE != NULL) {
265 char path[4096]; // FIXME
266 int len = readlink(PROC_SELF_EXE, path, sizeof(path));
267 if (len == sizeof(path))
268 die(2, "unable to resolve symlink %s: %s\n",
269 PROC_SELF_EXE, strerror(errno));
272 return strdup(dirname(path));
275 case ENOENT: case EACCES: case EINVAL: case ELOOP: case ENOTDIR:
279 die(2, "cannot resolve %s: %s\n", path, strerror(errno));
283 return find_exe_parent(argv_0);
286 #endif // use /proc if possible, and if all else fails, search in the PATh
289 setenv_or_die(const char *name, const char *value)
291 int rc = setenv(name, value, 1);
293 die(2, "setenv %s=%s failed (%s)\n", name, value, strerror(errno));
297 prepend_lib_to_pythonpath(const char * const exec_path,
298 const char * const relative_path)
300 char *parent = exe_parent_dir(exec_path);
303 int rc = asprintf(&bupmodpath, "%s/%s", parent, relative_path);
306 rc = stat(bupmodpath, &st);
308 die(2, "unable find lib dir (%s): %s\n", strerror(errno), bupmodpath);
309 if (!S_ISDIR(st.st_mode))
310 die(2, "lib path is not dir: %s\n", bupmodpath);
311 char *curpypath = getenv("PYTHONPATH");
314 int rc = asprintf(&path, "%s:%s", bupmodpath, curpypath);
316 setenv_or_die("PYTHONPATH", path);
319 setenv_or_die("PYTHONPATH", bupmodpath);
326 #if PY_MAJOR_VERSION > 2
327 #define bup_py_main Py_BytesMain
329 #define bup_py_main Py_Main
332 #if defined(BUP_DEV_BUP_PYTHON) && defined(BUP_DEV_BUP_EXEC)
333 # error "Both BUP_DEV_BUP_PYTHON and BUP_DEV_BUP_EXEC are defined"
336 #ifdef BUP_DEV_BUP_PYTHON
338 int main(int argc, char **argv)
342 setup_bup_main_module();
343 prepend_lib_to_pythonpath(argv[0], "../lib");
344 return bup_py_main (argc, argv);
347 #elif defined(BUP_DEV_BUP_EXEC)
349 int main(int argc, char **argv)
351 prog_argc = argc - 1;
352 prog_argv = argv + 1;
353 setup_bup_main_module();
354 prepend_lib_to_pythonpath(argv[0], "../lib");
356 return bup_py_main (1, argv);
357 // This can't handle a script with a name like "-c", but that's
358 // python's problem, not ours.
359 return bup_py_main (2, argv);
362 #else // normal bup command
364 int main(int argc, char **argv)
368 setup_bup_main_module();
369 prepend_lib_to_pythonpath(argv[0], "..");
370 char *bup_argv[] = { argv[0], "-m", "bup.main" };
371 return bup_py_main (3, bup_argv);
374 #endif // normal bup command