]> arthur.barton.de Git - bup.git/blob - lib/cmd/bup.c
cmd/bup: add some missing safety checks
[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/2/c-api/intro.html#include-files
8 //   http://docs.python.org/3/c-api/intro.html#include-files
9 #include <Python.h>
10
11 #include <libgen.h>
12 #include <limits.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #if defined(__FreeBSD__) || defined(__NetBSD__)
19 # include <sys/sysctl.h>
20 #endif
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include "bup/compat.h"
25 #include "bup/intprops.h"
26 #include "bup/io.h"
27
28 static int prog_argc = 0;
29 static char **prog_argv = NULL;
30 static char *orig_env_pythonpath = NULL;
31
32 static PyObject*
33 get_argv(PyObject *self, PyObject *args)
34 {
35     if (!PyArg_ParseTuple(args, ""))
36         return NULL;
37
38     PyObject *result = PyList_New(prog_argc);
39     int i;
40     for (i = 0; i < prog_argc; i++) {
41         PyObject *s = PyBytes_FromString(prog_argv[i]);
42         if (!s)
43             die(2, "cannot convert argument to bytes: %s\n", prog_argv[i]);
44         PyList_SET_ITEM(result, i, s);
45     }
46     return result;
47 }
48
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." },
52     {NULL, NULL, 0, NULL}
53 };
54
55 static int setup_module(PyObject *mod)
56 {
57     if (!orig_env_pythonpath) {
58         PyObject_SetAttrString(mod, "env_pythonpath", Py_None);
59     } else {
60         PyObject *py_p = PyBytes_FromString(orig_env_pythonpath);
61         if (!py_p)
62             die(2, "cannot convert PYTHONPATH to bytes: %s\n",
63                 orig_env_pythonpath);
64         PyObject_SetAttrString(mod, "env_pythonpath", py_p);
65         Py_DECREF(py_p);
66     }
67     return 1;
68 }
69
70 #if PY_MAJOR_VERSION >= 3
71
72 static struct PyModuleDef bup_main_module_def = {
73     .m_base = PyModuleDef_HEAD_INIT,
74     .m_name = "bup_main",
75     .m_doc = "Built-in bup module providing direct access to argv.",
76     .m_size = -1,
77     .m_methods = bup_main_methods
78 };
79
80 PyObject *
81 PyInit_bup_main(void) {
82     PyObject *mod =  PyModule_Create(&bup_main_module_def);
83     if (!setup_module(mod))
84     {
85         Py_DECREF(mod);
86         return NULL;
87     }
88     return mod;
89 }
90
91 #else // PY_MAJOR_VERSION < 3
92
93 void PyInit_bup_main(void)
94 {
95     PyObject *mod = Py_InitModule("bup_main", bup_main_methods);
96     if (mod == NULL) {
97         PyErr_SetString(PyExc_RuntimeError, "bup._helpers init failed");
98         return;
99     }
100     if (!setup_module(mod))
101     {
102         PyErr_SetString(PyExc_RuntimeError, "bup._helpers set up failed");
103         Py_DECREF(mod);
104         return;
105     }
106 }
107
108 #endif // PY_MAJOR_VERSION < 3
109
110 static void
111 setup_bup_main_module(void) {
112
113     char *path = getenv("PYTHONPATH");
114     if (path)
115         orig_env_pythonpath = strdup(path);
116
117     if (PyImport_AppendInittab("bup_main", PyInit_bup_main) == -1)
118         die(2, "unable to register bup_main module\n");
119 }
120
121 #if defined(__APPLE__) && defined(__MACH__)
122
123 static char *exe_parent_dir(const char * const argv_0) {
124     char *mpath = NULL;
125     char spath[2048];
126     uint32_t size = sizeof(spath);
127     int rc = _NSGetExecutablePath(spath, &size);
128     if (rc == -1) {
129         mpath = malloc(size);
130         if (!mpath) die(2, "unable to allocate memory for executable path\n");
131         rc = _NSGetExecutablePath(mpath, &size);
132     }
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);
136     if (!abs_exe)
137         die(2, "cannot resolve path (%s): %s\n", strerror(errno), path);
138     char * const abs_parent = strdup(dirname(abs_exe));
139     assert(abs_parent);
140     if (mpath) free(mpath);
141     free(abs_exe);
142     return abs_parent;
143 }
144
145 #elif defined(__FreeBSD__) || defined(__NetBSD__)
146
147 static char *exe_path ()
148 {
149     const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
150     size_t path_len;
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");
157     return path;
158 }
159
160 static char *exe_parent_dir(const char * const argv_0)
161 {
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");
166     free(exe);
167     return parent;
168 }
169
170 #else // not defined(__FreeBSD__) || defined(__NetBSD__)
171
172 /// Use /proc if possible, and if all else fails, search in the PATH
173
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"
178 #else
179 # define PROC_SELF_EXE NULL
180 #endif
181
182 static char *find_in_path(const char * const name, const char * const path)
183 {
184     char *result = NULL;
185     char *tmp_path = strdup(path);
186     assert(tmp_path);
187     const char *elt;
188     char *tok_path = tmp_path;
189     while ((elt = strtok(tok_path, ":")) != NULL) {
190         tok_path = NULL;
191         char *candidate;
192         int rc = asprintf(&candidate, "%s/%s", elt, name);
193         assert(rc >= 0);
194         struct stat st;
195         rc = stat(candidate, &st);
196         if (rc != 0) {
197             switch (errno) {
198                 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
199                 case ENOTDIR:
200                     break;
201                 default:
202                     die(2, "cannot stat %s: %s\n", candidate, strerror(errno));
203                     break;
204             }
205         } else if (S_ISREG(st.st_mode)) {
206             if (access(candidate, X_OK) == 0) {
207                 result = candidate;
208                 break;
209             }
210             switch (errno) {
211                 case EACCES: case ELOOP: case ENOENT: case ENAMETOOLONG:
212                 case ENOTDIR:
213                     break;
214                 default:
215                     die(2, "cannot determine executability of %s: %s\n",
216                         candidate, strerror(errno));
217                     break;
218             }
219         }
220         free(candidate);
221     }
222     free(tmp_path);
223     return result;
224 }
225
226 static char *find_exe_parent(const char * const argv_0)
227 {
228     char *candidate = NULL;
229     const char * const slash = index(argv_0, '/');
230     if (slash) {
231         candidate = strdup(argv_0);
232         assert(candidate);
233     } else {
234         const char * const env_path = getenv("PATH");
235         if (!env_path)
236             die(2, "no PATH and executable isn't relative or absolute: %s\n",
237                 argv_0);
238         char *path_exe = find_in_path(argv_0, env_path);
239         if (path_exe) {
240             char * abs_exe = realpath(path_exe, NULL);
241             if (!abs_exe)
242                 die(2, "cannot resolve path (%s): %s\n",
243                     strerror(errno), path_exe);
244             free(path_exe);
245             candidate = abs_exe;
246         }
247     }
248     if (!candidate)
249         return NULL;
250
251     char * const abs_exe = realpath(candidate, NULL);
252     if (!abs_exe)
253         die(2, "cannot resolve path (%s): %s\n", strerror(errno), candidate);
254     free(candidate);
255     char * const abs_parent = strdup(dirname(abs_exe));
256     assert(abs_parent);
257     free(abs_exe);
258     return abs_parent;
259 }
260
261 static char *exe_parent_dir(const char * const argv_0)
262 {
263     if (PROC_SELF_EXE != NULL) {
264         char sbuf[2048];
265         char *path = sbuf;
266         size_t path_n = sizeof(sbuf);
267         ssize_t len;
268         while (1) {
269             len = readlink(PROC_SELF_EXE, path, path_n);
270             if (len == -1 || (size_t) len != path_n)
271                 break;
272             if (!INT_MULTIPLY_OK(path_n, 2, &path_n))
273                 die(2, "memory buffer for executable path would be too big\n");
274             path_n *= 2;
275             if (path != sbuf) free(path);
276             path = malloc(path_n);
277             if (!path)
278                 die(2, "unable to allocate memory for executable path\n");
279         }
280         if (len != -1) {
281             path[len] = '\0';
282             char *result = strdup(dirname(path));
283             if (path != sbuf)
284                 free(path);
285             return result;
286         }
287         switch (errno) {
288         case ENOENT: case EACCES: case EINVAL: case ELOOP: case ENOTDIR:
289         case ENAMETOOLONG:
290             break;
291         default:
292             die(2, "cannot resolve %s: %s\n", path, strerror(errno));
293             break;
294         }
295         if (path != sbuf)
296             free(path);
297     }
298     return find_exe_parent(argv_0);
299 }
300
301 #endif // use /proc if possible, and if all else fails, search in the PATh
302
303 static void
304 setenv_or_die(const char *name, const char *value)
305 {
306     int rc = setenv(name, value, 1);
307     if (rc != 0)
308         die(2, "setenv %s=%s failed (%s)\n", name, value, strerror(errno));
309 }
310
311 static void
312 prepend_lib_to_pythonpath(const char * const exec_path,
313                           const char * const relative_path)
314 {
315     char *parent = exe_parent_dir(exec_path);
316     assert(parent);
317     char *bupmodpath;
318     int rc = asprintf(&bupmodpath, "%s/%s", parent, relative_path);
319     assert(rc >= 0);
320     struct stat st;
321     rc = stat(bupmodpath, &st);
322     if (rc != 0)
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");
327     if (curpypath) {
328         char *path;
329         int rc = asprintf(&path, "%s:%s", bupmodpath, curpypath);
330         assert(rc >= 0);
331         setenv_or_die("PYTHONPATH", path);
332         free(path);
333     } else {
334         setenv_or_die("PYTHONPATH", bupmodpath);
335     }
336
337     free(bupmodpath);
338     free(parent);
339 }
340
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
345 #else
346 # define bup_py_main Py_Main
347 #endif
348
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"
351 #endif
352
353 #ifdef BUP_DEV_BUP_PYTHON
354
355 int main(int argc, char **argv)
356 {
357     prog_argc = argc;
358     prog_argv = argv;
359     setup_bup_main_module();
360     prepend_lib_to_pythonpath(argv[0], "../lib");
361     return bup_py_main (argc, argv);
362 }
363
364 #elif defined(BUP_DEV_BUP_EXEC)
365
366 int main(int argc, char **argv)
367 {
368     assert(argc > 0);
369     prog_argc = argc - 1;
370     prog_argv = argv + 1;
371     setup_bup_main_module();
372     prepend_lib_to_pythonpath(argv[0], "../lib");
373     if (argc == 1)
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);
378 }
379
380 #else // normal bup command
381
382 int main(int argc, char **argv)
383 {
384     prog_argc = argc;
385     prog_argv = 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);
390 }
391
392 #endif // normal bup command