]>
Commit | Line | Data |
---|---|---|
931d97a0 MT |
1 | /*############################################################################# |
2 | # # | |
3 | # Pakfire - The IPFire package management system # | |
4 | # Copyright (C) 2021 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 | #include <errno.h> | |
3d2cc9e6 | 22 | #include <limits.h> |
931d97a0 MT |
23 | #include <stdlib.h> |
24 | ||
57a8b2d4 MT |
25 | #include <json.h> |
26 | ||
931d97a0 | 27 | #include <pakfire/buildservice.h> |
3d2cc9e6 | 28 | #include <pakfire/config.h> |
931d97a0 | 29 | #include <pakfire/ctx.h> |
01840335 | 30 | #include <pakfire/digest.h> |
10db1fae | 31 | #include <pakfire/httpclient.h> |
3d2cc9e6 | 32 | #include <pakfire/logging.h> |
01840335 | 33 | #include <pakfire/path.h> |
931d97a0 | 34 | #include <pakfire/private.h> |
3d2cc9e6 | 35 | #include <pakfire/string.h> |
57a8b2d4 | 36 | #include <pakfire/util.h> |
c26aca37 | 37 | #include <pakfire/xfer.h> |
931d97a0 | 38 | |
ff5cb6ba MT |
39 | #include <krb5/krb5.h> |
40 | ||
1e4b70d0 MT |
41 | #define DEFAULT_KEYTAB "/etc/krb5.keytab" |
42 | ||
931d97a0 MT |
43 | struct pakfire_buildservice { |
44 | struct pakfire_ctx* ctx; | |
45 | int nrefs; | |
3d2cc9e6 | 46 | |
d188b602 | 47 | // Configuration |
3d2cc9e6 | 48 | char url[PATH_MAX]; |
1e4b70d0 | 49 | char keytab[PATH_MAX]; |
d188b602 MT |
50 | |
51 | // A HTTP Client | |
10db1fae | 52 | struct pakfire_httpclient* httpclient; |
ff5cb6ba MT |
53 | |
54 | // Kerberos Context | |
55 | krb5_context krb5_ctx; | |
931d97a0 MT |
56 | }; |
57 | ||
ff5cb6ba MT |
58 | static int pakfire_buildservice_setup_auth(struct pakfire_buildservice* service) { |
59 | const char* error = NULL; | |
60 | int r; | |
61 | ||
62 | // Setup a Kerberos context | |
63 | r = krb5_init_context(&service->krb5_ctx); | |
64 | if (r) { | |
65 | error = krb5_get_error_message(service->krb5_ctx, r); | |
66 | ||
67 | CTX_ERROR(service->ctx, "Could not initialize Kerberos: %s\n", error); | |
68 | krb5_free_error_message(service->krb5_ctx, error); | |
69 | ||
70 | goto ERROR; | |
71 | } | |
72 | ||
73 | ERROR: | |
74 | return r; | |
75 | } | |
76 | ||
3d2cc9e6 MT |
77 | static int pakfire_buildservice_setup(struct pakfire_buildservice* service) { |
78 | struct pakfire_config* config = NULL; | |
79 | const char* url = NULL; | |
1e4b70d0 | 80 | const char* keytab = NULL; |
3d2cc9e6 MT |
81 | int r; |
82 | ||
83 | // Fetch the configuration | |
84 | config = pakfire_ctx_get_config(service->ctx); | |
85 | if (!config) { | |
86 | r = 1; | |
87 | goto ERROR; | |
88 | } | |
89 | ||
90 | // Fetch the URL | |
91 | url = pakfire_config_get(config, "client", "url", NULL); | |
92 | if (!url) { | |
93 | CTX_ERROR(service->ctx, "Build Service URL is not configured\n"); | |
94 | r = 1; | |
95 | goto ERROR; | |
96 | } | |
97 | ||
98 | // Store the URL | |
99 | r = pakfire_string_set(service->url, url); | |
100 | if (r) | |
101 | goto ERROR; | |
102 | ||
1e4b70d0 MT |
103 | // Fetch the keytab |
104 | keytab = pakfire_config_get(config, "client", "keytab", DEFAULT_KEYTAB); | |
105 | ||
106 | // Store the keytab | |
107 | r = pakfire_string_set(service->keytab, keytab); | |
108 | if (r) | |
109 | goto ERROR; | |
110 | ||
10db1fae MT |
111 | // Setup the HTTP client |
112 | r = pakfire_httpclient_create(&service->httpclient, service->ctx); | |
d188b602 MT |
113 | if (r) |
114 | goto ERROR; | |
115 | ||
ff5cb6ba MT |
116 | // Setup authentication |
117 | r = pakfire_buildservice_setup_auth(service); | |
118 | if (r) | |
119 | goto ERROR; | |
120 | ||
3d2cc9e6 MT |
121 | ERROR: |
122 | if (config) | |
123 | pakfire_config_unref(config); | |
124 | ||
125 | return r; | |
126 | } | |
127 | ||
931d97a0 | 128 | static void pakfire_buildservice_free(struct pakfire_buildservice* service) { |
ff5cb6ba MT |
129 | if (service->krb5_ctx) |
130 | krb5_free_context(service->krb5_ctx); | |
d188b602 | 131 | if (service->httpclient) |
10db1fae | 132 | pakfire_httpclient_unref(service->httpclient); |
931d97a0 MT |
133 | if (service->ctx) |
134 | pakfire_ctx_unref(service->ctx); | |
135 | ||
136 | free(service); | |
137 | } | |
138 | ||
139 | PAKFIRE_EXPORT int pakfire_buildservice_create( | |
140 | struct pakfire_buildservice** service, struct pakfire_ctx* ctx) { | |
141 | struct pakfire_buildservice* s = NULL; | |
3d2cc9e6 | 142 | int r; |
931d97a0 MT |
143 | |
144 | // Allocate some memory | |
145 | s = calloc(1, sizeof(*s)); | |
146 | if (!s) | |
147 | return -errno; | |
148 | ||
149 | // Store a reference to the context | |
150 | s->ctx = pakfire_ctx_ref(ctx); | |
151 | ||
152 | // Initialize the reference counter | |
153 | s->nrefs = 1; | |
154 | ||
3d2cc9e6 MT |
155 | // Setup everything |
156 | r = pakfire_buildservice_setup(s); | |
157 | if (r) | |
158 | goto ERROR; | |
159 | ||
bc10d86d MT |
160 | CTX_DEBUG(s->ctx, "Pakfire Build Service initialized for %s\n", s->url); |
161 | ||
931d97a0 MT |
162 | // Return the pointer |
163 | *service = s; | |
164 | ||
165 | return 0; | |
3d2cc9e6 MT |
166 | |
167 | ERROR: | |
168 | pakfire_buildservice_free(s); | |
169 | ||
170 | return r; | |
931d97a0 MT |
171 | } |
172 | ||
173 | PAKFIRE_EXPORT struct pakfire_buildservice* pakfire_buildservice_ref( | |
174 | struct pakfire_buildservice* service) { | |
175 | ++service->nrefs; | |
176 | ||
177 | return service; | |
178 | } | |
179 | ||
180 | PAKFIRE_EXPORT struct pakfire_buildservice* pakfire_buildservice_unref( | |
181 | struct pakfire_buildservice* service) { | |
182 | if (--service->nrefs > 0) | |
183 | return service; | |
184 | ||
185 | pakfire_buildservice_free(service); | |
186 | return NULL; | |
187 | } | |
57a8b2d4 | 188 | |
04cc2479 MT |
189 | PAKFIRE_EXPORT const char* pakfire_buildservice_get_url(struct pakfire_buildservice* service) { |
190 | return service->url; | |
191 | } | |
192 | ||
c26aca37 | 193 | static int pakfire_buildservice_create_xfer(struct pakfire_xfer** xfer, |
57a8b2d4 | 194 | struct pakfire_buildservice* service, const char* url) { |
c26aca37 | 195 | struct pakfire_xfer* t = NULL; |
57a8b2d4 MT |
196 | int r; |
197 | ||
c26aca37 | 198 | // Create a new xfer |
10db1fae | 199 | r = pakfire_httpclient_create_xfer(&t, service->httpclient, url); |
57a8b2d4 MT |
200 | if (r) |
201 | goto ERROR; | |
202 | ||
203 | // Set the base URL | |
c26aca37 | 204 | r = pakfire_xfer_set_baseurl(t, service->url); |
57a8b2d4 MT |
205 | if (r) |
206 | goto ERROR; | |
207 | ||
c26aca37 MT |
208 | // Return the new xfer |
209 | *xfer = pakfire_xfer_ref(t); | |
57a8b2d4 MT |
210 | |
211 | ERROR: | |
212 | if (t) | |
c26aca37 | 213 | pakfire_xfer_unref(t); |
57a8b2d4 MT |
214 | |
215 | return r; | |
216 | } | |
217 | ||
33de78f2 | 218 | static int pakfire_buildservice_handle_error(struct pakfire_buildservice* service, |
c26aca37 | 219 | struct pakfire_xfer* xfer, const struct json_object* error) { |
33de78f2 MT |
220 | struct json_object* message = NULL; |
221 | struct json_object* code = NULL; | |
222 | const char* m = NULL; | |
223 | unsigned int c = 0; | |
224 | ||
225 | // Fetch the URL | |
c26aca37 | 226 | const char* url = pakfire_xfer_get_effective_url(xfer); |
33de78f2 MT |
227 | |
228 | // Fetch the code | |
229 | if (!json_object_object_get_ex(error, "code", &code)) | |
230 | return -EBADMSG; | |
231 | ||
232 | // Check if the code is an integer | |
233 | if (!json_object_is_type(code, json_type_int)) | |
234 | return -EBADMSG; | |
235 | ||
236 | // Fetch the message | |
237 | if (!json_object_object_get_ex(error, "message", &message)) | |
238 | return -EBADMSG; | |
239 | ||
240 | // Check if the message is a string | |
241 | if (!json_object_is_type(message, json_type_string)) | |
242 | return -EBADMSG; | |
243 | ||
244 | c = json_object_get_uint64(code); | |
245 | m = json_object_get_string(message); | |
246 | ||
247 | // Log the error | |
605615a2 MT |
248 | CTX_ERROR(service->ctx, "%s responded with error %u (%s):\n %s\n", |
249 | url, c, strerror(c), m); | |
33de78f2 | 250 | |
605615a2 | 251 | return -c; |
33de78f2 MT |
252 | } |
253 | ||
254 | /* | |
255 | This function parses an API response | |
256 | */ | |
257 | static int pakfire_buildservice_parse_response(struct pakfire_buildservice* service, | |
c26aca37 | 258 | struct pakfire_xfer* xfer, const char* buffer, const size_t length, |
33de78f2 MT |
259 | struct json_object** object) { |
260 | struct json_object* error = NULL; | |
261 | struct json_object* o = NULL; | |
262 | int r; | |
263 | ||
cc2371c1 MT |
264 | // Check if we received any data |
265 | if (!length) { | |
266 | CTX_ERROR(service->ctx, "Received an empty response\n"); | |
267 | r = -EBADMSG; | |
268 | goto ERROR; | |
269 | } | |
270 | ||
33de78f2 MT |
271 | // XXX Maybe fetch the parser's error message here?! |
272 | ||
273 | // Parse the buffer | |
274 | o = pakfire_json_parse(service->ctx, buffer, length); | |
275 | if (!o) { | |
276 | CTX_ERROR(service->ctx, "Could not parse the response\n"); | |
277 | r = -EBADMSG; | |
278 | goto ERROR; | |
279 | } | |
280 | ||
281 | // Check if the response is a dictionary | |
282 | if (!json_object_is_type(o, json_type_object)) { | |
283 | CTX_ERROR(service->ctx, "The received object is not a JSON dict\n"); | |
284 | r = -EBADMSG; | |
285 | goto ERROR; | |
286 | } | |
287 | ||
288 | // Fetch error | |
289 | r = json_object_object_get_ex(o, "error", &error); | |
290 | if (r) { | |
c26aca37 | 291 | r = pakfire_buildservice_handle_error(service, xfer, error); |
33de78f2 MT |
292 | goto ERROR; |
293 | } | |
294 | ||
295 | // Return the object | |
296 | *object = o; | |
297 | ||
298 | return 0; | |
299 | ||
300 | ERROR: | |
301 | if (o) | |
302 | json_object_put(o); | |
303 | ||
304 | return r; | |
305 | } | |
306 | ||
27629aaf MT |
307 | // Build |
308 | ||
309 | int pakfire_buildservice_build(struct pakfire_buildservice* service, const char* upload, | |
310 | const char* repo, const char** arches, int flags) { | |
c26aca37 | 311 | struct pakfire_xfer* xfer = NULL; |
27629aaf MT |
312 | struct json_object* response = NULL; |
313 | char* buffer = NULL; | |
314 | size_t length = 0; | |
315 | int r; | |
316 | ||
c26aca37 MT |
317 | // Create a new xfer |
318 | r = pakfire_buildservice_create_xfer(&xfer, service, "/api/v1/builds"); | |
27629aaf MT |
319 | if (r) |
320 | goto ERROR; | |
321 | ||
322 | // Enable authentication | |
c26aca37 | 323 | r = pakfire_xfer_auth(xfer); |
27629aaf MT |
324 | if (r) |
325 | goto ERROR; | |
326 | ||
327 | // Add the upload parameter | |
c26aca37 | 328 | r = pakfire_xfer_add_param(xfer, "upload", "%s", upload); |
27629aaf MT |
329 | if (r) |
330 | goto ERROR; | |
331 | ||
332 | // Add the repo parameter | |
c26aca37 | 333 | r = pakfire_xfer_add_param(xfer, "repo", "%s", repo); |
27629aaf MT |
334 | if (r) |
335 | goto ERROR; | |
336 | ||
337 | // Add any arches | |
338 | if (arches) { | |
339 | for (const char** arch = arches; *arch; arch++) { | |
c26aca37 | 340 | r = pakfire_xfer_add_param(xfer, "arch", "%s", *arch); |
27629aaf MT |
341 | if (r) |
342 | goto ERROR; | |
343 | } | |
344 | } | |
345 | ||
346 | // Disable tests? | |
347 | if (flags & PAKFIRE_BUILD_DISABLE_TESTS) { | |
c26aca37 | 348 | r = pakfire_xfer_add_param(xfer, "disable_test_builds", "%s", "yes"); |
27629aaf MT |
349 | if (r) |
350 | goto ERROR; | |
351 | } | |
352 | ||
353 | // Write the response to the buffer | |
c26aca37 | 354 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
27629aaf MT |
355 | if (r) |
356 | goto ERROR; | |
357 | ||
c26aca37 MT |
358 | // Run the xfer |
359 | r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); | |
27629aaf MT |
360 | if (r) |
361 | goto ERROR; | |
362 | ||
363 | // Parse the response | |
c26aca37 | 364 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
27629aaf MT |
365 | if (r) { |
366 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
367 | goto ERROR; | |
368 | } | |
369 | ||
370 | ERROR: | |
c26aca37 MT |
371 | if (xfer) |
372 | pakfire_xfer_unref(xfer); | |
27629aaf MT |
373 | if (response) |
374 | json_object_put(response); | |
375 | if (buffer) | |
376 | free(buffer); | |
377 | ||
378 | return r; | |
379 | } | |
380 | ||
57a8b2d4 MT |
381 | // Uploads |
382 | ||
01840335 MT |
383 | static int pakfire_buildservice_create_upload(struct pakfire_buildservice* service, |
384 | const char* path, const char* filename, FILE* f, char** uuid) { | |
c26aca37 | 385 | struct pakfire_xfer* xfer = NULL; |
27e7b6f6 | 386 | struct pakfire_digests digests = {}; |
01840335 MT |
387 | struct json_object* response = NULL; |
388 | struct json_object* id = NULL; | |
01840335 MT |
389 | const char* __id = NULL; |
390 | char* hexdigest = NULL; | |
391 | char* buffer = NULL; | |
392 | size_t length = 0; | |
393 | struct stat stat; | |
394 | int r; | |
395 | ||
396 | const int fd = fileno(f); | |
397 | ||
398 | // Stat the file | |
399 | r = fstat(fd, &stat); | |
400 | if (r) { | |
401 | CTX_ERROR(service->ctx, "Could not stat %s: %s\n", path, strerror(errno)); | |
402 | goto ERROR; | |
403 | } | |
404 | ||
405 | // Compute the digest | |
406 | r = pakfire_digests_compute_from_file(service->ctx, &digests, PAKFIRE_DIGEST_BLAKE2B512, f); | |
407 | if (r) { | |
408 | CTX_ERROR(service->ctx, "Could not compute the digest of %s: %s\n", | |
409 | path, strerror(-r)); | |
410 | goto ERROR; | |
411 | } | |
412 | ||
413 | // Convert the digest into hex format | |
414 | hexdigest = pakfire_digest_get_hex(&digests, PAKFIRE_DIGEST_BLAKE2B512); | |
415 | if (!hexdigest) | |
416 | goto ERROR; | |
417 | ||
c26aca37 MT |
418 | // Create a new xfer |
419 | r = pakfire_buildservice_create_xfer(&xfer, service, "/api/v1/uploads"); | |
01840335 MT |
420 | if (r) |
421 | goto ERROR; | |
422 | ||
423 | // Enable authentication | |
c26aca37 | 424 | r = pakfire_xfer_auth(xfer); |
01840335 MT |
425 | if (r) |
426 | goto ERROR; | |
427 | ||
428 | // Add the filename parameter | |
c26aca37 | 429 | r = pakfire_xfer_add_param(xfer, "filename", "%s", filename); |
01840335 MT |
430 | if (r) |
431 | goto ERROR; | |
432 | ||
433 | // Add the size parameter | |
c26aca37 | 434 | r = pakfire_xfer_add_param(xfer, "size", "%jd", stat.st_size); |
01840335 MT |
435 | if (r) |
436 | goto ERROR; | |
437 | ||
438 | // Add the hexdigest algo parameter | |
c26aca37 | 439 | r = pakfire_xfer_add_param(xfer, "hexdigest_algo", "%s", "blake2b512"); |
01840335 MT |
440 | if (r) |
441 | goto ERROR; | |
442 | ||
443 | // Add the hexdigest parameter | |
c26aca37 | 444 | r = pakfire_xfer_add_param(xfer, "hexdigest", "%s", hexdigest); |
01840335 MT |
445 | if (r) |
446 | goto ERROR; | |
447 | ||
448 | // Write the response to the buffer | |
c26aca37 | 449 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
01840335 MT |
450 | if (r) |
451 | goto ERROR; | |
452 | ||
c26aca37 MT |
453 | // Run the xfer |
454 | r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); | |
01840335 MT |
455 | if (r) |
456 | goto ERROR; | |
457 | ||
33de78f2 | 458 | // Parse the response |
c26aca37 | 459 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
33de78f2 MT |
460 | if (r) { |
461 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
01840335 MT |
462 | goto ERROR; |
463 | } | |
464 | ||
465 | // Fetch the ID | |
466 | r = json_object_object_get_ex(response, "id", &id); | |
467 | if (r == 0) { | |
468 | CTX_ERROR(service->ctx, "Could not fetch ID from response\n"); | |
469 | r = -EBADMSG; | |
470 | goto ERROR; | |
471 | } | |
472 | ||
473 | // Extract the UUID | |
474 | __id = json_object_get_string(id); | |
475 | if (!__id) { | |
476 | CTX_ERROR(service->ctx, "Could not fetch ID from response\n"); | |
477 | r = -EBADMSG; | |
478 | goto ERROR; | |
479 | } | |
480 | ||
481 | // Return the UUID | |
482 | *uuid = strdup(__id); | |
483 | if (!*uuid) { | |
484 | r = -errno; | |
485 | goto ERROR; | |
486 | } | |
487 | ||
488 | // Success | |
489 | r = 0; | |
490 | ||
491 | ERROR: | |
c26aca37 MT |
492 | if (xfer) |
493 | pakfire_xfer_unref(xfer); | |
01840335 MT |
494 | if (response) |
495 | json_object_put(response); | |
496 | if (hexdigest) | |
497 | free(hexdigest); | |
498 | if (buffer) | |
499 | free(buffer); | |
500 | ||
501 | return r; | |
502 | } | |
503 | ||
504 | static int pakfire_buildservice_upload_payload(struct pakfire_buildservice* service, | |
505 | const char* filename, const char* uuid, FILE* f) { | |
c26aca37 | 506 | struct pakfire_xfer* xfer = NULL; |
33de78f2 MT |
507 | struct json_object* response = NULL; |
508 | char* buffer = NULL; | |
509 | size_t length = 0; | |
01840335 MT |
510 | char url[PATH_MAX]; |
511 | int r; | |
512 | ||
513 | // Make the URL | |
514 | r = pakfire_string_format(url, "/api/v1/uploads/%s", uuid); | |
515 | if (r) | |
516 | goto ERROR; | |
517 | ||
c26aca37 MT |
518 | // Create a new xfer |
519 | r = pakfire_buildservice_create_xfer(&xfer, service, url); | |
01840335 MT |
520 | if (r) |
521 | goto ERROR; | |
522 | ||
523 | // Set the title | |
c26aca37 | 524 | r = pakfire_xfer_set_title(xfer, filename); |
01840335 MT |
525 | if (r) |
526 | goto ERROR; | |
527 | ||
528 | // Set source file | |
c26aca37 | 529 | r = pakfire_xfer_set_input(xfer, f); |
01840335 MT |
530 | if (r) |
531 | goto ERROR; | |
532 | ||
33de78f2 | 533 | // Set the output buffer |
c26aca37 | 534 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
33de78f2 MT |
535 | if (r) |
536 | goto ERROR; | |
537 | ||
c26aca37 MT |
538 | // Run the xfer |
539 | r = pakfire_xfer_run(xfer, 0); | |
01840335 MT |
540 | if (r) |
541 | goto ERROR; | |
542 | ||
33de78f2 | 543 | // Parse the response |
c26aca37 | 544 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
33de78f2 MT |
545 | if (r) { |
546 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
547 | goto ERROR; | |
548 | } | |
549 | ||
01840335 | 550 | ERROR: |
c26aca37 MT |
551 | if (xfer) |
552 | pakfire_xfer_unref(xfer); | |
33de78f2 MT |
553 | if (response) |
554 | json_object_put(response); | |
01840335 MT |
555 | |
556 | return r; | |
557 | } | |
558 | ||
559 | PAKFIRE_EXPORT int pakfire_buildservice_upload(struct pakfire_buildservice* service, | |
81adcd5c | 560 | const char* path, const char* filename, char** uuid) { |
01840335 | 561 | char basename[NAME_MAX]; |
01840335 MT |
562 | FILE* f = NULL; |
563 | int r; | |
564 | ||
565 | // Compute the basename | |
566 | r = pakfire_path_basename(basename, path); | |
567 | if (r) | |
568 | goto ERROR; | |
569 | ||
570 | // Set the basename as default filename | |
571 | if (!filename) | |
572 | filename = basename; | |
573 | ||
574 | // Open the source file | |
575 | f = fopen(path, "r"); | |
576 | if (!f) { | |
577 | CTX_ERROR(service->ctx, "Could not open file for upload %s: %m\n", path); | |
578 | return -errno; | |
579 | } | |
580 | ||
581 | // Create a new upload | |
81adcd5c | 582 | r = pakfire_buildservice_create_upload(service, path, filename, f, uuid); |
01840335 MT |
583 | if (r) |
584 | goto ERROR; | |
585 | ||
81adcd5c | 586 | CTX_DEBUG(service->ctx, "Created a new download (%s)\n", *uuid); |
01840335 MT |
587 | |
588 | // Send the payload | |
81adcd5c | 589 | r = pakfire_buildservice_upload_payload(service, filename, *uuid, f); |
01840335 MT |
590 | if (r) |
591 | goto ERROR; | |
592 | ||
593 | ERROR: | |
81adcd5c MT |
594 | if (r) { |
595 | if (*uuid) | |
596 | free(*uuid); | |
597 | ||
598 | *uuid = NULL; | |
599 | } | |
01840335 MT |
600 | if (f) |
601 | fclose(f); | |
602 | ||
603 | return r; | |
604 | } | |
605 | ||
57a8b2d4 MT |
606 | PAKFIRE_EXPORT int pakfire_buildservice_list_uploads( |
607 | struct pakfire_buildservice* service, struct json_object** p) { | |
c26aca37 | 608 | struct pakfire_xfer* xfer = NULL; |
57a8b2d4 MT |
609 | struct json_object* response = NULL; |
610 | struct json_object* uploads = NULL; | |
611 | char* buffer = NULL; | |
612 | size_t length = 0; | |
613 | int r; | |
614 | ||
c26aca37 MT |
615 | // Create a new xfer |
616 | r = pakfire_buildservice_create_xfer(&xfer, service, "/api/v1/uploads"); | |
57a8b2d4 MT |
617 | if (r) |
618 | goto ERROR; | |
619 | ||
620 | // Enable authentication | |
c26aca37 | 621 | r = pakfire_xfer_auth(xfer); |
57a8b2d4 MT |
622 | if (r) |
623 | goto ERROR; | |
624 | ||
625 | // Write the response to the buffer | |
c26aca37 | 626 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
57a8b2d4 MT |
627 | if (r) |
628 | goto ERROR; | |
629 | ||
c26aca37 MT |
630 | // Run the xfer |
631 | r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); | |
57a8b2d4 MT |
632 | if (r) |
633 | goto ERROR; | |
634 | ||
57a8b2d4 | 635 | // Parse the response |
c26aca37 | 636 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
33de78f2 MT |
637 | if (r) { |
638 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
57a8b2d4 MT |
639 | goto ERROR; |
640 | } | |
641 | ||
642 | // Fetch the uploads | |
643 | uploads = json_object_object_get(response, "uploads"); | |
644 | if (!uploads) { | |
645 | CTX_ERROR(service->ctx, "Malformed response\n"); | |
646 | r = -EBADMSG; | |
647 | goto ERROR; | |
648 | } | |
649 | ||
650 | // Return the pointer | |
651 | *p = json_object_get(uploads); | |
652 | ||
653 | ERROR: | |
c26aca37 MT |
654 | if (xfer) |
655 | pakfire_xfer_unref(xfer); | |
57a8b2d4 MT |
656 | if (response) |
657 | json_object_put(response); | |
658 | if (buffer) | |
659 | free(buffer); | |
660 | ||
661 | return r; | |
662 | } | |
c0b6198a MT |
663 | |
664 | PAKFIRE_EXPORT int pakfire_buildservice_delete_upload( | |
665 | struct pakfire_buildservice* service, const char* uuid) { | |
c26aca37 | 666 | struct pakfire_xfer* xfer = NULL; |
c0b6198a MT |
667 | struct json_object* response = NULL; |
668 | char* buffer = NULL; | |
669 | size_t length = 0; | |
670 | char url[PATH_MAX]; | |
671 | int r; | |
672 | ||
673 | // Compose the URL | |
674 | r = pakfire_string_format(url, "/api/v1/uploads/%s", uuid); | |
675 | if (r) | |
676 | goto ERROR; | |
677 | ||
c26aca37 MT |
678 | // Create a new xfer |
679 | r = pakfire_buildservice_create_xfer(&xfer, service, url); | |
c0b6198a MT |
680 | if (r) |
681 | goto ERROR; | |
682 | ||
683 | // Ask to DELETE | |
c26aca37 | 684 | r = pakfire_xfer_set_method(xfer, PAKFIRE_METHOD_DELETE); |
c0b6198a MT |
685 | if (r) |
686 | goto ERROR; | |
687 | ||
688 | // Enable authentication | |
c26aca37 | 689 | r = pakfire_xfer_auth(xfer); |
c0b6198a MT |
690 | if (r) |
691 | goto ERROR; | |
692 | ||
693 | // Write the response to the buffer | |
c26aca37 | 694 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
c0b6198a MT |
695 | if (r) |
696 | goto ERROR; | |
697 | ||
c26aca37 MT |
698 | // Run the xfer |
699 | r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); | |
c0b6198a MT |
700 | if (r) |
701 | goto ERROR; | |
702 | ||
703 | // Parse the response | |
c26aca37 | 704 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
c0b6198a MT |
705 | if (r) { |
706 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
707 | goto ERROR; | |
708 | } | |
709 | ||
710 | ERROR: | |
c26aca37 MT |
711 | if (xfer) |
712 | pakfire_xfer_unref(xfer); | |
c0b6198a MT |
713 | if (response) |
714 | json_object_put(response); | |
715 | if (buffer) | |
716 | free(buffer); | |
717 | ||
718 | return r; | |
719 | } | |
d554dcde MT |
720 | |
721 | // Repositories | |
722 | ||
723 | PAKFIRE_EXPORT int pakfire_buildservice_list_repos(struct pakfire_buildservice* service, | |
724 | const char* distro, struct json_object** p) { | |
c26aca37 | 725 | struct pakfire_xfer* xfer = NULL; |
d554dcde MT |
726 | struct json_object* response = NULL; |
727 | struct json_object* repos = NULL; | |
728 | char url[PATH_MAX]; | |
729 | char* buffer = NULL; | |
730 | size_t length = 0; | |
731 | int r; | |
732 | ||
733 | // Check inputs | |
734 | if (!distro) | |
735 | return -EINVAL; | |
736 | ||
737 | // Compose path | |
738 | r = pakfire_string_format(url, "/api/v1/repos/%s", distro); | |
739 | if (r) | |
740 | goto ERROR; | |
741 | ||
c26aca37 MT |
742 | // Create a new xfer |
743 | r = pakfire_buildservice_create_xfer(&xfer, service, url); | |
d554dcde MT |
744 | if (r) |
745 | goto ERROR; | |
746 | ||
747 | // Enable authentication | |
c26aca37 | 748 | r = pakfire_xfer_auth(xfer); |
d554dcde MT |
749 | if (r) |
750 | goto ERROR; | |
751 | ||
752 | // Write the response to the buffer | |
c26aca37 | 753 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
d554dcde MT |
754 | if (r) |
755 | goto ERROR; | |
756 | ||
c26aca37 MT |
757 | // Run the xfer |
758 | r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); | |
d554dcde MT |
759 | if (r) |
760 | goto ERROR; | |
761 | ||
762 | // Parse the response | |
c26aca37 | 763 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
d554dcde MT |
764 | if (r) { |
765 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
766 | goto ERROR; | |
767 | } | |
768 | ||
769 | // Fetch the repos | |
770 | if (!json_object_object_get_ex(response, "repos", &repos)) { | |
771 | CTX_ERROR(service->ctx, "Malformed response\n"); | |
772 | r = -EBADMSG; | |
773 | goto ERROR; | |
774 | } | |
775 | ||
776 | // Return the pointer | |
777 | *p = json_object_get(repos); | |
778 | ||
779 | ERROR: | |
c26aca37 MT |
780 | if (xfer) |
781 | pakfire_xfer_unref(xfer); | |
d554dcde MT |
782 | if (response) |
783 | json_object_put(response); | |
784 | if (buffer) | |
785 | free(buffer); | |
786 | ||
787 | return r; | |
788 | } | |
9aa3397d MT |
789 | |
790 | PAKFIRE_EXPORT int pakfire_buildservice_get_repo(struct pakfire_buildservice* service, | |
791 | const char* distro, const char* name, struct json_object** p) { | |
c26aca37 | 792 | struct pakfire_xfer* xfer = NULL; |
9aa3397d MT |
793 | struct json_object* response = NULL; |
794 | char url[PATH_MAX]; | |
795 | char* buffer = NULL; | |
796 | size_t length = 0; | |
797 | int r; | |
798 | ||
799 | // Check inputs | |
800 | if (!distro || !name) | |
801 | return -EINVAL; | |
802 | ||
803 | // Compose URL | |
804 | r = pakfire_string_format(url, "/api/v1/repos/%s/%s", distro, name); | |
805 | if (r) | |
806 | goto ERROR; | |
807 | ||
c26aca37 MT |
808 | // Create a new xfer |
809 | r = pakfire_buildservice_create_xfer(&xfer, service, url); | |
9aa3397d MT |
810 | if (r) |
811 | goto ERROR; | |
812 | ||
813 | // Enable authentication | |
c26aca37 | 814 | r = pakfire_xfer_auth(xfer); |
9aa3397d MT |
815 | if (r) |
816 | goto ERROR; | |
817 | ||
818 | // Write the response to the buffer | |
c26aca37 | 819 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
9aa3397d MT |
820 | if (r) |
821 | goto ERROR; | |
822 | ||
c26aca37 MT |
823 | // Run the xfer |
824 | r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); | |
9aa3397d MT |
825 | if (r) |
826 | goto ERROR; | |
827 | ||
828 | // Parse the response | |
c26aca37 | 829 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
9aa3397d MT |
830 | if (r) { |
831 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
832 | goto ERROR; | |
833 | } | |
834 | ||
835 | // Return the pointer | |
836 | *p = json_object_get(response); | |
837 | ||
838 | ERROR: | |
c26aca37 MT |
839 | if (xfer) |
840 | pakfire_xfer_unref(xfer); | |
9aa3397d MT |
841 | if (response) |
842 | json_object_put(response); | |
843 | if (buffer) | |
844 | free(buffer); | |
845 | ||
846 | return r; | |
847 | } | |
110ab7da MT |
848 | |
849 | PAKFIRE_EXPORT int pakfire_buildservice_create_repo(struct pakfire_buildservice* service, | |
850 | const char* distro, const char* name, const char* description, struct json_object** p) { | |
c26aca37 | 851 | struct pakfire_xfer* xfer = NULL; |
110ab7da MT |
852 | struct json_object* response = NULL; |
853 | char url[PATH_MAX]; | |
854 | char* buffer = NULL; | |
855 | size_t length = 0; | |
856 | int r; | |
857 | ||
858 | // Check inputs | |
859 | if (!distro) | |
860 | return -EINVAL; | |
861 | ||
862 | // Compose path | |
863 | r = pakfire_string_format(url, "/api/v1/repos/%s", distro); | |
864 | if (r) | |
865 | goto ERROR; | |
866 | ||
c26aca37 MT |
867 | // Create a new xfer |
868 | r = pakfire_buildservice_create_xfer(&xfer, service, url); | |
110ab7da MT |
869 | if (r) |
870 | goto ERROR; | |
871 | ||
872 | // Enable authentication | |
c26aca37 | 873 | r = pakfire_xfer_auth(xfer); |
110ab7da MT |
874 | if (r) |
875 | goto ERROR; | |
876 | ||
877 | // Set name | |
c26aca37 | 878 | r = pakfire_xfer_add_param(xfer, "name", "%s", name); |
110ab7da MT |
879 | if (r) |
880 | goto ERROR; | |
881 | ||
882 | // Set description | |
883 | if (description) { | |
c26aca37 | 884 | r = pakfire_xfer_add_param(xfer, "description", "%s", description); |
110ab7da MT |
885 | if (r) |
886 | goto ERROR; | |
887 | } | |
888 | ||
889 | // Write the response to the buffer | |
c26aca37 | 890 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
110ab7da MT |
891 | if (r) |
892 | goto ERROR; | |
893 | ||
c26aca37 MT |
894 | // Run the xfer |
895 | r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); | |
110ab7da MT |
896 | if (r) |
897 | goto ERROR; | |
898 | ||
899 | // Parse the response | |
c26aca37 | 900 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
110ab7da MT |
901 | if (r) { |
902 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
903 | goto ERROR; | |
904 | } | |
905 | ||
906 | // Return the pointer | |
907 | if (p) | |
908 | *p = json_object_get(response); | |
909 | ||
910 | ERROR: | |
c26aca37 MT |
911 | if (xfer) |
912 | pakfire_xfer_unref(xfer); | |
110ab7da MT |
913 | if (response) |
914 | json_object_put(response); | |
915 | if (buffer) | |
916 | free(buffer); | |
917 | ||
918 | return r; | |
919 | } | |
0948a9b6 MT |
920 | |
921 | PAKFIRE_EXPORT int pakfire_buildservice_delete_repo(struct pakfire_buildservice* service, | |
922 | const char* distro, const char* name) { | |
c26aca37 | 923 | struct pakfire_xfer* xfer = NULL; |
0948a9b6 MT |
924 | struct json_object* response = NULL; |
925 | char* buffer = NULL; | |
926 | size_t length = 0; | |
927 | char url[PATH_MAX]; | |
928 | int r; | |
929 | ||
930 | // Compose the URL | |
931 | r = pakfire_string_format(url, "/api/v1/repos/%s/%s", distro, name); | |
932 | if (r) | |
933 | goto ERROR; | |
934 | ||
c26aca37 MT |
935 | // Create a new xfer |
936 | r = pakfire_buildservice_create_xfer(&xfer, service, url); | |
0948a9b6 MT |
937 | if (r) |
938 | goto ERROR; | |
939 | ||
940 | // Ask to DELETE | |
c26aca37 | 941 | r = pakfire_xfer_set_method(xfer, PAKFIRE_METHOD_DELETE); |
0948a9b6 MT |
942 | if (r) |
943 | goto ERROR; | |
944 | ||
945 | // Enable authentication | |
c26aca37 | 946 | r = pakfire_xfer_auth(xfer); |
0948a9b6 MT |
947 | if (r) |
948 | goto ERROR; | |
949 | ||
950 | // Write the response to the buffer | |
c26aca37 | 951 | r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); |
0948a9b6 MT |
952 | if (r) |
953 | goto ERROR; | |
954 | ||
c26aca37 MT |
955 | // Run the xfer |
956 | r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); | |
0948a9b6 MT |
957 | if (r) |
958 | goto ERROR; | |
959 | ||
960 | // Parse the response | |
c26aca37 | 961 | r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); |
0948a9b6 MT |
962 | if (r) { |
963 | CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); | |
964 | goto ERROR; | |
965 | } | |
966 | ||
967 | ERROR: | |
c26aca37 MT |
968 | if (xfer) |
969 | pakfire_xfer_unref(xfer); | |
0948a9b6 MT |
970 | if (response) |
971 | json_object_put(response); | |
972 | if (buffer) | |
973 | free(buffer); | |
974 | ||
975 | return r; | |
976 | } |