projects/aports·blob v2.27.2 · refs

203 lines · 4.3 KiB

1/* MIT license
2
3Copyright (C) 2015 Natanael Copa <[email protected]>
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
22
23*/
24
25
26#include <sys/wait.h>
27
28#include <err.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <limits.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37static char *program;
38static char lockfile[PATH_MAX] = "";
39
40struct cmdarray {
41 size_t argc;
42 char *argv[32];
43};
44
45void add_opt(struct cmdarray *cmd, char *opt)
46{
47 cmd->argv[cmd->argc++] = opt;
48 cmd->argv[cmd->argc] = NULL;
49}
50
51int usage(int eval)
52{
53 printf("usage: %s [-d DESTDIR] URL\n", program);
54 return eval;
55}
56
57/* create or wait for an NFS-safe lockfile and fetch url with curl or wget */
58int fetch(char *url, const char *destdir)
59{
60 int lockfd, status=0;
61 pid_t childpid;
62 char outfile[PATH_MAX], partfile[PATH_MAX];
63 char *name, *p;
64 struct flock fl = {
65 .l_type = F_WRLCK,
66 .l_whence = SEEK_SET,
67 .l_start = 1,
68 .l_len = 0,
69 };
70 struct cmdarray curlcmd = {
71 .argc = 6,
72 .argv = { "curl", "-k", "-L", "-f", "-o", partfile, NULL }
73 };
74 struct cmdarray wgetcmd = {
75 .argc = 3,
76 .argv = { "wget", "-O", partfile, NULL }
77 };
78
79 name = strrchr(url, '/');
80 if (name == NULL)
81 errx(1, "%s: no '/' in url", url);
82 p = strstr(url, "::");
83 if (p != NULL) {
84 name = url;
85 *p = '\0';
86 url = p + 2;
87 } else if (strstr(url, "saveas-") == url) {
88 *name++ = '\0';
89 url += 7; /* strlen("saveas-") */
90 } else {
91 name++;
92 }
93
94 snprintf(outfile, sizeof(outfile), "%s/%s", destdir, name);
95 snprintf(lockfile, sizeof(lockfile), "%s.lock", outfile);
96 snprintf(partfile, sizeof(partfile), "%s.part", outfile);
97
98 lockfd = open(lockfile, O_WRONLY|O_CREAT, 0660);
99 if (lockfd < 0)
100 err(1, "%s", lockfile);
101
102 if (fcntl(lockfd, F_SETLK, &fl) < 0) {
103 int i;
104 printf("Waiting for %s ...\n", lockfile);
105 for (i=0; i<10; i++) {
106 int r = fcntl(lockfd, F_SETLKW, &fl);
107 if (r == 0)
108 break;
109 if (r == -1 && errno != ESTALE)
110 err(1, "fcntl(F_SETLKW)");
111 sleep(1);
112 }
113 }
114
115 if (access(outfile, F_OK) == 0)
116 goto fetch_done;
117
118 if (access(partfile, F_OK) == 0) {
119 printf("Partial download found. Trying to resume.\n");
120 add_opt(&curlcmd, "-C");
121 add_opt(&curlcmd, "-");
122 add_opt(&wgetcmd, "-c");
123 }
124
125 add_opt(&curlcmd, url);
126 add_opt(&wgetcmd, url);
127
128 childpid = fork();
129 if (childpid < 0 )
130 err(1, "fork");
131
132 if (childpid == 0) {
133 execvp(curlcmd.argv[0], curlcmd.argv);
134 printf("Using wget\n");
135 execvp(wgetcmd.argv[0], wgetcmd.argv);
136 warn("%s", wgetcmd.argv[0]);
137 unlink(lockfile);
138 _exit(1);
139 }
140 wait(&status);
141 rename(partfile, outfile);
142
143fetch_done:
144 unlink(lockfile);
145 close(lockfd);
146 lockfile[0] = '\0';
147 return status;
148
149}
150
151void sighandler(int sig)
152{
153 switch(sig) {
154 case SIGABRT:
155 case SIGINT:
156 case SIGQUIT:
157 case SIGTERM:
158 unlink(lockfile);
159 exit(0);
160 break;
161 default:
162 break;
163 }
164}
165
166int main(int argc, char *argv[])
167{
168 int opt, r=0, i;
169 char *destdir = "/var/cache/distfiles";
170
171 program = argv[0];
172 while ((opt = getopt(argc, argv, "hd:")) != -1) {
173 switch (opt) {
174 case 'h':
175 return usage(0);
176 break;
177 case 'd':
178 destdir = optarg;
179 break;
180 default:
181 printf("Unkonwn option '%c'\n", opt);
182 return usage(1);
183 break;
184 }
185 }
186
187 argv += optind;
188 argc -= optind;
189
190 if (argc < 1)
191 return usage(1);
192
193 signal(SIGABRT, sighandler);
194 signal(SIGINT, sighandler);
195 signal(SIGQUIT, sighandler);
196 signal(SIGTERM, sighandler);
197
198 for (i = 0; i < argc; i++) {
199 if (fetch(argv[i], destdir))
200 r++;
201 }
202 return r;
203}