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