projects/aports·blob v2.25.0_rc1 · refs

195 lines · 4.2 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 <fcntl.h>
30#include <limits.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35
36static char *program;
37static char lockfile[PATH_MAX] = "";
38
39struct cmdarray {
40 size_t argc;
41 char *argv[32];
42};
43
44void add_opt(struct cmdarray *cmd, char *opt)
45{
46 cmd->argv[cmd->argc++] = opt;
47 cmd->argv[cmd->argc] = NULL;
48}
49
50int usage(int eval)
51{
52 printf("usage: %s [-d DESTDIR] URL\n", program);
53 return eval;
54}
55
56/* create or wait for an NFS-safe lockfile and fetch url with curl or wget */
57int fetch(char *url, const char *destdir)
58{
59 int lockfd, status=0;
60 pid_t childpid;
61 char outfile[PATH_MAX], partfile[PATH_MAX];
62 char *name, *p;
63 struct flock fl = {
64 .l_type = F_WRLCK,
65 .l_whence = SEEK_SET,
66 .l_start = 1,
67 .l_len = 0,
68 };
69 struct cmdarray curlcmd = {
70 .argc = 6,
71 .argv = { "curl", "-k", "-L", "-f", "-o", partfile, NULL }
72 };
73 struct cmdarray wgetcmd = {
74 .argc = 3,
75 .argv = { "wget", "-O", partfile, NULL }
76 };
77
78 name = strrchr(url, '/');
79 if (name == NULL)
80 errx(1, "%s: no '/' in url");
81 p = strstr(url, "::");
82 if (p != NULL) {
83 name = url;
84 *p = '\0';
85 url = p + 2;
86 } else if (strstr(url, "saveas-") == url) {
87 *name++ = '\0';
88 url += 7; /* strlen("saveas-") */
89 } else {
90 name++;
91 }
92
93 snprintf(outfile, sizeof(outfile), "%s/%s", destdir, name);
94 snprintf(lockfile, sizeof(lockfile), "%s.lock", outfile);
95 snprintf(partfile, sizeof(partfile), "%s.part", outfile);
96
97 lockfd = open(lockfile, O_WRONLY|O_CREAT, 0660);
98 if (lockfd < 0)
99 err(1, lockfile);
100
101 if (fcntl(lockfd, F_SETLK, &fl) < 0) {
102 printf("Waiting for %s ...\n", lockfile);
103 if (fcntl(lockfd, F_SETLKW, &fl) < 0)
104 err(1, "fcntl(F_SETLKW)");
105 }
106
107 if (access(outfile, F_OK) == 0)
108 goto fetch_done;
109
110 if (access(partfile, F_OK) == 0) {
111 printf("Partial download found. Trying to resume.\n");
112 add_opt(&curlcmd, "-C");
113 add_opt(&curlcmd, "-");
114 add_opt(&wgetcmd, "-c");
115 }
116
117 add_opt(&curlcmd, url);
118 add_opt(&wgetcmd, url);
119
120 childpid = fork();
121 if (childpid < 0 )
122 err(1, "fork");
123
124 if (childpid == 0) {
125 execvp(curlcmd.argv[0], curlcmd.argv);
126 printf("Using wget\n");
127 execvp(wgetcmd.argv[0], wgetcmd.argv);
128 warn(wgetcmd.argv[0]);
129 unlink(lockfile);
130 exit(1);
131 }
132 wait(&status);
133 rename(partfile, outfile);
134
135fetch_done:
136 unlink(lockfile);
137 close(lockfd);
138 lockfile[0] = '\0';
139 return status;
140
141}
142
143void sighandler(int sig)
144{
145 switch(sig) {
146 case SIGABRT:
147 case SIGINT:
148 case SIGQUIT:
149 case SIGTERM:
150 unlink(lockfile);
151 exit(0);
152 break;
153 default:
154 break;
155 }
156}
157
158int main(int argc, char *argv[])
159{
160 int opt, r=0, i;
161 char *destdir = "/var/cache/distfiles";
162
163 program = argv[0];
164 while ((opt = getopt(argc, argv, "hd:")) != -1) {
165 switch (opt) {
166 case 'h':
167 return usage(0);
168 break;
169 case 'd':
170 destdir = optarg;
171 break;
172 default:
173 printf("Unkonwn option '%c'\n", opt);
174 return usage(1);
175 break;
176 }
177 }
178
179 argv += optind;
180 argc -= optind;
181
182 if (argc < 1)
183 return usage(1);
184
185 signal(SIGABRT, sighandler);
186 signal(SIGINT, sighandler);
187 signal(SIGQUIT, sighandler);
188 signal(SIGTERM, sighandler);
189
190 for (i = 0; i < argc; i++) {
191 if (fetch(argv[i], destdir))
192 r++;
193 }
194 return r;
195}