]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/_pakfire/pakfire.c
jail: Add new way to communicate with child processes
[people/ms/pakfire.git] / src / _pakfire / pakfire.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2017 Pakfire development team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #define PY_SSIZE_T_CLEAN
22 #include <Python.h>
23 #include <errno.h>
24
25 #include <pakfire/archive.h>
26 #include <pakfire/build.h>
27 #include <pakfire/constants.h>
28 #include <pakfire/dist.h>
29 #include <pakfire/jail.h>
30 #include <pakfire/logging.h>
31 #include <pakfire/mount.h>
32 #include <pakfire/packagelist.h>
33 #include <pakfire/pakfire.h>
34 #include <pakfire/key.h>
35 #include <pakfire/repo.h>
36 #include <pakfire/repolist.h>
37 #include <pakfire/request.h>
38 #include <pakfire/transaction.h>
39 #include <pakfire/util.h>
40
41 #include "archive.h"
42 #include "errors.h"
43 #include "key.h"
44 #include "pakfire.h"
45 #include "repo.h"
46 #include "util.h"
47
48 static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
49 PakfireObject* self = (PakfireObject *)type->tp_alloc(type, 0);
50 if (self) {
51 self->pakfire = NULL;
52
53 // Callbacks
54 self->callbacks.log = NULL;
55 self->callbacks.confirm = NULL;
56 }
57
58 return (PyObject *)self;
59 }
60
61 static void Pakfire_log_callback(void* data, int priority, const char* file, int line,
62 const char* fn, const char* format, va_list args) {
63 PyObject* callback = (PyObject*)data;
64 PyObject* exception = NULL;
65
66 // Do nothing if callback isn't set
67 if (!callback)
68 return;
69
70 // Translate priority to Python logging priorities
71 switch (priority) {
72 case LOG_DEBUG:
73 priority = 10;
74 break;
75
76 case LOG_INFO:
77 priority = 20;
78 break;
79
80 case LOG_ERR:
81 priority = 40;
82 break;
83
84 // Drop messages of an unknown priority
85 default:
86 return;
87 }
88
89 PyObject* tuple = NULL;
90 PyObject* result = NULL;
91 char* buffer = NULL;
92
93 // Make line
94 int r = vasprintf(&buffer, format, args);
95 if (r < 0)
96 goto ERROR;
97
98 // Build a tuple with the priority and the log message
99 tuple = Py_BuildValue("(is)", priority, buffer);
100 if (!tuple)
101 goto ERROR;
102
103 // Call the callback
104 result = PyObject_CallObject(callback, tuple);
105
106 ERROR:
107 /*
108 We cannot really catch any Python errors here, since we cannot send
109 any error codes up the chain.
110
111 So, in order to debug the problem, We will check if an exception has
112 occurred and if so, print it to the console.
113 */
114 exception = PyErr_Occurred();
115 if (exception)
116 PyErr_Print();
117
118 if (buffer)
119 free(buffer);
120 Py_XDECREF(tuple);
121 Py_XDECREF(result);
122 }
123
124 static int Pakfire_confirm_callback(struct pakfire* pakfire, void* data,
125 const char* message, const char* question) {
126 PyObject* callback = (PyObject*)data;
127 int r = 0;
128
129 // Do nothing if callback isn't set
130 if (!callback)
131 return 0;
132
133 PyObject* args = Py_BuildValue("(ss)", message, question);
134 if (!args)
135 return -1;
136
137 PyObject* result = PyObject_CallObject(callback, args);
138
139 // If the callback raised an exception, we will ignore it and indicate
140 // that an error happened, but we cannot re-raise the exception
141 if (!result) {
142 r = -1;
143 goto ERROR;
144 }
145
146 // Set the return code
147 if (result == Py_True)
148 r = 0;
149 else
150 r = 1;
151
152 ERROR:
153 Py_DECREF(args);
154 Py_DECREF(result);
155
156 return r;
157 }
158
159 static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
160 char* kwlist[] = {
161 "path",
162 "arch",
163 "logger",
164 "offline",
165 "conf",
166 "confirm_callback",
167 NULL,
168 };
169 const char* path = NULL;
170 const char* arch = NULL;
171 const char* conf = NULL;
172 int offline = 0;
173
174 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOpzO", kwlist,
175 &path, &arch, &self->callbacks.log, &offline, &conf, &self->callbacks.confirm))
176 return -1;
177
178 // Check if log callback is callable
179 if (self->callbacks.log && !PyCallable_Check(self->callbacks.log)) {
180 PyErr_SetString(PyExc_TypeError, "logger must be callable\n");
181 return -1;
182 }
183
184 // Check if confirm callback is callable
185 if (self->callbacks.confirm && !PyCallable_Check(self->callbacks.confirm)) {
186 PyErr_SetString(PyExc_TypeError, "Confirm callback is not callable");
187 return -1;
188 }
189
190 int flags = 0;
191
192 // Enable offline mode
193 if (offline)
194 flags |= PAKFIRE_FLAGS_OFFLINE;
195
196 // Configure callbacks
197 if (self->callbacks.log)
198 Py_INCREF(self->callbacks.log);
199
200 // Create a new Pakfire instance
201 int r = pakfire_create(&self->pakfire, path, arch, conf, flags,
202 LOG_DEBUG, Pakfire_log_callback, self->callbacks.log);
203 if (r) {
204 switch (errno) {
205 // Invalid architecture or path
206 case EINVAL:
207 PyErr_SetString(PyExc_ValueError, "Invalid architecture or path");
208 break;
209
210 // Anything else
211 default:
212 PyErr_SetFromErrno(PyExc_OSError);
213 }
214
215 return -1;
216 }
217
218 // Configure confirm callback
219 if (self->callbacks.confirm) {
220 pakfire_set_confirm_callback(self->pakfire,
221 Pakfire_confirm_callback, self->callbacks.confirm);
222
223 Py_INCREF(self->callbacks.confirm);
224 }
225
226 return 0;
227 }
228
229 static void Pakfire_dealloc(PakfireObject* self) {
230 if (self->pakfire) {
231 // Reset log callback
232 if (self->callbacks.log) {
233 pakfire_set_log_callback(self->pakfire, NULL, NULL);
234 Py_DECREF(self->callbacks.log);
235 }
236
237 // Reset confirm callback
238 if (self->callbacks.confirm) {
239 pakfire_set_confirm_callback(self->pakfire, NULL, NULL);
240 Py_DECREF(self->callbacks.confirm);
241 }
242
243 pakfire_unref(self->pakfire);
244 }
245
246 Py_TYPE(self)->tp_free((PyObject *)self);
247 }
248
249 static PyObject* Pakfire_repr(PakfireObject* self) {
250 const char* path = pakfire_get_path(self->pakfire);
251 const char* arch = pakfire_get_arch(self->pakfire);
252
253 return PyUnicode_FromFormat("<_pakfire.Pakfire %s (%s)>", path, arch);
254 }
255
256 static PyObject* Pakfire_get_path(PakfireObject* self) {
257 const char* path = pakfire_get_path(self->pakfire);
258
259 return PyUnicode_FromString(path);
260 }
261
262 static PyObject* Pakfire_get_arch(PakfireObject* self) {
263 const char* arch = pakfire_get_arch(self->pakfire);
264
265 return PyUnicode_FromString(arch);
266 }
267
268 static PyObject* Pakfire_get_repo(PakfireObject* self, PyObject* args) {
269 const char* name = NULL;
270
271 if (!PyArg_ParseTuple(args, "s", &name))
272 return NULL;
273
274 struct pakfire_repo* repo = pakfire_get_repo(self->pakfire, name);
275 if (!repo)
276 Py_RETURN_NONE;
277
278 PyObject* obj = new_repo(&RepoType, repo);
279 pakfire_repo_unref(repo);
280
281 return obj;
282 }
283
284 static void Pakfire_status_callback(struct pakfire* pakfire, void* data,
285 int progress, const char* status) {
286 PyObject* callback = (PyObject*)data;
287
288 // Do not attempt to call nothing
289 if (!callback)
290 return;
291
292 // Compile arguments
293 PyObject* args = Py_BuildValue("(is)", progress, status);
294 if (!args)
295 return;
296
297 // Call the callback
298 PyObject* result = PyObject_CallObject(callback, args);
299
300 Py_XDECREF(result);
301 Py_DECREF(args);
302 }
303
304 static int convert_packages(PyObject* object, void* address) {
305 char*** packages = (char***)address;
306
307 // Called for cleanup
308 if (!object)
309 goto ERROR;
310
311 // Nothing to do when object is None
312 if (object == Py_None)
313 return Py_CLEANUP_SUPPORTED;
314
315 if (!PySequence_Check(object)) {
316 PyErr_SetString(PyExc_ValueError, "Packages must be a sequence");
317 goto ERROR;
318 }
319
320 const unsigned int length = PySequence_Length(object);
321 if (!length)
322 return Py_CLEANUP_SUPPORTED;
323
324 // Allocate array
325 *packages = calloc(length + 1, sizeof(*packages));
326 if (!*packages) {
327 PyErr_SetFromErrno(PyExc_OSError);
328 goto ERROR;
329 }
330
331 for (unsigned int i = 0; i < length; i++) {
332 PyObject* item = PySequence_GetItem(object, i);
333
334 // Check if input is a string
335 if (!PyUnicode_Check(item)) {
336 Py_DECREF(item);
337
338 PyErr_SetString(PyExc_AttributeError, "Expected a string");
339 goto ERROR;
340 }
341
342 // Fetch string
343 const char* package = PyUnicode_AsUTF8(item);
344 if (!package) {
345 Py_DECREF(item);
346 goto ERROR;
347 }
348
349 // Add package to array
350 (*packages)[i] = strdup(package);
351 if (!(*packages)[i]) {
352 Py_DECREF(item);
353 goto ERROR;
354 }
355
356 Py_DECREF(item);
357 }
358
359 // Success
360 return Py_CLEANUP_SUPPORTED;
361
362 ERROR:
363 if (*packages) {
364 for (char** package = *packages; *package; package++)
365 free(*package);
366 free(*packages);
367 }
368
369 return 0;
370 }
371
372 static PyObject* Pakfire_install(PakfireObject* self, PyObject* args, PyObject* kwargs) {
373 char* kwlist[] = {
374 "packages",
375 "dryrun",
376 "without_recommended",
377 "allow_uninstall",
378 "allow_downgrade",
379 "status_callback",
380 NULL
381 };
382 char** packages = NULL;
383 int dryrun = 0;
384 int without_recommended = 0;
385 int allow_uninstall = 0;
386 int allow_downgrade = 0;
387 int solver_flags = 0;
388 int transaction_flags = 0;
389 PyObject* status_callback = NULL;
390
391 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$ppppO", kwlist,
392 convert_packages, &packages, &dryrun, &without_recommended, &allow_uninstall,
393 &allow_downgrade, &status_callback))
394 return NULL;
395
396 // Check if callback is callable
397 if (status_callback && !PyCallable_Check(status_callback)) {
398 PyErr_SetString(PyExc_TypeError, "status_callback must be callable");
399 return NULL;
400 }
401
402 // Enable dry-run mode
403 if (dryrun)
404 transaction_flags |= PAKFIRE_TRANSACTION_DRY_RUN;
405
406 // Do not install recommended packages
407 if (without_recommended)
408 solver_flags |= PAKFIRE_REQUEST_WITHOUT_RECOMMENDED;
409
410 // Can the solver uninstall packages?
411 if (allow_uninstall)
412 solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL;
413
414 // Can the solver downgrade packages?
415 if (allow_downgrade)
416 solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE;
417
418 // Run pakfire_install
419 int r = pakfire_install(self->pakfire, transaction_flags, solver_flags,
420 (const char**)packages, NULL, 0, NULL, Pakfire_status_callback, status_callback);
421 if (r)
422 PyErr_SetFromErrno(PyExc_OSError);
423
424 if (packages) {
425 for (char** package = packages; *package; package++)
426 free(*package);
427 free(packages);
428 }
429
430 if (r)
431 return NULL;
432
433 Py_RETURN_NONE;
434 }
435
436 static PyObject* Pakfire_erase(PakfireObject* self, PyObject* args, PyObject* kwargs) {
437 char* kwlist[] = {
438 "packages",
439 "dryrun",
440 "keep_dependencies",
441 "status_callback",
442 NULL
443 };
444 char** packages = NULL;
445 int dryrun = 0;
446 int keep_dependencies = 0;
447 int transaction_flags = 0;
448 int flags = 0;
449 PyObject* status_callback = NULL;
450
451 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$ppO", kwlist,
452 convert_packages, &packages, &dryrun, &keep_dependencies, &status_callback))
453 return NULL;
454
455 // Check if callback is callable
456 if (status_callback && !PyCallable_Check(status_callback)) {
457 PyErr_SetString(PyExc_TypeError, "status_callback must be callable");
458 return NULL;
459 }
460
461 if (dryrun)
462 transaction_flags |= PAKFIRE_TRANSACTION_DRY_RUN;
463
464 if (keep_dependencies)
465 flags |= PAKFIRE_REQUEST_KEEP_DEPS;
466
467 // Run pakfire_erase
468 int r = pakfire_erase(self->pakfire, transaction_flags, 0, (const char**)packages,
469 NULL, flags, NULL, Pakfire_status_callback, status_callback);
470 if (r)
471 PyErr_SetFromErrno(PyExc_OSError);
472
473 if (packages) {
474 for (char** package = packages; *package; package++)
475 free(*package);
476 free(packages);
477 }
478
479 if (r)
480 return NULL;
481
482 Py_RETURN_NONE;
483 }
484
485 static PyObject* Pakfire_update(PakfireObject* self, PyObject* args, PyObject* kwargs) {
486 char* kwlist[] = {
487 "packages",
488 "dryrun",
489 "excludes",
490 "allow_uninstall",
491 "allow_downgrade",
492 "status_callback",
493 NULL
494 };
495 char** packages = NULL;
496 char** excludes = NULL;
497 int dryrun = 0;
498 int allow_uninstall = 0;
499 int allow_downgrade = 0;
500 int solver_flags = 0;
501 int transaction_flags = 0;
502 PyObject* status_callback = NULL;
503
504 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$pO&ppO", kwlist,
505 convert_packages, &packages, &dryrun, convert_packages, &excludes,
506 &allow_uninstall, &allow_downgrade, &status_callback))
507 return NULL;
508
509 // Check if callback is callable
510 if (status_callback && !PyCallable_Check(status_callback)) {
511 PyErr_SetString(PyExc_TypeError, "status_callback must be callable");
512 return NULL;
513 }
514
515 if (dryrun)
516 transaction_flags = PAKFIRE_TRANSACTION_DRY_RUN;
517
518 // Can the solver uninstall packages?
519 if (allow_uninstall)
520 solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL;
521
522 // Can the solver downgrade packages?
523 if (allow_downgrade)
524 solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE;
525
526 // Run pakfire_update
527 int r = pakfire_update(self->pakfire, transaction_flags, solver_flags,
528 (const char**)packages, (const char**)excludes, 0, NULL,
529 Pakfire_status_callback, status_callback);
530 if (r)
531 PyErr_SetFromErrno(PyExc_OSError);
532
533 if (packages) {
534 for (char** package = packages; *package; package++)
535 free(*package);
536 free(packages);
537 }
538
539 if (excludes) {
540 for (char** exclude = excludes; *exclude; exclude++)
541 free(*exclude);
542 free(excludes);
543 }
544
545 if (r)
546 return NULL;
547
548 Py_RETURN_NONE;
549 }
550
551 static PyObject* Pakfire_keys_to_list(struct pakfire_key** keys) {
552 PyObject* list = PyList_New(0);
553
554 // Empty input?
555 if (!keys)
556 return list;
557
558 // Push all keys onto the list
559 for (struct pakfire_key** key = keys; *key; key++) {
560 PyObject* object = new_key(&KeyType, *key);
561 if (!object)
562 goto ERROR;
563
564 PyList_Append(list, object);
565 Py_DECREF(object);
566 }
567
568 return list;
569
570 ERROR:
571 Py_DECREF(list);
572 return NULL;
573 }
574
575 static PyObject* Pakfire_get_keys(PakfireObject* self) {
576 struct pakfire_key** keys = NULL;
577
578 int r = pakfire_list_keys(self->pakfire, &keys);
579 if (r) {
580 PyErr_SetFromErrno(PyExc_OSError);
581 return NULL;
582 }
583
584 // Convert keys to list
585 PyObject* list = Pakfire_keys_to_list(keys);
586
587 // Free keys
588 if (keys) {
589 for (struct pakfire_key** key = keys; *key; key++)
590 pakfire_key_unref(*key);
591 free(keys);
592 }
593
594 return list;
595 }
596
597 static PyObject* Pakfire_get_key(PakfireObject* self, PyObject* args) {
598 const char* pattern = NULL;
599
600 if (!PyArg_ParseTuple(args, "s", &pattern))
601 return NULL;
602
603 // Try finding the key
604 struct pakfire_key* key = pakfire_key_get(self->pakfire, pattern);
605 if (!key)
606 Py_RETURN_NONE;
607
608 PyObject* object = new_key(&KeyType, key);
609 pakfire_key_unref(key);
610
611 return object;
612 }
613
614 static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args, PyObject* kwds) {
615 char* kwlist[] = { "userid", "algorithm", NULL };
616 struct pakfire_key* key = NULL;
617 const char* userid = NULL;
618 const char* algo = NULL;
619
620 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$z", kwlist, &userid, &algo))
621 return NULL;
622
623 // Generate a new key
624 int r = pakfire_key_generate(&key, self->pakfire, algo, userid);
625 if (r) {
626 PyErr_SetFromErrno(PyExc_OSError);
627 return NULL;
628 }
629
630 PyObject* object = new_key(&KeyType, key);
631 pakfire_key_unref(key);
632
633 return object;
634 }
635
636 static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) {
637 PyObject* object = NULL;
638
639 if (!PyArg_ParseTuple(args, "O", &object))
640 return NULL;
641
642 // Get a file descriptor from object
643 int fd = PyObject_AsFileDescriptor(object);
644 if (fd < 0)
645 return NULL;
646
647 // Convert to FILE*
648 FILE* f = fdopen(fd, "r");
649 if (!f) {
650 PyErr_SetFromErrno(PyExc_OSError);
651 return NULL;
652 }
653
654 struct pakfire_key** keys = NULL;
655
656 // Import keys from f
657 int r = pakfire_key_import(self->pakfire, f, &keys);
658 if (r) {
659 PyErr_SetFromErrno(PyExc_OSError);
660 return NULL;
661 }
662
663 // Convert keys to list
664 PyObject* list = Pakfire_keys_to_list(keys);
665
666 // Free keys
667 for (struct pakfire_key** key = keys; *key; key++)
668 pakfire_key_unref(*key);
669 free(keys);
670
671 return list;
672 }
673
674 static PyObject* Pakfire_fetch_key(PakfireObject* self, PyObject* args, PyObject* kwds) {
675 char* kwlist[] = { "userid", "fingerprint", NULL };
676 struct pakfire_key* key = NULL;
677 const char* userid = NULL;
678 const char* fingerprint = NULL;
679
680 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$zz", kwlist, &userid, &fingerprint))
681 return NULL;
682
683 // Fetch the key
684 int r = pakfire_key_fetch(&key, self->pakfire, userid, fingerprint);
685 if (r) {
686 PyErr_SetFromErrno(PyExc_OSError);
687 return NULL;
688 }
689
690 // Return the result
691 if (key) {
692 PyObject* object = new_key(&KeyType, key);
693 pakfire_key_unref(key);
694
695 return object;
696 }
697
698 Py_RETURN_NONE;
699 }
700
701 static PyObject* Pakfire_whatprovides(PakfireObject* self, PyObject* args) {
702 const char* provides = NULL;
703 struct pakfire_packagelist* list = NULL;
704
705 if (!PyArg_ParseTuple(args, "s", &provides))
706 return NULL;
707
708 int r = pakfire_whatprovides(self->pakfire, provides, 0, &list);
709 if (r) {
710 PyErr_SetFromErrno(PyExc_OSError);
711 return NULL;
712 }
713
714 PyObject* obj = PyList_FromPackageList(list);
715 pakfire_packagelist_unref(list);
716
717 return obj;
718 }
719
720 static PyObject* Pakfire_whatrequires(PakfireObject* self, PyObject* args) {
721 const char* requires = NULL;
722 struct pakfire_packagelist* list = NULL;
723
724 if (!PyArg_ParseTuple(args, "s", &requires))
725 return NULL;
726
727 int r = pakfire_whatrequires(self->pakfire, requires, 0, &list);
728 if (r) {
729 PyErr_SetFromErrno(PyExc_OSError);
730 return NULL;
731 }
732
733 PyObject* obj = PyList_FromPackageList(list);
734 pakfire_packagelist_unref(list);
735
736 return obj;
737 }
738
739 static PyObject* Pakfire_search(PakfireObject* self, PyObject* args, PyObject* kwds) {
740 char* kwlist[] = { "pattern", "name_only", NULL };
741 struct pakfire_packagelist* list = NULL;
742 const char* pattern = NULL;
743 int name_only = 0;
744 int flags = 0;
745
746 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$p", kwlist, &pattern, &name_only))
747 return NULL;
748
749 // Search for package names only
750 if (name_only)
751 flags |= PAKFIRE_SEARCH_NAME_ONLY;
752
753 int r = pakfire_search(self->pakfire, pattern, flags, &list);
754 if (r) {
755 PyErr_SetFromErrno(PyExc_OSError);
756 return NULL;
757 }
758
759 PyObject* obj = PyList_FromPackageList(list);
760 pakfire_packagelist_unref(list);
761
762 return obj;
763 }
764
765 static PyObject* Pakfire_version_compare(PakfireObject* self, PyObject* args) {
766 const char* evr1 = NULL;
767 const char* evr2 = NULL;
768
769 if (!PyArg_ParseTuple(args, "ss", &evr1, &evr2))
770 return NULL;
771
772 int cmp = pakfire_version_compare(self->pakfire, evr1, evr2);
773
774 return PyLong_FromLong(cmp);
775 }
776
777 static int Pakfire_execute_output_callback(struct pakfire* pakfire, void* data,
778 int priority, const char* line, size_t length) {
779 PyObject* callback = (PyObject*)data;
780 int r = 0;
781
782 // Do nothing if callback isn't set
783 if (!callback)
784 return 0;
785
786 // Translate priority to Python logging priorities
787 switch (priority) {
788 case LOG_INFO:
789 priority = 20;
790 break;
791
792 case LOG_ERR:
793 priority = 40;
794 break;
795 }
796
797 // Remove the trailing newline
798 if (line && line[length - 1] == '\n')
799 length--;
800
801 // Create tuple with arguments for the callback function
802 PyObject* args = Py_BuildValue("(is#)", priority, line, (Py_ssize_t)length);
803 if (!args)
804 return 1;
805
806 PyObject* result = PyObject_CallObject(callback, args);
807 if (result && PyLong_Check(result)) {
808 r = PyLong_AsLong(result);
809 }
810
811 Py_XDECREF(args);
812 Py_XDECREF(result);
813
814 return r;
815 }
816
817 static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject* kwds) {
818 char* kwlist[] = {
819 "command",
820 "environ",
821 "bind",
822 "callback",
823 "nice",
824 NULL
825 };
826
827 struct pakfire_jail* jail = NULL;
828 const char** argv = NULL;
829 int flags = 0;
830 int r;
831 PyObject* ret = NULL;
832
833 PyObject* command = NULL;
834 PyObject* environ = NULL;
835 PyObject* bind = NULL;
836 PyObject* callback = NULL;
837 int nice = 0;
838
839 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOOi", kwlist, &command, &environ,
840 &bind, &callback, &nice))
841 return NULL;
842
843 // Check if command is a list
844 if (!PyList_Check(command)) {
845 PyErr_SetString(PyExc_TypeError, "command must be a list");
846 goto ERROR;
847 }
848
849 const ssize_t command_length = PyList_Size(command);
850
851 // Check if command is not empty
852 if (command_length == 0) {
853 PyErr_SetString(PyExc_ValueError, "command is empty");
854 goto ERROR;
855 }
856
857 // Allocate argv
858 argv = calloc(command_length + 1, sizeof(*argv));
859 if (!argv)
860 goto ERROR;
861
862 // All arguments in command must be strings
863 for (unsigned int i = 0; i < command_length; i++) {
864 PyObject* item = PyList_GET_ITEM(command, i);
865
866 if (!PyUnicode_Check(item)) {
867 PyErr_Format(PyExc_TypeError, "Item %u in command is not a string", i);
868 return NULL;
869 }
870
871 // Copy to argv
872 argv[i] = PyUnicode_AsUTF8(item);
873 }
874
875 // Check if bind is a sequence
876 if (bind && !PySequence_Check(bind)) {
877 PyErr_SetString(PyExc_ValueError, "bind is not a sequence");
878 goto ERROR;
879 }
880
881 // Check callback
882 if (callback && !PyCallable_Check(callback)) {
883 PyErr_SetString(PyExc_TypeError, "callback must be callable\n");
884 goto ERROR;
885 }
886
887 // Create jail
888 r = pakfire_jail_create(&jail, self->pakfire, flags);
889 if (r) {
890 PyErr_SetFromErrno(PyExc_OSError);
891 goto ERROR;
892 }
893
894 // Check callback
895 if (callback && !PyCallable_Check(callback)) {
896 PyErr_SetString(PyExc_TypeError, "callback must be callable\n");
897 goto ERROR;
898 }
899
900 // Set nice
901 if (nice) {
902 r = pakfire_jail_nice(jail, nice);
903 if (r) {
904 PyErr_SetFromErrno(PyExc_OSError);
905 goto ERROR;
906 }
907 }
908
909 PyObject* key = NULL;
910 PyObject* value = NULL;
911 Py_ssize_t p = 0;
912
913 // Parse the environment
914 if (environ) {
915 // Check if environ is a dictionary
916 if (!PyDict_Check(environ)) {
917 PyErr_SetString(PyExc_TypeError, "environ must be a dictionary");
918 goto ERROR;
919 }
920
921 // All keys and values must be strings
922 while (PyDict_Next(environ, &p, &key, &value)) {
923 if (!PyUnicode_Check(key) || !PyUnicode_Check(value)) {
924 PyErr_SetString(PyExc_TypeError, "Environment contains a non-string object");
925 goto ERROR;
926 }
927
928 // Set environment value
929 r = pakfire_jail_set_env(jail, PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(value));
930 if (r) {
931 PyErr_SetFromErrno(PyExc_OSError);
932 goto ERROR;
933 }
934 }
935 }
936
937 const Py_ssize_t num_bind = PySequence_Length(bind);
938
939 // Bind
940 for (unsigned int i = 0; i < num_bind; i++) {
941 PyObject* b = PySequence_ITEM(bind, i);
942 if (!b)
943 goto ERROR;
944
945 // Check if this is a Unicode object
946 if (!PyUnicode_Check(b)) {
947 PyErr_SetString(PyExc_ValueError, "bind contains a non-Unicode object");
948 Py_DECREF(b);
949 goto ERROR;
950 }
951
952 const char* path = PyUnicode_AsUTF8(b);
953
954 // Perform bind
955 r = pakfire_jail_bind(jail, path, path, 0);
956 if (r) {
957 PyErr_SetFromErrno(PyExc_OSError);
958 Py_DECREF(b);
959 goto ERROR;
960 }
961
962 Py_DECREF(b);
963 }
964
965 // Execute command
966 r = pakfire_jail_exec_communicate(jail, argv,
967 NULL, Pakfire_execute_output_callback, callback);
968
969 // If the return code was negative, we had some internal error
970 if (r < 0) {
971 PyErr_SetFromErrno(PyExc_OSError);
972 goto ERROR;
973
974 // Otherwise the executed command returned some error code
975 } else if (r > 0) {
976 PyObject* code = PyLong_FromLong(r);
977
978 // Raise CommandExecutionError
979 PyErr_SetObject(PyExc_CommandExecutionError, code);
980 Py_DECREF(code);
981
982 goto ERROR;
983 }
984
985 // The process has exited successfully
986
987 // Return None
988 ret = Py_None;
989 Py_INCREF(ret);
990
991 ERROR:
992 if (argv)
993 free(argv);
994 if (jail)
995 pakfire_jail_unref(jail);
996
997 return ret;
998 }
999
1000 static PyObject* Pakfire_dist(PakfireObject* self, PyObject* args) {
1001 const char* path = NULL;
1002 const char* target = NULL;
1003 char* result = NULL;
1004
1005 if (!PyArg_ParseTuple(args, "s|z", &path, &target))
1006 return NULL;
1007
1008 int r = pakfire_dist(self->pakfire, path, target, &result);
1009 if (r) {
1010 PyErr_SetFromErrno(PyExc_OSError);
1011 return NULL;
1012 }
1013
1014 PyObject* ret = PyUnicode_FromString(result);
1015 free(result);
1016
1017 return ret;
1018 }
1019
1020 static PyObject* Pakfire_copy_in(PakfireObject* self, PyObject* args) {
1021 const char* src = NULL;
1022 const char* dst = NULL;
1023
1024 if (!PyArg_ParseTuple(args, "ss", &src, &dst))
1025 return NULL;
1026
1027 int r = pakfire_copy_in(self->pakfire, src, dst);
1028 if (r) {
1029 PyErr_SetFromErrno(PyExc_OSError);
1030 return NULL;
1031 }
1032
1033 Py_RETURN_NONE;
1034 }
1035
1036 static PyObject* Pakfire_copy_out(PakfireObject* self, PyObject* args) {
1037 const char* src = NULL;
1038 const char* dst = NULL;
1039
1040 if (!PyArg_ParseTuple(args, "ss", &src, &dst))
1041 return NULL;
1042
1043 int r = pakfire_copy_out(self->pakfire, src, dst);
1044 if (r) {
1045 PyErr_SetFromErrno(PyExc_OSError);
1046 return NULL;
1047 }
1048
1049 Py_RETURN_NONE;
1050 }
1051
1052 static PyObject* Pakfire_get_repos(PakfireObject* self) {
1053 struct pakfire_repolist* repos = pakfire_get_repos(self->pakfire);
1054 if (!repos) {
1055 PyErr_SetFromErrno(PyExc_OSError);
1056 return NULL;
1057 }
1058
1059 const size_t l = pakfire_repolist_size(repos);
1060
1061 PyObject* list = PyList_New(l);
1062 if (!list)
1063 goto ERROR;
1064
1065 for (unsigned int i = 0; i < l; i++) {
1066 struct pakfire_repo* repo = pakfire_repolist_get(repos, i);
1067 if (!repo)
1068 continue;
1069
1070 PyObject* obj = new_repo(&RepoType, repo);
1071 PyList_SET_ITEM(list, i, obj);
1072
1073 pakfire_repo_unref(repo);
1074 }
1075
1076 ERROR:
1077 pakfire_repolist_unref(repos);
1078
1079 return list;
1080 }
1081
1082 static PyObject* execute_return_value(int r) {
1083 // Raise an OS error if r < 0
1084 if (r < 0) {
1085 errno = -r;
1086
1087 PyErr_SetFromErrno(PyExc_OSError);
1088 return NULL;
1089
1090 // Raise exception when the command failed
1091 } else if (r > 0) {
1092 PyObject* code = PyLong_FromLong(r);
1093
1094 PyErr_SetObject(PyExc_CommandExecutionError, code);
1095 Py_DECREF(code);
1096
1097 return NULL;
1098 }
1099
1100 Py_RETURN_NONE;
1101 }
1102
1103 static PyObject* Pakfire_build(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1104 char* kwlist[] = {
1105 "path",
1106 "target",
1107 "build_id",
1108 "interactive",
1109 "disable_snapshot",
1110 "disable_ccache",
1111 "disable_tests",
1112 NULL,
1113 };
1114
1115 const char* path = NULL;
1116 const char* target = NULL;
1117 const char* build_id = NULL;
1118 int interactive = 0;
1119 int disable_snapshot = 0;
1120 int disable_ccache = 0;
1121 int disable_tests = 0;
1122
1123 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzpppp", kwlist, &path, &target,
1124 &build_id, &interactive, &disable_snapshot, &disable_ccache, &disable_tests))
1125 return NULL;
1126
1127 int flags = 0;
1128
1129 if (interactive)
1130 flags |= PAKFIRE_BUILD_INTERACTIVE;
1131
1132 // Disable snapshot if requested
1133 if (disable_snapshot)
1134 flags |= PAKFIRE_BUILD_DISABLE_SNAPSHOT;
1135
1136 // Disable ccache if requested
1137 if (disable_ccache)
1138 flags |= PAKFIRE_BUILD_DISABLE_CCACHE;
1139
1140 // Disable tests if requested
1141 if (disable_tests)
1142 flags |= PAKFIRE_BUILD_DISABLE_TESTS;
1143
1144 // Run build
1145 int r = pakfire_build(self->pakfire, path, target, build_id, flags);
1146
1147 return execute_return_value(r);
1148 }
1149
1150 static PyObject* Pakfire_shell(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1151 char* kwlist[] = {
1152 "install",
1153 "disable_snapshot",
1154 NULL,
1155 };
1156 char** packages = NULL;
1157 int disable_snapshot = 0;
1158
1159 // Parse everything
1160 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&p", kwlist,
1161 convert_packages, &packages, &disable_snapshot))
1162 return NULL;
1163
1164 int flags = 0;
1165
1166 if (disable_snapshot)
1167 flags |= PAKFIRE_BUILD_DISABLE_SNAPSHOT;
1168
1169 int r = pakfire_shell(self->pakfire, (const char**)packages, flags);
1170
1171 return execute_return_value(r);
1172 }
1173
1174 static PyObject* Pakfire_clean(PakfireObject* self) {
1175 int r = pakfire_clean(self->pakfire, 0);
1176 if (r) {
1177 PyErr_SetFromErrno(PyExc_OSError);
1178 return NULL;
1179 }
1180
1181 Py_RETURN_NONE;
1182 }
1183
1184 static PyObject* Pakfire_refresh(PakfireObject* self, PyObject* args) {
1185 int force = 0;
1186
1187 if (!PyArg_ParseTuple(args, "|p", &force))
1188 return NULL;
1189
1190 int r = pakfire_refresh(self->pakfire, force);
1191 if (r) {
1192 PyErr_SetFromErrno(PyExc_OSError);
1193 return NULL;
1194 }
1195
1196 Py_RETURN_NONE;
1197 }
1198
1199 static PyObject* Pakfire_check(PakfireObject* self) {
1200 struct pakfire_filelist* errors = NULL;
1201 int r;
1202
1203 // Allocate a filelist for errors
1204 r = pakfire_filelist_create(&errors, self->pakfire);
1205 if (r)
1206 goto ERROR;
1207
1208 // Perform check
1209 r = pakfire_check(self->pakfire, errors);
1210 if (r)
1211 goto ERROR;
1212
1213 const size_t num_errors = pakfire_filelist_size(errors);
1214
1215 // Did we find any errors?
1216 if (num_errors) {
1217 PyObject* _errors = PyList_FromFileList(errors);
1218 if (!_errors)
1219 goto ERROR;
1220
1221 pakfire_filelist_unref(errors);
1222
1223 // Raise CheckFileVerificationError
1224 PyErr_SetObject(PyExc_CheckFileVerificationError, _errors);
1225 Py_DECREF(_errors);
1226 return NULL;
1227 }
1228
1229 pakfire_filelist_unref(errors);
1230 Py_RETURN_NONE;
1231
1232 ERROR:
1233 // Cleanup
1234 if (errors)
1235 pakfire_filelist_unref(errors);
1236
1237 // Raise exception from errno
1238 PyErr_SetFromErrno(PyExc_OSError);
1239 return NULL;
1240 }
1241
1242 static PyObject* Pakfire_sync(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1243 char* kwlist[] = {
1244 "keep_orphaned",
1245 "status_callback",
1246 NULL,
1247 };
1248 int keep_orphaned = 0;
1249 int flags = 0;
1250 PyObject* status_callback = NULL;
1251
1252 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$pO", kwlist,
1253 &keep_orphaned, &status_callback))
1254 return NULL;
1255
1256 if (keep_orphaned)
1257 flags |= PAKFIRE_REQUEST_KEEP_ORPHANED;
1258
1259 int r = pakfire_sync(self->pakfire, 0, flags, NULL,
1260 Pakfire_status_callback, status_callback);
1261 if (r) {
1262 PyErr_SetFromErrno(PyExc_OSError);
1263 return NULL;
1264 }
1265
1266 Py_RETURN_NONE;
1267 }
1268
1269 static PyObject* Pakfire_open(PakfireObject* self, PyObject* args) {
1270 struct pakfire_archive* archive = NULL;
1271 const char* path = NULL;
1272
1273 if (!PyArg_ParseTuple(args, "s", &path))
1274 return NULL;
1275
1276 int r = pakfire_archive_open(&archive, self->pakfire, path);
1277 if (r) {
1278 PyErr_SetFromErrno(PyExc_OSError);
1279 return NULL;
1280 }
1281
1282 // Create Python object
1283 PyObject* object = new_archive(&ArchiveType, archive);
1284 pakfire_archive_unref(archive);
1285
1286 return object;
1287 }
1288
1289 static PyObject* Pakfire_repo_compose(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1290 char* kwlist[] = { "path", "files", NULL };
1291 const char* path = NULL;
1292 PyObject* list = NULL;
1293
1294 PyObject* ret = NULL;
1295
1296 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO", kwlist, &path, &list))
1297 return NULL;
1298
1299 // List must be a sequence
1300 if (!PySequence_Check(list)) {
1301 PyErr_SetString(PyExc_ValueError, "Expected a sequence.");
1302 return NULL;
1303 }
1304
1305 const int flags = 0;
1306
1307 // How many new files do we have?
1308 ssize_t num_files = PySequence_Length(list);
1309 if (num_files < 0)
1310 return NULL;
1311
1312 // Allocate files array
1313 const char** files = calloc(num_files + 1, sizeof(*files));
1314 if (!files) {
1315 PyErr_SetFromErrno(PyExc_OSError);
1316 return NULL;
1317 }
1318
1319 for (int i = 0; i < num_files; i++) {
1320 PyObject* file = PySequence_GetItem(list, i);
1321 if (!file)
1322 goto ERROR;
1323
1324 // Check if file is a Unicode object
1325 if (!PyUnicode_Check(file)) {
1326 PyErr_SetString(PyExc_ValueError, "Expected a string.");
1327 goto ERROR;
1328 }
1329
1330 // Add pointer to string to files array
1331 files[i] = PyUnicode_AsUTF8(file);
1332 if (!files[i])
1333 goto ERROR;
1334
1335 Py_DECREF(file);
1336 }
1337
1338 int r = pakfire_repo_compose(self->pakfire, path, flags, files);
1339 if (r) {
1340 PyErr_SetFromErrno(PyExc_OSError);
1341 return NULL;
1342 }
1343
1344 // Return None on success
1345 ret = Py_None;
1346 Py_INCREF(ret);
1347
1348 ERROR:
1349 if (files)
1350 free(files);
1351
1352 return ret;
1353 }
1354
1355 static struct PyMethodDef Pakfire_methods[] = {
1356 {
1357 "build",
1358 (PyCFunction)Pakfire_build,
1359 METH_VARARGS|METH_KEYWORDS,
1360 NULL
1361 },
1362 {
1363 "check",
1364 (PyCFunction)Pakfire_check,
1365 METH_NOARGS,
1366 NULL,
1367 },
1368 {
1369 "clean",
1370 (PyCFunction)Pakfire_clean,
1371 METH_NOARGS,
1372 NULL,
1373 },
1374 {
1375 "copy_in",
1376 (PyCFunction)Pakfire_copy_in,
1377 METH_VARARGS,
1378 NULL,
1379 },
1380 {
1381 "copy_out",
1382 (PyCFunction)Pakfire_copy_out,
1383 METH_VARARGS,
1384 NULL,
1385 },
1386 {
1387 "dist",
1388 (PyCFunction)Pakfire_dist,
1389 METH_VARARGS,
1390 NULL
1391 },
1392 {
1393 "erase",
1394 (PyCFunction)Pakfire_erase,
1395 METH_VARARGS|METH_KEYWORDS,
1396 NULL
1397 },
1398 {
1399 "execute",
1400 (PyCFunction)Pakfire_execute,
1401 METH_VARARGS|METH_KEYWORDS,
1402 NULL
1403 },
1404 {
1405 "fetch_key",
1406 (PyCFunction)Pakfire_fetch_key,
1407 METH_VARARGS|METH_KEYWORDS,
1408 NULL
1409 },
1410 {
1411 "generate_key",
1412 (PyCFunction)Pakfire_generate_key,
1413 METH_VARARGS|METH_KEYWORDS,
1414 NULL
1415 },
1416 {
1417 "get_key",
1418 (PyCFunction)Pakfire_get_key,
1419 METH_VARARGS,
1420 NULL
1421 },
1422 {
1423 "get_repo",
1424 (PyCFunction)Pakfire_get_repo,
1425 METH_VARARGS,
1426 NULL
1427 },
1428 {
1429 "import_key",
1430 (PyCFunction)Pakfire_import_key,
1431 METH_VARARGS,
1432 NULL
1433 },
1434 {
1435 "install",
1436 (PyCFunction)Pakfire_install,
1437 METH_VARARGS|METH_KEYWORDS,
1438 NULL,
1439 },
1440 {
1441 "open",
1442 (PyCFunction)Pakfire_open,
1443 METH_VARARGS,
1444 NULL
1445 },
1446 {
1447 "refresh",
1448 (PyCFunction)Pakfire_refresh,
1449 METH_VARARGS,
1450 NULL,
1451 },
1452 {
1453 "repo_compose",
1454 (PyCFunction)Pakfire_repo_compose,
1455 METH_VARARGS|METH_KEYWORDS,
1456 NULL
1457 },
1458 {
1459 "search",
1460 (PyCFunction)Pakfire_search,
1461 METH_VARARGS|METH_KEYWORDS,
1462 NULL
1463 },
1464 {
1465 "shell",
1466 (PyCFunction)Pakfire_shell,
1467 METH_VARARGS|METH_KEYWORDS,
1468 NULL,
1469 },
1470 {
1471 "sync",
1472 (PyCFunction)Pakfire_sync,
1473 METH_VARARGS|METH_KEYWORDS,
1474 NULL,
1475 },
1476 {
1477 "update",
1478 (PyCFunction)Pakfire_update,
1479 METH_VARARGS|METH_KEYWORDS,
1480 NULL
1481 },
1482 {
1483 "version_compare",
1484 (PyCFunction)Pakfire_version_compare,
1485 METH_VARARGS,
1486 NULL
1487 },
1488 {
1489 "whatprovides",
1490 (PyCFunction)Pakfire_whatprovides,
1491 METH_VARARGS,
1492 NULL
1493 },
1494 {
1495 "whatrequires",
1496 (PyCFunction)Pakfire_whatrequires,
1497 METH_VARARGS,
1498 NULL
1499 },
1500 { NULL },
1501 };
1502
1503 static struct PyGetSetDef Pakfire_getsetters[] = {
1504 {
1505 "arch",
1506 (getter)Pakfire_get_arch,
1507 NULL,
1508 NULL,
1509 NULL
1510 },
1511 {
1512 "keys",
1513 (getter)Pakfire_get_keys,
1514 NULL,
1515 NULL,
1516 NULL
1517 },
1518 {
1519 "path",
1520 (getter)Pakfire_get_path,
1521 NULL,
1522 NULL,
1523 NULL
1524 },
1525 {
1526 "repos",
1527 (getter)Pakfire_get_repos,
1528 NULL,
1529 NULL,
1530 NULL
1531 },
1532 { NULL },
1533 };
1534
1535 PyTypeObject PakfireType = {
1536 PyVarObject_HEAD_INIT(NULL, 0)
1537 tp_name: "_pakfire.Pakfire",
1538 tp_basicsize: sizeof(PakfireObject),
1539 tp_flags: Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
1540 tp_new: Pakfire_new,
1541 tp_dealloc: (destructor)Pakfire_dealloc,
1542 tp_init: (initproc)Pakfire_init,
1543 tp_doc: "Pakfire object",
1544 tp_methods: Pakfire_methods,
1545 tp_getset: Pakfire_getsetters,
1546 tp_repr: (reprfunc)Pakfire_repr,
1547 };