f5ba8b9020adcad7261dad4f235d65385ef24393
[platform/upstream/libsolv.git] / examples / solv / repoinfo_download.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <sys/types.h>
6 #include <sys/wait.h>
7
8 #include "pool.h"
9 #include "repo.h"
10 #include "chksum.h"
11 #include "solv_xfopen.h"
12
13 #include "repoinfo.h"
14 #include "mirror.h"
15 #include "checksig.h"
16 #if defined(FEDORA) || defined(MAGEIA)
17 #include "repoinfo_config_yum.h"
18 #endif
19 #include "repoinfo_download.h"
20
21 static inline int
22 opentmpfile()
23 {
24   char tmpl[100];
25   int fd;
26
27   strcpy(tmpl, "/var/tmp/solvXXXXXX");
28   fd = mkstemp(tmpl);
29   if (fd < 0) 
30     {    
31       perror("mkstemp");
32       exit(1);
33     }    
34   unlink(tmpl);
35   return fd;
36 }
37
38 int
39 verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype)
40 {
41   char buf[1024];
42   const unsigned char *sum;
43   Chksum *h;
44   int l;
45
46   h = solv_chksum_create(chksumtype);
47   if (!h)
48     {
49       printf("%s: unknown checksum type\n", file);
50       return 0;
51     }
52   while ((l = read(fd, buf, sizeof(buf))) > 0)
53     solv_chksum_add(h, buf, l);
54   lseek(fd, 0, SEEK_SET);
55   l = 0;
56   sum = solv_chksum_get(h, &l);
57   if (memcmp(sum, chksum, l))
58     {
59       printf("%s: checksum mismatch\n", file);
60       solv_chksum_free(h, 0);
61       return 0;
62     }
63   solv_chksum_free(h, 0);
64   return 1;
65 }
66
67 FILE *
68 curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete)
69 {
70   FILE *fp;
71   pid_t pid;
72   int fd;
73   int status;
74   char url[4096];
75   const char *baseurl = cinfo->baseurl;
76
77   if (!baseurl)
78     {
79       if (!cinfo->metalink && !cinfo->mirrorlist)
80         return 0;
81       if (file != cinfo->metalink && file != cinfo->mirrorlist)
82         {
83           unsigned char mlchksum[32];
84           Id mlchksumtype = 0;
85           fp = curlfopen(cinfo, cinfo->metalink ? cinfo->metalink : cinfo->mirrorlist, 0, 0, 0, 0);
86           if (!fp)
87             return 0;
88           if (cinfo->metalink)
89             cinfo->baseurl = findmetalinkurl(fp, mlchksum, &mlchksumtype);
90           else
91             cinfo->baseurl = findmirrorlisturl(fp);
92           fclose(fp);
93           if (!cinfo->baseurl)
94             return 0;
95 #if defined(FEDORA) || defined(MAGEIA)
96           if (strchr(cinfo->baseurl, '$'))
97             {
98               char *b = yum_substitute(cinfo->repo->pool, cinfo->baseurl);
99               free(cinfo->baseurl);
100               cinfo->baseurl = strdup(b);
101             }
102 #endif
103           if (!chksumtype && mlchksumtype && !strcmp(file, "repodata/repomd.xml"))
104             {
105               chksumtype = mlchksumtype;
106               chksum = mlchksum;
107             }
108           return curlfopen(cinfo, file, uncompress, chksum, chksumtype, markincomplete);
109         }
110       snprintf(url, sizeof(url), "%s", file);
111     }
112   else
113     {
114       const char *path = cinfo->path && strcmp(cinfo->path, "/") != 0 ? cinfo->path : "";
115       int l = strlen(baseurl);
116       int pl = strlen(path);
117       const char *sep = l && baseurl[l - 1] == '/' ? "" : "/";
118       const char *psep = pl && cinfo->path[pl - 1] == '/' ? "" : "/";
119       snprintf(url, sizeof(url), "%s%s%s%s%s", baseurl, sep, path, psep, file);
120     }
121   fd = opentmpfile();
122   // printf("url: %s\n", url);
123   if ((pid = fork()) == (pid_t)-1)
124     {
125       perror("fork");
126       exit(1);
127     }
128   if (pid == 0)
129     {
130       if (fd != 1)
131         {
132           dup2(fd, 1);
133           close(fd);
134         }
135       execlp("curl", "curl", "-f", "-s", "-L", url, (char *)0);
136       perror("curl");
137       _exit(0);
138     }
139   status = 0;
140   while (waitpid(pid, &status, 0) != pid)
141     ;
142   if (lseek(fd, 0, SEEK_END) == 0 && (!status || !chksumtype))
143     {
144       /* empty file */
145       close(fd);
146       return 0;
147     }
148   lseek(fd, 0, SEEK_SET);
149   if (status)
150     {
151       printf("%s: download error %d\n", file, status >> 8 ? status >> 8 : status);
152       if (markincomplete)
153         cinfo->incomplete = 1;
154       close(fd);
155       return 0;
156     }
157   if (chksumtype && !verify_checksum(fd, file, chksum, chksumtype))
158     {
159       if (markincomplete)
160         cinfo->incomplete = 1;
161       close(fd);
162       return 0;
163     }
164   fcntl(fd, F_SETFD, FD_CLOEXEC);
165   if (uncompress)
166     {
167       if (solv_xfopen_iscompressed(file) < 0)
168         {
169           printf("%s: unsupported compression\n", file);
170           if (markincomplete)
171             cinfo->incomplete = 1;
172           close(fd);
173           return 0;
174         }
175       fp = solv_xfopen_fd(file, fd, "r");
176     }
177   else
178     fp = fdopen(fd, "r");
179   if (!fp)
180     close(fd);
181   return fp;
182 }
183
184 FILE *
185 downloadpackage(Solvable *s, const char *loc)
186 {
187   const unsigned char *chksum;
188   Id chksumtype;
189   struct repoinfo *cinfo = s->repo->appdata;
190
191 #ifdef ENABLE_SUSEREPO
192   if (cinfo->type == TYPE_SUSETAGS)
193     {
194       const char *datadir = repo_lookup_str(cinfo->repo, SOLVID_META, SUSETAGS_DATADIR);
195       loc = pool_tmpjoin(s->repo->pool, datadir ? datadir : "suse", "/", loc);
196     }
197 #endif
198   chksumtype = 0;
199   chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype);
200   return curlfopen(cinfo, loc, 0, chksum, chksumtype, 0);
201 }
202
203 int
204 downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool)
205 {
206   FILE *sigfp;
207   sigfp = curlfopen(cinfo, sigurl, 0, 0, 0, 0); 
208   if (!sigfp)
209     {    
210       printf(" unsigned, skipped\n");
211       return 0;
212     }    
213   if (!*sigpool)
214     *sigpool = read_sigs();
215   if (!checksig(*sigpool, fp, sigfp))
216     {    
217       printf(" checksig failed, skipped\n");
218       fclose(sigfp);
219       return 0;
220     }    
221   fclose(sigfp);
222   return 1;
223 }
224