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 }