1*7304104dSAndroid Build Coastguard Worker /* Retrieve ELF / DWARF / source files from the debuginfod.
2*7304104dSAndroid Build Coastguard Worker Copyright (C) 2019-2021 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker Copyright (C) 2021, 2022 Mark J. Wielaard <[email protected]>
4*7304104dSAndroid Build Coastguard Worker This file is part of elfutils.
5*7304104dSAndroid Build Coastguard Worker
6*7304104dSAndroid Build Coastguard Worker This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker it under the terms of either
8*7304104dSAndroid Build Coastguard Worker
9*7304104dSAndroid Build Coastguard Worker * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker your option) any later version
12*7304104dSAndroid Build Coastguard Worker
13*7304104dSAndroid Build Coastguard Worker or
14*7304104dSAndroid Build Coastguard Worker
15*7304104dSAndroid Build Coastguard Worker * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker your option) any later version
18*7304104dSAndroid Build Coastguard Worker
19*7304104dSAndroid Build Coastguard Worker or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker
21*7304104dSAndroid Build Coastguard Worker elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24*7304104dSAndroid Build Coastguard Worker General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker
26*7304104dSAndroid Build Coastguard Worker You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker the GNU Lesser General Public License along with this program. If
28*7304104dSAndroid Build Coastguard Worker not, see <http://www.gnu.org/licenses/>. */
29*7304104dSAndroid Build Coastguard Worker
30*7304104dSAndroid Build Coastguard Worker
31*7304104dSAndroid Build Coastguard Worker /* cargo-cult from libdwfl linux-kernel-modules.c */
32*7304104dSAndroid Build Coastguard Worker /* In case we have a bad fts we include this before config.h because it
33*7304104dSAndroid Build Coastguard Worker can't handle _FILE_OFFSET_BITS.
34*7304104dSAndroid Build Coastguard Worker Everything we need here is fine if its declarations just come first.
35*7304104dSAndroid Build Coastguard Worker Also, include sys/types.h before fts. On some systems fts.h is not self
36*7304104dSAndroid Build Coastguard Worker contained. */
37*7304104dSAndroid Build Coastguard Worker #ifdef BAD_FTS
38*7304104dSAndroid Build Coastguard Worker #include <sys/types.h>
39*7304104dSAndroid Build Coastguard Worker #include <fts.h>
40*7304104dSAndroid Build Coastguard Worker #endif
41*7304104dSAndroid Build Coastguard Worker
42*7304104dSAndroid Build Coastguard Worker #include "config.h"
43*7304104dSAndroid Build Coastguard Worker #include "debuginfod.h"
44*7304104dSAndroid Build Coastguard Worker #include "system.h"
45*7304104dSAndroid Build Coastguard Worker #include <ctype.h>
46*7304104dSAndroid Build Coastguard Worker #include <errno.h>
47*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
48*7304104dSAndroid Build Coastguard Worker #include <gelf.h>
49*7304104dSAndroid Build Coastguard Worker
50*7304104dSAndroid Build Coastguard Worker /* We might be building a bootstrap dummy library, which is really simple. */
51*7304104dSAndroid Build Coastguard Worker #ifdef DUMMY_LIBDEBUGINFOD
52*7304104dSAndroid Build Coastguard Worker
debuginfod_begin(void)53*7304104dSAndroid Build Coastguard Worker debuginfod_client *debuginfod_begin (void) { errno = ENOSYS; return NULL; }
debuginfod_find_debuginfo(debuginfod_client * c,const unsigned char * b,int s,char ** p)54*7304104dSAndroid Build Coastguard Worker int debuginfod_find_debuginfo (debuginfod_client *c, const unsigned char *b,
55*7304104dSAndroid Build Coastguard Worker int s, char **p) { return -ENOSYS; }
debuginfod_find_executable(debuginfod_client * c,const unsigned char * b,int s,char ** p)56*7304104dSAndroid Build Coastguard Worker int debuginfod_find_executable (debuginfod_client *c, const unsigned char *b,
57*7304104dSAndroid Build Coastguard Worker int s, char **p) { return -ENOSYS; }
debuginfod_find_source(debuginfod_client * c,const unsigned char * b,int s,const char * f,char ** p)58*7304104dSAndroid Build Coastguard Worker int debuginfod_find_source (debuginfod_client *c, const unsigned char *b,
59*7304104dSAndroid Build Coastguard Worker int s, const char *f, char **p) { return -ENOSYS; }
debuginfod_find_section(debuginfod_client * c,const unsigned char * b,int s,const char * scn,char ** p)60*7304104dSAndroid Build Coastguard Worker int debuginfod_find_section (debuginfod_client *c, const unsigned char *b,
61*7304104dSAndroid Build Coastguard Worker int s, const char *scn, char **p)
62*7304104dSAndroid Build Coastguard Worker { return -ENOSYS; }
debuginfod_set_progressfn(debuginfod_client * c,debuginfod_progressfn_t fn)63*7304104dSAndroid Build Coastguard Worker void debuginfod_set_progressfn(debuginfod_client *c,
64*7304104dSAndroid Build Coastguard Worker debuginfod_progressfn_t fn) { }
debuginfod_set_verbose_fd(debuginfod_client * c,int fd)65*7304104dSAndroid Build Coastguard Worker void debuginfod_set_verbose_fd(debuginfod_client *c, int fd) { }
debuginfod_set_user_data(debuginfod_client * c,void * d)66*7304104dSAndroid Build Coastguard Worker void debuginfod_set_user_data (debuginfod_client *c, void *d) { }
debuginfod_get_user_data(debuginfod_client * c)67*7304104dSAndroid Build Coastguard Worker void* debuginfod_get_user_data (debuginfod_client *c) { return NULL; }
debuginfod_get_url(debuginfod_client * c)68*7304104dSAndroid Build Coastguard Worker const char* debuginfod_get_url (debuginfod_client *c) { return NULL; }
debuginfod_add_http_header(debuginfod_client * c,const char * h)69*7304104dSAndroid Build Coastguard Worker int debuginfod_add_http_header (debuginfod_client *c,
70*7304104dSAndroid Build Coastguard Worker const char *h) { return -ENOSYS; }
debuginfod_get_headers(debuginfod_client * c)71*7304104dSAndroid Build Coastguard Worker const char* debuginfod_get_headers (debuginfod_client *c) { return NULL; }
72*7304104dSAndroid Build Coastguard Worker
debuginfod_end(debuginfod_client * c)73*7304104dSAndroid Build Coastguard Worker void debuginfod_end (debuginfod_client *c) { }
74*7304104dSAndroid Build Coastguard Worker
75*7304104dSAndroid Build Coastguard Worker #else /* DUMMY_LIBDEBUGINFOD */
76*7304104dSAndroid Build Coastguard Worker
77*7304104dSAndroid Build Coastguard Worker #include <assert.h>
78*7304104dSAndroid Build Coastguard Worker #include <dirent.h>
79*7304104dSAndroid Build Coastguard Worker #include <stdio.h>
80*7304104dSAndroid Build Coastguard Worker #include <errno.h>
81*7304104dSAndroid Build Coastguard Worker #include <unistd.h>
82*7304104dSAndroid Build Coastguard Worker #include <fcntl.h>
83*7304104dSAndroid Build Coastguard Worker #include <fts.h>
84*7304104dSAndroid Build Coastguard Worker #include <regex.h>
85*7304104dSAndroid Build Coastguard Worker #include <string.h>
86*7304104dSAndroid Build Coastguard Worker #include <stdbool.h>
87*7304104dSAndroid Build Coastguard Worker #include <linux/limits.h>
88*7304104dSAndroid Build Coastguard Worker #include <time.h>
89*7304104dSAndroid Build Coastguard Worker #include <utime.h>
90*7304104dSAndroid Build Coastguard Worker #include <sys/syscall.h>
91*7304104dSAndroid Build Coastguard Worker #include <sys/types.h>
92*7304104dSAndroid Build Coastguard Worker #include <sys/stat.h>
93*7304104dSAndroid Build Coastguard Worker #include <sys/utsname.h>
94*7304104dSAndroid Build Coastguard Worker #include <curl/curl.h>
95*7304104dSAndroid Build Coastguard Worker
96*7304104dSAndroid Build Coastguard Worker /* If fts.h is included before config.h, its indirect inclusions may not
97*7304104dSAndroid Build Coastguard Worker give us the right LFS aliases of these functions, so map them manually. */
98*7304104dSAndroid Build Coastguard Worker #ifdef BAD_FTS
99*7304104dSAndroid Build Coastguard Worker #ifdef _FILE_OFFSET_BITS
100*7304104dSAndroid Build Coastguard Worker #define open open64
101*7304104dSAndroid Build Coastguard Worker #define fopen fopen64
102*7304104dSAndroid Build Coastguard Worker #endif
103*7304104dSAndroid Build Coastguard Worker #else
104*7304104dSAndroid Build Coastguard Worker #include <sys/types.h>
105*7304104dSAndroid Build Coastguard Worker #include <fts.h>
106*7304104dSAndroid Build Coastguard Worker #endif
107*7304104dSAndroid Build Coastguard Worker
108*7304104dSAndroid Build Coastguard Worker /* Older curl.h don't define CURL_AT_LEAST_VERSION. */
109*7304104dSAndroid Build Coastguard Worker #ifndef CURL_AT_LEAST_VERSION
110*7304104dSAndroid Build Coastguard Worker #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
111*7304104dSAndroid Build Coastguard Worker #define CURL_AT_LEAST_VERSION(x,y,z) \
112*7304104dSAndroid Build Coastguard Worker (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
113*7304104dSAndroid Build Coastguard Worker #endif
114*7304104dSAndroid Build Coastguard Worker
115*7304104dSAndroid Build Coastguard Worker #include <pthread.h>
116*7304104dSAndroid Build Coastguard Worker
117*7304104dSAndroid Build Coastguard Worker static pthread_once_t init_control = PTHREAD_ONCE_INIT;
118*7304104dSAndroid Build Coastguard Worker
119*7304104dSAndroid Build Coastguard Worker static void
libcurl_init(void)120*7304104dSAndroid Build Coastguard Worker libcurl_init(void)
121*7304104dSAndroid Build Coastguard Worker {
122*7304104dSAndroid Build Coastguard Worker curl_global_init(CURL_GLOBAL_DEFAULT);
123*7304104dSAndroid Build Coastguard Worker }
124*7304104dSAndroid Build Coastguard Worker
125*7304104dSAndroid Build Coastguard Worker struct debuginfod_client
126*7304104dSAndroid Build Coastguard Worker {
127*7304104dSAndroid Build Coastguard Worker /* Progress/interrupt callback function. */
128*7304104dSAndroid Build Coastguard Worker debuginfod_progressfn_t progressfn;
129*7304104dSAndroid Build Coastguard Worker
130*7304104dSAndroid Build Coastguard Worker /* Stores user data. */
131*7304104dSAndroid Build Coastguard Worker void* user_data;
132*7304104dSAndroid Build Coastguard Worker
133*7304104dSAndroid Build Coastguard Worker /* Stores current/last url, if any. */
134*7304104dSAndroid Build Coastguard Worker char* url;
135*7304104dSAndroid Build Coastguard Worker
136*7304104dSAndroid Build Coastguard Worker /* Accumulates outgoing http header names/values. */
137*7304104dSAndroid Build Coastguard Worker int user_agent_set_p; /* affects add_default_headers */
138*7304104dSAndroid Build Coastguard Worker struct curl_slist *headers;
139*7304104dSAndroid Build Coastguard Worker
140*7304104dSAndroid Build Coastguard Worker /* Flags the default_progressfn having printed something that
141*7304104dSAndroid Build Coastguard Worker debuginfod_end needs to terminate. */
142*7304104dSAndroid Build Coastguard Worker int default_progressfn_printed_p;
143*7304104dSAndroid Build Coastguard Worker
144*7304104dSAndroid Build Coastguard Worker /* Indicates whether the last query was cancelled by progressfn. */
145*7304104dSAndroid Build Coastguard Worker bool progressfn_cancel;
146*7304104dSAndroid Build Coastguard Worker
147*7304104dSAndroid Build Coastguard Worker /* File descriptor to output any verbose messages if > 0. */
148*7304104dSAndroid Build Coastguard Worker int verbose_fd;
149*7304104dSAndroid Build Coastguard Worker
150*7304104dSAndroid Build Coastguard Worker /* Maintain a long-lived curl multi-handle, which keeps a
151*7304104dSAndroid Build Coastguard Worker connection/tls/dns cache to recently seen servers. */
152*7304104dSAndroid Build Coastguard Worker CURLM *server_mhandle;
153*7304104dSAndroid Build Coastguard Worker
154*7304104dSAndroid Build Coastguard Worker /* Can contain all other context, like cache_path, server_urls,
155*7304104dSAndroid Build Coastguard Worker timeout or other info gotten from environment variables, the
156*7304104dSAndroid Build Coastguard Worker handle data, etc. So those don't have to be reparsed and
157*7304104dSAndroid Build Coastguard Worker recreated on each request. */
158*7304104dSAndroid Build Coastguard Worker char * winning_headers;
159*7304104dSAndroid Build Coastguard Worker };
160*7304104dSAndroid Build Coastguard Worker
161*7304104dSAndroid Build Coastguard Worker /* The cache_clean_interval_s file within the debuginfod cache specifies
162*7304104dSAndroid Build Coastguard Worker how frequently the cache should be cleaned. The file's st_mtime represents
163*7304104dSAndroid Build Coastguard Worker the time of last cleaning. */
164*7304104dSAndroid Build Coastguard Worker static const char *cache_clean_interval_filename = "cache_clean_interval_s";
165*7304104dSAndroid Build Coastguard Worker static const long cache_clean_default_interval_s = 86400; /* 1 day */
166*7304104dSAndroid Build Coastguard Worker
167*7304104dSAndroid Build Coastguard Worker /* The cache_miss_default_s within the debuginfod cache specifies how
168*7304104dSAndroid Build Coastguard Worker frequently the empty file should be released.*/
169*7304104dSAndroid Build Coastguard Worker static const long cache_miss_default_s = 600; /* 10 min */
170*7304104dSAndroid Build Coastguard Worker static const char *cache_miss_filename = "cache_miss_s";
171*7304104dSAndroid Build Coastguard Worker
172*7304104dSAndroid Build Coastguard Worker /* The cache_max_unused_age_s file within the debuginfod cache specifies the
173*7304104dSAndroid Build Coastguard Worker the maximum time since last access that a file will remain in the cache. */
174*7304104dSAndroid Build Coastguard Worker static const char *cache_max_unused_age_filename = "max_unused_age_s";
175*7304104dSAndroid Build Coastguard Worker static const long cache_default_max_unused_age_s = 604800; /* 1 week */
176*7304104dSAndroid Build Coastguard Worker
177*7304104dSAndroid Build Coastguard Worker /* Location of the cache of files downloaded from debuginfods.
178*7304104dSAndroid Build Coastguard Worker The default parent directory is $HOME, or '/' if $HOME doesn't exist. */
179*7304104dSAndroid Build Coastguard Worker static const char *cache_default_name = ".debuginfod_client_cache";
180*7304104dSAndroid Build Coastguard Worker static const char *cache_xdg_name = "debuginfod_client";
181*7304104dSAndroid Build Coastguard Worker
182*7304104dSAndroid Build Coastguard Worker /* URLs of debuginfods, separated by url_delim. */
183*7304104dSAndroid Build Coastguard Worker static const char *url_delim = " ";
184*7304104dSAndroid Build Coastguard Worker
185*7304104dSAndroid Build Coastguard Worker /* Timeout for debuginfods, in seconds (to get at least 100K). */
186*7304104dSAndroid Build Coastguard Worker static const long default_timeout = 90;
187*7304104dSAndroid Build Coastguard Worker
188*7304104dSAndroid Build Coastguard Worker /* Default retry count for download error. */
189*7304104dSAndroid Build Coastguard Worker static const long default_retry_limit = 2;
190*7304104dSAndroid Build Coastguard Worker
191*7304104dSAndroid Build Coastguard Worker /* Data associated with a particular CURL easy handle. Passed to
192*7304104dSAndroid Build Coastguard Worker the write callback. */
193*7304104dSAndroid Build Coastguard Worker struct handle_data
194*7304104dSAndroid Build Coastguard Worker {
195*7304104dSAndroid Build Coastguard Worker /* Cache file to be written to in case query is successful. */
196*7304104dSAndroid Build Coastguard Worker int fd;
197*7304104dSAndroid Build Coastguard Worker
198*7304104dSAndroid Build Coastguard Worker /* URL queried by this handle. */
199*7304104dSAndroid Build Coastguard Worker char url[PATH_MAX];
200*7304104dSAndroid Build Coastguard Worker
201*7304104dSAndroid Build Coastguard Worker /* error buffer for this handle. */
202*7304104dSAndroid Build Coastguard Worker char errbuf[CURL_ERROR_SIZE];
203*7304104dSAndroid Build Coastguard Worker
204*7304104dSAndroid Build Coastguard Worker /* This handle. */
205*7304104dSAndroid Build Coastguard Worker CURL *handle;
206*7304104dSAndroid Build Coastguard Worker
207*7304104dSAndroid Build Coastguard Worker /* The client object whom we're serving. */
208*7304104dSAndroid Build Coastguard Worker debuginfod_client *client;
209*7304104dSAndroid Build Coastguard Worker
210*7304104dSAndroid Build Coastguard Worker /* Pointer to handle that should write to fd. Initially points to NULL,
211*7304104dSAndroid Build Coastguard Worker then points to the first handle that begins writing the target file
212*7304104dSAndroid Build Coastguard Worker to the cache. Used to ensure that a file is not downloaded from
213*7304104dSAndroid Build Coastguard Worker multiple servers unnecessarily. */
214*7304104dSAndroid Build Coastguard Worker CURL **target_handle;
215*7304104dSAndroid Build Coastguard Worker /* Response http headers for this client handle, sent from the server */
216*7304104dSAndroid Build Coastguard Worker char *response_data;
217*7304104dSAndroid Build Coastguard Worker size_t response_data_size;
218*7304104dSAndroid Build Coastguard Worker };
219*7304104dSAndroid Build Coastguard Worker
220*7304104dSAndroid Build Coastguard Worker static size_t
debuginfod_write_callback(char * ptr,size_t size,size_t nmemb,void * data)221*7304104dSAndroid Build Coastguard Worker debuginfod_write_callback (char *ptr, size_t size, size_t nmemb, void *data)
222*7304104dSAndroid Build Coastguard Worker {
223*7304104dSAndroid Build Coastguard Worker ssize_t count = size * nmemb;
224*7304104dSAndroid Build Coastguard Worker
225*7304104dSAndroid Build Coastguard Worker struct handle_data *d = (struct handle_data*)data;
226*7304104dSAndroid Build Coastguard Worker
227*7304104dSAndroid Build Coastguard Worker /* Indicate to other handles that they can abort their transfer. */
228*7304104dSAndroid Build Coastguard Worker if (*d->target_handle == NULL)
229*7304104dSAndroid Build Coastguard Worker {
230*7304104dSAndroid Build Coastguard Worker *d->target_handle = d->handle;
231*7304104dSAndroid Build Coastguard Worker /* update the client object */
232*7304104dSAndroid Build Coastguard Worker const char *url = NULL;
233*7304104dSAndroid Build Coastguard Worker CURLcode curl_res = curl_easy_getinfo (d->handle,
234*7304104dSAndroid Build Coastguard Worker CURLINFO_EFFECTIVE_URL, &url);
235*7304104dSAndroid Build Coastguard Worker if (curl_res == CURLE_OK && url)
236*7304104dSAndroid Build Coastguard Worker {
237*7304104dSAndroid Build Coastguard Worker free (d->client->url);
238*7304104dSAndroid Build Coastguard Worker d->client->url = strdup(url); /* ok if fails */
239*7304104dSAndroid Build Coastguard Worker }
240*7304104dSAndroid Build Coastguard Worker }
241*7304104dSAndroid Build Coastguard Worker
242*7304104dSAndroid Build Coastguard Worker /* If this handle isn't the target handle, abort transfer. */
243*7304104dSAndroid Build Coastguard Worker if (*d->target_handle != d->handle)
244*7304104dSAndroid Build Coastguard Worker return -1;
245*7304104dSAndroid Build Coastguard Worker
246*7304104dSAndroid Build Coastguard Worker return (size_t) write(d->fd, (void*)ptr, count);
247*7304104dSAndroid Build Coastguard Worker }
248*7304104dSAndroid Build Coastguard Worker
249*7304104dSAndroid Build Coastguard Worker /* handle config file read and write */
250*7304104dSAndroid Build Coastguard Worker static int
debuginfod_config_cache(debuginfod_client * c,char * config_path,long cache_config_default_s,struct stat * st)251*7304104dSAndroid Build Coastguard Worker debuginfod_config_cache(debuginfod_client *c, char *config_path,
252*7304104dSAndroid Build Coastguard Worker long cache_config_default_s,
253*7304104dSAndroid Build Coastguard Worker struct stat *st)
254*7304104dSAndroid Build Coastguard Worker {
255*7304104dSAndroid Build Coastguard Worker int fd = open(config_path, O_CREAT | O_RDWR, DEFFILEMODE);
256*7304104dSAndroid Build Coastguard Worker if (fd < 0)
257*7304104dSAndroid Build Coastguard Worker return -errno;
258*7304104dSAndroid Build Coastguard Worker
259*7304104dSAndroid Build Coastguard Worker if (fstat (fd, st) < 0)
260*7304104dSAndroid Build Coastguard Worker {
261*7304104dSAndroid Build Coastguard Worker int ret = -errno;
262*7304104dSAndroid Build Coastguard Worker close (fd);
263*7304104dSAndroid Build Coastguard Worker return ret;
264*7304104dSAndroid Build Coastguard Worker }
265*7304104dSAndroid Build Coastguard Worker
266*7304104dSAndroid Build Coastguard Worker if (st->st_size == 0)
267*7304104dSAndroid Build Coastguard Worker {
268*7304104dSAndroid Build Coastguard Worker if (dprintf(fd, "%ld", cache_config_default_s) < 0)
269*7304104dSAndroid Build Coastguard Worker {
270*7304104dSAndroid Build Coastguard Worker int ret = -errno;
271*7304104dSAndroid Build Coastguard Worker close (fd);
272*7304104dSAndroid Build Coastguard Worker return ret;
273*7304104dSAndroid Build Coastguard Worker }
274*7304104dSAndroid Build Coastguard Worker
275*7304104dSAndroid Build Coastguard Worker close (fd);
276*7304104dSAndroid Build Coastguard Worker return cache_config_default_s;
277*7304104dSAndroid Build Coastguard Worker }
278*7304104dSAndroid Build Coastguard Worker
279*7304104dSAndroid Build Coastguard Worker long cache_config;
280*7304104dSAndroid Build Coastguard Worker /* PR29696 - NB: When using fdopen, the file descriptor is NOT
281*7304104dSAndroid Build Coastguard Worker dup'ed and will be closed when the stream is closed. Manually
282*7304104dSAndroid Build Coastguard Worker closing fd after fclose is called will lead to a race condition
283*7304104dSAndroid Build Coastguard Worker where, if reused, the file descriptor will compete for its
284*7304104dSAndroid Build Coastguard Worker regular use before being incorrectly closed here. */
285*7304104dSAndroid Build Coastguard Worker FILE *config_file = fdopen(fd, "r");
286*7304104dSAndroid Build Coastguard Worker if (config_file)
287*7304104dSAndroid Build Coastguard Worker {
288*7304104dSAndroid Build Coastguard Worker if (fscanf(config_file, "%ld", &cache_config) != 1)
289*7304104dSAndroid Build Coastguard Worker cache_config = cache_config_default_s;
290*7304104dSAndroid Build Coastguard Worker if (0 != fclose (config_file) && c->verbose_fd >= 0)
291*7304104dSAndroid Build Coastguard Worker dprintf (c->verbose_fd, "fclose failed with %s (err=%d)\n",
292*7304104dSAndroid Build Coastguard Worker strerror (errno), errno);
293*7304104dSAndroid Build Coastguard Worker }
294*7304104dSAndroid Build Coastguard Worker else
295*7304104dSAndroid Build Coastguard Worker {
296*7304104dSAndroid Build Coastguard Worker cache_config = cache_config_default_s;
297*7304104dSAndroid Build Coastguard Worker if (0 != close (fd) && c->verbose_fd >= 0)
298*7304104dSAndroid Build Coastguard Worker dprintf (c->verbose_fd, "close failed with %s (err=%d)\n",
299*7304104dSAndroid Build Coastguard Worker strerror (errno), errno);
300*7304104dSAndroid Build Coastguard Worker }
301*7304104dSAndroid Build Coastguard Worker return cache_config;
302*7304104dSAndroid Build Coastguard Worker }
303*7304104dSAndroid Build Coastguard Worker
304*7304104dSAndroid Build Coastguard Worker /* Delete any files that have been unmodied for a period
305*7304104dSAndroid Build Coastguard Worker longer than $DEBUGINFOD_CACHE_CLEAN_INTERVAL_S. */
306*7304104dSAndroid Build Coastguard Worker static int
debuginfod_clean_cache(debuginfod_client * c,char * cache_path,char * interval_path,char * max_unused_path)307*7304104dSAndroid Build Coastguard Worker debuginfod_clean_cache(debuginfod_client *c,
308*7304104dSAndroid Build Coastguard Worker char *cache_path, char *interval_path,
309*7304104dSAndroid Build Coastguard Worker char *max_unused_path)
310*7304104dSAndroid Build Coastguard Worker {
311*7304104dSAndroid Build Coastguard Worker time_t clean_interval, max_unused_age;
312*7304104dSAndroid Build Coastguard Worker int rc = -1;
313*7304104dSAndroid Build Coastguard Worker struct stat st;
314*7304104dSAndroid Build Coastguard Worker
315*7304104dSAndroid Build Coastguard Worker /* Create new interval file. */
316*7304104dSAndroid Build Coastguard Worker rc = debuginfod_config_cache(c, interval_path,
317*7304104dSAndroid Build Coastguard Worker cache_clean_default_interval_s, &st);
318*7304104dSAndroid Build Coastguard Worker if (rc < 0)
319*7304104dSAndroid Build Coastguard Worker return rc;
320*7304104dSAndroid Build Coastguard Worker clean_interval = (time_t)rc;
321*7304104dSAndroid Build Coastguard Worker
322*7304104dSAndroid Build Coastguard Worker /* Check timestamp of interval file to see whether cleaning is necessary. */
323*7304104dSAndroid Build Coastguard Worker if (time(NULL) - st.st_mtime < clean_interval)
324*7304104dSAndroid Build Coastguard Worker /* Interval has not passed, skip cleaning. */
325*7304104dSAndroid Build Coastguard Worker return 0;
326*7304104dSAndroid Build Coastguard Worker
327*7304104dSAndroid Build Coastguard Worker /* Update timestamp representing when the cache was last cleaned.
328*7304104dSAndroid Build Coastguard Worker Do it at the start to reduce the number of threads trying to do a
329*7304104dSAndroid Build Coastguard Worker cleanup simultaneously. */
330*7304104dSAndroid Build Coastguard Worker utime (interval_path, NULL);
331*7304104dSAndroid Build Coastguard Worker
332*7304104dSAndroid Build Coastguard Worker /* Read max unused age value from config file. */
333*7304104dSAndroid Build Coastguard Worker rc = debuginfod_config_cache(c, max_unused_path,
334*7304104dSAndroid Build Coastguard Worker cache_default_max_unused_age_s, &st);
335*7304104dSAndroid Build Coastguard Worker if (rc < 0)
336*7304104dSAndroid Build Coastguard Worker return rc;
337*7304104dSAndroid Build Coastguard Worker max_unused_age = (time_t)rc;
338*7304104dSAndroid Build Coastguard Worker
339*7304104dSAndroid Build Coastguard Worker char * const dirs[] = { cache_path, NULL, };
340*7304104dSAndroid Build Coastguard Worker
341*7304104dSAndroid Build Coastguard Worker FTS *fts = fts_open(dirs, 0, NULL);
342*7304104dSAndroid Build Coastguard Worker if (fts == NULL)
343*7304104dSAndroid Build Coastguard Worker return -errno;
344*7304104dSAndroid Build Coastguard Worker
345*7304104dSAndroid Build Coastguard Worker regex_t re;
346*7304104dSAndroid Build Coastguard Worker const char * pattern = ".*/[a-f0-9]+(/debuginfo|/executable|/source.*|)$"; /* include dirs */
347*7304104dSAndroid Build Coastguard Worker if (regcomp (&re, pattern, REG_EXTENDED | REG_NOSUB) != 0)
348*7304104dSAndroid Build Coastguard Worker return -ENOMEM;
349*7304104dSAndroid Build Coastguard Worker
350*7304104dSAndroid Build Coastguard Worker FTSENT *f;
351*7304104dSAndroid Build Coastguard Worker long files = 0;
352*7304104dSAndroid Build Coastguard Worker time_t now = time(NULL);
353*7304104dSAndroid Build Coastguard Worker while ((f = fts_read(fts)) != NULL)
354*7304104dSAndroid Build Coastguard Worker {
355*7304104dSAndroid Build Coastguard Worker /* ignore any files that do not match the pattern. */
356*7304104dSAndroid Build Coastguard Worker if (regexec (&re, f->fts_path, 0, NULL, 0) != 0)
357*7304104dSAndroid Build Coastguard Worker continue;
358*7304104dSAndroid Build Coastguard Worker
359*7304104dSAndroid Build Coastguard Worker files++;
360*7304104dSAndroid Build Coastguard Worker if (c->progressfn) /* inform/check progress callback */
361*7304104dSAndroid Build Coastguard Worker if ((c->progressfn) (c, files, 0))
362*7304104dSAndroid Build Coastguard Worker break;
363*7304104dSAndroid Build Coastguard Worker
364*7304104dSAndroid Build Coastguard Worker switch (f->fts_info)
365*7304104dSAndroid Build Coastguard Worker {
366*7304104dSAndroid Build Coastguard Worker case FTS_F:
367*7304104dSAndroid Build Coastguard Worker /* delete file if max_unused_age has been met or exceeded w.r.t. atime. */
368*7304104dSAndroid Build Coastguard Worker if (now - f->fts_statp->st_atime >= max_unused_age)
369*7304104dSAndroid Build Coastguard Worker (void) unlink (f->fts_path);
370*7304104dSAndroid Build Coastguard Worker break;
371*7304104dSAndroid Build Coastguard Worker
372*7304104dSAndroid Build Coastguard Worker case FTS_DP:
373*7304104dSAndroid Build Coastguard Worker /* Remove if old & empty. Weaken race against concurrent creation by
374*7304104dSAndroid Build Coastguard Worker checking mtime. */
375*7304104dSAndroid Build Coastguard Worker if (now - f->fts_statp->st_mtime >= max_unused_age)
376*7304104dSAndroid Build Coastguard Worker (void) rmdir (f->fts_path);
377*7304104dSAndroid Build Coastguard Worker break;
378*7304104dSAndroid Build Coastguard Worker
379*7304104dSAndroid Build Coastguard Worker default:
380*7304104dSAndroid Build Coastguard Worker ;
381*7304104dSAndroid Build Coastguard Worker }
382*7304104dSAndroid Build Coastguard Worker }
383*7304104dSAndroid Build Coastguard Worker fts_close (fts);
384*7304104dSAndroid Build Coastguard Worker regfree (&re);
385*7304104dSAndroid Build Coastguard Worker
386*7304104dSAndroid Build Coastguard Worker return 0;
387*7304104dSAndroid Build Coastguard Worker }
388*7304104dSAndroid Build Coastguard Worker
389*7304104dSAndroid Build Coastguard Worker
390*7304104dSAndroid Build Coastguard Worker #define MAX_BUILD_ID_BYTES 64
391*7304104dSAndroid Build Coastguard Worker
392*7304104dSAndroid Build Coastguard Worker
393*7304104dSAndroid Build Coastguard Worker static void
add_default_headers(debuginfod_client * client)394*7304104dSAndroid Build Coastguard Worker add_default_headers(debuginfod_client *client)
395*7304104dSAndroid Build Coastguard Worker {
396*7304104dSAndroid Build Coastguard Worker if (client->user_agent_set_p)
397*7304104dSAndroid Build Coastguard Worker return;
398*7304104dSAndroid Build Coastguard Worker
399*7304104dSAndroid Build Coastguard Worker /* Compute a User-Agent: string to send. The more accurately this
400*7304104dSAndroid Build Coastguard Worker describes this host, the likelier that the debuginfod servers
401*7304104dSAndroid Build Coastguard Worker might be able to locate debuginfo for us. */
402*7304104dSAndroid Build Coastguard Worker
403*7304104dSAndroid Build Coastguard Worker char* utspart = NULL;
404*7304104dSAndroid Build Coastguard Worker struct utsname uts;
405*7304104dSAndroid Build Coastguard Worker int rc = 0;
406*7304104dSAndroid Build Coastguard Worker rc = uname (&uts);
407*7304104dSAndroid Build Coastguard Worker if (rc == 0)
408*7304104dSAndroid Build Coastguard Worker rc = asprintf(& utspart, "%s/%s", uts.sysname, uts.machine);
409*7304104dSAndroid Build Coastguard Worker if (rc < 0)
410*7304104dSAndroid Build Coastguard Worker utspart = NULL;
411*7304104dSAndroid Build Coastguard Worker
412*7304104dSAndroid Build Coastguard Worker FILE *f = fopen ("/etc/os-release", "r");
413*7304104dSAndroid Build Coastguard Worker if (f == NULL)
414*7304104dSAndroid Build Coastguard Worker f = fopen ("/usr/lib/os-release", "r");
415*7304104dSAndroid Build Coastguard Worker char *id = NULL;
416*7304104dSAndroid Build Coastguard Worker char *version = NULL;
417*7304104dSAndroid Build Coastguard Worker if (f != NULL)
418*7304104dSAndroid Build Coastguard Worker {
419*7304104dSAndroid Build Coastguard Worker while (id == NULL || version == NULL)
420*7304104dSAndroid Build Coastguard Worker {
421*7304104dSAndroid Build Coastguard Worker char buf[128];
422*7304104dSAndroid Build Coastguard Worker char *s = &buf[0];
423*7304104dSAndroid Build Coastguard Worker if (fgets (s, sizeof(buf), f) == NULL)
424*7304104dSAndroid Build Coastguard Worker break;
425*7304104dSAndroid Build Coastguard Worker
426*7304104dSAndroid Build Coastguard Worker int len = strlen (s);
427*7304104dSAndroid Build Coastguard Worker if (len < 3)
428*7304104dSAndroid Build Coastguard Worker continue;
429*7304104dSAndroid Build Coastguard Worker if (s[len - 1] == '\n')
430*7304104dSAndroid Build Coastguard Worker {
431*7304104dSAndroid Build Coastguard Worker s[len - 1] = '\0';
432*7304104dSAndroid Build Coastguard Worker len--;
433*7304104dSAndroid Build Coastguard Worker }
434*7304104dSAndroid Build Coastguard Worker
435*7304104dSAndroid Build Coastguard Worker char *v = strchr (s, '=');
436*7304104dSAndroid Build Coastguard Worker if (v == NULL || strlen (v) < 2)
437*7304104dSAndroid Build Coastguard Worker continue;
438*7304104dSAndroid Build Coastguard Worker
439*7304104dSAndroid Build Coastguard Worker /* Split var and value. */
440*7304104dSAndroid Build Coastguard Worker *v = '\0';
441*7304104dSAndroid Build Coastguard Worker v++;
442*7304104dSAndroid Build Coastguard Worker
443*7304104dSAndroid Build Coastguard Worker /* Remove optional quotes around value string. */
444*7304104dSAndroid Build Coastguard Worker if (*v == '"' || *v == '\'')
445*7304104dSAndroid Build Coastguard Worker {
446*7304104dSAndroid Build Coastguard Worker v++;
447*7304104dSAndroid Build Coastguard Worker s[len - 1] = '\0';
448*7304104dSAndroid Build Coastguard Worker }
449*7304104dSAndroid Build Coastguard Worker if (strcmp (s, "ID") == 0)
450*7304104dSAndroid Build Coastguard Worker id = strdup (v);
451*7304104dSAndroid Build Coastguard Worker if (strcmp (s, "VERSION_ID") == 0)
452*7304104dSAndroid Build Coastguard Worker version = strdup (v);
453*7304104dSAndroid Build Coastguard Worker }
454*7304104dSAndroid Build Coastguard Worker fclose (f);
455*7304104dSAndroid Build Coastguard Worker }
456*7304104dSAndroid Build Coastguard Worker
457*7304104dSAndroid Build Coastguard Worker char *ua = NULL;
458*7304104dSAndroid Build Coastguard Worker rc = asprintf(& ua, "User-Agent: %s/%s,%s,%s/%s",
459*7304104dSAndroid Build Coastguard Worker PACKAGE_NAME, PACKAGE_VERSION,
460*7304104dSAndroid Build Coastguard Worker utspart ?: "",
461*7304104dSAndroid Build Coastguard Worker id ?: "",
462*7304104dSAndroid Build Coastguard Worker version ?: "");
463*7304104dSAndroid Build Coastguard Worker if (rc < 0)
464*7304104dSAndroid Build Coastguard Worker ua = NULL;
465*7304104dSAndroid Build Coastguard Worker
466*7304104dSAndroid Build Coastguard Worker if (ua)
467*7304104dSAndroid Build Coastguard Worker (void) debuginfod_add_http_header (client, ua);
468*7304104dSAndroid Build Coastguard Worker
469*7304104dSAndroid Build Coastguard Worker free (ua);
470*7304104dSAndroid Build Coastguard Worker free (id);
471*7304104dSAndroid Build Coastguard Worker free (version);
472*7304104dSAndroid Build Coastguard Worker free (utspart);
473*7304104dSAndroid Build Coastguard Worker }
474*7304104dSAndroid Build Coastguard Worker
475*7304104dSAndroid Build Coastguard Worker /* Add HTTP headers found in the given file, one per line. Blank lines or invalid
476*7304104dSAndroid Build Coastguard Worker * headers are ignored.
477*7304104dSAndroid Build Coastguard Worker */
478*7304104dSAndroid Build Coastguard Worker static void
add_headers_from_file(debuginfod_client * client,const char * filename)479*7304104dSAndroid Build Coastguard Worker add_headers_from_file(debuginfod_client *client, const char* filename)
480*7304104dSAndroid Build Coastguard Worker {
481*7304104dSAndroid Build Coastguard Worker int vds = client->verbose_fd;
482*7304104dSAndroid Build Coastguard Worker FILE *f = fopen (filename, "r");
483*7304104dSAndroid Build Coastguard Worker if (f == NULL)
484*7304104dSAndroid Build Coastguard Worker {
485*7304104dSAndroid Build Coastguard Worker if (vds >= 0)
486*7304104dSAndroid Build Coastguard Worker dprintf(vds, "header file %s: %s\n", filename, strerror(errno));
487*7304104dSAndroid Build Coastguard Worker return;
488*7304104dSAndroid Build Coastguard Worker }
489*7304104dSAndroid Build Coastguard Worker
490*7304104dSAndroid Build Coastguard Worker while (1)
491*7304104dSAndroid Build Coastguard Worker {
492*7304104dSAndroid Build Coastguard Worker char buf[8192];
493*7304104dSAndroid Build Coastguard Worker char *s = &buf[0];
494*7304104dSAndroid Build Coastguard Worker if (feof(f))
495*7304104dSAndroid Build Coastguard Worker break;
496*7304104dSAndroid Build Coastguard Worker if (fgets (s, sizeof(buf), f) == NULL)
497*7304104dSAndroid Build Coastguard Worker break;
498*7304104dSAndroid Build Coastguard Worker for (char *c = s; *c != '\0'; ++c)
499*7304104dSAndroid Build Coastguard Worker if (!isspace(*c))
500*7304104dSAndroid Build Coastguard Worker goto nonempty;
501*7304104dSAndroid Build Coastguard Worker continue;
502*7304104dSAndroid Build Coastguard Worker nonempty:
503*7304104dSAndroid Build Coastguard Worker ;
504*7304104dSAndroid Build Coastguard Worker size_t last = strlen(s)-1;
505*7304104dSAndroid Build Coastguard Worker if (s[last] == '\n')
506*7304104dSAndroid Build Coastguard Worker s[last] = '\0';
507*7304104dSAndroid Build Coastguard Worker int rc = debuginfod_add_http_header(client, s);
508*7304104dSAndroid Build Coastguard Worker if (rc < 0 && vds >= 0)
509*7304104dSAndroid Build Coastguard Worker dprintf(vds, "skipping bad header: %s\n", strerror(-rc));
510*7304104dSAndroid Build Coastguard Worker }
511*7304104dSAndroid Build Coastguard Worker fclose (f);
512*7304104dSAndroid Build Coastguard Worker }
513*7304104dSAndroid Build Coastguard Worker
514*7304104dSAndroid Build Coastguard Worker
515*7304104dSAndroid Build Coastguard Worker #define xalloc_str(p, fmt, args...) \
516*7304104dSAndroid Build Coastguard Worker do \
517*7304104dSAndroid Build Coastguard Worker { \
518*7304104dSAndroid Build Coastguard Worker if (asprintf (&p, fmt, args) < 0) \
519*7304104dSAndroid Build Coastguard Worker { \
520*7304104dSAndroid Build Coastguard Worker p = NULL; \
521*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM; \
522*7304104dSAndroid Build Coastguard Worker goto out; \
523*7304104dSAndroid Build Coastguard Worker } \
524*7304104dSAndroid Build Coastguard Worker } while (0)
525*7304104dSAndroid Build Coastguard Worker
526*7304104dSAndroid Build Coastguard Worker
527*7304104dSAndroid Build Coastguard Worker /* Offer a basic form of progress tracing */
528*7304104dSAndroid Build Coastguard Worker static int
default_progressfn(debuginfod_client * c,long a,long b)529*7304104dSAndroid Build Coastguard Worker default_progressfn (debuginfod_client *c, long a, long b)
530*7304104dSAndroid Build Coastguard Worker {
531*7304104dSAndroid Build Coastguard Worker const char* url = debuginfod_get_url (c);
532*7304104dSAndroid Build Coastguard Worker int len = 0;
533*7304104dSAndroid Build Coastguard Worker
534*7304104dSAndroid Build Coastguard Worker /* We prefer to print the host part of the URL to keep the
535*7304104dSAndroid Build Coastguard Worker message short. */
536*7304104dSAndroid Build Coastguard Worker if (url != NULL)
537*7304104dSAndroid Build Coastguard Worker {
538*7304104dSAndroid Build Coastguard Worker const char* buildid = strstr(url, "buildid/");
539*7304104dSAndroid Build Coastguard Worker if (buildid != NULL)
540*7304104dSAndroid Build Coastguard Worker len = (buildid - url);
541*7304104dSAndroid Build Coastguard Worker else
542*7304104dSAndroid Build Coastguard Worker len = strlen(url);
543*7304104dSAndroid Build Coastguard Worker }
544*7304104dSAndroid Build Coastguard Worker
545*7304104dSAndroid Build Coastguard Worker if (b == 0 || url==NULL) /* early stage */
546*7304104dSAndroid Build Coastguard Worker dprintf(STDERR_FILENO,
547*7304104dSAndroid Build Coastguard Worker "\rDownloading %c", "-/|\\"[a % 4]);
548*7304104dSAndroid Build Coastguard Worker else if (b < 0) /* download in progress but unknown total length */
549*7304104dSAndroid Build Coastguard Worker dprintf(STDERR_FILENO,
550*7304104dSAndroid Build Coastguard Worker "\rDownloading from %.*s %ld",
551*7304104dSAndroid Build Coastguard Worker len, url, a);
552*7304104dSAndroid Build Coastguard Worker else /* download in progress, and known total length */
553*7304104dSAndroid Build Coastguard Worker dprintf(STDERR_FILENO,
554*7304104dSAndroid Build Coastguard Worker "\rDownloading from %.*s %ld/%ld",
555*7304104dSAndroid Build Coastguard Worker len, url, a, b);
556*7304104dSAndroid Build Coastguard Worker c->default_progressfn_printed_p = 1;
557*7304104dSAndroid Build Coastguard Worker
558*7304104dSAndroid Build Coastguard Worker return 0;
559*7304104dSAndroid Build Coastguard Worker }
560*7304104dSAndroid Build Coastguard Worker
561*7304104dSAndroid Build Coastguard Worker /* This is a callback function that receives http response headers in buffer for use
562*7304104dSAndroid Build Coastguard Worker * in this program. https://curl.se/libcurl/c/CURLOPT_HEADERFUNCTION.html is the
563*7304104dSAndroid Build Coastguard Worker * online documentation.
564*7304104dSAndroid Build Coastguard Worker */
565*7304104dSAndroid Build Coastguard Worker static size_t
header_callback(char * buffer,size_t size,size_t numitems,void * userdata)566*7304104dSAndroid Build Coastguard Worker header_callback (char * buffer, size_t size, size_t numitems, void * userdata)
567*7304104dSAndroid Build Coastguard Worker {
568*7304104dSAndroid Build Coastguard Worker struct handle_data *data = (struct handle_data *) userdata;
569*7304104dSAndroid Build Coastguard Worker if (size != 1)
570*7304104dSAndroid Build Coastguard Worker return 0;
571*7304104dSAndroid Build Coastguard Worker if (data->client
572*7304104dSAndroid Build Coastguard Worker && data->client->verbose_fd >= 0
573*7304104dSAndroid Build Coastguard Worker && numitems > 2)
574*7304104dSAndroid Build Coastguard Worker dprintf (data->client->verbose_fd, "header %.*s", (int)numitems, buffer);
575*7304104dSAndroid Build Coastguard Worker // Some basic checks to ensure the headers received are of the expected format
576*7304104dSAndroid Build Coastguard Worker if (strncasecmp(buffer, "X-DEBUGINFOD", 11)
577*7304104dSAndroid Build Coastguard Worker || buffer[numitems-2] != '\r'
578*7304104dSAndroid Build Coastguard Worker || buffer[numitems-1] != '\n'
579*7304104dSAndroid Build Coastguard Worker || (buffer == strstr(buffer, ":")) ){
580*7304104dSAndroid Build Coastguard Worker return numitems;
581*7304104dSAndroid Build Coastguard Worker }
582*7304104dSAndroid Build Coastguard Worker /* Temporary buffer for realloc */
583*7304104dSAndroid Build Coastguard Worker char *temp = NULL;
584*7304104dSAndroid Build Coastguard Worker if (data->response_data == NULL)
585*7304104dSAndroid Build Coastguard Worker {
586*7304104dSAndroid Build Coastguard Worker temp = malloc(numitems);
587*7304104dSAndroid Build Coastguard Worker if (temp == NULL)
588*7304104dSAndroid Build Coastguard Worker return 0;
589*7304104dSAndroid Build Coastguard Worker }
590*7304104dSAndroid Build Coastguard Worker else
591*7304104dSAndroid Build Coastguard Worker {
592*7304104dSAndroid Build Coastguard Worker temp = realloc(data->response_data, data->response_data_size + numitems);
593*7304104dSAndroid Build Coastguard Worker if (temp == NULL)
594*7304104dSAndroid Build Coastguard Worker return 0;
595*7304104dSAndroid Build Coastguard Worker }
596*7304104dSAndroid Build Coastguard Worker
597*7304104dSAndroid Build Coastguard Worker memcpy(temp + data->response_data_size, buffer, numitems-1);
598*7304104dSAndroid Build Coastguard Worker data->response_data = temp;
599*7304104dSAndroid Build Coastguard Worker data->response_data_size += numitems-1;
600*7304104dSAndroid Build Coastguard Worker data->response_data[data->response_data_size-1] = '\n';
601*7304104dSAndroid Build Coastguard Worker data->response_data[data->response_data_size] = '\0';
602*7304104dSAndroid Build Coastguard Worker return numitems;
603*7304104dSAndroid Build Coastguard Worker }
604*7304104dSAndroid Build Coastguard Worker
605*7304104dSAndroid Build Coastguard Worker /* Copy SRC to DEST, s,/,#,g */
606*7304104dSAndroid Build Coastguard Worker
607*7304104dSAndroid Build Coastguard Worker static void
path_escape(const char * src,char * dest)608*7304104dSAndroid Build Coastguard Worker path_escape (const char *src, char *dest)
609*7304104dSAndroid Build Coastguard Worker {
610*7304104dSAndroid Build Coastguard Worker unsigned q = 0;
611*7304104dSAndroid Build Coastguard Worker
612*7304104dSAndroid Build Coastguard Worker for (unsigned fi=0; q < PATH_MAX-2; fi++) /* -2, escape is 2 chars. */
613*7304104dSAndroid Build Coastguard Worker switch (src[fi])
614*7304104dSAndroid Build Coastguard Worker {
615*7304104dSAndroid Build Coastguard Worker case '\0':
616*7304104dSAndroid Build Coastguard Worker dest[q] = '\0';
617*7304104dSAndroid Build Coastguard Worker return;
618*7304104dSAndroid Build Coastguard Worker case '/': /* escape / to prevent dir escape */
619*7304104dSAndroid Build Coastguard Worker dest[q++]='#';
620*7304104dSAndroid Build Coastguard Worker dest[q++]='#';
621*7304104dSAndroid Build Coastguard Worker break;
622*7304104dSAndroid Build Coastguard Worker case '#': /* escape # to prevent /# vs #/ collisions */
623*7304104dSAndroid Build Coastguard Worker dest[q++]='#';
624*7304104dSAndroid Build Coastguard Worker dest[q++]='_';
625*7304104dSAndroid Build Coastguard Worker break;
626*7304104dSAndroid Build Coastguard Worker default:
627*7304104dSAndroid Build Coastguard Worker dest[q++]=src[fi];
628*7304104dSAndroid Build Coastguard Worker }
629*7304104dSAndroid Build Coastguard Worker
630*7304104dSAndroid Build Coastguard Worker dest[q] = '\0';
631*7304104dSAndroid Build Coastguard Worker }
632*7304104dSAndroid Build Coastguard Worker
633*7304104dSAndroid Build Coastguard Worker /* Attempt to update the atime */
634*7304104dSAndroid Build Coastguard Worker static void
update_atime(int fd)635*7304104dSAndroid Build Coastguard Worker update_atime (int fd)
636*7304104dSAndroid Build Coastguard Worker {
637*7304104dSAndroid Build Coastguard Worker struct timespec tvs[2];
638*7304104dSAndroid Build Coastguard Worker
639*7304104dSAndroid Build Coastguard Worker tvs[0].tv_sec = tvs[1].tv_sec = 0;
640*7304104dSAndroid Build Coastguard Worker tvs[0].tv_nsec = UTIME_NOW;
641*7304104dSAndroid Build Coastguard Worker tvs[1].tv_nsec = UTIME_OMIT;
642*7304104dSAndroid Build Coastguard Worker
643*7304104dSAndroid Build Coastguard Worker (void) futimens (fd, tvs); /* best effort */
644*7304104dSAndroid Build Coastguard Worker }
645*7304104dSAndroid Build Coastguard Worker
646*7304104dSAndroid Build Coastguard Worker /* Attempt to read an ELF/DWARF section with name SECTION from FD and write
647*7304104dSAndroid Build Coastguard Worker it to a separate file in the debuginfod cache. If successful the absolute
648*7304104dSAndroid Build Coastguard Worker path of the separate file containing SECTION will be stored in USR_PATH.
649*7304104dSAndroid Build Coastguard Worker FD_PATH is the absolute path for FD.
650*7304104dSAndroid Build Coastguard Worker
651*7304104dSAndroid Build Coastguard Worker If the section cannot be extracted, then return a negative error code.
652*7304104dSAndroid Build Coastguard Worker -ENOENT indicates that the parent file was able to be read but the
653*7304104dSAndroid Build Coastguard Worker section name was not found. -EEXIST indicates that the section was
654*7304104dSAndroid Build Coastguard Worker found but had type SHT_NOBITS. */
655*7304104dSAndroid Build Coastguard Worker
656*7304104dSAndroid Build Coastguard Worker static int
extract_section(int fd,const char * section,char * fd_path,char ** usr_path)657*7304104dSAndroid Build Coastguard Worker extract_section (int fd, const char *section, char *fd_path, char **usr_path)
658*7304104dSAndroid Build Coastguard Worker {
659*7304104dSAndroid Build Coastguard Worker elf_version (EV_CURRENT);
660*7304104dSAndroid Build Coastguard Worker
661*7304104dSAndroid Build Coastguard Worker Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
662*7304104dSAndroid Build Coastguard Worker if (elf == NULL)
663*7304104dSAndroid Build Coastguard Worker return -EIO;
664*7304104dSAndroid Build Coastguard Worker
665*7304104dSAndroid Build Coastguard Worker size_t shstrndx;
666*7304104dSAndroid Build Coastguard Worker int rc = elf_getshdrstrndx (elf, &shstrndx);
667*7304104dSAndroid Build Coastguard Worker if (rc < 0)
668*7304104dSAndroid Build Coastguard Worker {
669*7304104dSAndroid Build Coastguard Worker rc = -EIO;
670*7304104dSAndroid Build Coastguard Worker goto out;
671*7304104dSAndroid Build Coastguard Worker }
672*7304104dSAndroid Build Coastguard Worker
673*7304104dSAndroid Build Coastguard Worker int sec_fd = -1;
674*7304104dSAndroid Build Coastguard Worker char *escaped_name = NULL;
675*7304104dSAndroid Build Coastguard Worker char *sec_path_tmp = NULL;
676*7304104dSAndroid Build Coastguard Worker Elf_Scn *scn = NULL;
677*7304104dSAndroid Build Coastguard Worker
678*7304104dSAndroid Build Coastguard Worker /* Try to find the target section and copy the contents into a
679*7304104dSAndroid Build Coastguard Worker separate file. */
680*7304104dSAndroid Build Coastguard Worker while (true)
681*7304104dSAndroid Build Coastguard Worker {
682*7304104dSAndroid Build Coastguard Worker scn = elf_nextscn (elf, scn);
683*7304104dSAndroid Build Coastguard Worker if (scn == NULL)
684*7304104dSAndroid Build Coastguard Worker {
685*7304104dSAndroid Build Coastguard Worker rc = -ENOENT;
686*7304104dSAndroid Build Coastguard Worker goto out;
687*7304104dSAndroid Build Coastguard Worker }
688*7304104dSAndroid Build Coastguard Worker GElf_Shdr shdr_storage;
689*7304104dSAndroid Build Coastguard Worker GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_storage);
690*7304104dSAndroid Build Coastguard Worker if (shdr == NULL)
691*7304104dSAndroid Build Coastguard Worker {
692*7304104dSAndroid Build Coastguard Worker rc = -EIO;
693*7304104dSAndroid Build Coastguard Worker goto out;
694*7304104dSAndroid Build Coastguard Worker }
695*7304104dSAndroid Build Coastguard Worker
696*7304104dSAndroid Build Coastguard Worker const char *scn_name = elf_strptr (elf, shstrndx, shdr->sh_name);
697*7304104dSAndroid Build Coastguard Worker if (scn_name == NULL)
698*7304104dSAndroid Build Coastguard Worker {
699*7304104dSAndroid Build Coastguard Worker rc = -EIO;
700*7304104dSAndroid Build Coastguard Worker goto out;
701*7304104dSAndroid Build Coastguard Worker }
702*7304104dSAndroid Build Coastguard Worker if (strcmp (scn_name, section) == 0)
703*7304104dSAndroid Build Coastguard Worker {
704*7304104dSAndroid Build Coastguard Worker /* We found the desired section. */
705*7304104dSAndroid Build Coastguard Worker if (shdr->sh_type == SHT_NOBITS)
706*7304104dSAndroid Build Coastguard Worker {
707*7304104dSAndroid Build Coastguard Worker rc = -EEXIST;
708*7304104dSAndroid Build Coastguard Worker goto out;
709*7304104dSAndroid Build Coastguard Worker }
710*7304104dSAndroid Build Coastguard Worker
711*7304104dSAndroid Build Coastguard Worker Elf_Data *data = NULL;
712*7304104dSAndroid Build Coastguard Worker data = elf_rawdata (scn, NULL);
713*7304104dSAndroid Build Coastguard Worker if (data == NULL)
714*7304104dSAndroid Build Coastguard Worker {
715*7304104dSAndroid Build Coastguard Worker rc = -EIO;
716*7304104dSAndroid Build Coastguard Worker goto out;
717*7304104dSAndroid Build Coastguard Worker }
718*7304104dSAndroid Build Coastguard Worker
719*7304104dSAndroid Build Coastguard Worker if (data->d_buf == NULL)
720*7304104dSAndroid Build Coastguard Worker {
721*7304104dSAndroid Build Coastguard Worker rc = -EIO;
722*7304104dSAndroid Build Coastguard Worker goto out;
723*7304104dSAndroid Build Coastguard Worker }
724*7304104dSAndroid Build Coastguard Worker
725*7304104dSAndroid Build Coastguard Worker /* Compute the absolute filename we'll write the section to.
726*7304104dSAndroid Build Coastguard Worker Replace the last component of FD_PATH with the path-escaped
727*7304104dSAndroid Build Coastguard Worker section filename. */
728*7304104dSAndroid Build Coastguard Worker int i = strlen (fd_path);
729*7304104dSAndroid Build Coastguard Worker while (i >= 0)
730*7304104dSAndroid Build Coastguard Worker {
731*7304104dSAndroid Build Coastguard Worker if (fd_path[i] == '/')
732*7304104dSAndroid Build Coastguard Worker {
733*7304104dSAndroid Build Coastguard Worker fd_path[i] = '\0';
734*7304104dSAndroid Build Coastguard Worker break;
735*7304104dSAndroid Build Coastguard Worker }
736*7304104dSAndroid Build Coastguard Worker --i;
737*7304104dSAndroid Build Coastguard Worker }
738*7304104dSAndroid Build Coastguard Worker
739*7304104dSAndroid Build Coastguard Worker escaped_name = malloc (strlen (section) * 2 + 1);
740*7304104dSAndroid Build Coastguard Worker if (escaped_name == NULL)
741*7304104dSAndroid Build Coastguard Worker {
742*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
743*7304104dSAndroid Build Coastguard Worker goto out;
744*7304104dSAndroid Build Coastguard Worker }
745*7304104dSAndroid Build Coastguard Worker path_escape (section, escaped_name);
746*7304104dSAndroid Build Coastguard Worker
747*7304104dSAndroid Build Coastguard Worker rc = asprintf (&sec_path_tmp, "%s/section-%s.XXXXXX",
748*7304104dSAndroid Build Coastguard Worker fd_path, escaped_name);
749*7304104dSAndroid Build Coastguard Worker if (rc == -1)
750*7304104dSAndroid Build Coastguard Worker {
751*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
752*7304104dSAndroid Build Coastguard Worker goto out1;
753*7304104dSAndroid Build Coastguard Worker }
754*7304104dSAndroid Build Coastguard Worker
755*7304104dSAndroid Build Coastguard Worker sec_fd = mkstemp (sec_path_tmp);
756*7304104dSAndroid Build Coastguard Worker if (sec_fd < 0)
757*7304104dSAndroid Build Coastguard Worker {
758*7304104dSAndroid Build Coastguard Worker rc = -EIO;
759*7304104dSAndroid Build Coastguard Worker goto out2;
760*7304104dSAndroid Build Coastguard Worker }
761*7304104dSAndroid Build Coastguard Worker
762*7304104dSAndroid Build Coastguard Worker ssize_t res = write_retry (sec_fd, data->d_buf, data->d_size);
763*7304104dSAndroid Build Coastguard Worker if (res < 0 || (size_t) res != data->d_size)
764*7304104dSAndroid Build Coastguard Worker {
765*7304104dSAndroid Build Coastguard Worker rc = -EIO;
766*7304104dSAndroid Build Coastguard Worker goto out3;
767*7304104dSAndroid Build Coastguard Worker }
768*7304104dSAndroid Build Coastguard Worker
769*7304104dSAndroid Build Coastguard Worker /* Success. Rename tmp file and update USR_PATH. */
770*7304104dSAndroid Build Coastguard Worker char *sec_path;
771*7304104dSAndroid Build Coastguard Worker if (asprintf (&sec_path, "%s/section-%s", fd_path, section) == -1)
772*7304104dSAndroid Build Coastguard Worker {
773*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
774*7304104dSAndroid Build Coastguard Worker goto out3;
775*7304104dSAndroid Build Coastguard Worker }
776*7304104dSAndroid Build Coastguard Worker
777*7304104dSAndroid Build Coastguard Worker rc = rename (sec_path_tmp, sec_path);
778*7304104dSAndroid Build Coastguard Worker if (rc < 0)
779*7304104dSAndroid Build Coastguard Worker {
780*7304104dSAndroid Build Coastguard Worker free (sec_path);
781*7304104dSAndroid Build Coastguard Worker rc = -EIO;
782*7304104dSAndroid Build Coastguard Worker goto out3;
783*7304104dSAndroid Build Coastguard Worker }
784*7304104dSAndroid Build Coastguard Worker
785*7304104dSAndroid Build Coastguard Worker if (usr_path != NULL)
786*7304104dSAndroid Build Coastguard Worker *usr_path = sec_path;
787*7304104dSAndroid Build Coastguard Worker else
788*7304104dSAndroid Build Coastguard Worker free (sec_path);
789*7304104dSAndroid Build Coastguard Worker update_atime(fd);
790*7304104dSAndroid Build Coastguard Worker rc = sec_fd;
791*7304104dSAndroid Build Coastguard Worker goto out2;
792*7304104dSAndroid Build Coastguard Worker }
793*7304104dSAndroid Build Coastguard Worker }
794*7304104dSAndroid Build Coastguard Worker
795*7304104dSAndroid Build Coastguard Worker out3:
796*7304104dSAndroid Build Coastguard Worker close (sec_fd);
797*7304104dSAndroid Build Coastguard Worker unlink (sec_path_tmp);
798*7304104dSAndroid Build Coastguard Worker
799*7304104dSAndroid Build Coastguard Worker out2:
800*7304104dSAndroid Build Coastguard Worker free (sec_path_tmp);
801*7304104dSAndroid Build Coastguard Worker
802*7304104dSAndroid Build Coastguard Worker out1:
803*7304104dSAndroid Build Coastguard Worker free (escaped_name);
804*7304104dSAndroid Build Coastguard Worker
805*7304104dSAndroid Build Coastguard Worker out:
806*7304104dSAndroid Build Coastguard Worker elf_end (elf);
807*7304104dSAndroid Build Coastguard Worker return rc;
808*7304104dSAndroid Build Coastguard Worker }
809*7304104dSAndroid Build Coastguard Worker
810*7304104dSAndroid Build Coastguard Worker /* Search TARGET_CACHE_DIR for a debuginfo or executable file containing
811*7304104dSAndroid Build Coastguard Worker an ELF/DWARF section with name SCN_NAME. If found, extract the section
812*7304104dSAndroid Build Coastguard Worker to a separate file in TARGET_CACHE_DIR and return a file descriptor
813*7304104dSAndroid Build Coastguard Worker for the section file. The path for this file will be stored in USR_PATH.
814*7304104dSAndroid Build Coastguard Worker Return a negative errno if unsuccessful. -ENOENT indicates that SCN_NAME
815*7304104dSAndroid Build Coastguard Worker is confirmed to not exist. */
816*7304104dSAndroid Build Coastguard Worker
817*7304104dSAndroid Build Coastguard Worker static int
cache_find_section(const char * scn_name,const char * target_cache_dir,char ** usr_path)818*7304104dSAndroid Build Coastguard Worker cache_find_section (const char *scn_name, const char *target_cache_dir,
819*7304104dSAndroid Build Coastguard Worker char **usr_path)
820*7304104dSAndroid Build Coastguard Worker {
821*7304104dSAndroid Build Coastguard Worker int debug_fd;
822*7304104dSAndroid Build Coastguard Worker int rc = -EEXIST;
823*7304104dSAndroid Build Coastguard Worker char parent_path[PATH_MAX];
824*7304104dSAndroid Build Coastguard Worker
825*7304104dSAndroid Build Coastguard Worker /* Check the debuginfo first. */
826*7304104dSAndroid Build Coastguard Worker snprintf (parent_path, PATH_MAX, "%s/debuginfo", target_cache_dir);
827*7304104dSAndroid Build Coastguard Worker debug_fd = open (parent_path, O_RDONLY);
828*7304104dSAndroid Build Coastguard Worker if (debug_fd >= 0)
829*7304104dSAndroid Build Coastguard Worker {
830*7304104dSAndroid Build Coastguard Worker rc = extract_section (debug_fd, scn_name, parent_path, usr_path);
831*7304104dSAndroid Build Coastguard Worker close (debug_fd);
832*7304104dSAndroid Build Coastguard Worker }
833*7304104dSAndroid Build Coastguard Worker
834*7304104dSAndroid Build Coastguard Worker /* If the debuginfo file couldn't be found or the section type was
835*7304104dSAndroid Build Coastguard Worker SHT_NOBITS, check the executable. */
836*7304104dSAndroid Build Coastguard Worker if (rc == -EEXIST)
837*7304104dSAndroid Build Coastguard Worker {
838*7304104dSAndroid Build Coastguard Worker snprintf (parent_path, PATH_MAX, "%s/executable", target_cache_dir);
839*7304104dSAndroid Build Coastguard Worker int exec_fd = open (parent_path, O_RDONLY);
840*7304104dSAndroid Build Coastguard Worker
841*7304104dSAndroid Build Coastguard Worker if (exec_fd >= 0)
842*7304104dSAndroid Build Coastguard Worker {
843*7304104dSAndroid Build Coastguard Worker rc = extract_section (exec_fd, scn_name, parent_path, usr_path);
844*7304104dSAndroid Build Coastguard Worker close (exec_fd);
845*7304104dSAndroid Build Coastguard Worker
846*7304104dSAndroid Build Coastguard Worker /* Don't return -ENOENT if the debuginfo wasn't opened. The
847*7304104dSAndroid Build Coastguard Worker section may exist in the debuginfo but not the executable. */
848*7304104dSAndroid Build Coastguard Worker if (debug_fd < 0 && rc == -ENOENT)
849*7304104dSAndroid Build Coastguard Worker rc = -EREMOTE;
850*7304104dSAndroid Build Coastguard Worker }
851*7304104dSAndroid Build Coastguard Worker }
852*7304104dSAndroid Build Coastguard Worker
853*7304104dSAndroid Build Coastguard Worker return rc;
854*7304104dSAndroid Build Coastguard Worker }
855*7304104dSAndroid Build Coastguard Worker
856*7304104dSAndroid Build Coastguard Worker /* Query each of the server URLs found in $DEBUGINFOD_URLS for the file
857*7304104dSAndroid Build Coastguard Worker with the specified build-id and type (debuginfo, executable, source or
858*7304104dSAndroid Build Coastguard Worker section). If type is source, then type_arg should be a filename. If
859*7304104dSAndroid Build Coastguard Worker type is section, then type_arg should be the name of an ELF/DWARF
860*7304104dSAndroid Build Coastguard Worker section. Otherwise type_arg may be NULL. Return a file descriptor
861*7304104dSAndroid Build Coastguard Worker for the target if successful, otherwise return an error code.
862*7304104dSAndroid Build Coastguard Worker */
863*7304104dSAndroid Build Coastguard Worker static int
debuginfod_query_server(debuginfod_client * c,const unsigned char * build_id,int build_id_len,const char * type,const char * type_arg,char ** path)864*7304104dSAndroid Build Coastguard Worker debuginfod_query_server (debuginfod_client *c,
865*7304104dSAndroid Build Coastguard Worker const unsigned char *build_id,
866*7304104dSAndroid Build Coastguard Worker int build_id_len,
867*7304104dSAndroid Build Coastguard Worker const char *type,
868*7304104dSAndroid Build Coastguard Worker const char *type_arg,
869*7304104dSAndroid Build Coastguard Worker char **path)
870*7304104dSAndroid Build Coastguard Worker {
871*7304104dSAndroid Build Coastguard Worker char *server_urls;
872*7304104dSAndroid Build Coastguard Worker char *urls_envvar;
873*7304104dSAndroid Build Coastguard Worker const char *section = NULL;
874*7304104dSAndroid Build Coastguard Worker const char *filename = NULL;
875*7304104dSAndroid Build Coastguard Worker char *cache_path = NULL;
876*7304104dSAndroid Build Coastguard Worker char *maxage_path = NULL;
877*7304104dSAndroid Build Coastguard Worker char *interval_path = NULL;
878*7304104dSAndroid Build Coastguard Worker char *cache_miss_path = NULL;
879*7304104dSAndroid Build Coastguard Worker char *target_cache_dir = NULL;
880*7304104dSAndroid Build Coastguard Worker char *target_cache_path = NULL;
881*7304104dSAndroid Build Coastguard Worker char *target_cache_tmppath = NULL;
882*7304104dSAndroid Build Coastguard Worker char suffix[PATH_MAX + 1]; /* +1 for zero terminator. */
883*7304104dSAndroid Build Coastguard Worker char build_id_bytes[MAX_BUILD_ID_BYTES * 2 + 1];
884*7304104dSAndroid Build Coastguard Worker int vfd = c->verbose_fd;
885*7304104dSAndroid Build Coastguard Worker int rc;
886*7304104dSAndroid Build Coastguard Worker
887*7304104dSAndroid Build Coastguard Worker c->progressfn_cancel = false;
888*7304104dSAndroid Build Coastguard Worker
889*7304104dSAndroid Build Coastguard Worker if (strcmp (type, "source") == 0)
890*7304104dSAndroid Build Coastguard Worker filename = type_arg;
891*7304104dSAndroid Build Coastguard Worker else if (strcmp (type, "section") == 0)
892*7304104dSAndroid Build Coastguard Worker {
893*7304104dSAndroid Build Coastguard Worker section = type_arg;
894*7304104dSAndroid Build Coastguard Worker if (section == NULL)
895*7304104dSAndroid Build Coastguard Worker return -EINVAL;
896*7304104dSAndroid Build Coastguard Worker }
897*7304104dSAndroid Build Coastguard Worker
898*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
899*7304104dSAndroid Build Coastguard Worker {
900*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "debuginfod_find_%s ", type);
901*7304104dSAndroid Build Coastguard Worker if (build_id_len == 0) /* expect clean hexadecimal */
902*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "%s", (const char *) build_id);
903*7304104dSAndroid Build Coastguard Worker else
904*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < build_id_len; i++)
905*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "%02x", build_id[i]);
906*7304104dSAndroid Build Coastguard Worker if (filename != NULL)
907*7304104dSAndroid Build Coastguard Worker dprintf (vfd, " %s\n", filename);
908*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "\n");
909*7304104dSAndroid Build Coastguard Worker }
910*7304104dSAndroid Build Coastguard Worker
911*7304104dSAndroid Build Coastguard Worker /* Is there any server we can query? If not, don't do any work,
912*7304104dSAndroid Build Coastguard Worker just return with ENOSYS. Don't even access the cache. */
913*7304104dSAndroid Build Coastguard Worker urls_envvar = getenv(DEBUGINFOD_URLS_ENV_VAR);
914*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
915*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "server urls \"%s\"\n",
916*7304104dSAndroid Build Coastguard Worker urls_envvar != NULL ? urls_envvar : "");
917*7304104dSAndroid Build Coastguard Worker if (urls_envvar == NULL || urls_envvar[0] == '\0')
918*7304104dSAndroid Build Coastguard Worker {
919*7304104dSAndroid Build Coastguard Worker rc = -ENOSYS;
920*7304104dSAndroid Build Coastguard Worker goto out;
921*7304104dSAndroid Build Coastguard Worker }
922*7304104dSAndroid Build Coastguard Worker
923*7304104dSAndroid Build Coastguard Worker /* Clear the obsolete data from a previous _find operation. */
924*7304104dSAndroid Build Coastguard Worker free (c->url);
925*7304104dSAndroid Build Coastguard Worker c->url = NULL;
926*7304104dSAndroid Build Coastguard Worker free (c->winning_headers);
927*7304104dSAndroid Build Coastguard Worker c->winning_headers = NULL;
928*7304104dSAndroid Build Coastguard Worker
929*7304104dSAndroid Build Coastguard Worker /* PR 27982: Add max size if DEBUGINFOD_MAXSIZE is set. */
930*7304104dSAndroid Build Coastguard Worker long maxsize = 0;
931*7304104dSAndroid Build Coastguard Worker const char *maxsize_envvar;
932*7304104dSAndroid Build Coastguard Worker maxsize_envvar = getenv(DEBUGINFOD_MAXSIZE_ENV_VAR);
933*7304104dSAndroid Build Coastguard Worker if (maxsize_envvar != NULL)
934*7304104dSAndroid Build Coastguard Worker maxsize = atol (maxsize_envvar);
935*7304104dSAndroid Build Coastguard Worker
936*7304104dSAndroid Build Coastguard Worker /* PR 27982: Add max time if DEBUGINFOD_MAXTIME is set. */
937*7304104dSAndroid Build Coastguard Worker long maxtime = 0;
938*7304104dSAndroid Build Coastguard Worker const char *maxtime_envvar;
939*7304104dSAndroid Build Coastguard Worker maxtime_envvar = getenv(DEBUGINFOD_MAXTIME_ENV_VAR);
940*7304104dSAndroid Build Coastguard Worker if (maxtime_envvar != NULL)
941*7304104dSAndroid Build Coastguard Worker maxtime = atol (maxtime_envvar);
942*7304104dSAndroid Build Coastguard Worker if (maxtime && vfd >= 0)
943*7304104dSAndroid Build Coastguard Worker dprintf(vfd, "using max time %lds\n", maxtime);
944*7304104dSAndroid Build Coastguard Worker
945*7304104dSAndroid Build Coastguard Worker const char *headers_file_envvar;
946*7304104dSAndroid Build Coastguard Worker headers_file_envvar = getenv(DEBUGINFOD_HEADERS_FILE_ENV_VAR);
947*7304104dSAndroid Build Coastguard Worker if (headers_file_envvar != NULL)
948*7304104dSAndroid Build Coastguard Worker add_headers_from_file(c, headers_file_envvar);
949*7304104dSAndroid Build Coastguard Worker
950*7304104dSAndroid Build Coastguard Worker /* Maxsize is valid*/
951*7304104dSAndroid Build Coastguard Worker if (maxsize > 0)
952*7304104dSAndroid Build Coastguard Worker {
953*7304104dSAndroid Build Coastguard Worker if (vfd)
954*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "using max size %ldB\n", maxsize);
955*7304104dSAndroid Build Coastguard Worker char *size_header = NULL;
956*7304104dSAndroid Build Coastguard Worker rc = asprintf (&size_header, "X-DEBUGINFOD-MAXSIZE: %ld", maxsize);
957*7304104dSAndroid Build Coastguard Worker if (rc < 0)
958*7304104dSAndroid Build Coastguard Worker {
959*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
960*7304104dSAndroid Build Coastguard Worker goto out;
961*7304104dSAndroid Build Coastguard Worker }
962*7304104dSAndroid Build Coastguard Worker rc = debuginfod_add_http_header(c, size_header);
963*7304104dSAndroid Build Coastguard Worker free(size_header);
964*7304104dSAndroid Build Coastguard Worker if (rc < 0)
965*7304104dSAndroid Build Coastguard Worker goto out;
966*7304104dSAndroid Build Coastguard Worker }
967*7304104dSAndroid Build Coastguard Worker add_default_headers(c);
968*7304104dSAndroid Build Coastguard Worker
969*7304104dSAndroid Build Coastguard Worker /* Copy lowercase hex representation of build_id into buf. */
970*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
971*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "checking build-id\n");
972*7304104dSAndroid Build Coastguard Worker if ((build_id_len >= MAX_BUILD_ID_BYTES) ||
973*7304104dSAndroid Build Coastguard Worker (build_id_len == 0 &&
974*7304104dSAndroid Build Coastguard Worker strlen ((const char *) build_id) > MAX_BUILD_ID_BYTES*2))
975*7304104dSAndroid Build Coastguard Worker {
976*7304104dSAndroid Build Coastguard Worker rc = -EINVAL;
977*7304104dSAndroid Build Coastguard Worker goto out;
978*7304104dSAndroid Build Coastguard Worker }
979*7304104dSAndroid Build Coastguard Worker
980*7304104dSAndroid Build Coastguard Worker if (build_id_len == 0) /* expect clean hexadecimal */
981*7304104dSAndroid Build Coastguard Worker strcpy (build_id_bytes, (const char *) build_id);
982*7304104dSAndroid Build Coastguard Worker else
983*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < build_id_len; i++)
984*7304104dSAndroid Build Coastguard Worker sprintf(build_id_bytes + (i * 2), "%02x", build_id[i]);
985*7304104dSAndroid Build Coastguard Worker
986*7304104dSAndroid Build Coastguard Worker if (filename != NULL)
987*7304104dSAndroid Build Coastguard Worker {
988*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
989*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "checking filename\n");
990*7304104dSAndroid Build Coastguard Worker if (filename[0] != '/') // must start with /
991*7304104dSAndroid Build Coastguard Worker {
992*7304104dSAndroid Build Coastguard Worker rc = -EINVAL;
993*7304104dSAndroid Build Coastguard Worker goto out;
994*7304104dSAndroid Build Coastguard Worker }
995*7304104dSAndroid Build Coastguard Worker
996*7304104dSAndroid Build Coastguard Worker path_escape (filename, suffix);
997*7304104dSAndroid Build Coastguard Worker /* If the DWARF filenames are super long, this could exceed
998*7304104dSAndroid Build Coastguard Worker PATH_MAX and truncate/collide. Oh well, that'll teach
999*7304104dSAndroid Build Coastguard Worker them! */
1000*7304104dSAndroid Build Coastguard Worker }
1001*7304104dSAndroid Build Coastguard Worker else if (section != NULL)
1002*7304104dSAndroid Build Coastguard Worker path_escape (section, suffix);
1003*7304104dSAndroid Build Coastguard Worker else
1004*7304104dSAndroid Build Coastguard Worker suffix[0] = '\0';
1005*7304104dSAndroid Build Coastguard Worker
1006*7304104dSAndroid Build Coastguard Worker if (suffix[0] != '\0' && vfd >= 0)
1007*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "suffix %s\n", suffix);
1008*7304104dSAndroid Build Coastguard Worker
1009*7304104dSAndroid Build Coastguard Worker /* set paths needed to perform the query
1010*7304104dSAndroid Build Coastguard Worker
1011*7304104dSAndroid Build Coastguard Worker example format
1012*7304104dSAndroid Build Coastguard Worker cache_path: $HOME/.cache
1013*7304104dSAndroid Build Coastguard Worker target_cache_dir: $HOME/.cache/0123abcd
1014*7304104dSAndroid Build Coastguard Worker target_cache_path: $HOME/.cache/0123abcd/debuginfo
1015*7304104dSAndroid Build Coastguard Worker target_cache_path: $HOME/.cache/0123abcd/source#PATH#TO#SOURCE ?
1016*7304104dSAndroid Build Coastguard Worker
1017*7304104dSAndroid Build Coastguard Worker $XDG_CACHE_HOME takes priority over $HOME/.cache.
1018*7304104dSAndroid Build Coastguard Worker $DEBUGINFOD_CACHE_PATH takes priority over $HOME/.cache and $XDG_CACHE_HOME.
1019*7304104dSAndroid Build Coastguard Worker */
1020*7304104dSAndroid Build Coastguard Worker
1021*7304104dSAndroid Build Coastguard Worker /* Determine location of the cache. The path specified by the debuginfod
1022*7304104dSAndroid Build Coastguard Worker cache environment variable takes priority. */
1023*7304104dSAndroid Build Coastguard Worker char *cache_var = getenv(DEBUGINFOD_CACHE_PATH_ENV_VAR);
1024*7304104dSAndroid Build Coastguard Worker if (cache_var != NULL && strlen (cache_var) > 0)
1025*7304104dSAndroid Build Coastguard Worker xalloc_str (cache_path, "%s", cache_var);
1026*7304104dSAndroid Build Coastguard Worker else
1027*7304104dSAndroid Build Coastguard Worker {
1028*7304104dSAndroid Build Coastguard Worker /* If a cache already exists in $HOME ('/' if $HOME isn't set), then use
1029*7304104dSAndroid Build Coastguard Worker that. Otherwise use the XDG cache directory naming format. */
1030*7304104dSAndroid Build Coastguard Worker xalloc_str (cache_path, "%s/%s", getenv ("HOME") ?: "/", cache_default_name);
1031*7304104dSAndroid Build Coastguard Worker
1032*7304104dSAndroid Build Coastguard Worker struct stat st;
1033*7304104dSAndroid Build Coastguard Worker if (stat (cache_path, &st) < 0)
1034*7304104dSAndroid Build Coastguard Worker {
1035*7304104dSAndroid Build Coastguard Worker char cachedir[PATH_MAX];
1036*7304104dSAndroid Build Coastguard Worker char *xdg = getenv ("XDG_CACHE_HOME");
1037*7304104dSAndroid Build Coastguard Worker
1038*7304104dSAndroid Build Coastguard Worker if (xdg != NULL && strlen (xdg) > 0)
1039*7304104dSAndroid Build Coastguard Worker snprintf (cachedir, PATH_MAX, "%s", xdg);
1040*7304104dSAndroid Build Coastguard Worker else
1041*7304104dSAndroid Build Coastguard Worker snprintf (cachedir, PATH_MAX, "%s/.cache", getenv ("HOME") ?: "/");
1042*7304104dSAndroid Build Coastguard Worker
1043*7304104dSAndroid Build Coastguard Worker /* Create XDG cache directory if it doesn't exist. */
1044*7304104dSAndroid Build Coastguard Worker if (stat (cachedir, &st) == 0)
1045*7304104dSAndroid Build Coastguard Worker {
1046*7304104dSAndroid Build Coastguard Worker if (! S_ISDIR (st.st_mode))
1047*7304104dSAndroid Build Coastguard Worker {
1048*7304104dSAndroid Build Coastguard Worker rc = -EEXIST;
1049*7304104dSAndroid Build Coastguard Worker goto out;
1050*7304104dSAndroid Build Coastguard Worker }
1051*7304104dSAndroid Build Coastguard Worker }
1052*7304104dSAndroid Build Coastguard Worker else
1053*7304104dSAndroid Build Coastguard Worker {
1054*7304104dSAndroid Build Coastguard Worker rc = mkdir (cachedir, 0700);
1055*7304104dSAndroid Build Coastguard Worker
1056*7304104dSAndroid Build Coastguard Worker /* Also check for EEXIST and S_ISDIR in case another client just
1057*7304104dSAndroid Build Coastguard Worker happened to create the cache. */
1058*7304104dSAndroid Build Coastguard Worker if (rc < 0
1059*7304104dSAndroid Build Coastguard Worker && (errno != EEXIST
1060*7304104dSAndroid Build Coastguard Worker || stat (cachedir, &st) != 0
1061*7304104dSAndroid Build Coastguard Worker || ! S_ISDIR (st.st_mode)))
1062*7304104dSAndroid Build Coastguard Worker {
1063*7304104dSAndroid Build Coastguard Worker rc = -errno;
1064*7304104dSAndroid Build Coastguard Worker goto out;
1065*7304104dSAndroid Build Coastguard Worker }
1066*7304104dSAndroid Build Coastguard Worker }
1067*7304104dSAndroid Build Coastguard Worker
1068*7304104dSAndroid Build Coastguard Worker free (cache_path);
1069*7304104dSAndroid Build Coastguard Worker xalloc_str (cache_path, "%s/%s", cachedir, cache_xdg_name);
1070*7304104dSAndroid Build Coastguard Worker }
1071*7304104dSAndroid Build Coastguard Worker }
1072*7304104dSAndroid Build Coastguard Worker
1073*7304104dSAndroid Build Coastguard Worker xalloc_str (target_cache_dir, "%s/%s", cache_path, build_id_bytes);
1074*7304104dSAndroid Build Coastguard Worker if (section != NULL)
1075*7304104dSAndroid Build Coastguard Worker xalloc_str (target_cache_path, "%s/%s-%s", target_cache_dir, type, suffix);
1076*7304104dSAndroid Build Coastguard Worker else
1077*7304104dSAndroid Build Coastguard Worker xalloc_str (target_cache_path, "%s/%s%s", target_cache_dir, type, suffix);
1078*7304104dSAndroid Build Coastguard Worker xalloc_str (target_cache_tmppath, "%s.XXXXXX", target_cache_path);
1079*7304104dSAndroid Build Coastguard Worker
1080*7304104dSAndroid Build Coastguard Worker /* XXX combine these */
1081*7304104dSAndroid Build Coastguard Worker xalloc_str (interval_path, "%s/%s", cache_path, cache_clean_interval_filename);
1082*7304104dSAndroid Build Coastguard Worker xalloc_str (cache_miss_path, "%s/%s", cache_path, cache_miss_filename);
1083*7304104dSAndroid Build Coastguard Worker xalloc_str (maxage_path, "%s/%s", cache_path, cache_max_unused_age_filename);
1084*7304104dSAndroid Build Coastguard Worker
1085*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1086*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "checking cache dir %s\n", cache_path);
1087*7304104dSAndroid Build Coastguard Worker
1088*7304104dSAndroid Build Coastguard Worker /* Make sure cache dir exists. debuginfo_clean_cache will then make
1089*7304104dSAndroid Build Coastguard Worker sure the interval, cache_miss and maxage files exist. */
1090*7304104dSAndroid Build Coastguard Worker if (mkdir (cache_path, ACCESSPERMS) != 0
1091*7304104dSAndroid Build Coastguard Worker && errno != EEXIST)
1092*7304104dSAndroid Build Coastguard Worker {
1093*7304104dSAndroid Build Coastguard Worker rc = -errno;
1094*7304104dSAndroid Build Coastguard Worker goto out;
1095*7304104dSAndroid Build Coastguard Worker }
1096*7304104dSAndroid Build Coastguard Worker
1097*7304104dSAndroid Build Coastguard Worker rc = debuginfod_clean_cache(c, cache_path, interval_path, maxage_path);
1098*7304104dSAndroid Build Coastguard Worker if (rc != 0)
1099*7304104dSAndroid Build Coastguard Worker goto out;
1100*7304104dSAndroid Build Coastguard Worker
1101*7304104dSAndroid Build Coastguard Worker /* Check if the target is already in the cache. */
1102*7304104dSAndroid Build Coastguard Worker int fd = open(target_cache_path, O_RDONLY);
1103*7304104dSAndroid Build Coastguard Worker if (fd >= 0)
1104*7304104dSAndroid Build Coastguard Worker {
1105*7304104dSAndroid Build Coastguard Worker struct stat st;
1106*7304104dSAndroid Build Coastguard Worker if (fstat(fd, &st) != 0)
1107*7304104dSAndroid Build Coastguard Worker {
1108*7304104dSAndroid Build Coastguard Worker rc = -errno;
1109*7304104dSAndroid Build Coastguard Worker close (fd);
1110*7304104dSAndroid Build Coastguard Worker goto out;
1111*7304104dSAndroid Build Coastguard Worker }
1112*7304104dSAndroid Build Coastguard Worker
1113*7304104dSAndroid Build Coastguard Worker /* If the file is non-empty, then we are done. */
1114*7304104dSAndroid Build Coastguard Worker if (st.st_size > 0)
1115*7304104dSAndroid Build Coastguard Worker {
1116*7304104dSAndroid Build Coastguard Worker if (path != NULL)
1117*7304104dSAndroid Build Coastguard Worker {
1118*7304104dSAndroid Build Coastguard Worker *path = strdup(target_cache_path);
1119*7304104dSAndroid Build Coastguard Worker if (*path == NULL)
1120*7304104dSAndroid Build Coastguard Worker {
1121*7304104dSAndroid Build Coastguard Worker rc = -errno;
1122*7304104dSAndroid Build Coastguard Worker close (fd);
1123*7304104dSAndroid Build Coastguard Worker goto out;
1124*7304104dSAndroid Build Coastguard Worker }
1125*7304104dSAndroid Build Coastguard Worker }
1126*7304104dSAndroid Build Coastguard Worker /* Success!!!! */
1127*7304104dSAndroid Build Coastguard Worker update_atime(fd);
1128*7304104dSAndroid Build Coastguard Worker rc = fd;
1129*7304104dSAndroid Build Coastguard Worker goto out;
1130*7304104dSAndroid Build Coastguard Worker }
1131*7304104dSAndroid Build Coastguard Worker else
1132*7304104dSAndroid Build Coastguard Worker {
1133*7304104dSAndroid Build Coastguard Worker /* The file is empty. Attempt to download only if enough time
1134*7304104dSAndroid Build Coastguard Worker has passed since the last attempt. */
1135*7304104dSAndroid Build Coastguard Worker time_t cache_miss;
1136*7304104dSAndroid Build Coastguard Worker time_t target_mtime = st.st_mtime;
1137*7304104dSAndroid Build Coastguard Worker
1138*7304104dSAndroid Build Coastguard Worker close(fd); /* no need to hold onto the negative-hit file descriptor */
1139*7304104dSAndroid Build Coastguard Worker
1140*7304104dSAndroid Build Coastguard Worker rc = debuginfod_config_cache(c, cache_miss_path,
1141*7304104dSAndroid Build Coastguard Worker cache_miss_default_s, &st);
1142*7304104dSAndroid Build Coastguard Worker if (rc < 0)
1143*7304104dSAndroid Build Coastguard Worker goto out;
1144*7304104dSAndroid Build Coastguard Worker
1145*7304104dSAndroid Build Coastguard Worker cache_miss = (time_t)rc;
1146*7304104dSAndroid Build Coastguard Worker if (time(NULL) - target_mtime <= cache_miss)
1147*7304104dSAndroid Build Coastguard Worker {
1148*7304104dSAndroid Build Coastguard Worker rc = -ENOENT;
1149*7304104dSAndroid Build Coastguard Worker goto out;
1150*7304104dSAndroid Build Coastguard Worker }
1151*7304104dSAndroid Build Coastguard Worker else
1152*7304104dSAndroid Build Coastguard Worker /* TOCTOU non-problem: if another task races, puts a working
1153*7304104dSAndroid Build Coastguard Worker download or an empty file in its place, unlinking here just
1154*7304104dSAndroid Build Coastguard Worker means WE will try to download again as uncached. */
1155*7304104dSAndroid Build Coastguard Worker unlink(target_cache_path);
1156*7304104dSAndroid Build Coastguard Worker }
1157*7304104dSAndroid Build Coastguard Worker }
1158*7304104dSAndroid Build Coastguard Worker else if (errno == EACCES)
1159*7304104dSAndroid Build Coastguard Worker /* Ensure old 000-permission files are not lingering in the cache. */
1160*7304104dSAndroid Build Coastguard Worker unlink(target_cache_path);
1161*7304104dSAndroid Build Coastguard Worker
1162*7304104dSAndroid Build Coastguard Worker if (section != NULL)
1163*7304104dSAndroid Build Coastguard Worker {
1164*7304104dSAndroid Build Coastguard Worker /* Try to extract the section from a cached file before querying
1165*7304104dSAndroid Build Coastguard Worker any servers. */
1166*7304104dSAndroid Build Coastguard Worker rc = cache_find_section (section, target_cache_dir, path);
1167*7304104dSAndroid Build Coastguard Worker
1168*7304104dSAndroid Build Coastguard Worker /* If the section was found or confirmed to not exist, then we
1169*7304104dSAndroid Build Coastguard Worker are done. */
1170*7304104dSAndroid Build Coastguard Worker if (rc >= 0 || rc == -ENOENT)
1171*7304104dSAndroid Build Coastguard Worker goto out;
1172*7304104dSAndroid Build Coastguard Worker }
1173*7304104dSAndroid Build Coastguard Worker
1174*7304104dSAndroid Build Coastguard Worker long timeout = default_timeout;
1175*7304104dSAndroid Build Coastguard Worker const char* timeout_envvar = getenv(DEBUGINFOD_TIMEOUT_ENV_VAR);
1176*7304104dSAndroid Build Coastguard Worker if (timeout_envvar != NULL)
1177*7304104dSAndroid Build Coastguard Worker timeout = atoi (timeout_envvar);
1178*7304104dSAndroid Build Coastguard Worker
1179*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1180*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "using timeout %ld\n", timeout);
1181*7304104dSAndroid Build Coastguard Worker
1182*7304104dSAndroid Build Coastguard Worker /* make a copy of the envvar so it can be safely modified. */
1183*7304104dSAndroid Build Coastguard Worker server_urls = strdup(urls_envvar);
1184*7304104dSAndroid Build Coastguard Worker if (server_urls == NULL)
1185*7304104dSAndroid Build Coastguard Worker {
1186*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
1187*7304104dSAndroid Build Coastguard Worker goto out;
1188*7304104dSAndroid Build Coastguard Worker }
1189*7304104dSAndroid Build Coastguard Worker /* thereafter, goto out0 on error*/
1190*7304104dSAndroid Build Coastguard Worker
1191*7304104dSAndroid Build Coastguard Worker /* Because of a race with cache cleanup / rmdir, try to mkdir/mkstemp up to twice. */
1192*7304104dSAndroid Build Coastguard Worker for(int i=0; i<2; i++) {
1193*7304104dSAndroid Build Coastguard Worker /* (re)create target directory in cache */
1194*7304104dSAndroid Build Coastguard Worker (void) mkdir(target_cache_dir, 0700); /* files will be 0400 later */
1195*7304104dSAndroid Build Coastguard Worker
1196*7304104dSAndroid Build Coastguard Worker /* NB: write to a temporary file first, to avoid race condition of
1197*7304104dSAndroid Build Coastguard Worker multiple clients checking the cache, while a partially-written or empty
1198*7304104dSAndroid Build Coastguard Worker file is in there, being written from libcurl. */
1199*7304104dSAndroid Build Coastguard Worker fd = mkstemp (target_cache_tmppath);
1200*7304104dSAndroid Build Coastguard Worker if (fd >= 0) break;
1201*7304104dSAndroid Build Coastguard Worker }
1202*7304104dSAndroid Build Coastguard Worker if (fd < 0) /* Still failed after two iterations. */
1203*7304104dSAndroid Build Coastguard Worker {
1204*7304104dSAndroid Build Coastguard Worker rc = -errno;
1205*7304104dSAndroid Build Coastguard Worker goto out0;
1206*7304104dSAndroid Build Coastguard Worker }
1207*7304104dSAndroid Build Coastguard Worker
1208*7304104dSAndroid Build Coastguard Worker /* Initialize the memory to zero */
1209*7304104dSAndroid Build Coastguard Worker char *strtok_saveptr;
1210*7304104dSAndroid Build Coastguard Worker char **server_url_list = NULL;
1211*7304104dSAndroid Build Coastguard Worker char *server_url = strtok_r(server_urls, url_delim, &strtok_saveptr);
1212*7304104dSAndroid Build Coastguard Worker /* Count number of URLs. */
1213*7304104dSAndroid Build Coastguard Worker int num_urls = 0;
1214*7304104dSAndroid Build Coastguard Worker
1215*7304104dSAndroid Build Coastguard Worker while (server_url != NULL)
1216*7304104dSAndroid Build Coastguard Worker {
1217*7304104dSAndroid Build Coastguard Worker /* PR 27983: If the url is already set to be used use, skip it */
1218*7304104dSAndroid Build Coastguard Worker char *slashbuildid;
1219*7304104dSAndroid Build Coastguard Worker if (strlen(server_url) > 1 && server_url[strlen(server_url)-1] == '/')
1220*7304104dSAndroid Build Coastguard Worker slashbuildid = "buildid";
1221*7304104dSAndroid Build Coastguard Worker else
1222*7304104dSAndroid Build Coastguard Worker slashbuildid = "/buildid";
1223*7304104dSAndroid Build Coastguard Worker
1224*7304104dSAndroid Build Coastguard Worker char *tmp_url;
1225*7304104dSAndroid Build Coastguard Worker if (asprintf(&tmp_url, "%s%s", server_url, slashbuildid) == -1)
1226*7304104dSAndroid Build Coastguard Worker {
1227*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
1228*7304104dSAndroid Build Coastguard Worker goto out1;
1229*7304104dSAndroid Build Coastguard Worker }
1230*7304104dSAndroid Build Coastguard Worker int url_index;
1231*7304104dSAndroid Build Coastguard Worker for (url_index = 0; url_index < num_urls; ++url_index)
1232*7304104dSAndroid Build Coastguard Worker {
1233*7304104dSAndroid Build Coastguard Worker if(strcmp(tmp_url, server_url_list[url_index]) == 0)
1234*7304104dSAndroid Build Coastguard Worker {
1235*7304104dSAndroid Build Coastguard Worker url_index = -1;
1236*7304104dSAndroid Build Coastguard Worker break;
1237*7304104dSAndroid Build Coastguard Worker }
1238*7304104dSAndroid Build Coastguard Worker }
1239*7304104dSAndroid Build Coastguard Worker if (url_index == -1)
1240*7304104dSAndroid Build Coastguard Worker {
1241*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1242*7304104dSAndroid Build Coastguard Worker dprintf(vfd, "duplicate url: %s, skipping\n", tmp_url);
1243*7304104dSAndroid Build Coastguard Worker free(tmp_url);
1244*7304104dSAndroid Build Coastguard Worker }
1245*7304104dSAndroid Build Coastguard Worker else
1246*7304104dSAndroid Build Coastguard Worker {
1247*7304104dSAndroid Build Coastguard Worker num_urls++;
1248*7304104dSAndroid Build Coastguard Worker char ** realloc_ptr;
1249*7304104dSAndroid Build Coastguard Worker realloc_ptr = reallocarray(server_url_list, num_urls,
1250*7304104dSAndroid Build Coastguard Worker sizeof(char*));
1251*7304104dSAndroid Build Coastguard Worker if (realloc_ptr == NULL)
1252*7304104dSAndroid Build Coastguard Worker {
1253*7304104dSAndroid Build Coastguard Worker free (tmp_url);
1254*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
1255*7304104dSAndroid Build Coastguard Worker goto out1;
1256*7304104dSAndroid Build Coastguard Worker }
1257*7304104dSAndroid Build Coastguard Worker server_url_list = realloc_ptr;
1258*7304104dSAndroid Build Coastguard Worker server_url_list[num_urls-1] = tmp_url;
1259*7304104dSAndroid Build Coastguard Worker }
1260*7304104dSAndroid Build Coastguard Worker server_url = strtok_r(NULL, url_delim, &strtok_saveptr);
1261*7304104dSAndroid Build Coastguard Worker }
1262*7304104dSAndroid Build Coastguard Worker
1263*7304104dSAndroid Build Coastguard Worker int retry_limit = default_retry_limit;
1264*7304104dSAndroid Build Coastguard Worker const char* retry_limit_envvar = getenv(DEBUGINFOD_RETRY_LIMIT_ENV_VAR);
1265*7304104dSAndroid Build Coastguard Worker if (retry_limit_envvar != NULL)
1266*7304104dSAndroid Build Coastguard Worker retry_limit = atoi (retry_limit_envvar);
1267*7304104dSAndroid Build Coastguard Worker
1268*7304104dSAndroid Build Coastguard Worker CURLM *curlm = c->server_mhandle;
1269*7304104dSAndroid Build Coastguard Worker assert (curlm != NULL);
1270*7304104dSAndroid Build Coastguard Worker
1271*7304104dSAndroid Build Coastguard Worker /* Tracks which handle should write to fd. Set to the first
1272*7304104dSAndroid Build Coastguard Worker handle that is ready to write the target file to the cache. */
1273*7304104dSAndroid Build Coastguard Worker CURL *target_handle = NULL;
1274*7304104dSAndroid Build Coastguard Worker struct handle_data *data = malloc(sizeof(struct handle_data) * num_urls);
1275*7304104dSAndroid Build Coastguard Worker if (data == NULL)
1276*7304104dSAndroid Build Coastguard Worker {
1277*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
1278*7304104dSAndroid Build Coastguard Worker goto out1;
1279*7304104dSAndroid Build Coastguard Worker }
1280*7304104dSAndroid Build Coastguard Worker
1281*7304104dSAndroid Build Coastguard Worker /* thereafter, goto out2 on error. */
1282*7304104dSAndroid Build Coastguard Worker
1283*7304104dSAndroid Build Coastguard Worker /*The beginning of goto block query_in_parallel.*/
1284*7304104dSAndroid Build Coastguard Worker query_in_parallel:
1285*7304104dSAndroid Build Coastguard Worker rc = -ENOENT; /* Reset rc to default.*/
1286*7304104dSAndroid Build Coastguard Worker
1287*7304104dSAndroid Build Coastguard Worker /* Initialize handle_data with default values. */
1288*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; i++)
1289*7304104dSAndroid Build Coastguard Worker {
1290*7304104dSAndroid Build Coastguard Worker data[i].handle = NULL;
1291*7304104dSAndroid Build Coastguard Worker data[i].fd = -1;
1292*7304104dSAndroid Build Coastguard Worker data[i].errbuf[0] = '\0';
1293*7304104dSAndroid Build Coastguard Worker data[i].response_data = NULL;
1294*7304104dSAndroid Build Coastguard Worker data[i].response_data_size = 0;
1295*7304104dSAndroid Build Coastguard Worker }
1296*7304104dSAndroid Build Coastguard Worker
1297*7304104dSAndroid Build Coastguard Worker char *escaped_string = NULL;
1298*7304104dSAndroid Build Coastguard Worker size_t escaped_strlen = 0;
1299*7304104dSAndroid Build Coastguard Worker if (filename)
1300*7304104dSAndroid Build Coastguard Worker {
1301*7304104dSAndroid Build Coastguard Worker escaped_string = curl_easy_escape(&target_handle, filename+1, 0);
1302*7304104dSAndroid Build Coastguard Worker if (!escaped_string)
1303*7304104dSAndroid Build Coastguard Worker {
1304*7304104dSAndroid Build Coastguard Worker rc = -ENOMEM;
1305*7304104dSAndroid Build Coastguard Worker goto out2;
1306*7304104dSAndroid Build Coastguard Worker }
1307*7304104dSAndroid Build Coastguard Worker char *loc = escaped_string;
1308*7304104dSAndroid Build Coastguard Worker escaped_strlen = strlen(escaped_string);
1309*7304104dSAndroid Build Coastguard Worker while ((loc = strstr(loc, "%2F")))
1310*7304104dSAndroid Build Coastguard Worker {
1311*7304104dSAndroid Build Coastguard Worker loc[0] = '/';
1312*7304104dSAndroid Build Coastguard Worker //pull the string back after replacement
1313*7304104dSAndroid Build Coastguard Worker // loc-escaped_string finds the distance from the origin to the new location
1314*7304104dSAndroid Build Coastguard Worker // - 2 accounts for the 2F which remain and don't need to be measured.
1315*7304104dSAndroid Build Coastguard Worker // The two above subtracted from escaped_strlen yields the remaining characters
1316*7304104dSAndroid Build Coastguard Worker // in the string which we want to pull back
1317*7304104dSAndroid Build Coastguard Worker memmove(loc+1, loc+3,escaped_strlen - (loc-escaped_string) - 2);
1318*7304104dSAndroid Build Coastguard Worker //Because the 2F was overwritten in the memmove (as desired) escaped_strlen is
1319*7304104dSAndroid Build Coastguard Worker // now two shorter.
1320*7304104dSAndroid Build Coastguard Worker escaped_strlen -= 2;
1321*7304104dSAndroid Build Coastguard Worker }
1322*7304104dSAndroid Build Coastguard Worker }
1323*7304104dSAndroid Build Coastguard Worker /* Initialize each handle. */
1324*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; i++)
1325*7304104dSAndroid Build Coastguard Worker {
1326*7304104dSAndroid Build Coastguard Worker if ((server_url = server_url_list[i]) == NULL)
1327*7304104dSAndroid Build Coastguard Worker break;
1328*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1329*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "init server %d %s\n", i, server_url);
1330*7304104dSAndroid Build Coastguard Worker
1331*7304104dSAndroid Build Coastguard Worker data[i].fd = fd;
1332*7304104dSAndroid Build Coastguard Worker data[i].target_handle = &target_handle;
1333*7304104dSAndroid Build Coastguard Worker data[i].handle = curl_easy_init();
1334*7304104dSAndroid Build Coastguard Worker if (data[i].handle == NULL)
1335*7304104dSAndroid Build Coastguard Worker {
1336*7304104dSAndroid Build Coastguard Worker if (filename) curl_free (escaped_string);
1337*7304104dSAndroid Build Coastguard Worker rc = -ENETUNREACH;
1338*7304104dSAndroid Build Coastguard Worker goto out2;
1339*7304104dSAndroid Build Coastguard Worker }
1340*7304104dSAndroid Build Coastguard Worker data[i].client = c;
1341*7304104dSAndroid Build Coastguard Worker
1342*7304104dSAndroid Build Coastguard Worker if (filename) /* must start with / */
1343*7304104dSAndroid Build Coastguard Worker {
1344*7304104dSAndroid Build Coastguard Worker /* PR28034 escape characters in completed url to %hh format. */
1345*7304104dSAndroid Build Coastguard Worker snprintf(data[i].url, PATH_MAX, "%s/%s/%s/%s", server_url,
1346*7304104dSAndroid Build Coastguard Worker build_id_bytes, type, escaped_string);
1347*7304104dSAndroid Build Coastguard Worker }
1348*7304104dSAndroid Build Coastguard Worker else if (section)
1349*7304104dSAndroid Build Coastguard Worker snprintf(data[i].url, PATH_MAX, "%s/%s/%s/%s", server_url,
1350*7304104dSAndroid Build Coastguard Worker build_id_bytes, type, section);
1351*7304104dSAndroid Build Coastguard Worker else
1352*7304104dSAndroid Build Coastguard Worker snprintf(data[i].url, PATH_MAX, "%s/%s/%s", server_url, build_id_bytes, type);
1353*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1354*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "url %d %s\n", i, data[i].url);
1355*7304104dSAndroid Build Coastguard Worker
1356*7304104dSAndroid Build Coastguard Worker /* Some boilerplate for checking curl_easy_setopt. */
1357*7304104dSAndroid Build Coastguard Worker #define curl_easy_setopt_ck(H,O,P) do { \
1358*7304104dSAndroid Build Coastguard Worker CURLcode curl_res = curl_easy_setopt (H,O,P); \
1359*7304104dSAndroid Build Coastguard Worker if (curl_res != CURLE_OK) \
1360*7304104dSAndroid Build Coastguard Worker { \
1361*7304104dSAndroid Build Coastguard Worker if (vfd >= 0) \
1362*7304104dSAndroid Build Coastguard Worker dprintf (vfd, \
1363*7304104dSAndroid Build Coastguard Worker "Bad curl_easy_setopt: %s\n", \
1364*7304104dSAndroid Build Coastguard Worker curl_easy_strerror(curl_res)); \
1365*7304104dSAndroid Build Coastguard Worker rc = -EINVAL; \
1366*7304104dSAndroid Build Coastguard Worker goto out2; \
1367*7304104dSAndroid Build Coastguard Worker } \
1368*7304104dSAndroid Build Coastguard Worker } while (0)
1369*7304104dSAndroid Build Coastguard Worker
1370*7304104dSAndroid Build Coastguard Worker /* Only allow http:// + https:// + file:// so we aren't being
1371*7304104dSAndroid Build Coastguard Worker redirected to some unsupported protocol. */
1372*7304104dSAndroid Build Coastguard Worker #if CURL_AT_LEAST_VERSION(7, 85, 0)
1373*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_PROTOCOLS_STR,
1374*7304104dSAndroid Build Coastguard Worker "http,https,file");
1375*7304104dSAndroid Build Coastguard Worker #else
1376*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_PROTOCOLS,
1377*7304104dSAndroid Build Coastguard Worker (CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FILE));
1378*7304104dSAndroid Build Coastguard Worker #endif
1379*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_URL, data[i].url);
1380*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1381*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_ERRORBUFFER,
1382*7304104dSAndroid Build Coastguard Worker data[i].errbuf);
1383*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle,
1384*7304104dSAndroid Build Coastguard Worker CURLOPT_WRITEFUNCTION,
1385*7304104dSAndroid Build Coastguard Worker debuginfod_write_callback);
1386*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_WRITEDATA, (void*)&data[i]);
1387*7304104dSAndroid Build Coastguard Worker if (timeout > 0)
1388*7304104dSAndroid Build Coastguard Worker {
1389*7304104dSAndroid Build Coastguard Worker /* Make sure there is at least some progress,
1390*7304104dSAndroid Build Coastguard Worker try to get at least 100K per timeout seconds. */
1391*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck (data[i].handle, CURLOPT_LOW_SPEED_TIME,
1392*7304104dSAndroid Build Coastguard Worker timeout);
1393*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck (data[i].handle, CURLOPT_LOW_SPEED_LIMIT,
1394*7304104dSAndroid Build Coastguard Worker 100 * 1024L);
1395*7304104dSAndroid Build Coastguard Worker }
1396*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_FILETIME, (long) 1);
1397*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_FOLLOWLOCATION, (long) 1);
1398*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_FAILONERROR, (long) 1);
1399*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_NOSIGNAL, (long) 1);
1400*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_HEADERFUNCTION,
1401*7304104dSAndroid Build Coastguard Worker header_callback);
1402*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_HEADERDATA,
1403*7304104dSAndroid Build Coastguard Worker (void *) &(data[i]));
1404*7304104dSAndroid Build Coastguard Worker #if LIBCURL_VERSION_NUM >= 0x072a00 /* 7.42.0 */
1405*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_PATH_AS_IS, (long) 1);
1406*7304104dSAndroid Build Coastguard Worker #else
1407*7304104dSAndroid Build Coastguard Worker /* On old curl; no big deal, canonicalization here is almost the
1408*7304104dSAndroid Build Coastguard Worker same, except perhaps for ? # type decorations at the tail. */
1409*7304104dSAndroid Build Coastguard Worker #endif
1410*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_AUTOREFERER, (long) 1);
1411*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_ACCEPT_ENCODING, "");
1412*7304104dSAndroid Build Coastguard Worker curl_easy_setopt_ck(data[i].handle, CURLOPT_HTTPHEADER, c->headers);
1413*7304104dSAndroid Build Coastguard Worker
1414*7304104dSAndroid Build Coastguard Worker curl_multi_add_handle(curlm, data[i].handle);
1415*7304104dSAndroid Build Coastguard Worker }
1416*7304104dSAndroid Build Coastguard Worker
1417*7304104dSAndroid Build Coastguard Worker if (filename) curl_free(escaped_string);
1418*7304104dSAndroid Build Coastguard Worker /* Query servers in parallel. */
1419*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1420*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "query %d urls in parallel\n", num_urls);
1421*7304104dSAndroid Build Coastguard Worker int still_running;
1422*7304104dSAndroid Build Coastguard Worker long loops = 0;
1423*7304104dSAndroid Build Coastguard Worker int committed_to = -1;
1424*7304104dSAndroid Build Coastguard Worker bool verbose_reported = false;
1425*7304104dSAndroid Build Coastguard Worker struct timespec start_time, cur_time;
1426*7304104dSAndroid Build Coastguard Worker
1427*7304104dSAndroid Build Coastguard Worker free (c->winning_headers);
1428*7304104dSAndroid Build Coastguard Worker c->winning_headers = NULL;
1429*7304104dSAndroid Build Coastguard Worker if ( maxtime > 0 && clock_gettime(CLOCK_MONOTONIC_RAW, &start_time) == -1)
1430*7304104dSAndroid Build Coastguard Worker {
1431*7304104dSAndroid Build Coastguard Worker rc = -errno;
1432*7304104dSAndroid Build Coastguard Worker goto out2;
1433*7304104dSAndroid Build Coastguard Worker }
1434*7304104dSAndroid Build Coastguard Worker long delta = 0;
1435*7304104dSAndroid Build Coastguard Worker do
1436*7304104dSAndroid Build Coastguard Worker {
1437*7304104dSAndroid Build Coastguard Worker /* Check to see how long querying is taking. */
1438*7304104dSAndroid Build Coastguard Worker if (maxtime > 0)
1439*7304104dSAndroid Build Coastguard Worker {
1440*7304104dSAndroid Build Coastguard Worker if (clock_gettime(CLOCK_MONOTONIC_RAW, &cur_time) == -1)
1441*7304104dSAndroid Build Coastguard Worker {
1442*7304104dSAndroid Build Coastguard Worker rc = -errno;
1443*7304104dSAndroid Build Coastguard Worker goto out2;
1444*7304104dSAndroid Build Coastguard Worker }
1445*7304104dSAndroid Build Coastguard Worker delta = cur_time.tv_sec - start_time.tv_sec;
1446*7304104dSAndroid Build Coastguard Worker if ( delta > maxtime)
1447*7304104dSAndroid Build Coastguard Worker {
1448*7304104dSAndroid Build Coastguard Worker dprintf(vfd, "Timeout with max time=%lds and transfer time=%lds\n", maxtime, delta );
1449*7304104dSAndroid Build Coastguard Worker rc = -ETIME;
1450*7304104dSAndroid Build Coastguard Worker goto out2;
1451*7304104dSAndroid Build Coastguard Worker }
1452*7304104dSAndroid Build Coastguard Worker }
1453*7304104dSAndroid Build Coastguard Worker /* Wait 1 second, the minimum DEBUGINFOD_TIMEOUT. */
1454*7304104dSAndroid Build Coastguard Worker curl_multi_wait(curlm, NULL, 0, 1000, NULL);
1455*7304104dSAndroid Build Coastguard Worker CURLMcode curlm_res = curl_multi_perform(curlm, &still_running);
1456*7304104dSAndroid Build Coastguard Worker
1457*7304104dSAndroid Build Coastguard Worker /* If the target file has been found, abort the other queries. */
1458*7304104dSAndroid Build Coastguard Worker if (target_handle != NULL)
1459*7304104dSAndroid Build Coastguard Worker {
1460*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; i++)
1461*7304104dSAndroid Build Coastguard Worker if (data[i].handle != target_handle)
1462*7304104dSAndroid Build Coastguard Worker curl_multi_remove_handle(curlm, data[i].handle);
1463*7304104dSAndroid Build Coastguard Worker else
1464*7304104dSAndroid Build Coastguard Worker {
1465*7304104dSAndroid Build Coastguard Worker committed_to = i;
1466*7304104dSAndroid Build Coastguard Worker if (c->winning_headers == NULL)
1467*7304104dSAndroid Build Coastguard Worker {
1468*7304104dSAndroid Build Coastguard Worker c->winning_headers = data[committed_to].response_data;
1469*7304104dSAndroid Build Coastguard Worker data[committed_to].response_data = NULL;
1470*7304104dSAndroid Build Coastguard Worker data[committed_to].response_data_size = 0;
1471*7304104dSAndroid Build Coastguard Worker }
1472*7304104dSAndroid Build Coastguard Worker
1473*7304104dSAndroid Build Coastguard Worker }
1474*7304104dSAndroid Build Coastguard Worker }
1475*7304104dSAndroid Build Coastguard Worker
1476*7304104dSAndroid Build Coastguard Worker if (vfd >= 0 && !verbose_reported && committed_to >= 0)
1477*7304104dSAndroid Build Coastguard Worker {
1478*7304104dSAndroid Build Coastguard Worker bool pnl = (c->default_progressfn_printed_p && vfd == STDERR_FILENO);
1479*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "%scommitted to url %d\n", pnl ? "\n" : "",
1480*7304104dSAndroid Build Coastguard Worker committed_to);
1481*7304104dSAndroid Build Coastguard Worker if (pnl)
1482*7304104dSAndroid Build Coastguard Worker c->default_progressfn_printed_p = 0;
1483*7304104dSAndroid Build Coastguard Worker verbose_reported = true;
1484*7304104dSAndroid Build Coastguard Worker }
1485*7304104dSAndroid Build Coastguard Worker
1486*7304104dSAndroid Build Coastguard Worker if (curlm_res != CURLM_OK)
1487*7304104dSAndroid Build Coastguard Worker {
1488*7304104dSAndroid Build Coastguard Worker switch (curlm_res)
1489*7304104dSAndroid Build Coastguard Worker {
1490*7304104dSAndroid Build Coastguard Worker case CURLM_CALL_MULTI_PERFORM: continue;
1491*7304104dSAndroid Build Coastguard Worker case CURLM_OUT_OF_MEMORY: rc = -ENOMEM; break;
1492*7304104dSAndroid Build Coastguard Worker default: rc = -ENETUNREACH; break;
1493*7304104dSAndroid Build Coastguard Worker }
1494*7304104dSAndroid Build Coastguard Worker goto out2;
1495*7304104dSAndroid Build Coastguard Worker }
1496*7304104dSAndroid Build Coastguard Worker
1497*7304104dSAndroid Build Coastguard Worker long dl_size = -1;
1498*7304104dSAndroid Build Coastguard Worker if (target_handle && (c->progressfn || maxsize > 0))
1499*7304104dSAndroid Build Coastguard Worker {
1500*7304104dSAndroid Build Coastguard Worker /* Get size of file being downloaded. NB: If going through
1501*7304104dSAndroid Build Coastguard Worker deflate-compressing proxies, this number is likely to be
1502*7304104dSAndroid Build Coastguard Worker unavailable, so -1 may show. */
1503*7304104dSAndroid Build Coastguard Worker CURLcode curl_res;
1504*7304104dSAndroid Build Coastguard Worker #if CURL_AT_LEAST_VERSION(7, 55, 0)
1505*7304104dSAndroid Build Coastguard Worker curl_off_t cl;
1506*7304104dSAndroid Build Coastguard Worker curl_res = curl_easy_getinfo(target_handle,
1507*7304104dSAndroid Build Coastguard Worker CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,
1508*7304104dSAndroid Build Coastguard Worker &cl);
1509*7304104dSAndroid Build Coastguard Worker if (curl_res == CURLE_OK && cl >= 0)
1510*7304104dSAndroid Build Coastguard Worker dl_size = (cl > LONG_MAX ? LONG_MAX : (long)cl);
1511*7304104dSAndroid Build Coastguard Worker #else
1512*7304104dSAndroid Build Coastguard Worker double cl;
1513*7304104dSAndroid Build Coastguard Worker curl_res = curl_easy_getinfo(target_handle,
1514*7304104dSAndroid Build Coastguard Worker CURLINFO_CONTENT_LENGTH_DOWNLOAD,
1515*7304104dSAndroid Build Coastguard Worker &cl);
1516*7304104dSAndroid Build Coastguard Worker if (curl_res == CURLE_OK && cl >= 0)
1517*7304104dSAndroid Build Coastguard Worker dl_size = (cl >= (double)(LONG_MAX+1UL) ? LONG_MAX : (long)cl);
1518*7304104dSAndroid Build Coastguard Worker #endif
1519*7304104dSAndroid Build Coastguard Worker /* If Content-Length is -1, try to get the size from
1520*7304104dSAndroid Build Coastguard Worker X-Debuginfod-Size */
1521*7304104dSAndroid Build Coastguard Worker if (dl_size == -1 && c->winning_headers != NULL)
1522*7304104dSAndroid Build Coastguard Worker {
1523*7304104dSAndroid Build Coastguard Worker long xdl;
1524*7304104dSAndroid Build Coastguard Worker char *hdr = strcasestr(c->winning_headers, "x-debuginfod-size");
1525*7304104dSAndroid Build Coastguard Worker size_t off = strlen("x-debuginfod-size:");
1526*7304104dSAndroid Build Coastguard Worker
1527*7304104dSAndroid Build Coastguard Worker if (hdr != NULL && sscanf(hdr + off, "%ld", &xdl) == 1)
1528*7304104dSAndroid Build Coastguard Worker dl_size = xdl;
1529*7304104dSAndroid Build Coastguard Worker }
1530*7304104dSAndroid Build Coastguard Worker }
1531*7304104dSAndroid Build Coastguard Worker
1532*7304104dSAndroid Build Coastguard Worker if (c->progressfn) /* inform/check progress callback */
1533*7304104dSAndroid Build Coastguard Worker {
1534*7304104dSAndroid Build Coastguard Worker loops ++;
1535*7304104dSAndroid Build Coastguard Worker long pa = loops; /* default param for progress callback */
1536*7304104dSAndroid Build Coastguard Worker if (target_handle) /* we've committed to a server; report its download progress */
1537*7304104dSAndroid Build Coastguard Worker {
1538*7304104dSAndroid Build Coastguard Worker /* PR30809: Check actual size of cached file. This same
1539*7304104dSAndroid Build Coastguard Worker fd is shared by all the multi-curl handles (but only
1540*7304104dSAndroid Build Coastguard Worker one will end up writing to it). Another way could be
1541*7304104dSAndroid Build Coastguard Worker to tabulate totals in debuginfod_write_callback(). */
1542*7304104dSAndroid Build Coastguard Worker struct stat cached;
1543*7304104dSAndroid Build Coastguard Worker int statrc = fstat(fd, &cached);
1544*7304104dSAndroid Build Coastguard Worker if (statrc == 0)
1545*7304104dSAndroid Build Coastguard Worker pa = (long) cached.st_size;
1546*7304104dSAndroid Build Coastguard Worker else
1547*7304104dSAndroid Build Coastguard Worker {
1548*7304104dSAndroid Build Coastguard Worker /* Otherwise, query libcurl for its tabulated total.
1549*7304104dSAndroid Build Coastguard Worker However, that counts http body length, not
1550*7304104dSAndroid Build Coastguard Worker decoded/decompressed content length, so does not
1551*7304104dSAndroid Build Coastguard Worker measure quite the same thing as dl. */
1552*7304104dSAndroid Build Coastguard Worker CURLcode curl_res;
1553*7304104dSAndroid Build Coastguard Worker #if CURL_AT_LEAST_VERSION(7, 55, 0)
1554*7304104dSAndroid Build Coastguard Worker curl_off_t dl;
1555*7304104dSAndroid Build Coastguard Worker curl_res = curl_easy_getinfo(target_handle,
1556*7304104dSAndroid Build Coastguard Worker CURLINFO_SIZE_DOWNLOAD_T,
1557*7304104dSAndroid Build Coastguard Worker &dl);
1558*7304104dSAndroid Build Coastguard Worker if (curl_res == 0 && dl >= 0)
1559*7304104dSAndroid Build Coastguard Worker pa = (dl > LONG_MAX ? LONG_MAX : (long)dl);
1560*7304104dSAndroid Build Coastguard Worker #else
1561*7304104dSAndroid Build Coastguard Worker double dl;
1562*7304104dSAndroid Build Coastguard Worker curl_res = curl_easy_getinfo(target_handle,
1563*7304104dSAndroid Build Coastguard Worker CURLINFO_SIZE_DOWNLOAD,
1564*7304104dSAndroid Build Coastguard Worker &dl);
1565*7304104dSAndroid Build Coastguard Worker if (curl_res == 0)
1566*7304104dSAndroid Build Coastguard Worker pa = (dl >= (double)(LONG_MAX+1UL) ? LONG_MAX : (long)dl);
1567*7304104dSAndroid Build Coastguard Worker #endif
1568*7304104dSAndroid Build Coastguard Worker }
1569*7304104dSAndroid Build Coastguard Worker }
1570*7304104dSAndroid Build Coastguard Worker
1571*7304104dSAndroid Build Coastguard Worker if ((*c->progressfn) (c, pa, dl_size == -1 ? 0 : dl_size))
1572*7304104dSAndroid Build Coastguard Worker {
1573*7304104dSAndroid Build Coastguard Worker c->progressfn_cancel = true;
1574*7304104dSAndroid Build Coastguard Worker break;
1575*7304104dSAndroid Build Coastguard Worker }
1576*7304104dSAndroid Build Coastguard Worker }
1577*7304104dSAndroid Build Coastguard Worker
1578*7304104dSAndroid Build Coastguard Worker /* Check to see if we are downloading something which exceeds maxsize, if set.*/
1579*7304104dSAndroid Build Coastguard Worker if (target_handle && dl_size > maxsize && maxsize > 0)
1580*7304104dSAndroid Build Coastguard Worker {
1581*7304104dSAndroid Build Coastguard Worker if (vfd >=0)
1582*7304104dSAndroid Build Coastguard Worker dprintf(vfd, "Content-Length too large.\n");
1583*7304104dSAndroid Build Coastguard Worker rc = -EFBIG;
1584*7304104dSAndroid Build Coastguard Worker goto out2;
1585*7304104dSAndroid Build Coastguard Worker }
1586*7304104dSAndroid Build Coastguard Worker } while (still_running);
1587*7304104dSAndroid Build Coastguard Worker
1588*7304104dSAndroid Build Coastguard Worker /* Check whether a query was successful. If so, assign its handle
1589*7304104dSAndroid Build Coastguard Worker to verified_handle. */
1590*7304104dSAndroid Build Coastguard Worker int num_msg;
1591*7304104dSAndroid Build Coastguard Worker rc = -ENOENT;
1592*7304104dSAndroid Build Coastguard Worker CURL *verified_handle = NULL;
1593*7304104dSAndroid Build Coastguard Worker do
1594*7304104dSAndroid Build Coastguard Worker {
1595*7304104dSAndroid Build Coastguard Worker CURLMsg *msg;
1596*7304104dSAndroid Build Coastguard Worker
1597*7304104dSAndroid Build Coastguard Worker msg = curl_multi_info_read(curlm, &num_msg);
1598*7304104dSAndroid Build Coastguard Worker if (msg != NULL && msg->msg == CURLMSG_DONE)
1599*7304104dSAndroid Build Coastguard Worker {
1600*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1601*7304104dSAndroid Build Coastguard Worker {
1602*7304104dSAndroid Build Coastguard Worker bool pnl = (c->default_progressfn_printed_p
1603*7304104dSAndroid Build Coastguard Worker && vfd == STDERR_FILENO);
1604*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "%sserver response %s\n", pnl ? "\n" : "",
1605*7304104dSAndroid Build Coastguard Worker curl_easy_strerror (msg->data.result));
1606*7304104dSAndroid Build Coastguard Worker if (pnl)
1607*7304104dSAndroid Build Coastguard Worker c->default_progressfn_printed_p = 0;
1608*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; i++)
1609*7304104dSAndroid Build Coastguard Worker if (msg->easy_handle == data[i].handle)
1610*7304104dSAndroid Build Coastguard Worker {
1611*7304104dSAndroid Build Coastguard Worker if (strlen (data[i].errbuf) > 0)
1612*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "url %d %s\n", i, data[i].errbuf);
1613*7304104dSAndroid Build Coastguard Worker break;
1614*7304104dSAndroid Build Coastguard Worker }
1615*7304104dSAndroid Build Coastguard Worker }
1616*7304104dSAndroid Build Coastguard Worker
1617*7304104dSAndroid Build Coastguard Worker if (msg->data.result != CURLE_OK)
1618*7304104dSAndroid Build Coastguard Worker {
1619*7304104dSAndroid Build Coastguard Worker long resp_code;
1620*7304104dSAndroid Build Coastguard Worker CURLcode ok0;
1621*7304104dSAndroid Build Coastguard Worker /* Unsuccessful query, determine error code. */
1622*7304104dSAndroid Build Coastguard Worker switch (msg->data.result)
1623*7304104dSAndroid Build Coastguard Worker {
1624*7304104dSAndroid Build Coastguard Worker case CURLE_COULDNT_RESOLVE_HOST: rc = -EHOSTUNREACH; break; // no NXDOMAIN
1625*7304104dSAndroid Build Coastguard Worker case CURLE_URL_MALFORMAT: rc = -EINVAL; break;
1626*7304104dSAndroid Build Coastguard Worker case CURLE_COULDNT_CONNECT: rc = -ECONNREFUSED; break;
1627*7304104dSAndroid Build Coastguard Worker case CURLE_PEER_FAILED_VERIFICATION: rc = -ECONNREFUSED; break;
1628*7304104dSAndroid Build Coastguard Worker case CURLE_REMOTE_ACCESS_DENIED: rc = -EACCES; break;
1629*7304104dSAndroid Build Coastguard Worker case CURLE_WRITE_ERROR: rc = -EIO; break;
1630*7304104dSAndroid Build Coastguard Worker case CURLE_OUT_OF_MEMORY: rc = -ENOMEM; break;
1631*7304104dSAndroid Build Coastguard Worker case CURLE_TOO_MANY_REDIRECTS: rc = -EMLINK; break;
1632*7304104dSAndroid Build Coastguard Worker case CURLE_SEND_ERROR: rc = -ECONNRESET; break;
1633*7304104dSAndroid Build Coastguard Worker case CURLE_RECV_ERROR: rc = -ECONNRESET; break;
1634*7304104dSAndroid Build Coastguard Worker case CURLE_OPERATION_TIMEDOUT: rc = -ETIME; break;
1635*7304104dSAndroid Build Coastguard Worker case CURLE_HTTP_RETURNED_ERROR:
1636*7304104dSAndroid Build Coastguard Worker ok0 = curl_easy_getinfo (msg->easy_handle,
1637*7304104dSAndroid Build Coastguard Worker CURLINFO_RESPONSE_CODE,
1638*7304104dSAndroid Build Coastguard Worker &resp_code);
1639*7304104dSAndroid Build Coastguard Worker /* 406 signals that the requested file was too large */
1640*7304104dSAndroid Build Coastguard Worker if ( ok0 == CURLE_OK && resp_code == 406)
1641*7304104dSAndroid Build Coastguard Worker rc = -EFBIG;
1642*7304104dSAndroid Build Coastguard Worker else if (section != NULL && resp_code == 503)
1643*7304104dSAndroid Build Coastguard Worker rc = -EINVAL;
1644*7304104dSAndroid Build Coastguard Worker else
1645*7304104dSAndroid Build Coastguard Worker rc = -ENOENT;
1646*7304104dSAndroid Build Coastguard Worker break;
1647*7304104dSAndroid Build Coastguard Worker default: rc = -ENOENT; break;
1648*7304104dSAndroid Build Coastguard Worker }
1649*7304104dSAndroid Build Coastguard Worker }
1650*7304104dSAndroid Build Coastguard Worker else
1651*7304104dSAndroid Build Coastguard Worker {
1652*7304104dSAndroid Build Coastguard Worker /* Query completed without an error. Confirm that the
1653*7304104dSAndroid Build Coastguard Worker response code is 200 when using HTTP/HTTPS and 0 when
1654*7304104dSAndroid Build Coastguard Worker using file:// and set verified_handle. */
1655*7304104dSAndroid Build Coastguard Worker
1656*7304104dSAndroid Build Coastguard Worker if (msg->easy_handle != NULL)
1657*7304104dSAndroid Build Coastguard Worker {
1658*7304104dSAndroid Build Coastguard Worker char *effective_url = NULL;
1659*7304104dSAndroid Build Coastguard Worker long resp_code = 500;
1660*7304104dSAndroid Build Coastguard Worker CURLcode ok1 = curl_easy_getinfo (target_handle,
1661*7304104dSAndroid Build Coastguard Worker CURLINFO_EFFECTIVE_URL,
1662*7304104dSAndroid Build Coastguard Worker &effective_url);
1663*7304104dSAndroid Build Coastguard Worker CURLcode ok2 = curl_easy_getinfo (target_handle,
1664*7304104dSAndroid Build Coastguard Worker CURLINFO_RESPONSE_CODE,
1665*7304104dSAndroid Build Coastguard Worker &resp_code);
1666*7304104dSAndroid Build Coastguard Worker if(ok1 == CURLE_OK && ok2 == CURLE_OK && effective_url)
1667*7304104dSAndroid Build Coastguard Worker {
1668*7304104dSAndroid Build Coastguard Worker if (strncasecmp (effective_url, "HTTP", 4) == 0)
1669*7304104dSAndroid Build Coastguard Worker if (resp_code == 200)
1670*7304104dSAndroid Build Coastguard Worker {
1671*7304104dSAndroid Build Coastguard Worker verified_handle = msg->easy_handle;
1672*7304104dSAndroid Build Coastguard Worker break;
1673*7304104dSAndroid Build Coastguard Worker }
1674*7304104dSAndroid Build Coastguard Worker if (strncasecmp (effective_url, "FILE", 4) == 0)
1675*7304104dSAndroid Build Coastguard Worker if (resp_code == 0)
1676*7304104dSAndroid Build Coastguard Worker {
1677*7304104dSAndroid Build Coastguard Worker verified_handle = msg->easy_handle;
1678*7304104dSAndroid Build Coastguard Worker break;
1679*7304104dSAndroid Build Coastguard Worker }
1680*7304104dSAndroid Build Coastguard Worker }
1681*7304104dSAndroid Build Coastguard Worker /* - libcurl since 7.52.0 version start to support
1682*7304104dSAndroid Build Coastguard Worker CURLINFO_SCHEME;
1683*7304104dSAndroid Build Coastguard Worker - before 7.61.0, effective_url would give us a
1684*7304104dSAndroid Build Coastguard Worker url with upper case SCHEME added in the front;
1685*7304104dSAndroid Build Coastguard Worker - effective_url between 7.61 and 7.69 can be lack
1686*7304104dSAndroid Build Coastguard Worker of scheme if the original url doesn't include one;
1687*7304104dSAndroid Build Coastguard Worker - since version 7.69 effective_url will be provide
1688*7304104dSAndroid Build Coastguard Worker a scheme in lower case. */
1689*7304104dSAndroid Build Coastguard Worker #if LIBCURL_VERSION_NUM >= 0x073d00 /* 7.61.0 */
1690*7304104dSAndroid Build Coastguard Worker #if LIBCURL_VERSION_NUM <= 0x074500 /* 7.69.0 */
1691*7304104dSAndroid Build Coastguard Worker char *scheme = NULL;
1692*7304104dSAndroid Build Coastguard Worker CURLcode ok3 = curl_easy_getinfo (target_handle,
1693*7304104dSAndroid Build Coastguard Worker CURLINFO_SCHEME,
1694*7304104dSAndroid Build Coastguard Worker &scheme);
1695*7304104dSAndroid Build Coastguard Worker if(ok3 == CURLE_OK && scheme)
1696*7304104dSAndroid Build Coastguard Worker {
1697*7304104dSAndroid Build Coastguard Worker if (startswith (scheme, "HTTP"))
1698*7304104dSAndroid Build Coastguard Worker if (resp_code == 200)
1699*7304104dSAndroid Build Coastguard Worker {
1700*7304104dSAndroid Build Coastguard Worker verified_handle = msg->easy_handle;
1701*7304104dSAndroid Build Coastguard Worker break;
1702*7304104dSAndroid Build Coastguard Worker }
1703*7304104dSAndroid Build Coastguard Worker }
1704*7304104dSAndroid Build Coastguard Worker #endif
1705*7304104dSAndroid Build Coastguard Worker #endif
1706*7304104dSAndroid Build Coastguard Worker }
1707*7304104dSAndroid Build Coastguard Worker }
1708*7304104dSAndroid Build Coastguard Worker }
1709*7304104dSAndroid Build Coastguard Worker } while (num_msg > 0);
1710*7304104dSAndroid Build Coastguard Worker
1711*7304104dSAndroid Build Coastguard Worker /* Create an empty file in the cache if the query fails with ENOENT and
1712*7304104dSAndroid Build Coastguard Worker it wasn't cancelled early. */
1713*7304104dSAndroid Build Coastguard Worker if (rc == -ENOENT && !c->progressfn_cancel)
1714*7304104dSAndroid Build Coastguard Worker {
1715*7304104dSAndroid Build Coastguard Worker int efd = open (target_cache_path, O_CREAT|O_EXCL, DEFFILEMODE);
1716*7304104dSAndroid Build Coastguard Worker if (efd >= 0)
1717*7304104dSAndroid Build Coastguard Worker close(efd);
1718*7304104dSAndroid Build Coastguard Worker }
1719*7304104dSAndroid Build Coastguard Worker else if (rc == -EFBIG)
1720*7304104dSAndroid Build Coastguard Worker goto out2;
1721*7304104dSAndroid Build Coastguard Worker
1722*7304104dSAndroid Build Coastguard Worker /* If the verified_handle is NULL and rc != -ENOENT, the query fails with
1723*7304104dSAndroid Build Coastguard Worker * an error code other than 404, then do several retry within the retry_limit.
1724*7304104dSAndroid Build Coastguard Worker * Clean up all old handles and jump back to the beginning of query_in_parallel,
1725*7304104dSAndroid Build Coastguard Worker * reinitialize handles and query again.*/
1726*7304104dSAndroid Build Coastguard Worker if (verified_handle == NULL)
1727*7304104dSAndroid Build Coastguard Worker {
1728*7304104dSAndroid Build Coastguard Worker if (rc != -ENOENT && retry_limit-- > 0)
1729*7304104dSAndroid Build Coastguard Worker {
1730*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1731*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "Retry failed query, %d attempt(s) remaining\n", retry_limit);
1732*7304104dSAndroid Build Coastguard Worker /* remove all handles from multi */
1733*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; i++)
1734*7304104dSAndroid Build Coastguard Worker {
1735*7304104dSAndroid Build Coastguard Worker curl_multi_remove_handle(curlm, data[i].handle); /* ok to repeat */
1736*7304104dSAndroid Build Coastguard Worker curl_easy_cleanup (data[i].handle);
1737*7304104dSAndroid Build Coastguard Worker free(data[i].response_data);
1738*7304104dSAndroid Build Coastguard Worker }
1739*7304104dSAndroid Build Coastguard Worker free(c->winning_headers);
1740*7304104dSAndroid Build Coastguard Worker c->winning_headers = NULL;
1741*7304104dSAndroid Build Coastguard Worker goto query_in_parallel;
1742*7304104dSAndroid Build Coastguard Worker }
1743*7304104dSAndroid Build Coastguard Worker else
1744*7304104dSAndroid Build Coastguard Worker goto out2;
1745*7304104dSAndroid Build Coastguard Worker }
1746*7304104dSAndroid Build Coastguard Worker
1747*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1748*7304104dSAndroid Build Coastguard Worker {
1749*7304104dSAndroid Build Coastguard Worker bool pnl = c->default_progressfn_printed_p && vfd == STDERR_FILENO;
1750*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "%sgot file from server\n", pnl ? "\n" : "");
1751*7304104dSAndroid Build Coastguard Worker if (pnl)
1752*7304104dSAndroid Build Coastguard Worker c->default_progressfn_printed_p = 0;
1753*7304104dSAndroid Build Coastguard Worker }
1754*7304104dSAndroid Build Coastguard Worker
1755*7304104dSAndroid Build Coastguard Worker /* we've got one!!!! */
1756*7304104dSAndroid Build Coastguard Worker time_t mtime;
1757*7304104dSAndroid Build Coastguard Worker #if defined(_TIME_BITS) && _TIME_BITS == 64
1758*7304104dSAndroid Build Coastguard Worker CURLcode curl_res = curl_easy_getinfo(verified_handle, CURLINFO_FILETIME_T, (void*) &mtime);
1759*7304104dSAndroid Build Coastguard Worker #else
1760*7304104dSAndroid Build Coastguard Worker CURLcode curl_res = curl_easy_getinfo(verified_handle, CURLINFO_FILETIME, (void*) &mtime);
1761*7304104dSAndroid Build Coastguard Worker #endif
1762*7304104dSAndroid Build Coastguard Worker if (curl_res == CURLE_OK)
1763*7304104dSAndroid Build Coastguard Worker {
1764*7304104dSAndroid Build Coastguard Worker struct timespec tvs[2];
1765*7304104dSAndroid Build Coastguard Worker tvs[0].tv_sec = 0;
1766*7304104dSAndroid Build Coastguard Worker tvs[0].tv_nsec = UTIME_OMIT;
1767*7304104dSAndroid Build Coastguard Worker tvs[1].tv_sec = mtime;
1768*7304104dSAndroid Build Coastguard Worker tvs[1].tv_nsec = 0;
1769*7304104dSAndroid Build Coastguard Worker (void) futimens (fd, tvs); /* best effort */
1770*7304104dSAndroid Build Coastguard Worker }
1771*7304104dSAndroid Build Coastguard Worker
1772*7304104dSAndroid Build Coastguard Worker /* PR27571: make cache files casually unwriteable; dirs are already 0700 */
1773*7304104dSAndroid Build Coastguard Worker (void) fchmod(fd, 0400);
1774*7304104dSAndroid Build Coastguard Worker /* PR31248: lseek back to beginning */
1775*7304104dSAndroid Build Coastguard Worker (void) lseek(fd, 0, SEEK_SET);
1776*7304104dSAndroid Build Coastguard Worker
1777*7304104dSAndroid Build Coastguard Worker /* rename tmp->real */
1778*7304104dSAndroid Build Coastguard Worker rc = rename (target_cache_tmppath, target_cache_path);
1779*7304104dSAndroid Build Coastguard Worker if (rc < 0)
1780*7304104dSAndroid Build Coastguard Worker {
1781*7304104dSAndroid Build Coastguard Worker rc = -errno;
1782*7304104dSAndroid Build Coastguard Worker goto out2;
1783*7304104dSAndroid Build Coastguard Worker /* Perhaps we need not give up right away; could retry or something ... */
1784*7304104dSAndroid Build Coastguard Worker }
1785*7304104dSAndroid Build Coastguard Worker
1786*7304104dSAndroid Build Coastguard Worker /* remove all handles from multi */
1787*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; i++)
1788*7304104dSAndroid Build Coastguard Worker {
1789*7304104dSAndroid Build Coastguard Worker curl_multi_remove_handle(curlm, data[i].handle); /* ok to repeat */
1790*7304104dSAndroid Build Coastguard Worker curl_easy_cleanup (data[i].handle);
1791*7304104dSAndroid Build Coastguard Worker free (data[i].response_data);
1792*7304104dSAndroid Build Coastguard Worker }
1793*7304104dSAndroid Build Coastguard Worker
1794*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; ++i)
1795*7304104dSAndroid Build Coastguard Worker free(server_url_list[i]);
1796*7304104dSAndroid Build Coastguard Worker free(server_url_list);
1797*7304104dSAndroid Build Coastguard Worker free (data);
1798*7304104dSAndroid Build Coastguard Worker free (server_urls);
1799*7304104dSAndroid Build Coastguard Worker
1800*7304104dSAndroid Build Coastguard Worker /* don't close fd - we're returning it */
1801*7304104dSAndroid Build Coastguard Worker /* don't unlink the tmppath; it's already been renamed. */
1802*7304104dSAndroid Build Coastguard Worker if (path != NULL)
1803*7304104dSAndroid Build Coastguard Worker *path = strdup(target_cache_path);
1804*7304104dSAndroid Build Coastguard Worker
1805*7304104dSAndroid Build Coastguard Worker rc = fd;
1806*7304104dSAndroid Build Coastguard Worker goto out;
1807*7304104dSAndroid Build Coastguard Worker
1808*7304104dSAndroid Build Coastguard Worker /* error exits */
1809*7304104dSAndroid Build Coastguard Worker out2:
1810*7304104dSAndroid Build Coastguard Worker /* remove all handles from multi */
1811*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; i++)
1812*7304104dSAndroid Build Coastguard Worker {
1813*7304104dSAndroid Build Coastguard Worker if (data[i].handle != NULL)
1814*7304104dSAndroid Build Coastguard Worker {
1815*7304104dSAndroid Build Coastguard Worker curl_multi_remove_handle(curlm, data[i].handle); /* ok to repeat */
1816*7304104dSAndroid Build Coastguard Worker curl_easy_cleanup (data[i].handle);
1817*7304104dSAndroid Build Coastguard Worker free (data[i].response_data);
1818*7304104dSAndroid Build Coastguard Worker }
1819*7304104dSAndroid Build Coastguard Worker }
1820*7304104dSAndroid Build Coastguard Worker
1821*7304104dSAndroid Build Coastguard Worker unlink (target_cache_tmppath);
1822*7304104dSAndroid Build Coastguard Worker close (fd); /* before the rmdir, otherwise it'll fail */
1823*7304104dSAndroid Build Coastguard Worker (void) rmdir (target_cache_dir); /* nop if not empty */
1824*7304104dSAndroid Build Coastguard Worker free(data);
1825*7304104dSAndroid Build Coastguard Worker
1826*7304104dSAndroid Build Coastguard Worker out1:
1827*7304104dSAndroid Build Coastguard Worker for (int i = 0; i < num_urls; ++i)
1828*7304104dSAndroid Build Coastguard Worker free(server_url_list[i]);
1829*7304104dSAndroid Build Coastguard Worker free(server_url_list);
1830*7304104dSAndroid Build Coastguard Worker
1831*7304104dSAndroid Build Coastguard Worker out0:
1832*7304104dSAndroid Build Coastguard Worker free (server_urls);
1833*7304104dSAndroid Build Coastguard Worker
1834*7304104dSAndroid Build Coastguard Worker /* general purpose exit */
1835*7304104dSAndroid Build Coastguard Worker out:
1836*7304104dSAndroid Build Coastguard Worker /* Reset sent headers */
1837*7304104dSAndroid Build Coastguard Worker curl_slist_free_all (c->headers);
1838*7304104dSAndroid Build Coastguard Worker c->headers = NULL;
1839*7304104dSAndroid Build Coastguard Worker c->user_agent_set_p = 0;
1840*7304104dSAndroid Build Coastguard Worker
1841*7304104dSAndroid Build Coastguard Worker /* Conclude the last \r status line */
1842*7304104dSAndroid Build Coastguard Worker /* Another possibility is to use the ANSI CSI n K EL "Erase in Line"
1843*7304104dSAndroid Build Coastguard Worker code. That way, the previously printed messages would be erased,
1844*7304104dSAndroid Build Coastguard Worker and without a newline. */
1845*7304104dSAndroid Build Coastguard Worker if (c->default_progressfn_printed_p)
1846*7304104dSAndroid Build Coastguard Worker dprintf(STDERR_FILENO, "\n");
1847*7304104dSAndroid Build Coastguard Worker
1848*7304104dSAndroid Build Coastguard Worker if (vfd >= 0)
1849*7304104dSAndroid Build Coastguard Worker {
1850*7304104dSAndroid Build Coastguard Worker if (rc < 0)
1851*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "not found %s (err=%d)\n", strerror (-rc), rc);
1852*7304104dSAndroid Build Coastguard Worker else
1853*7304104dSAndroid Build Coastguard Worker dprintf (vfd, "found %s (fd=%d)\n", target_cache_path, rc);
1854*7304104dSAndroid Build Coastguard Worker }
1855*7304104dSAndroid Build Coastguard Worker
1856*7304104dSAndroid Build Coastguard Worker free (cache_path);
1857*7304104dSAndroid Build Coastguard Worker free (maxage_path);
1858*7304104dSAndroid Build Coastguard Worker free (interval_path);
1859*7304104dSAndroid Build Coastguard Worker free (cache_miss_path);
1860*7304104dSAndroid Build Coastguard Worker free (target_cache_dir);
1861*7304104dSAndroid Build Coastguard Worker free (target_cache_path);
1862*7304104dSAndroid Build Coastguard Worker free (target_cache_tmppath);
1863*7304104dSAndroid Build Coastguard Worker return rc;
1864*7304104dSAndroid Build Coastguard Worker }
1865*7304104dSAndroid Build Coastguard Worker
1866*7304104dSAndroid Build Coastguard Worker
1867*7304104dSAndroid Build Coastguard Worker
1868*7304104dSAndroid Build Coastguard Worker /* See debuginfod.h */
1869*7304104dSAndroid Build Coastguard Worker debuginfod_client *
debuginfod_begin(void)1870*7304104dSAndroid Build Coastguard Worker debuginfod_begin (void)
1871*7304104dSAndroid Build Coastguard Worker {
1872*7304104dSAndroid Build Coastguard Worker /* Initialize libcurl lazily, but only once. */
1873*7304104dSAndroid Build Coastguard Worker pthread_once (&init_control, libcurl_init);
1874*7304104dSAndroid Build Coastguard Worker
1875*7304104dSAndroid Build Coastguard Worker debuginfod_client *client;
1876*7304104dSAndroid Build Coastguard Worker size_t size = sizeof (struct debuginfod_client);
1877*7304104dSAndroid Build Coastguard Worker client = calloc (1, size);
1878*7304104dSAndroid Build Coastguard Worker
1879*7304104dSAndroid Build Coastguard Worker if (client != NULL)
1880*7304104dSAndroid Build Coastguard Worker {
1881*7304104dSAndroid Build Coastguard Worker if (getenv(DEBUGINFOD_PROGRESS_ENV_VAR))
1882*7304104dSAndroid Build Coastguard Worker client->progressfn = default_progressfn;
1883*7304104dSAndroid Build Coastguard Worker if (getenv(DEBUGINFOD_VERBOSE_ENV_VAR))
1884*7304104dSAndroid Build Coastguard Worker client->verbose_fd = STDERR_FILENO;
1885*7304104dSAndroid Build Coastguard Worker else
1886*7304104dSAndroid Build Coastguard Worker client->verbose_fd = -1;
1887*7304104dSAndroid Build Coastguard Worker
1888*7304104dSAndroid Build Coastguard Worker // allocate 1 curl multi handle
1889*7304104dSAndroid Build Coastguard Worker client->server_mhandle = curl_multi_init ();
1890*7304104dSAndroid Build Coastguard Worker if (client->server_mhandle == NULL)
1891*7304104dSAndroid Build Coastguard Worker goto out1;
1892*7304104dSAndroid Build Coastguard Worker }
1893*7304104dSAndroid Build Coastguard Worker
1894*7304104dSAndroid Build Coastguard Worker // extra future initialization
1895*7304104dSAndroid Build Coastguard Worker
1896*7304104dSAndroid Build Coastguard Worker goto out;
1897*7304104dSAndroid Build Coastguard Worker
1898*7304104dSAndroid Build Coastguard Worker out1:
1899*7304104dSAndroid Build Coastguard Worker free (client);
1900*7304104dSAndroid Build Coastguard Worker client = NULL;
1901*7304104dSAndroid Build Coastguard Worker
1902*7304104dSAndroid Build Coastguard Worker out:
1903*7304104dSAndroid Build Coastguard Worker return client;
1904*7304104dSAndroid Build Coastguard Worker }
1905*7304104dSAndroid Build Coastguard Worker
1906*7304104dSAndroid Build Coastguard Worker void
debuginfod_set_user_data(debuginfod_client * client,void * data)1907*7304104dSAndroid Build Coastguard Worker debuginfod_set_user_data(debuginfod_client *client,
1908*7304104dSAndroid Build Coastguard Worker void *data)
1909*7304104dSAndroid Build Coastguard Worker {
1910*7304104dSAndroid Build Coastguard Worker client->user_data = data;
1911*7304104dSAndroid Build Coastguard Worker }
1912*7304104dSAndroid Build Coastguard Worker
1913*7304104dSAndroid Build Coastguard Worker void *
debuginfod_get_user_data(debuginfod_client * client)1914*7304104dSAndroid Build Coastguard Worker debuginfod_get_user_data(debuginfod_client *client)
1915*7304104dSAndroid Build Coastguard Worker {
1916*7304104dSAndroid Build Coastguard Worker return client->user_data;
1917*7304104dSAndroid Build Coastguard Worker }
1918*7304104dSAndroid Build Coastguard Worker
1919*7304104dSAndroid Build Coastguard Worker const char *
debuginfod_get_url(debuginfod_client * client)1920*7304104dSAndroid Build Coastguard Worker debuginfod_get_url(debuginfod_client *client)
1921*7304104dSAndroid Build Coastguard Worker {
1922*7304104dSAndroid Build Coastguard Worker return client->url;
1923*7304104dSAndroid Build Coastguard Worker }
1924*7304104dSAndroid Build Coastguard Worker
1925*7304104dSAndroid Build Coastguard Worker const char *
debuginfod_get_headers(debuginfod_client * client)1926*7304104dSAndroid Build Coastguard Worker debuginfod_get_headers(debuginfod_client *client)
1927*7304104dSAndroid Build Coastguard Worker {
1928*7304104dSAndroid Build Coastguard Worker return client->winning_headers;
1929*7304104dSAndroid Build Coastguard Worker }
1930*7304104dSAndroid Build Coastguard Worker
1931*7304104dSAndroid Build Coastguard Worker void
debuginfod_end(debuginfod_client * client)1932*7304104dSAndroid Build Coastguard Worker debuginfod_end (debuginfod_client *client)
1933*7304104dSAndroid Build Coastguard Worker {
1934*7304104dSAndroid Build Coastguard Worker if (client == NULL)
1935*7304104dSAndroid Build Coastguard Worker return;
1936*7304104dSAndroid Build Coastguard Worker
1937*7304104dSAndroid Build Coastguard Worker curl_multi_cleanup (client->server_mhandle);
1938*7304104dSAndroid Build Coastguard Worker curl_slist_free_all (client->headers);
1939*7304104dSAndroid Build Coastguard Worker free (client->winning_headers);
1940*7304104dSAndroid Build Coastguard Worker free (client->url);
1941*7304104dSAndroid Build Coastguard Worker free (client);
1942*7304104dSAndroid Build Coastguard Worker }
1943*7304104dSAndroid Build Coastguard Worker
1944*7304104dSAndroid Build Coastguard Worker int
debuginfod_find_debuginfo(debuginfod_client * client,const unsigned char * build_id,int build_id_len,char ** path)1945*7304104dSAndroid Build Coastguard Worker debuginfod_find_debuginfo (debuginfod_client *client,
1946*7304104dSAndroid Build Coastguard Worker const unsigned char *build_id, int build_id_len,
1947*7304104dSAndroid Build Coastguard Worker char **path)
1948*7304104dSAndroid Build Coastguard Worker {
1949*7304104dSAndroid Build Coastguard Worker return debuginfod_query_server(client, build_id, build_id_len,
1950*7304104dSAndroid Build Coastguard Worker "debuginfo", NULL, path);
1951*7304104dSAndroid Build Coastguard Worker }
1952*7304104dSAndroid Build Coastguard Worker
1953*7304104dSAndroid Build Coastguard Worker
1954*7304104dSAndroid Build Coastguard Worker /* See debuginfod.h */
1955*7304104dSAndroid Build Coastguard Worker int
debuginfod_find_executable(debuginfod_client * client,const unsigned char * build_id,int build_id_len,char ** path)1956*7304104dSAndroid Build Coastguard Worker debuginfod_find_executable(debuginfod_client *client,
1957*7304104dSAndroid Build Coastguard Worker const unsigned char *build_id, int build_id_len,
1958*7304104dSAndroid Build Coastguard Worker char **path)
1959*7304104dSAndroid Build Coastguard Worker {
1960*7304104dSAndroid Build Coastguard Worker return debuginfod_query_server(client, build_id, build_id_len,
1961*7304104dSAndroid Build Coastguard Worker "executable", NULL, path);
1962*7304104dSAndroid Build Coastguard Worker }
1963*7304104dSAndroid Build Coastguard Worker
1964*7304104dSAndroid Build Coastguard Worker /* See debuginfod.h */
debuginfod_find_source(debuginfod_client * client,const unsigned char * build_id,int build_id_len,const char * filename,char ** path)1965*7304104dSAndroid Build Coastguard Worker int debuginfod_find_source(debuginfod_client *client,
1966*7304104dSAndroid Build Coastguard Worker const unsigned char *build_id, int build_id_len,
1967*7304104dSAndroid Build Coastguard Worker const char *filename, char **path)
1968*7304104dSAndroid Build Coastguard Worker {
1969*7304104dSAndroid Build Coastguard Worker return debuginfod_query_server(client, build_id, build_id_len,
1970*7304104dSAndroid Build Coastguard Worker "source", filename, path);
1971*7304104dSAndroid Build Coastguard Worker }
1972*7304104dSAndroid Build Coastguard Worker
1973*7304104dSAndroid Build Coastguard Worker int
debuginfod_find_section(debuginfod_client * client,const unsigned char * build_id,int build_id_len,const char * section,char ** path)1974*7304104dSAndroid Build Coastguard Worker debuginfod_find_section (debuginfod_client *client,
1975*7304104dSAndroid Build Coastguard Worker const unsigned char *build_id, int build_id_len,
1976*7304104dSAndroid Build Coastguard Worker const char *section, char **path)
1977*7304104dSAndroid Build Coastguard Worker {
1978*7304104dSAndroid Build Coastguard Worker int rc = debuginfod_query_server(client, build_id, build_id_len,
1979*7304104dSAndroid Build Coastguard Worker "section", section, path);
1980*7304104dSAndroid Build Coastguard Worker if (rc != -EINVAL)
1981*7304104dSAndroid Build Coastguard Worker return rc;
1982*7304104dSAndroid Build Coastguard Worker
1983*7304104dSAndroid Build Coastguard Worker /* The servers may have lacked support for section queries. Attempt to
1984*7304104dSAndroid Build Coastguard Worker download the debuginfo or executable containing the section in order
1985*7304104dSAndroid Build Coastguard Worker to extract it. */
1986*7304104dSAndroid Build Coastguard Worker rc = -EEXIST;
1987*7304104dSAndroid Build Coastguard Worker int fd = -1;
1988*7304104dSAndroid Build Coastguard Worker char *tmp_path = NULL;
1989*7304104dSAndroid Build Coastguard Worker
1990*7304104dSAndroid Build Coastguard Worker fd = debuginfod_find_debuginfo (client, build_id, build_id_len, &tmp_path);
1991*7304104dSAndroid Build Coastguard Worker if (client->progressfn_cancel)
1992*7304104dSAndroid Build Coastguard Worker {
1993*7304104dSAndroid Build Coastguard Worker if (fd >= 0)
1994*7304104dSAndroid Build Coastguard Worker {
1995*7304104dSAndroid Build Coastguard Worker /* This shouldn't happen, but we'll check this condition
1996*7304104dSAndroid Build Coastguard Worker just in case. */
1997*7304104dSAndroid Build Coastguard Worker close (fd);
1998*7304104dSAndroid Build Coastguard Worker free (tmp_path);
1999*7304104dSAndroid Build Coastguard Worker }
2000*7304104dSAndroid Build Coastguard Worker return -ENOENT;
2001*7304104dSAndroid Build Coastguard Worker }
2002*7304104dSAndroid Build Coastguard Worker if (fd >= 0)
2003*7304104dSAndroid Build Coastguard Worker {
2004*7304104dSAndroid Build Coastguard Worker rc = extract_section (fd, section, tmp_path, path);
2005*7304104dSAndroid Build Coastguard Worker close (fd);
2006*7304104dSAndroid Build Coastguard Worker }
2007*7304104dSAndroid Build Coastguard Worker
2008*7304104dSAndroid Build Coastguard Worker if (rc == -EEXIST)
2009*7304104dSAndroid Build Coastguard Worker {
2010*7304104dSAndroid Build Coastguard Worker /* Either the debuginfo couldn't be found or the section should
2011*7304104dSAndroid Build Coastguard Worker be in the executable. */
2012*7304104dSAndroid Build Coastguard Worker fd = debuginfod_find_executable (client, build_id,
2013*7304104dSAndroid Build Coastguard Worker build_id_len, &tmp_path);
2014*7304104dSAndroid Build Coastguard Worker if (fd >= 0)
2015*7304104dSAndroid Build Coastguard Worker {
2016*7304104dSAndroid Build Coastguard Worker rc = extract_section (fd, section, tmp_path, path);
2017*7304104dSAndroid Build Coastguard Worker close (fd);
2018*7304104dSAndroid Build Coastguard Worker }
2019*7304104dSAndroid Build Coastguard Worker else
2020*7304104dSAndroid Build Coastguard Worker /* Update rc so that we return the most recent error code. */
2021*7304104dSAndroid Build Coastguard Worker rc = fd;
2022*7304104dSAndroid Build Coastguard Worker }
2023*7304104dSAndroid Build Coastguard Worker
2024*7304104dSAndroid Build Coastguard Worker free (tmp_path);
2025*7304104dSAndroid Build Coastguard Worker return rc;
2026*7304104dSAndroid Build Coastguard Worker }
2027*7304104dSAndroid Build Coastguard Worker
2028*7304104dSAndroid Build Coastguard Worker /* Add an outgoing HTTP header. */
debuginfod_add_http_header(debuginfod_client * client,const char * header)2029*7304104dSAndroid Build Coastguard Worker int debuginfod_add_http_header (debuginfod_client *client, const char* header)
2030*7304104dSAndroid Build Coastguard Worker {
2031*7304104dSAndroid Build Coastguard Worker /* Sanity check header value is of the form Header: Value.
2032*7304104dSAndroid Build Coastguard Worker It should contain at least one colon that isn't the first or
2033*7304104dSAndroid Build Coastguard Worker last character. */
2034*7304104dSAndroid Build Coastguard Worker char *colon = strchr (header, ':'); /* first colon */
2035*7304104dSAndroid Build Coastguard Worker if (colon == NULL /* present */
2036*7304104dSAndroid Build Coastguard Worker || colon == header /* not at beginning - i.e., have a header name */
2037*7304104dSAndroid Build Coastguard Worker || *(colon + 1) == '\0') /* not at end - i.e., have a value */
2038*7304104dSAndroid Build Coastguard Worker /* NB: but it's okay for a value to contain other colons! */
2039*7304104dSAndroid Build Coastguard Worker return -EINVAL;
2040*7304104dSAndroid Build Coastguard Worker
2041*7304104dSAndroid Build Coastguard Worker struct curl_slist *temp = curl_slist_append (client->headers, header);
2042*7304104dSAndroid Build Coastguard Worker if (temp == NULL)
2043*7304104dSAndroid Build Coastguard Worker return -ENOMEM;
2044*7304104dSAndroid Build Coastguard Worker
2045*7304104dSAndroid Build Coastguard Worker /* Track if User-Agent: is being set. If so, signal not to add the
2046*7304104dSAndroid Build Coastguard Worker default one. */
2047*7304104dSAndroid Build Coastguard Worker if (startswith (header, "User-Agent:"))
2048*7304104dSAndroid Build Coastguard Worker client->user_agent_set_p = 1;
2049*7304104dSAndroid Build Coastguard Worker
2050*7304104dSAndroid Build Coastguard Worker client->headers = temp;
2051*7304104dSAndroid Build Coastguard Worker return 0;
2052*7304104dSAndroid Build Coastguard Worker }
2053*7304104dSAndroid Build Coastguard Worker
2054*7304104dSAndroid Build Coastguard Worker
2055*7304104dSAndroid Build Coastguard Worker void
debuginfod_set_progressfn(debuginfod_client * client,debuginfod_progressfn_t fn)2056*7304104dSAndroid Build Coastguard Worker debuginfod_set_progressfn(debuginfod_client *client,
2057*7304104dSAndroid Build Coastguard Worker debuginfod_progressfn_t fn)
2058*7304104dSAndroid Build Coastguard Worker {
2059*7304104dSAndroid Build Coastguard Worker client->progressfn = fn;
2060*7304104dSAndroid Build Coastguard Worker }
2061*7304104dSAndroid Build Coastguard Worker
2062*7304104dSAndroid Build Coastguard Worker void
debuginfod_set_verbose_fd(debuginfod_client * client,int fd)2063*7304104dSAndroid Build Coastguard Worker debuginfod_set_verbose_fd(debuginfod_client *client, int fd)
2064*7304104dSAndroid Build Coastguard Worker {
2065*7304104dSAndroid Build Coastguard Worker client->verbose_fd = fd;
2066*7304104dSAndroid Build Coastguard Worker }
2067*7304104dSAndroid Build Coastguard Worker
2068*7304104dSAndroid Build Coastguard Worker #endif /* DUMMY_LIBDEBUGINFOD */
2069