trepo.c - repo - list/download/sync packs with remote repositories
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
trepo.c (5356B)
---
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <libgen.h>
4 #include <limits.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/queue.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
12 #include <unistd.h>
13
14 #include <curl/curl.h>
15
16 #include "arg.h"
17 #include "repo.h"
18
19 void usage(char *);
20 int download(char *, FILE *);
21 int checkpack(char *, char *);
22 int cachepack(char *, char *, struct packs *, int);
23
24 int verbose = 0;
25 int fflag, lflag, sflag, uflag;
26
27 char *sickexec[] = { "sick", NULL };
28
29 void
30 usage(char *name)
31 {
32 fprintf(stderr, "usage: %s [-c FILE] [-flsu] [-r URL] [PACK..]\n", name);
33 exit(1);
34 }
35
36 struct pack *
37 addpack(struct packs *plist, char *name, char *version, char *url)
38 {
39 struct pack *p = NULL;
40
41 p = malloc(sizeof(struct pack));
42 if (!p) {
43 perror("malloc");
44 return NULL;
45 }
46
47 strncpy(p->url, url, sizeof(p->url));
48 strncpy(p->name, name, sizeof(p->name));
49 strncpy(p->version, version, sizeof(p->version));
50
51 TAILQ_INSERT_TAIL(plist, p, entries);
52
53 return p;
54 }
55
56 struct repo *
57 addrepo(struct repos *rlist, char *url)
58 {
59 struct repo *r = NULL;
60
61 r = malloc(sizeof(struct repo));
62 if (!r) {
63 perror("malloc");
64 exit(1);
65 }
66
67 r->url = strdup(url);
68 if (!r->url) {
69 perror("malloc");
70 exit(1);
71 }
72
73 TAILQ_INSERT_TAIL(rlist, r, entries);
74
75 return r;
76 }
77
78 int
79 repolist(struct packs *plist, char *local)
80 {
81 int r = 0;
82 char fn[PATH_MAX] = "";
83 char buf[LINE_MAX] = "";
84
85 char n[LINE_MAX], v[LINE_MAX], u[PATH_MAX];
86 FILE *list;
87
88 snprintf(fn, PATH_MAX, "%s/%s", local, DEFLISTFILE);
89 list = fopen(fn, "r");
90 if (!list) {
91 perror(fn);
92 exit(1);
93 }
94
95 while (fgets(buf, LINE_MAX, list)) {
96 r = sscanf(buf, "%s\t%s\t%s", n, v, u);
97 if (r < 3) {
98 fprintf(stderr, "%s: Invalid format detected\n", fn);
99 exit(1);
100 }
101 addpack(plist, n, v, u);
102 }
103 fclose(list);
104 return 0;
105 }
106
107 int
108 download(char *url, FILE *fd)
109 {
110 ssize_t len;
111 char *fn, *base, *encfile, *encurl;
112 CURL *c;
113 CURLcode r;
114
115 c = curl_easy_init();
116 if (!c)
117 return -1;
118
119
120 fn = strdup(basename(url));
121 base = strdup(dirname(url));
122 encfile = curl_easy_escape(c, fn, strlen(fn));
123
124 len = strlen(base) + strlen(encfile) + 1;
125 encurl = malloc(len + 1);
126 if (!encurl) {
127 perror("malloc");
128 exit(1);
129 }
130 snprintf(encurl, len + 1, "%s/%s", base, encfile);
131
132 curl_easy_setopt(c, CURLOPT_URL, encurl);
133 curl_easy_setopt(c, CURLOPT_WRITEDATA, fd);
134 if (verbose)
135 fprintf(stderr, "FETCH %s/%s\n", url, fn);
136
137 r = curl_easy_perform(c);
138 if (r != CURLE_OK) {
139 fprintf(stderr, "%s: %s\n", encurl, curl_easy_strerror(r));
140 exit(1);
141 }
142
143 free(fn);
144 curl_free(encfile);
145
146 return 0;
147 }
148
149 int
150 checkpack(char fn[PATH_MAX], char *url)
151 {
152 FILE *f;
153 int fd[2], out, status;
154 pipe(fd);
155 if (!fork()) {
156 close(0);
157 close(1);
158 close(fd[1]);
159 dup2(fd[0], 0);
160
161 if ((out = open(fn, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
162 perror(fn);
163 return -1;
164 }
165 dup2(out, 1);
166 execvp(sickexec[0], sickexec);
167 perror(sickexec[0]);
168 }
169
170 close(fd[0]);
171 f = fdopen(fd[1], "w");
172 if (!f) {
173 perror("pipe");
174 exit(1);
175 }
176
177 download(url, f);
178 fflush(f);
179 fclose(f);
180
181 wait(&status);
182 if (status) {
183 fprintf(stderr, "%s: Pack verification failed\n", basename(fn));
184 unlink(fn);
185 return -1;
186 }
187 return 0;
188 }
189
190
191 int
192 cachepack(char *name, char *localrepo, struct packs *plist, int untrust)
193 {
194 int ret = 0;
195 FILE *f;
196 char fn[PATH_MAX];;
197 struct pack *p = NULL;
198 struct stat sb;
199
200 TAILQ_FOREACH(p, plist, entries) {
201 if (!strncmp(p->name, name, PATH_MAX)) {
202 snprintf(fn, PATH_MAX, "%s/%s", localrepo, basename(p->url));
203 if (!stat(fn, &sb) && !fflag) {
204 puts(fn);
205 continue;
206 }
207
208 if (untrust) {
209 f = fopen(fn, "w");
210 if (!f) {
211 perror(fn);
212 exit(1);
213 }
214 download(p->url, f);
215 fflush(f);
216 fclose(f);
217 } else {
218 if (checkpack(fn, p->url)) {
219 ret++;
220 continue;
221 }
222 }
223
224 puts(fn);
225 break;
226 }
227 }
228 return ret;
229 }
230
231 int
232 main (int argc, char *argv[])
233 {
234 char *argv0, *n;
235 char cfgfile[PATH_MAX] = DEFCFGFILE;
236 char localrepo[PATH_MAX] = DEFLOCALREPO;
237 char fn[PATH_MAX], url[PATH_MAX];
238 FILE *fd;
239 struct stat sb;
240 struct packs plist;
241 struct repos rlist;
242 struct pack *p = NULL;
243 struct repo *r = NULL;
244
245 TAILQ_INIT(&plist);
246 TAILQ_INIT(&rlist);
247
248 fflag = lflag = sflag = 0;
249
250 ARGBEGIN{
251 case 'c':
252 snprintf(cfgfile, PATH_MAX, "%s", EARGF(usage(argv0)));
253 break;
254 case 'f':
255 fflag = 1;
256 break;
257 case 'r':
258 addrepo(&rlist, EARGF(usage(argv0)));
259 break;
260 case 's':
261 sflag = 1;
262 break;
263 case 'u':
264 uflag = 1;
265 break;
266 case 'l':
267 lflag = 1;
268 break;
269 case 'v':
270 verbose++;
271 break;
272 default:
273 usage(argv0);
274 }ARGEND;
275
276 if (!stat(cfgfile, &sb))
277 parseconf(&rlist, localrepo, &uflag, cfgfile);
278
279 if (sflag) {
280 snprintf(fn, PATH_MAX, "%s/%s", localrepo, DEFLISTFILE);
281 fd = fopen(fn, "w");
282 if (!fd) {
283 perror(fn);
284 exit(1);
285 }
286 TAILQ_FOREACH(r, &rlist, entries) {
287 if (verbose)
288 fprintf(stderr, "SYNC %s\n", r->url);
289 snprintf(url, PATH_MAX, "%s/%s", r->url, DEFLISTFILE);
290 download(url, fd);
291 }
292 fclose(fd);
293 }
294
295 repolist(&plist, localrepo);
296
297 if (lflag) {
298 TAILQ_FOREACH(p, &plist, entries) {
299 printf("%s\t%s\t%s\n", p->name, p->version, verbose ? p->url : "\b\0");
300 }
301 return 0;
302 }
303
304 while ((n = *(argv++)))
305 cachepack(n, localrepo, &plist, uflag);
306
307 return 0;
308 }