shared/curl-util: load libcurl via dlopen

Convert curl-util to the dlopen pattern used by other optional shared
libraries in libshared (libarchive, pcre2, idn, ...). Declare the curl
API entry points with DLSYM_PROTOTYPE, resolve them in a dlopen_curl()
helper, and call the sym_* wrappers from callers. curl_glue_new() now
loads the library on first use, so consumers going through CurlGlue
pick this up automatically; journal-upload and report-upload call
dlopen_curl() directly since they use curl without the glue layer.

With this in place curl-util can live in libshared itself, linked only
against libcurl's headers (via libcurl_cflags). The libcurlutil_static
convenience library and the libcurl link dependency on systemd-imdsd,
systemd-pull, systemd-journal-upload and systemd-report go away.

Also move the easy_setopt() helper macro next to the DLSYM declarations
so all consumers use a single sym-prefixed definition, and add a
dlopen_curl() check to test-dlopen-so.
This commit is contained in:
Daan De Meyer
2026-04-20 21:13:58 +02:00
committed by Daan De Meyer
parent 1b787f20cf
commit c99e93ce0a
13 changed files with 237 additions and 151 deletions
+1
View File
@@ -1296,6 +1296,7 @@ endforeach
libcurl = dependency('libcurl',
version : '>= 7.32.0',
required : get_option('libcurl'))
libcurl_cflags = libcurl.partial_dependency(includes: true, compile_args: true)
conf.set10('HAVE_LIBCURL', libcurl.found())
conf.set10('CURL_NO_OLDIES', conf.get('BUILD_MODE_DEVELOPER') == 1)
+24 -20
View File
@@ -257,9 +257,9 @@ static void context_reset_for_refresh(Context *c) {
c->curl_data = NULL;
}
curl_slist_free_all(c->request_header_token);
sym_curl_slist_free_all(c->request_header_token);
c->request_header_token = NULL;
curl_slist_free_all(c->request_header_data);
sym_curl_slist_free_all(c->request_header_data);
c->request_header_data = NULL;
c->cache_fd = safe_close(c->cache_fd);
@@ -723,9 +723,9 @@ static int context_acquire_http_status(Context *c, CURL *curl, long *ret_status)
*/
long status;
CURLcode code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
CURLcode code = sym_curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code));
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", sym_curl_easy_strerror(code));
context_log(c, LOG_DEBUG, "Got HTTP error code %li.", status);
@@ -906,7 +906,7 @@ static void curl_glue_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
/* Called whenever libcurl did its thing and reports a download being complete or having failed */
Context *c = NULL;
if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char**) &c) != CURLE_OK)
if (sym_curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char**) &c) != CURLE_OK)
return;
switch (result) {
@@ -927,7 +927,7 @@ static void curl_glue_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
case CURLE_GOT_NOTHING:
case CURLE_SEND_ERROR:
case CURLE_RECV_ERROR:
context_log(c, LOG_INFO, "Connection error from curl: %s", curl_easy_strerror(result));
context_log(c, LOG_INFO, "Connection error from curl: %s", sym_curl_easy_strerror(result));
/* Automatically retry on some transient errors from curl itself */
r = context_schedule_retry(c);
@@ -939,7 +939,7 @@ static void curl_glue_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
default:
return context_fail_full(
c,
context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EHOSTDOWN), "Transfer failed: %s", curl_easy_strerror(result)),
context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EHOSTDOWN), "Transfer failed: %s", sym_curl_easy_strerror(result)),
"io.systemd.InstanceMetadata.CommunicationFailure");
}
@@ -1122,25 +1122,25 @@ static int context_acquire_data(Context *c) {
return context_log_errno(c, LOG_ERR, r, "Failed to create curl header: %m");
if (c->request_header_data)
if (curl_easy_setopt(c->curl_data, CURLOPT_HTTPHEADER, c->request_header_data) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_data, CURLOPT_HTTPHEADER, c->request_header_data) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set HTTP request header.");
if (curl_easy_setopt(c->curl_data, CURLOPT_WRITEFUNCTION, data_write_callback) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_data, CURLOPT_WRITEFUNCTION, data_write_callback) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL write function.");
if (curl_easy_setopt(c->curl_data, CURLOPT_WRITEDATA, c) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_data, CURLOPT_WRITEDATA, c) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL write function userdata.");
if (curl_easy_setopt(c->curl_data, CURLOPT_SOCKOPTFUNCTION, setsockopt_callback) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_data, CURLOPT_SOCKOPTFUNCTION, setsockopt_callback) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL setsockopt function.");
if (curl_easy_setopt(c->curl_data, CURLOPT_SOCKOPTDATA, c) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_data, CURLOPT_SOCKOPTDATA, c) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL setsockopt function userdata.");
if (curl_easy_setopt(c->curl_data, CURLOPT_LOCALPORT, 1L) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_data, CURLOPT_LOCALPORT, 1L) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL setsockopt local port");
if (curl_easy_setopt(c->curl_data, CURLOPT_LOCALPORTRANGE, 1023L) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_data, CURLOPT_LOCALPORTRANGE, 1023L) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL setsockopt local port range");
r = curl_glue_add(c->glue, c->curl_data);
@@ -1216,22 +1216,22 @@ static int context_acquire_token(Context *c) {
return context_log_oom(c);
}
if (curl_easy_setopt(c->curl_token, CURLOPT_HTTPHEADER, c->request_header_token) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_token, CURLOPT_HTTPHEADER, c->request_header_token) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set HTTP request header.");
if (curl_easy_setopt(c->curl_token, CURLOPT_CUSTOMREQUEST, "PUT") != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_token, CURLOPT_CUSTOMREQUEST, "PUT") != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set HTTP request method.");
if (curl_easy_setopt(c->curl_token, CURLOPT_WRITEFUNCTION, token_write_callback) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_token, CURLOPT_WRITEFUNCTION, token_write_callback) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL write function.");
if (curl_easy_setopt(c->curl_token, CURLOPT_WRITEDATA, c) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_token, CURLOPT_WRITEDATA, c) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL write function userdata.");
if (curl_easy_setopt(c->curl_token, CURLOPT_SOCKOPTFUNCTION, setsockopt_callback) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_token, CURLOPT_SOCKOPTFUNCTION, setsockopt_callback) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL setsockopt function.");
if (curl_easy_setopt(c->curl_token, CURLOPT_SOCKOPTDATA, c) != CURLE_OK)
if (sym_curl_easy_setopt(c->curl_token, CURLOPT_SOCKOPTDATA, c) != CURLE_OK)
return context_log_errno(c, LOG_ERR, SYNTHETIC_ERRNO(EIO), "Failed to set CURL setsockopt function userdata.");
r = curl_glue_add(c->glue, c->curl_token);
@@ -3070,6 +3070,10 @@ static int run(int argc, char* argv[]) {
if (r <= 0)
return r;
r = dlopen_curl();
if (r < 0)
return r;
r = environment_server_info();
if (r < 0)
return r;
+6 -14
View File
@@ -8,27 +8,19 @@ executables += [
libexec_template + {
'name' : 'systemd-imdsd',
'public' : true,
'sources' : files(
'imdsd.c',
'imds-util.c'
),
'link_with' : [libcurlutil_static, libshared],
'dependencies' : [libcurl],
'sources' : files('imdsd.c'),
'extract' : files('imds-util.c'),
},
libexec_template + {
'name' : 'systemd-imds',
'public' : true,
'sources' : files(
'imds-tool.c',
'imds-util.c'
),
'sources' : files('imds-tool.c'),
'objects' : ['systemd-imdsd'],
},
generator_template + {
'name' : 'systemd-imds-generator',
'sources' : files(
'imds-generator.c',
'imds-util.c'
),
'sources' : files('imds-generator.c'),
'objects' : ['systemd-imdsd'],
},
]
+2 -15
View File
@@ -4,10 +4,6 @@ if conf.get('ENABLE_IMPORTD') != 1
subdir_done()
endif
common_deps = [
libcurl,
]
executables += [
libexec_template + {
'name' : 'systemd-importd',
@@ -21,7 +17,7 @@ executables += [
'import-common.c',
'qcow2-util.c',
),
'dependencies' : [common_deps, threads],
'dependencies' : threads,
},
libexec_template + {
'name' : 'systemd-pull',
@@ -35,10 +31,7 @@ executables += [
'pull-tar.c',
),
'objects' : ['systemd-importd'],
'link_with' : [libcurlutil_static, libshared],
'dependencies' : common_deps + [
libopenssl,
],
'dependencies' : libopenssl,
},
libexec_template + {
'name' : 'systemd-import',
@@ -49,7 +42,6 @@ executables += [
'import-tar.c',
),
'objects' : ['systemd-importd'],
'dependencies' : common_deps,
},
libexec_template + {
'name' : 'systemd-import-fs',
@@ -58,7 +50,6 @@ executables += [
'import-fs.c',
),
'objects' : ['systemd-importd'],
'dependencies' : common_deps,
},
libexec_template + {
'name' : 'systemd-export',
@@ -69,14 +60,12 @@ executables += [
'export-raw.c',
),
'objects' : ['systemd-importd'],
'dependencies' : common_deps,
},
executable_template + {
'name' : 'importctl',
'public' : true,
'sources' : files('importctl.c'),
'objects': ['systemd-importd'],
'dependencies' : common_deps,
},
generator_template + {
'name' : 'systemd-import-generator',
@@ -89,13 +78,11 @@ executables += [
test_template + {
'sources' : files('test-qcow2.c'),
'objects' : ['systemd-importd'],
'dependencies' : common_deps,
'type' : 'manual',
},
test_template + {
'sources' : files('test-oci-util.c'),
'objects': ['systemd-importd'],
'dependencies' : common_deps,
},
]
+19 -19
View File
@@ -52,7 +52,7 @@ PullJob* pull_job_unref(PullJob *j) {
pull_job_close_disk_fd(j);
curl_glue_remove_and_free(j->glue, j->curl);
curl_slist_free_all(j->request_header);
sym_curl_slist_free_all(j->request_header);
j->compress = compressor_free(j->compress);
@@ -164,13 +164,13 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
CURLcode code;
int r;
if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&j) != CURLE_OK)
if (sym_curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&j) != CURLE_OK)
return;
if (!j || IN_SET(j->state, PULL_JOB_DONE, PULL_JOB_FAILED))
return;
code = curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
code = sym_curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
if (code != CURLE_OK || !scheme) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve URL scheme.");
goto finish;
@@ -197,16 +197,16 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
}
if (result != CURLE_OK) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Transfer failed: %s", curl_easy_strerror(result));
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Transfer failed: %s", sym_curl_easy_strerror(result));
goto finish;
}
if (STRCASE_IN_SET(scheme, "HTTP", "HTTPS")) {
long status;
code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
code = sym_curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code));
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", sym_curl_easy_strerror(code));
goto finish;
}
@@ -236,9 +236,9 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
if (r < 0)
goto finish;
code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
code = sym_curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code));
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", sym_curl_easy_strerror(code));
goto finish;
}
@@ -589,9 +589,9 @@ static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb
assert(j->state == PULL_JOB_ANALYZING);
code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
code = sym_curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code));
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", sym_curl_easy_strerror(code));
goto fail;
}
@@ -781,7 +781,7 @@ int pull_job_add_request_header(PullJob *j, const char *hdr) {
if (j->request_header) {
struct curl_slist *l;
l = curl_slist_append(j->request_header, hdr);
l = sym_curl_slist_append(j->request_header, hdr);
if (!l)
return -ENOMEM;
@@ -824,29 +824,29 @@ int pull_job_begin(PullJob *j) {
}
if (j->request_header) {
if (curl_easy_setopt(j->curl, CURLOPT_HTTPHEADER, j->request_header) != CURLE_OK)
if (sym_curl_easy_setopt(j->curl, CURLOPT_HTTPHEADER, j->request_header) != CURLE_OK)
return -EIO;
}
if (curl_easy_setopt(j->curl, CURLOPT_WRITEFUNCTION, pull_job_write_callback) != CURLE_OK)
if (sym_curl_easy_setopt(j->curl, CURLOPT_WRITEFUNCTION, pull_job_write_callback) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_WRITEDATA, j) != CURLE_OK)
if (sym_curl_easy_setopt(j->curl, CURLOPT_WRITEDATA, j) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_HEADERFUNCTION, pull_job_header_callback) != CURLE_OK)
if (sym_curl_easy_setopt(j->curl, CURLOPT_HEADERFUNCTION, pull_job_header_callback) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_HEADERDATA, j) != CURLE_OK)
if (sym_curl_easy_setopt(j->curl, CURLOPT_HEADERDATA, j) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_XFERINFOFUNCTION, pull_job_progress_callback) != CURLE_OK)
if (sym_curl_easy_setopt(j->curl, CURLOPT_XFERINFOFUNCTION, pull_job_progress_callback) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_XFERINFODATA, j) != CURLE_OK)
if (sym_curl_easy_setopt(j->curl, CURLOPT_XFERINFODATA, j) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_NOPROGRESS, 0L) != CURLE_OK)
if (sym_curl_easy_setopt(j->curl, CURLOPT_NOPROGRESS, 0L) != CURLE_OK)
return -EIO;
r = curl_glue_add(j->glue, j->curl);
+21 -15
View File
@@ -188,16 +188,16 @@ int start_upload(Uploader *u,
_cleanup_(curl_slist_free_allp) struct curl_slist *h = NULL;
struct curl_slist *l;
h = curl_slist_append(NULL, "Content-Type: application/vnd.fdo.journal");
h = sym_curl_slist_append(NULL, "Content-Type: application/vnd.fdo.journal");
if (!h)
return log_oom();
l = curl_slist_append(h, "Transfer-Encoding: chunked");
l = sym_curl_slist_append(h, "Transfer-Encoding: chunked");
if (!l)
return log_oom();
h = l;
l = curl_slist_append(h, "Accept: text/plain");
l = sym_curl_slist_append(h, "Accept: text/plain");
if (!l)
return log_oom();
h = l;
@@ -207,7 +207,7 @@ int start_upload(Uploader *u,
if (!header)
return log_oom();
l = curl_slist_append(h, header);
l = sym_curl_slist_append(h, header);
if (!l)
return log_oom();
h = l;
@@ -229,7 +229,7 @@ int start_upload(Uploader *u,
if (!header)
return log_oom();
l = curl_slist_append(h, header);
l = sym_curl_slist_append(h, header);
if (!l)
return log_oom();
h = l;
@@ -241,7 +241,7 @@ int start_upload(Uploader *u,
if (!u->easy) {
_cleanup_(curl_easy_cleanupp) CURL *curl = NULL;
curl = curl_easy_init();
curl = sym_curl_easy_init();
if (!curl)
return log_error_errno(SYNTHETIC_ERRNO(ENOSR),
"Call to curl_easy_init failed.");
@@ -485,8 +485,10 @@ static int setup_uploader(Uploader *u, const char *url, const char *state_file)
static void destroy_uploader(Uploader *u) {
assert(u);
curl_easy_cleanup(u->easy);
curl_slist_free_all(u->header);
if (sym_curl_easy_cleanup)
sym_curl_easy_cleanup(u->easy);
if (sym_curl_slist_free_all)
sym_curl_slist_free_all(u->header);
free(u->answer);
free(u->last_cursor);
@@ -527,7 +529,7 @@ static int update_content_encoding_header(Uploader *u, const CompressionConfig *
/* If Content-Encoding header is not found, append new one. */
if (!found) {
struct curl_slist *l = curl_slist_append(u->header, header);
struct curl_slist *l = sym_curl_slist_append(u->header, header);
if (!l)
return log_oom();
u->header = l;
@@ -543,7 +545,7 @@ static int update_content_encoding_header(Uploader *u, const CompressionConfig *
else
u->header = TAKE_PTR(l->next);
curl_slist_free_all(l);
sym_curl_slist_free_all(l);
update_header = true;
break;
}
@@ -573,7 +575,7 @@ static int parse_accept_encoding_header(Uploader *u) {
return update_content_encoding_header(u, NULL);
struct curl_header *header;
CURLHcode hcode = curl_easy_header(u->easy, "Accept-Encoding", 0, CURLH_HEADER, -1, &header);
CURLHcode hcode = sym_curl_easy_header(u->easy, "Accept-Encoding", 0, CURLH_HEADER, -1, &header);
if (hcode != CURLHE_OK)
goto not_found;
@@ -622,7 +624,7 @@ static int perform_upload(Uploader *u) {
assert(u);
u->watchdog_timestamp = now(CLOCK_MONOTONIC);
code = curl_easy_perform(u->easy);
code = sym_curl_easy_perform(u->easy);
if (code) {
if (u->error[0])
return log_error_errno(SYNTHETIC_ERRNO(EIO),
@@ -631,14 +633,14 @@ static int perform_upload(Uploader *u) {
else
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Upload to %s failed: %s",
u->url, curl_easy_strerror(code));
u->url, sym_curl_easy_strerror(code));
}
code = curl_easy_getinfo(u->easy, CURLINFO_RESPONSE_CODE, &status);
code = sym_curl_easy_getinfo(u->easy, CURLINFO_RESPONSE_CODE, &status);
if (code)
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Failed to retrieve response code: %s",
curl_easy_strerror(code));
sym_curl_easy_strerror(code));
if (status >= 300)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
@@ -922,6 +924,10 @@ static int run(int argc, char **argv) {
if (r <= 0)
return r;
r = dlopen_curl();
if (r < 0)
return r;
r = compression_configs_mangle(&arg_compression);
if (r < 0)
return r;
+1 -1
View File
@@ -65,7 +65,7 @@ executables += [
'sources' : systemd_journal_upload_sources,
'extract' : systemd_journal_upload_extract_sources,
'objects' : ['systemd-journal-remote'],
'dependencies' : common_deps + [libcurl],
'dependencies' : common_deps,
},
test_template + {
'sources' : files('test-journal-header-util.c'),
-2
View File
@@ -8,8 +8,6 @@ executables += [
'report.c',
'report-upload.c',
),
'link_with' : [libcurlutil_static, libshared],
'dependencies' : [libcurl],
},
libexec_template + {
+9 -6
View File
@@ -12,7 +12,6 @@
#if HAVE_LIBCURL
#include "curl-util.h"
#include <curl/easy.h> /* Sadly this fails if ordered first. */
#define SERVER_ANSWER_MAX (1*1024*1024u)
@@ -86,6 +85,10 @@ int upload_collected(Context *context) {
_cleanup_free_ char *json = NULL;
int r;
r = dlopen_curl();
if (r < 0)
return r;
{
/* Convert our variant array to a JSON report.
* We won't need the JSON structure again, so free it quickly. */
@@ -110,7 +113,7 @@ int upload_collected(Context *context) {
if (r < 0)
return log_error_errno(r, "Failed to create curl header: %m");
_cleanup_(curl_easy_cleanupp) CURL *curl = curl_easy_init();
_cleanup_(curl_easy_cleanupp) CURL *curl = sym_curl_easy_init();
if (!curl)
return log_error_errno(SYNTHETIC_ERRNO(ENOSR),
"Call to curl_easy_init failed.");
@@ -173,18 +176,18 @@ int upload_collected(Context *context) {
if (!easy_setopt(curl, LOG_ERR, CURLOPT_POSTFIELDS, json))
return -EXFULL;
CURLcode code = curl_easy_perform(curl);
CURLcode code = sym_curl_easy_perform(curl);
if (code != CURLE_OK)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Upload to %s failed: %s", arg_url,
empty_to_null(&error[0]) ?: curl_easy_strerror(code));
empty_to_null(&error[0]) ?: sym_curl_easy_strerror(code));
long status;
code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
code = sym_curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK)
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
"Failed to retrieve response code: %s",
curl_easy_strerror(code));
sym_curl_easy_strerror(code));
_cleanup_free_ char *ans = iovw_to_cstring(&context->upload_answer);
if (!ans)
+103 -31
View File
@@ -1,9 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "curl-util.h"
#if HAVE_LIBCURL
#include "sd-dlopen.h"
#include "sd-event.h"
#include "alloc-util.h"
#include "curl-util.h"
#include "dlfcn-util.h"
#include "fd-util.h"
#include "hashmap.h"
#include "log.h"
@@ -12,6 +17,62 @@
#include "time-util.h"
#include "version.h"
static void *curl_dl = NULL;
DLSYM_PROTOTYPE(curl_easy_cleanup) = NULL;
DLSYM_PROTOTYPE(curl_easy_getinfo) = NULL;
DLSYM_PROTOTYPE(curl_easy_init) = NULL;
DLSYM_PROTOTYPE(curl_easy_perform) = NULL;
DLSYM_PROTOTYPE(curl_easy_setopt) = NULL;
DLSYM_PROTOTYPE(curl_easy_strerror) = NULL;
#if LIBCURL_VERSION_NUM >= 0x075300
DLSYM_PROTOTYPE(curl_easy_header) = NULL;
#endif
DLSYM_PROTOTYPE(curl_getdate) = NULL;
DLSYM_PROTOTYPE(curl_multi_add_handle) = NULL;
DLSYM_PROTOTYPE(curl_multi_assign) = NULL;
DLSYM_PROTOTYPE(curl_multi_cleanup) = NULL;
DLSYM_PROTOTYPE(curl_multi_info_read) = NULL;
DLSYM_PROTOTYPE(curl_multi_init) = NULL;
DLSYM_PROTOTYPE(curl_multi_remove_handle) = NULL;
DLSYM_PROTOTYPE(curl_multi_setopt) = NULL;
DLSYM_PROTOTYPE(curl_multi_socket_action) = NULL;
DLSYM_PROTOTYPE(curl_slist_append) = NULL;
DLSYM_PROTOTYPE(curl_slist_free_all) = NULL;
int dlopen_curl(void) {
SD_ELF_NOTE_DLOPEN(
"curl",
"Support for downloading and uploading files over HTTP",
SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
"libcurl.so.4");
return dlopen_many_sym_or_warn(
&curl_dl,
"libcurl.so.4",
LOG_DEBUG,
DLSYM_ARG(curl_easy_cleanup),
DLSYM_ARG(curl_easy_getinfo),
DLSYM_ARG(curl_easy_init),
DLSYM_ARG(curl_easy_perform),
DLSYM_ARG(curl_easy_setopt),
DLSYM_ARG(curl_easy_strerror),
#if LIBCURL_VERSION_NUM >= 0x075300
DLSYM_ARG(curl_easy_header),
#endif
DLSYM_ARG(curl_getdate),
DLSYM_ARG(curl_multi_add_handle),
DLSYM_ARG(curl_multi_assign),
DLSYM_ARG(curl_multi_cleanup),
DLSYM_ARG(curl_multi_info_read),
DLSYM_ARG(curl_multi_init),
DLSYM_ARG(curl_multi_remove_handle),
DLSYM_ARG(curl_multi_setopt),
DLSYM_ARG(curl_multi_socket_action),
DLSYM_ARG(curl_slist_append),
DLSYM_ARG(curl_slist_free_all));
}
static void curl_glue_check_finished(CurlGlue *g) {
int r;
@@ -26,7 +87,7 @@ static void curl_glue_check_finished(CurlGlue *g) {
CURLMsg *msg;
int k = 0;
msg = curl_multi_info_read(g->curl, &k);
msg = sym_curl_multi_info_read(g->curl, &k);
if (!msg)
return;
@@ -52,7 +113,7 @@ static int curl_glue_on_io(sd_event_source *s, int fd, uint32_t revents, void *u
else
action = 0;
if (curl_multi_socket_action(g->curl, fd, action, &k) != CURLM_OK)
if (sym_curl_multi_socket_action(g->curl, fd, action, &k) != CURLM_OK)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to propagate IO event.");
@@ -105,7 +166,7 @@ static int curl_glue_socket_callback(CURL *curl, curl_socket_t s, int action, vo
if (sd_event_add_io(g->event, &io, s, events, curl_glue_on_io, g) < 0)
return -1;
if (curl_multi_assign(g->curl, s, io) != CURLM_OK)
if (sym_curl_multi_assign(g->curl, s, io) != CURLM_OK)
return -1;
(void) sd_event_source_set_description(io, "curl-io");
@@ -127,7 +188,7 @@ static int curl_glue_on_timer(sd_event_source *s, uint64_t usec, void *userdata)
assert(s);
if (curl_multi_socket_action(g->curl, CURL_SOCKET_TIMEOUT, 0, &k) != CURLM_OK)
if (sym_curl_multi_socket_action(g->curl, CURL_SOCKET_TIMEOUT, 0, &k) != CURLM_OK)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to propagate timeout.");
@@ -189,7 +250,7 @@ CurlGlue *curl_glue_unref(CurlGlue *g) {
return NULL;
if (g->curl)
curl_multi_cleanup(g->curl);
sym_curl_multi_cleanup(g->curl);
while ((io = hashmap_steal_first(g->ios)))
sd_event_source_unref(io);
@@ -210,6 +271,10 @@ int curl_glue_new(CurlGlue **glue, sd_event *event) {
assert(glue);
r = dlopen_curl();
if (r < 0)
return r;
if (event)
e = sd_event_ref(event);
else {
@@ -218,7 +283,7 @@ int curl_glue_new(CurlGlue **glue, sd_event *event) {
return r;
}
c = curl_multi_init();
c = sym_curl_multi_init();
if (!c)
return -ENOMEM;
@@ -231,16 +296,16 @@ int curl_glue_new(CurlGlue **glue, sd_event *event) {
.curl = TAKE_PTR(c),
};
if (curl_multi_setopt(g->curl, CURLMOPT_SOCKETDATA, g) != CURLM_OK)
if (sym_curl_multi_setopt(g->curl, CURLMOPT_SOCKETDATA, g) != CURLM_OK)
return -EINVAL;
if (curl_multi_setopt(g->curl, CURLMOPT_SOCKETFUNCTION, curl_glue_socket_callback) != CURLM_OK)
if (sym_curl_multi_setopt(g->curl, CURLMOPT_SOCKETFUNCTION, curl_glue_socket_callback) != CURLM_OK)
return -EINVAL;
if (curl_multi_setopt(g->curl, CURLMOPT_TIMERDATA, g) != CURLM_OK)
if (sym_curl_multi_setopt(g->curl, CURLMOPT_TIMERDATA, g) != CURLM_OK)
return -EINVAL;
if (curl_multi_setopt(g->curl, CURLMOPT_TIMERFUNCTION, curl_glue_timer_callback) != CURLM_OK)
if (sym_curl_multi_setopt(g->curl, CURLMOPT_TIMERFUNCTION, curl_glue_timer_callback) != CURLM_OK)
return -EINVAL;
r = sd_event_add_defer(g->event, &g->defer, curl_glue_on_defer, g);
@@ -257,45 +322,50 @@ int curl_glue_new(CurlGlue **glue, sd_event *event) {
int curl_glue_make(CURL **ret, const char *url, void *userdata) {
_cleanup_(curl_easy_cleanupp) CURL *c = NULL;
const char *useragent;
int r;
assert(ret);
assert(url);
c = curl_easy_init();
r = dlopen_curl();
if (r < 0)
return r;
c = sym_curl_easy_init();
if (!c)
return -ENOMEM;
if (DEBUG_LOGGING)
(void) curl_easy_setopt(c, CURLOPT_VERBOSE, 1L);
(void) sym_curl_easy_setopt(c, CURLOPT_VERBOSE, 1L);
if (curl_easy_setopt(c, CURLOPT_URL, url) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_URL, url) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(c, CURLOPT_PRIVATE, userdata) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_PRIVATE, userdata) != CURLE_OK)
return -EIO;
useragent = strjoina(program_invocation_short_name, "/" GIT_VERSION);
if (curl_easy_setopt(c, CURLOPT_USERAGENT, useragent) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_USERAGENT, useragent) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(c, CURLOPT_LOW_SPEED_TIME, 60L) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_LOW_SPEED_TIME, 60L) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(c, CURLOPT_LOW_SPEED_LIMIT, 30L) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_LOW_SPEED_LIMIT, 30L) != CURLE_OK)
return -EIO;
#if LIBCURL_VERSION_NUM >= 0x075500 /* libcurl 7.85.0 */
if (curl_easy_setopt(c, CURLOPT_PROTOCOLS_STR, "HTTP,HTTPS,FILE") != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_PROTOCOLS_STR, "HTTP,HTTPS,FILE") != CURLE_OK)
#else
if (curl_easy_setopt(c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_FILE) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_FILE) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(c, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS) != CURLE_OK)
if (sym_curl_easy_setopt(c, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS) != CURLE_OK)
#endif
return -EIO;
@@ -307,7 +377,7 @@ int curl_glue_add(CurlGlue *g, CURL *c) {
assert(g);
assert(c);
if (curl_multi_add_handle(g->curl, c) != CURLM_OK)
if (sym_curl_multi_add_handle(g->curl, c) != CURLM_OK)
return -EIO;
return 0;
@@ -320,9 +390,9 @@ void curl_glue_remove_and_free(CurlGlue *g, CURL *c) {
return;
if (g->curl)
curl_multi_remove_handle(g->curl, c);
sym_curl_multi_remove_handle(g->curl, c);
curl_easy_cleanup(c);
sym_curl_easy_cleanup(c);
}
struct curl_slist *curl_slist_new(const char *first, ...) {
@@ -332,7 +402,7 @@ struct curl_slist *curl_slist_new(const char *first, ...) {
if (!first)
return NULL;
l = curl_slist_append(NULL, first);
l = sym_curl_slist_append(NULL, first);
if (!l)
return NULL;
@@ -346,10 +416,10 @@ struct curl_slist *curl_slist_new(const char *first, ...) {
if (!i)
break;
n = curl_slist_append(l, i);
n = sym_curl_slist_append(l, i);
if (!n) {
va_end(ap);
curl_slist_free_all(l);
sym_curl_slist_free_all(l);
return NULL;
}
@@ -397,7 +467,7 @@ int curl_parse_http_time(const char *t, usec_t *ret) {
assert(t);
assert(ret);
time_t v = curl_getdate(t, NULL);
time_t v = sym_curl_getdate(t, NULL);
if (v == (time_t) -1)
return -EINVAL;
@@ -416,7 +486,7 @@ int curl_append_to_header(struct curl_slist **list, char **headers) {
assert(list);
STRV_FOREACH(h, headers) {
struct curl_slist *l = curl_slist_append(*list, *h);
struct curl_slist *l = sym_curl_slist_append(*list, *h);
if (!l)
return -ENOMEM;
*list = l;
@@ -424,3 +494,5 @@ int curl_append_to_header(struct curl_slist **list, char **headers) {
return 0;
}
#endif
+47 -13
View File
@@ -1,22 +1,44 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <curl/curl.h>
#include "shared-forward.h"
#define easy_setopt(curl, log_level, opt, value) ({ \
CURLcode code = curl_easy_setopt(ASSERT_PTR(curl), opt, value); \
if (code) \
log_full(log_level, \
"curl_easy_setopt %s failed: %s", \
#opt, curl_easy_strerror(code)); \
code == CURLE_OK; \
})
#if HAVE_LIBCURL
#include <curl/curl.h> /* IWYU pragma: export */
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(CURL*, curl_easy_cleanup, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(CURLM*, curl_multi_cleanup, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct curl_slist*, curl_slist_free_all, NULL);
#include "dlfcn-util.h"
extern DLSYM_PROTOTYPE(curl_easy_cleanup);
extern DLSYM_PROTOTYPE(curl_easy_getinfo);
extern DLSYM_PROTOTYPE(curl_easy_init);
extern DLSYM_PROTOTYPE(curl_easy_perform);
extern DLSYM_PROTOTYPE(curl_easy_setopt);
extern DLSYM_PROTOTYPE(curl_easy_strerror);
#if LIBCURL_VERSION_NUM >= 0x075300
extern DLSYM_PROTOTYPE(curl_easy_header);
#endif
extern DLSYM_PROTOTYPE(curl_getdate);
extern DLSYM_PROTOTYPE(curl_multi_add_handle);
extern DLSYM_PROTOTYPE(curl_multi_assign);
extern DLSYM_PROTOTYPE(curl_multi_cleanup);
extern DLSYM_PROTOTYPE(curl_multi_info_read);
extern DLSYM_PROTOTYPE(curl_multi_init);
extern DLSYM_PROTOTYPE(curl_multi_remove_handle);
extern DLSYM_PROTOTYPE(curl_multi_setopt);
extern DLSYM_PROTOTYPE(curl_multi_socket_action);
extern DLSYM_PROTOTYPE(curl_slist_append);
extern DLSYM_PROTOTYPE(curl_slist_free_all);
int dlopen_curl(void);
#define easy_setopt(curl, log_level, opt, value) ({ \
CURLcode code = sym_curl_easy_setopt(ASSERT_PTR(curl), opt, value); \
if (code) \
log_full(log_level, \
"curl_easy_setopt %s failed: %s", \
#opt, sym_curl_easy_strerror(code)); \
code == CURLE_OK; \
})
typedef struct CurlGlue CurlGlue;
@@ -44,3 +66,15 @@ struct curl_slist *curl_slist_new(const char *first, ...) _sentinel_;
int curl_header_strdup(const void *contents, size_t sz, const char *field, char **value);
int curl_parse_http_time(const char *t, usec_t *ret);
int curl_append_to_header(struct curl_slist **list, char **headers);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(CURL*, sym_curl_easy_cleanup, curl_easy_cleanupp, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(CURLM*, sym_curl_multi_cleanup, curl_multi_cleanupp, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(struct curl_slist*, sym_curl_slist_free_all, curl_slist_free_allp, NULL);
#else
static inline int dlopen_curl(void) {
return -EOPNOTSUPP;
}
#endif
+2 -15
View File
@@ -53,6 +53,7 @@ shared_sources = files(
'cryptsetup-fido2.c',
'cryptsetup-tpm2.c',
'cryptsetup-util.c',
'curl-util.c',
'daemon-util.c',
'data-fd-util.c',
'dev-setup.c',
@@ -396,6 +397,7 @@ libshared_deps = [threads,
libbpf_cflags,
libcrypt_cflags,
libcryptsetup_cflags,
libcurl_cflags,
libdl,
libdw_cflags,
libelf_cflags,
@@ -459,18 +461,3 @@ libshared_fdisk = static_library(
userspace],
c_args : ['-fvisibility=default'],
build_by_default : false)
# A small shared file that is linked into a few places.
# It is not part of libshared because this code needs libcurl and
# we don't want to link libshared to libcurl.
if conf.get('HAVE_LIBCURL') == 1
libcurlutil_static = static_library(
'curl-util',
'curl-util.c',
implicit_include_directories : false,
dependencies : [userspace, libcurl],
include_directories : includes,
build_by_default : false)
else
libcurlutil_static = []
endif
+2
View File
@@ -6,6 +6,7 @@
#include "bpf-dlopen.h"
#include "compress.h"
#include "cryptsetup-util.h"
#include "curl-util.h"
#include "elf-util.h"
#include "gcrypt-util.h"
#include "idn-util.h"
@@ -45,6 +46,7 @@ static int run(int argc, char **argv) {
ASSERT_DLOPEN(dlopen_bzip2, HAVE_BZIP2);
ASSERT_DLOPEN(dlopen_bpf, HAVE_LIBBPF);
ASSERT_DLOPEN(dlopen_cryptsetup, HAVE_LIBCRYPTSETUP);
ASSERT_DLOPEN(dlopen_curl, HAVE_LIBCURL);
ASSERT_DLOPEN(dlopen_dw, HAVE_ELFUTILS);
ASSERT_DLOPEN(dlopen_elf, HAVE_ELFUTILS);
ASSERT_DLOPEN(dlopen_gcrypt, HAVE_GCRYPT);