]> arthur.barton.de Git - bup.git/blob - lib/cmd/bup.c
0d002a91c8bee8fea55d71179e0ff5861aa799dc
[bup.git] / lib / cmd / bup.c
1
2 #define PY_SSIZE_T_CLEAN
3 #define _GNU_SOURCE  1 // asprintf
4 #undef NDEBUG
5
6 // According to Python, its header has to go first:
7 //   http://docs.python.org/3/c-api/intro.html#include-files
8 #include <Python.h>
9
10 #include <libgen.h>
11 #include <limits.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 #if defined(__FreeBSD__) || defined(__NetBSD__)
18 # include <sys/sysctl.h>
19 #endif
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #include "bup/compat.h"
24 #include "bup/intprops.h"
25 #include "bup/io.h"
26
27 static int prog_argc = 0;
28 static char **prog_argv = NULL;
29 static char *orig_env_pythonpath = NULL;
30
31 static PyObject*
32 get_argv(PyObject *self, PyObject *args)
33 {
34     if (!PyArg_ParseTuple(args, ""))
35         return NULL;
36
37     PyObject *result = PyList_New(prog_argc);
38     int i;
39     for (i = 0; i < prog_argc; i++) {
40         PyObject *s = PyBytes_FromString(prog_argv[i]);
41         if (!s)
42             die(2, "cannot convert argument to bytes: %s\n", prog_argv[i]);
43         PyList_SET_ITEM(result, i, s);
44     }
45     return result;
46 }
47
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." },
51     {NULL, NULL, 0, NULL}
52 };
53
54 static int setup_module(PyObject *mod)
55 {
56     if (!orig_env_pythonpath) {
57         PyObject_SetAttrString(mod, "env_pythonpath", Py_None);
58     } else {
59         PyObject *py_p = PyBytes_FromString(orig_env_pythonpath);
60         if (!py_p)
61             die(2, "cannot convert PYTHONPATH to bytes: %s\n",
62                 orig_env_pythonpath);
63         PyObject_SetAttrString(mod, "env_pythonpath", py_p);
64         Py_DECREF(py_p);
65     }
66     return 1;
67 }
68
69 static struct PyModuleDef bup_main_module_def = {
70     .m_base = PyModuleDef_HEAD_INIT,
71     .m_name = "bup_main",
72     .m_doc = "Built-in bup module providing direct access to argv.",
73     .m_size = -1,
74     .m_methods = bup_main_methods
75 };
76
77 PyObject *
78 PyInit_bup_main(void) {
79     PyObject *mod =  PyModule_Create(&bup_main_module_def);
80     if (!setup_module(mod))
81     {
82         Py_DECREF(mod);
83         return NULL;
84     }
85     return mod;
86 }
87
88 static void
89 setup_bup_main_module(void) {
90
91     char *path = getenv("PYTHONPATH");
92     if (path)
93         orig_env_pythonpath = strdup(path);
94
95     if (PyImport_AppendInittab("bup_main", PyInit_bup_main) == -1)
96         die(2, "unable to register bup_main module\n");
97 }
98
99 /*
100  * Older realpath implementations (e.g. 4.4BSD) required the second
101  * argument to be non-NULL, and then POSIX added the option of NULL
102  * with the semantics of malloc'ing a big-enough buffer.  Define a
103  * helper function with the NULL semantics to accomodate older
104  * platforms.
105  *
106  * gnulib has a list of systems that are known to reject NULL as the
107  * 2nd argument:
108  *   https://www.gnu.org/software/gnulib/manual/html_node/realpath.html
109  */
110
111 #define BUP_HAVE_POSIX_REALPATH
112
113 // FreeBSD < 7: bup's FreeBSD code does not use realpath(3)
114 #if defined(__NetBSD__)
115 #  if !__NetBSD_Prereq__(7,0,0)
116 #    undef BUP_HAVE_POSIX_REALPATH
117 #  endif
118 // OpenBSD: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/sys/param.h.diff?r1=1.91&r2=1.92&f=h
119 #elif defined(__OpenBSD__) && __OpenBSD__ < 201111
120 #  undef BUP_HAVE_POSIX_REALPATH
121 #endif
122
123 char *
124 bup_realpath(const char *pathname)
125 {
126 #ifdef BUP_HAVE_POSIX_REALPATH
127     return realpath(pathname, NULL);
128 #else
129     char resolvedname[PATH_MAX];
130     char *ret = realpath(pathname, resolvedname);
131     if (ret != NULL) {
132         assert(ret == resolvedname);
133         ret = strdup(ret);
134     }
135     return ret;
136 #endif
137 }
138
139 #if defined(__APPLE__) && defined(__MACH__)
140
141 static char *exe_parent_dir(const char * const argv_0) {
142     char *mpath = NULL;
143     char spath[2048];
144     uint32_t size = sizeof(spath);
145     int rc = _NSGetExecutablePath(spath, &size);
146     if (rc == -1) {
147         mpath = malloc(size);
148         if (!mpath) die(2, "unable to allocate memory for executable path\n");
149         rc = _NSGetExecutablePath(mpath, &size);
150     }
151     if(rc != 0) die(2, "unable to find executable path\n");
152     char *path = mpath ? mpath : spath;
153     char *abs_exe = bup_realpath(path);
154     if (!abs_exe)
155         die(2, "cannot resolve path (%s): %s\n", strerror(errno), path);
156     char * const abs_parent = strdup(dirname(abs_exe));
157     assert(abs_parent);
158     if (mpath) free(mpath);
159     free(abs_exe);
160     return abs_parent;
161 }
162
163 #elif defined(__FreeBSD__)
164
165 static char *exe_path ()
166 {
167     const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
168     size_t path_len;
169     int rc = sysctl (mib, 4, NULL, &path_len, NULL, 0);
170     if (rc != 0) die(2, "unable to determine executable path length\n");
171     char *path = malloc (path_len);
172     if (!path) die(2, "unable to allocate memory for executable path\n");
173     rc = sysctl (mib, 4, path, &path_len, NULL, 0);
174     if (rc != 0) die(2, "unable to determine executable path via sysctl\n");
175     return path;
176 }
177
178 static char *exe_parent_dir(const char * const argv_0)
179 {
180     char * const exe = exe_path();
181     if (!exe) die(2, "unable to determine executable path\n");
182     char * const parent = strdup(dirname(exe));
183     if (!parent) die(2, "unable to determine parent directory of executable\n");
184     free(exe);
185     return parent;
186 }
187
188 #else // not defined(__FreeBSD__)
189
190 /// Use /proc if possible, and if all else fails, search in the PATH
191
192 #if defined(__linux__)
193 # define PROC_SELF_EXE "/proc/self/exe"
194 #elif defined(__sun) || defined (sun)
195 # define PROC_SELF_EXE "/proc/self/path/a.out"
196 #else
197 # define PROC_SELF_EXE NULL
198 #endif
199
200 static char *find_in_path(const char * const name, const char * const path)
201 {
202     char *result = NULL;
203     char *tmp_path = strdup(path);
204     assert(tmp_path);
205     const char *elt;
206     char *tok_path = tmp_path;
207     while ((elt = strtok(tok_path, ":")) != NULL) {
208         tok_path = NULL;
209         char *candidate;
210         int rc = asprintf(&candidate, "%s/%s", elt, name);
211         assert(rc >= 0);
212         struct stat st;
213         rc = stat(candidate, &st);
214         if (rc != 0) {
215             switch (errno) {
216                 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
217                 case ENOTDIR:
218                     break;
219                 default:
220                     die(2, "cannot stat %s: %s\n", candidate, strerror(errno));
221                     break;
222             }
223         } else if (S_ISREG(st.st_mode)) {
224             if (access(candidate, X_OK) == 0) {
225                 result = candidate;
226                 break;
227             }
228             switch (errno) {
229                 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
230                 case ENOTDIR:
231                     break;
232                 default:
233                     die(2, "cannot determine executability of %s: %s\n",
234                         candidate, strerror(errno));
235                     break;
236             }
237         }
238         free(candidate);
239     }
240     free(tmp_path);
241     return result;
242 }
243
244 static char *find_exe_parent(const char * const argv_0)
245 {
246     char *candidate = NULL;
247     const char * const slash = strchr(argv_0, '/');
248     if (slash) {
249         candidate = strdup(argv_0);
250         assert(candidate);
251     } else {
252         const char * const env_path = getenv("PATH");
253         if (!env_path)
254             die(2, "no PATH and executable isn't relative or absolute: %s\n",
255                 argv_0);
256         char *path_exe = find_in_path(argv_0, env_path);
257         if (path_exe) {
258             char * abs_exe = bup_realpath(path_exe);
259             if (!abs_exe)
260                 die(2, "cannot resolve path (%s): %s\n",
261                     strerror(errno), path_exe);
262             free(path_exe);
263             candidate = abs_exe;
264         }
265     }
266     if (!candidate)
267         return NULL;
268
269     char * const abs_exe = bup_realpath(candidate);
270     if (!abs_exe)
271         die(2, "cannot resolve path (%s): %s\n", strerror(errno), candidate);
272     free(candidate);
273     char * const abs_parent = strdup(dirname(abs_exe));
274     assert(abs_parent);
275     free(abs_exe);
276     return abs_parent;
277 }
278
279 static char *exe_parent_dir(const char * const argv_0)
280 {
281     if (PROC_SELF_EXE != NULL) {
282         char sbuf[2048];
283         char *path = sbuf;
284         size_t path_n = sizeof(sbuf);
285         ssize_t len;
286         while (1) {
287             len = readlink(PROC_SELF_EXE, path, path_n);
288             if (len == -1 || (size_t) len != path_n)
289                 break;
290             if (!INT_MULTIPLY_OK(path_n, 2, &path_n))
291                 die(2, "memory buffer for executable path would be too big\n");
292             if (path != sbuf) free(path);
293             path = malloc(path_n);
294             if (!path)
295                 die(2, "unable to allocate memory for executable path\n");
296         }
297         if (len != -1) {
298             path[len] = '\0';
299             char *result = strdup(dirname(path));
300             if (path != sbuf)
301                 free(path);
302             return result;
303         }
304         switch (errno) {
305         case ENOENT: case EACCES: case EINVAL: case ELOOP: case ENOTDIR:
306         case ENAMETOOLONG:
307             break;
308         default:
309             die(2, "cannot resolve %s: %s\n", path, strerror(errno));
310             break;
311         }
312         if (path != sbuf)
313             free(path);
314     }
315     return find_exe_parent(argv_0);
316 }
317
318 #endif // use /proc if possible, and if all else fails, search in the PATh
319
320 static void
321 setenv_or_die(const char *name, const char *value)
322 {
323     int rc = setenv(name, value, 1);
324     if (rc != 0)
325         die(2, "setenv %s=%s failed (%s)\n", name, value, strerror(errno));
326 }
327
328 static void
329 prepend_lib_to_pythonpath(const char * const exec_path,
330                           const char * const relative_path)
331 {
332     char *parent = exe_parent_dir(exec_path);
333     assert(parent);
334     char *bupmodpath;
335     int rc = asprintf(&bupmodpath, "%s/%s", parent, relative_path);
336     assert(rc >= 0);
337     struct stat st;
338     rc = stat(bupmodpath, &st);
339     if (rc != 0)
340         die(2, "unable find lib dir (%s): %s\n", strerror(errno), bupmodpath);
341     if (!S_ISDIR(st.st_mode))
342         die(2, "lib path is not dir: %s\n", bupmodpath);
343     char *curpypath = getenv("PYTHONPATH");
344     if (curpypath) {
345         char *path;
346         int rc = asprintf(&path, "%s:%s", bupmodpath, curpypath);
347         assert(rc >= 0);
348         setenv_or_die("PYTHONPATH", path);
349         free(path);
350     } else {
351         setenv_or_die("PYTHONPATH", bupmodpath);
352     }
353
354     free(bupmodpath);
355     free(parent);
356 }
357
358 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 8
359 # define bup_py_main bup_py_bytes_main
360 #else
361 # define bup_py_main Py_BytesMain
362 #endif
363
364 #if defined(BUP_DEV_BUP_PYTHON) && defined(BUP_DEV_BUP_EXEC)
365 # error "Both BUP_DEV_BUP_PYTHON and BUP_DEV_BUP_EXEC are defined"
366 #endif
367
368 #ifdef BUP_DEV_BUP_PYTHON
369
370 int main(int argc, char **argv)
371 {
372     assert(argc > 0);
373     prog_argc = argc;
374     prog_argv = argv;
375     setup_bup_main_module();
376     prepend_lib_to_pythonpath(argv[0], "../lib");
377     return bup_py_main (argc, argv);
378 }
379
380 #elif defined(BUP_DEV_BUP_EXEC)
381
382 int main(int argc, char **argv)
383 {
384     assert(argc > 0);
385     prog_argc = argc - 1;
386     prog_argv = argv + 1;
387     setup_bup_main_module();
388     prepend_lib_to_pythonpath(argv[0], "../lib");
389     if (argc == 1)
390         return bup_py_main (1, argv);
391     // This can't handle a script with a name like "-c", but that's
392     // python's problem, not ours.
393     return bup_py_main (2, argv);
394 }
395
396 #else // normal bup command
397
398 int main(int argc, char **argv)
399 {
400     assert(argc > 0);
401     prog_argc = argc;
402     prog_argv = argv;
403     setup_bup_main_module();
404     prepend_lib_to_pythonpath(argv[0], "..");
405     char *bup_argv[] = { argv[0], "-m", "bup.main" };
406     return bup_py_main (3, bup_argv);
407 }
408
409 #endif // normal bup command