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