2 * auc - attendedsysUpgrade CLI
3 * Copyright (C) 2017 Daniel Golle <daniel@makrotopia.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #define AUC_VERSION "0.0.9"
28 #include <json-c/json.h>
29 #include <libubox/ulog.h>
30 #include <libubox/list.h>
31 #include <libubox/vlist.h>
32 #include <libubox/blobmsg_json.h>
33 #include <libubox/avl-cmp.h>
34 #include <libubox/uclient.h>
35 #include <libubox/uclient-utils.h>
38 #define REQ_TIMEOUT 15
39 #define APIOBJ_CHECK "api/upgrade-check"
40 #define APIOBJ_REQUEST "api/upgrade-request"
42 #define PUBKEY_PATH "/etc/opkg/keys"
45 #define DPRINTF(...) if (debug) fprintf(stderr, __VA_ARGS__)
50 static const char server_issues
[]="https://github.com/aparcar/attendedsysupgrade-server/issues";
52 static char user_agent
[80];
53 static char *serverurl
;
54 static int upgrade_packages
;
55 static struct ustream_ssl_ctx
*ssl_ctx
;
56 static const struct ustream_ssl_ops
*ssl_ops
;
57 static off_t out_bytes
;
59 static off_t out_offset
;
60 static bool cur_resume
;
61 static int output_fd
= -1;
62 static int retry
, imagebuilder
, building
, ibready
;
63 static char *board_name
= NULL
;
64 static char *target
= NULL
, *subtarget
= NULL
;
65 static char *distribution
= NULL
, *version
= NULL
;
67 static char *filename
= NULL
;
75 * policy for ubus call system board
84 static const struct blobmsg_policy board_policy
[__BOARD_MAX
] = {
85 [BOARD_BOARD_NAME
] = { .name
= "board_name", .type
= BLOBMSG_TYPE_STRING
},
86 [BOARD_RELEASE
] = { .name
= "release", .type
= BLOBMSG_TYPE_TABLE
},
90 * policy for release information in system board reply
100 static const struct blobmsg_policy release_policy
[__RELEASE_MAX
] = {
101 [RELEASE_DISTRIBUTION
] = { .name
= "distribution", .type
= BLOBMSG_TYPE_STRING
},
102 [RELEASE_VERSION
] = { .name
= "version", .type
= BLOBMSG_TYPE_STRING
},
103 [RELEASE_TARGET
] = { .name
= "target", .type
= BLOBMSG_TYPE_STRING
},
107 * policy for packagelist
111 PACKAGELIST_PACKAGES
,
115 static const struct blobmsg_policy packagelist_policy
[__PACKAGELIST_MAX
] = {
116 [PACKAGELIST_PACKAGES
] = { .name
= "packages", .type
= BLOBMSG_TYPE_TABLE
},
120 * policy for upgrade_test
129 static const struct blobmsg_policy upgtest_policy
[__UPGTEST_MAX
] = {
130 [UPGTEST_CODE
] = { .name
= "code", .type
= BLOBMSG_TYPE_INT32
},
131 [UPGTEST_STDOUT
] = { .name
= "stdout", .type
= BLOBMSG_TYPE_STRING
},
136 * policy to extract version from upgrade-check response
144 static const struct blobmsg_policy check_policy
[__CHECK_MAX
] = {
145 [CHECK_VERSION
] = { .name
= "version", .type
= BLOBMSG_TYPE_STRING
},
146 [CHECK_UPGRADES
] = { .name
= "upgrades", .type
= BLOBMSG_TYPE_TABLE
},
149 static const struct blobmsg_policy pkg_upgrades_policy
[2] = {
150 { .type
= BLOBMSG_TYPE_STRING
},
151 { .type
= BLOBMSG_TYPE_STRING
},
155 * policy for upgrade-request response
156 * parse download information for the ready image.
168 static const struct blobmsg_policy image_policy
[__IMAGE_MAX
] = {
169 [IMAGE_REQHASH
] = { .name
= "request_hash", .type
= BLOBMSG_TYPE_STRING
},
170 [IMAGE_URL
] = { .name
= "url", .type
= BLOBMSG_TYPE_STRING
},
171 [IMAGE_FILES
] = { .name
= "files", .type
= BLOBMSG_TYPE_STRING
},
172 [IMAGE_SYSUPGRADE
] = { .name
= "sysupgrade", .type
= BLOBMSG_TYPE_STRING
},
176 * policy for HTTP headers received from server
187 static const struct blobmsg_policy policy
[__H_MAX
] = {
188 [H_RANGE
] = { .name
= "content-range", .type
= BLOBMSG_TYPE_STRING
},
189 [H_LEN
] = { .name
= "content-length", .type
= BLOBMSG_TYPE_STRING
},
190 [H_IBSTATUS
] = { .name
= "x-imagebuilder-status", .type
= BLOBMSG_TYPE_STRING
},
191 [H_IBQUEUEPOS
] = { .name
= "x-build-queue-position", .type
= BLOBMSG_TYPE_STRING
},
192 [H_UNKNOWN_PACKAGE
] = { .name
= "x-unknown-package", .type
= BLOBMSG_TYPE_STRING
},
196 * load serverurl from UCI
198 static int load_config() {
199 struct uci_context
*uci_ctx
;
200 struct uci_package
*uci_attendedsysupgrade
;
201 struct uci_section
*uci_s
;
203 uci_ctx
= uci_alloc_context();
207 uci_ctx
->flags
&= ~UCI_FLAG_STRICT
;
209 if (uci_load(uci_ctx
, "attendedsysupgrade", &uci_attendedsysupgrade
) ||
210 !uci_attendedsysupgrade
) {
211 fprintf(stderr
, "Failed to load attendedsysupgrade config\n");
215 uci_s
= uci_lookup_section(uci_ctx
, uci_attendedsysupgrade
, "server");
217 fprintf(stderr
, "Failed to read server url from config\n");
220 serverurl
= strdup(uci_lookup_option_string(uci_ctx
, uci_s
, "url"));
222 uci_s
= uci_lookup_section(uci_ctx
, uci_attendedsysupgrade
, "client");
224 fprintf(stderr
, "Failed to read client config\n");
227 upgrade_packages
= atoi(uci_lookup_option_string(uci_ctx
, uci_s
, "upgrade_packages"));
229 uci_free_context(uci_ctx
);
236 * UBUS response callbacks
240 * rpc-sys packagelist
241 * append packagelist response to blobbuf given in req->priv
243 static void pkglist_check_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
) {
244 struct blob_buf
*buf
= (struct blob_buf
*)req
->priv
;
245 struct blob_attr
*tb
[__PACKAGELIST_MAX
];
247 blobmsg_parse(packagelist_policy
, __PACKAGELIST_MAX
, tb
, blob_data(msg
), blob_len(msg
));
249 if (!tb
[PACKAGELIST_PACKAGES
]) {
250 fprintf(stderr
, "No packagelist received\n");
255 blobmsg_add_field(buf
, BLOBMSG_TYPE_TABLE
, "installed", blobmsg_data(tb
[PACKAGELIST_PACKAGES
]), blobmsg_data_len(tb
[PACKAGELIST_PACKAGES
]));
259 * rpc-sys packagelist
260 * append array of package names to blobbuf given in req->priv
262 static void pkglist_req_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
) {
263 struct blob_buf
*buf
= (struct blob_buf
*)req
->priv
;
264 struct blob_attr
*tb
[__PACKAGELIST_MAX
];
265 struct blob_attr
*cur
;
269 blobmsg_parse(packagelist_policy
, __PACKAGELIST_MAX
, tb
, blob_data(msg
), blob_len(msg
));
271 if (!tb
[PACKAGELIST_PACKAGES
]) {
272 fprintf(stderr
, "No packagelist received\n");
276 array
= blobmsg_open_array(buf
, "packages");
277 blobmsg_for_each_attr(cur
, tb
[PACKAGELIST_PACKAGES
], rem
)
278 blobmsg_add_string(buf
, NULL
, blobmsg_name(cur
));
280 blobmsg_close_array(buf
, array
);
286 * append append board information to blobbuf given in req->priv
287 * populate board and release global strings
289 static void board_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
) {
290 struct blob_buf
*buf
= (struct blob_buf
*)req
->priv
;
291 struct blob_attr
*tb
[__BOARD_MAX
];
292 struct blob_attr
*rel
[__RELEASE_MAX
];
294 blobmsg_parse(board_policy
, __BOARD_MAX
, tb
, blob_data(msg
), blob_len(msg
));
296 if (!tb
[BOARD_BOARD_NAME
]) {
297 fprintf(stderr
, "No board name received\n");
301 board_name
= strdup(blobmsg_get_string(tb
[BOARD_BOARD_NAME
]));
303 if (!tb
[BOARD_RELEASE
]) {
304 fprintf(stderr
, "No release received\n");
309 blobmsg_parse(release_policy
, __RELEASE_MAX
, rel
,
310 blobmsg_data(tb
[BOARD_RELEASE
]), blobmsg_data_len(tb
[BOARD_RELEASE
]));
312 if (!rel
[RELEASE_TARGET
]) {
313 fprintf(stderr
, "No target received\n");
318 target
= strdup(blobmsg_get_string(rel
[RELEASE_TARGET
]));
319 subtarget
= strchr(target
, '/');
322 distribution
= strdup(blobmsg_get_string(rel
[RELEASE_DISTRIBUTION
]));
323 version
= strdup(blobmsg_get_string(rel
[RELEASE_VERSION
]));
325 blobmsg_add_string(buf
, "distro", distribution
);
326 blobmsg_add_string(buf
, "target", target
);
327 blobmsg_add_string(buf
, "subtarget", subtarget
);
328 blobmsg_add_string(buf
, "version", version
);
332 * rpc-sys upgrade_test
333 * check if downloaded file is accepted by sysupgrade
335 static void upgtest_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
) {
336 int *valid
= (int *)req
->priv
;
337 struct blob_attr
*tb
[__UPGTEST_MAX
];
339 blobmsg_parse(upgtest_policy
, __UPGTEST_MAX
, tb
, blob_data(msg
), blob_len(msg
));
341 if (!tb
[UPGTEST_CODE
]) {
342 fprintf(stderr
, "No sysupgrade test return code received\n");
346 *valid
= (blobmsg_get_u32(tb
[UPGTEST_CODE
]) == 0)?1:0;
348 fprintf(stderr
, "%s", blobmsg_get_string(tb
[UPGTEST_STDOUT
]));
354 static int open_output_file(const char *path
, uint64_t resume_offset
)
356 char *filename
= NULL
;
363 flags
= O_WRONLY
| O_EXCL
;
367 filename
= uclient_get_url_filename(path
, "firmware.bin");
369 fprintf(stderr
, "Writing to '%s'\n", filename
);
370 ret
= open(filename
, flags
, 0644);
375 lseek(ret
, resume_offset
, SEEK_SET
) < 0) {
376 fprintf(stderr
, "Failed to seek %"PRIu64
" bytes in output file\n", resume_offset
);
382 out_offset
= resume_offset
;
383 out_bytes
+= resume_offset
;
392 struct blob_buf
*outbuf
;
395 static void request_done(struct uclient
*cl
)
397 struct jsonblobber
*jsb
= (struct jsonblobber
*)cl
->priv
;
399 json_tokener_free(jsb
->tok
);
403 uclient_disconnect(cl
);
407 static void header_done_cb(struct uclient
*cl
)
409 struct blob_attr
*tb
[__H_MAX
];
410 uint64_t resume_offset
= 0, resume_end
, resume_size
;
412 unsigned int queuepos
= 0;
414 if (uclient_http_redirect(cl
)) {
415 fprintf(stderr
, "Redirected to %s on %s\n", cl
->url
->location
, cl
->url
->host
);
420 if (cl
->status_code
== 204 && cur_resume
) {
421 /* Resume attempt failed, try normal download */
427 DPRINTF("headers:\n%s\n", blobmsg_format_json_indent(cl
->meta
, true, 0));
429 blobmsg_parse(policy
, __H_MAX
, tb
, blob_data(cl
->meta
), blob_len(cl
->meta
));
431 switch (cl
->status_code
) {
437 fprintf(stderr
, "%s target %s/%s (%s) not found. Please report this at %s\n",
438 distribution
, target
, subtarget
, board_name
, server_issues
);
443 fprintf(stderr
, "image too big.\n");
448 fprintf(stderr
, "File download already fully retrieved; nothing to do.\n");
452 fprintf(stderr
, "unknown package '%s' requested.\n",
453 blobmsg_get_string(tb
[H_UNKNOWN_PACKAGE
]));
458 fprintf(stderr
, "ImageBuilder didn't produce sysupgrade file.\n");
463 fprintf(stdout
, "system is up to date.\n");
469 fprintf(stderr
, "Error: Partial content received, full content requested\n");
475 fprintf(stderr
, "Content-Range header is missing\n");
479 if (sscanf(blobmsg_get_string(tb
[H_RANGE
]),
480 "bytes %"PRIu64
"-%"PRIu64
"/%"PRIu64
,
481 &resume_offset
, &resume_end
, &resume_size
) != 3) {
482 fprintf(stderr
, "Content-Range header is invalid\n");
489 ibstatus
= blobmsg_get_string(tb
[H_IBSTATUS
]);
491 if (!strncmp(ibstatus
, "queue", 6)) {
493 fprintf(stderr
, "server is dispatching build job\n");
496 if (tb
[H_IBQUEUEPOS
]) {
497 queuepos
= atoi(blobmsg_get_string(tb
[H_IBQUEUEPOS
]));
498 fprintf(stderr
, "build is in queue position %u.\n", queuepos
);
502 } else if (!strncmp(ibstatus
, "building", 9)) {
504 fprintf(stderr
, "server is now building image...\n");
508 } else if (!strncmp(ibstatus
, "initialize", 11)) {
510 fprintf(stderr
, "server is setting up ImageBuilder...\n");
515 fprintf(stderr
, "unrecognized remote imagebuilder status '%s'\n", ibstatus
);
524 out_len
= strtoul(blobmsg_get_string(tb
[H_LEN
]), NULL
, 10);
526 output_fd
= open_output_file(cl
->url
->location
, resume_offset
);
528 perror("Cannot open output file");
534 fprintf(stderr
, "HTTP error %d\n", cl
->status_code
);
540 static void read_data_cb(struct uclient
*cl
)
545 struct blob_buf
*outbuf
= NULL
;
546 json_tokener
*tok
= NULL
;
547 struct jsonblobber
*jsb
= (struct jsonblobber
*)cl
->priv
;
551 len
= uclient_read(cl
, buf
, sizeof(buf
));
556 write(output_fd
, buf
, len
);
561 outbuf
= jsb
->outbuf
;
565 len
= uclient_read(cl
, buf
, sizeof(buf
));
571 jsobj
= json_tokener_parse_ex(tok
, buf
, len
);
573 if (json_tokener_get_error(tok
) == json_tokener_continue
)
576 if (json_tokener_get_error(tok
) != json_tokener_success
)
581 if (json_object_get_type(jsobj
) == json_type_object
)
582 blobmsg_add_object(outbuf
, jsobj
);
584 json_object_put(jsobj
);
590 static void eof_cb(struct uclient
*cl
)
592 if (!cl
->data_eof
&& !uptodate
) {
593 fprintf(stderr
, "Connection reset prematurely\n");
598 static void handle_uclient_error(struct uclient
*cl
, int code
)
600 const char *type
= "Unknown error";
603 case UCLIENT_ERROR_CONNECT
:
604 type
= "Connection failed";
606 case UCLIENT_ERROR_TIMEDOUT
:
607 type
= "Connection timed out";
609 case UCLIENT_ERROR_SSL_INVALID_CERT
:
610 type
= "Invalid SSL certificate";
612 case UCLIENT_ERROR_SSL_CN_MISMATCH
:
613 type
= "Server hostname does not match SSL certificate";
619 fprintf(stderr
, "Connection error: %s\n", type
);
624 static const struct uclient_cb check_cb
= {
625 .header_done
= header_done_cb
,
626 .data_read
= read_data_cb
,
628 .error
= handle_uclient_error
,
631 static int server_request(const char *url
, struct blob_buf
*inbuf
, struct blob_buf
*outbuf
) {
633 struct jsonblobber
*jsb
= NULL
;
642 ucl
= uclient_new(url
, NULL
, &check_cb
);
644 jsb
= malloc(sizeof(struct jsonblobber
));
645 jsb
->outbuf
= outbuf
;
646 jsb
->tok
= json_tokener_new();
649 uclient_http_set_ssl_ctx(ucl
, ssl_ops
, ssl_ctx
, 1);
650 ucl
->timeout_msecs
= REQ_TIMEOUT
* 1000;
652 rc
= uclient_connect(ucl
);
656 rc
= uclient_http_set_request_type(ucl
, inbuf
?"POST":"GET");
660 uclient_http_reset_headers(ucl
);
661 uclient_http_set_header(ucl
, "User-Agent", user_agent
);
663 uclient_http_set_header(ucl
, "Content-Type", "text/json");
664 post_data
= blobmsg_format_json(inbuf
->head
, true);
665 uclient_write(ucl
, post_data
, strlen(post_data
));
667 rc
= uclient_request(ucl
);
681 static int init_ustream_ssl(void) {
686 dlh
= dlopen("libustream-ssl.so", RTLD_LAZY
| RTLD_LOCAL
);
690 ssl_ops
= dlsym(dlh
, "ustream_ssl_ops");
694 ssl_ctx
= ssl_ops
->context_new(false);
696 glob("/etc/ssl/certs/*.crt", 0, NULL
, &gl
);
700 for (i
= 0; i
< gl
.gl_pathc
; i
++)
701 ssl_ops
->context_add_ca_crt_file(ssl_ctx
, gl
.gl_pathv
[i
]);
706 static int ask_user(void)
708 fprintf(stderr
, "Are you sure you want to continue the upgrade process? [N/y] ");
709 if (getchar() != 'y')
714 static void print_package_updates(struct blob_attr
*upgrades
) {
715 struct blob_attr
*cur
;
716 struct blob_attr
*tb
[2];
719 blobmsg_for_each_attr(cur
, upgrades
, rem
) {
720 blobmsg_parse_array(pkg_upgrades_policy
, ARRAY_SIZE(policy
), tb
, blobmsg_data(cur
), blobmsg_data_len(cur
));
721 if (!tb
[0] || !tb
[1])
724 fprintf(stdout
, "\t%s (%s -> %s)\n", blobmsg_name(cur
),
725 blobmsg_get_string(tb
[1]), blobmsg_get_string(tb
[0]));
729 /* this main function is too big... todo: split */
730 int main(int args
, char *argv
[]) {
731 static struct blob_buf allpkg
, checkbuf
, infobuf
, reqbuf
, imgbuf
, upgbuf
;
732 struct ubus_context
*ctx
= ubus_connect(NULL
);
736 char *newversion
= NULL
;
737 struct blob_attr
*tb
[__IMAGE_MAX
];
738 struct blob_attr
*tbc
[__CHECK_MAX
];
743 unsigned char argc
= 1;
745 snprintf(user_agent
, sizeof(user_agent
), "%s (%s)", argv
[0], AUC_VERSION
);
746 fprintf(stdout
, "%s\n", user_agent
);
749 if (!strncmp(argv
[argc
], "-h", 3) ||
750 !strncmp(argv
[argc
], "--help", 7)) {
751 fprintf(stdout
, "%s: Attended sysUpgrade CLI client\n", argv
[0]);
752 fprintf(stdout
, "Usage: auc [-d] [-h]\n");
753 fprintf(stdout
, " -c\tonly check if system is up-to-date\n");
754 fprintf(stdout
, " -F\tignore result of signature verification\n");
756 fprintf(stdout
, " -d\tenable debugging output\n");
758 fprintf(stdout
, " -h\toutput help\n");
763 if (!strncmp(argv
[argc
], "-d", 3))
766 if (!strncmp(argv
[argc
], "-c", 3))
769 if (!strncmp(argv
[argc
], "-F", 3))
776 fprintf(stderr
, "failed to connect to ubus.\n");
789 if (!strncmp(serverurl
, "https", 5)) {
790 rc
= init_ustream_ssl();
792 fprintf(stderr
, "No CA certificates loaded, please install ca-certificates\n");
797 if (rc
|| !ssl_ctx
) {
798 fprintf(stderr
, "SSL support not available, please install ustream-ssl\n");
804 blobmsg_buf_init(&checkbuf
);
805 blobmsg_buf_init(&infobuf
);
806 blobmsg_buf_init(&reqbuf
);
807 blobmsg_buf_init(&imgbuf
);
808 /* ubus requires BLOBMSG_TYPE_UNSPEC */
809 blob_buf_init(&allpkg
, 0);
810 blob_buf_init(&upgbuf
, 0);
812 if (ubus_lookup_id(ctx
, "system", &id
) ||
813 ubus_invoke(ctx
, id
, "board", NULL
, board_cb
, &checkbuf
, 3000)) {
814 fprintf(stderr
, "cannot request board info from procd\n");
822 blobmsg_add_u8(&allpkg
, "all", 1);
823 blobmsg_add_string(&allpkg
, "dummy", "foo");
824 if (ubus_lookup_id(ctx
, "rpc-sys", &id
) ||
825 ubus_invoke(ctx
, id
, "packagelist", allpkg
.head
, pkglist_check_cb
, &checkbuf
, 3000)) {
826 fprintf(stderr
, "cannot request packagelist from rpcd\n");
834 blobmsg_add_u32(&checkbuf
, "upgrade_packages", upgrade_packages
);
836 fprintf(stdout
, "running %s %s on %s/%s (%s)\n", distribution
,
837 version
, target
, subtarget
, board_name
);
839 fprintf(stdout
, "checking %s for release upgrade%s\n", serverurl
,
840 upgrade_packages
?" or updated packages":"");
843 snprintf(url
, sizeof(url
), "%s/%s", serverurl
, APIOBJ_CHECK
);
848 DPRINTF("requesting:\n%s\n", blobmsg_format_json_indent(checkbuf
.head
, true, 0));
849 if (server_request(url
, &checkbuf
, &infobuf
)) {
850 fprintf(stderr
, "failed to connect to server\n");
859 DPRINTF("reply:\n%s\n", blobmsg_format_json_indent(infobuf
.head
, true, 0));
861 blobmsg_parse(check_policy
, __CHECK_MAX
, tbc
, blob_data(infobuf
.head
), blob_len(infobuf
.head
));
863 if (!tbc
[CHECK_VERSION
] && !tbc
[CHECK_UPGRADES
]) {
867 fprintf(stderr
, "server reply invalid.\n");
873 if (tbc
[CHECK_VERSION
]) {
874 newversion
= blobmsg_get_string(tbc
[CHECK_VERSION
]);
875 fprintf(stdout
, "new %s release %s found.\n", distribution
, newversion
);
877 newversion
= version
;
878 fprintf(stdout
, "staying on %s release version %s\n", distribution
, version
);
881 blobmsg_add_string(&reqbuf
, "version", newversion
);
883 if (tbc
[CHECK_UPGRADES
]) {
884 fprintf(stdout
, "package updates:\n");
885 print_package_updates(tbc
[CHECK_UPGRADES
]);
897 blobmsg_add_string(&reqbuf
, "distro", distribution
);
898 blobmsg_add_string(&reqbuf
, "target", target
);
899 blobmsg_add_string(&reqbuf
, "subtarget", subtarget
);
900 blobmsg_add_string(&reqbuf
, "board", board_name
);
902 blob_buf_init(&allpkg
, 0);
903 blobmsg_add_u8(&allpkg
, "all", 0);
904 blobmsg_add_string(&allpkg
, "dummy", "foo");
905 if (ubus_invoke(ctx
, id
, "packagelist", allpkg
.head
, pkglist_req_cb
, &reqbuf
, 3000)) {
906 fprintf(stderr
, "cannot request packagelist from rpcd\n");
911 snprintf(url
, sizeof(url
), "%s/%s", serverurl
, APIOBJ_REQUEST
);
920 DPRINTF("requesting:\n%s\n", use_get
?"":blobmsg_format_json_indent(reqbuf
.head
, true, 0));
922 server_request(url
, use_get
?NULL
:&reqbuf
, &imgbuf
);
923 blobmsg_parse(image_policy
, __IMAGE_MAX
, tb
, blob_data(imgbuf
.head
), blob_len(imgbuf
.head
));
925 if (!use_get
&& tb
[IMAGE_REQHASH
]) {
926 snprintf(url
, sizeof(url
), "%s/%s/%s", serverurl
,
928 blobmsg_get_string(tb
[IMAGE_REQHASH
]));
929 DPRINTF("polling via GET %s\n", url
);
935 blob_buf_free(&imgbuf
);
936 blobmsg_buf_init(&imgbuf
);
941 DPRINTF("reply:\n%s\n", blobmsg_format_json_indent(imgbuf
.head
, true, 0));
943 if (!tb
[IMAGE_SYSUPGRADE
]) {
945 fprintf(stderr
, "no sysupgrade image returned\n");
951 strncpy(url
, blobmsg_get_string(tb
[IMAGE_SYSUPGRADE
]), sizeof(url
));
953 server_request(url
, NULL
, NULL
);
955 filename
= uclient_get_url_filename(url
, "firmware.bin");
957 if (stat(filename
, &imgstat
)) {
958 fprintf(stderr
, "image download failed\n");
963 if ((intmax_t)imgstat
.st_size
!= out_len
) {
964 fprintf(stderr
, "file size mismatch\n");
970 if (strcmp(filename
, "firmware.bin")) {
971 if (rename(filename
, "firmware.bin")) {
972 fprintf(stderr
, "can't rename to firmware.bin\n");
980 ubus_invoke(ctx
, id
, "upgrade_test", NULL
, upgtest_cb
, &valid
, 3000);
982 fprintf(stdout
, "image verification failed\n");
987 blobmsg_add_u8(&upgbuf
, "keep", 1);
988 fprintf(stdout
, "invoking sysupgrade\n");
989 ubus_invoke(ctx
, id
, "upgrade_start", upgbuf
.head
, NULL
, NULL
, 3000);
994 /* subtarget is a pointer within target, don't free */
999 blob_buf_free(&checkbuf
);
1000 blob_buf_free(&infobuf
);
1001 blob_buf_free(&reqbuf
);
1002 blob_buf_free(&imgbuf
);
1003 blob_buf_free(&upgbuf
);
1007 ssl_ops
->context_free(ssl_ctx
);