handlr.c - geomyidae - A small C-based gopherd. | |
git clone git://bitreich.org/geomyidae/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfri… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
handlr.c (5663B) | |
--- | |
1 /* | |
2 * Copy me if you can. | |
3 * by 20h | |
4 */ | |
5 | |
6 #include <unistd.h> | |
7 #include <memory.h> | |
8 #include <netdb.h> | |
9 #include <netinet/in.h> | |
10 #include <fcntl.h> | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <string.h> | |
14 #include <sys/socket.h> | |
15 #include <sys/types.h> | |
16 #include <sys/stat.h> | |
17 #include <dirent.h> | |
18 #include <sys/wait.h> | |
19 #include <errno.h> | |
20 #include <libgen.h> | |
21 | |
22 #include "ind.h" | |
23 #include "arg.h" | |
24 | |
25 void | |
26 handledir(int sock, char *path, char *port, char *base, char *args, | |
27 char *sear, char *ohost, char *chost, char *bhost, int i… | |
28 char *sel, char *traverse) | |
29 { | |
30 char *pa, *file, *e, *par; | |
31 struct dirent **dirent; | |
32 int ndir, i, ret = 0; | |
33 struct stat st; | |
34 filetype *type; | |
35 | |
36 USED(args); | |
37 USED(sear); | |
38 USED(bhost); | |
39 USED(sel); | |
40 USED(traverse); | |
41 | |
42 pa = xstrdup(path); | |
43 | |
44 /* Is there any directory below the request? */ | |
45 if (strlen(pa+strlen(base)) > 1) { | |
46 par = xstrdup(pa+strlen(base)); | |
47 e = strrchr(par, '/'); | |
48 *e = '\0'; | |
49 dprintf(sock, "1..\t%s\t%s\t%s\r\n", | |
50 par, ohost, port); | |
51 free(par); | |
52 } | |
53 | |
54 ndir = scandir(pa, &dirent, 0, alphasort); | |
55 if (ndir < 0) { | |
56 perror("scandir"); | |
57 free(pa); | |
58 return; | |
59 } else { | |
60 for (i = 0; i < ndir && ret >= 0; i++) { | |
61 if (dirent[i]->d_name[0] == '.') | |
62 continue; | |
63 | |
64 type = gettype(dirent[i]->d_name); | |
65 | |
66 file = smprintf("%s%s%s", | |
67 pa, | |
68 pa[strlen(pa)-1] == '/'? "" : "/… | |
69 dirent[i]->d_name); | |
70 if (stat(file, &st) >= 0 && S_ISDIR(st.st_mode)) | |
71 type = gettype("index.gph"); | |
72 ret = dprintf(sock, | |
73 "%c%-50.50s %10s %16s\t%s\t%s\t%… | |
74 *type->type, | |
75 dirent[i]->d_name, | |
76 humansize(st.st_size), | |
77 humantime(&(st.st_mtime)), | |
78 file + strlen(base), ohost, port… | |
79 free(file); | |
80 } | |
81 for (i = 0; i < ndir; i++) | |
82 free(dirent[i]); | |
83 free(dirent); | |
84 } | |
85 dprintf(sock, ".\r\n"); | |
86 | |
87 free(pa); | |
88 } | |
89 | |
90 void | |
91 handlegph(int sock, char *file, char *port, char *base, char *args, | |
92 char *sear, char *ohost, char *chost, char *bhost, int i… | |
93 char *sel, char *traverse) | |
94 { | |
95 gphindex *act; | |
96 int i, ret = 0; | |
97 | |
98 USED(args); | |
99 USED(sear); | |
100 USED(bhost); | |
101 USED(sel); | |
102 USED(traverse); | |
103 | |
104 act = gph_scanfile(file); | |
105 if (act != NULL) { | |
106 for (i = 0; i < act->num && ret >= 0; i++) | |
107 ret = gph_printelem(sock, act->n[i], file, base,… | |
108 dprintf(sock, ".\r\n"); | |
109 | |
110 for (i = 0; i < act->num; i++) { | |
111 gph_freeelem(act->n[i]); | |
112 act->n[i] = NULL; | |
113 } | |
114 gph_freeindex(act); | |
115 } | |
116 } | |
117 | |
118 void | |
119 handlebin(int sock, char *file, char *port, char *base, char *args, | |
120 char *sear, char *ohost, char *chost, char *bhost, int i… | |
121 char *sel, char *traverse) | |
122 { | |
123 int fd; | |
124 | |
125 USED(port); | |
126 USED(base); | |
127 USED(args); | |
128 USED(sear); | |
129 USED(ohost); | |
130 USED(bhost); | |
131 USED(sel); | |
132 USED(traverse); | |
133 | |
134 fd = open(file, O_RDONLY); | |
135 if (fd >= 0) { | |
136 if (xsendfile(fd, sock) < 0) | |
137 perror("sendfile"); | |
138 close(fd); | |
139 } | |
140 } | |
141 | |
142 /* | |
143 * See RFC3875 5 NPH Scripts | |
144 * | |
145 * In gopher, with no header parsing, this allows bi-directional | |
146 * long-running communications. One example would be raw HTTP emulation. | |
147 */ | |
148 void | |
149 handlecgi(int sock, char *file, char *port, char *base, char *args, | |
150 char *sear, char *ohost, char *chost, char *bhost, int i… | |
151 char *sel, char *traverse) | |
152 { | |
153 char *script, *path, *filec, *scriptc; | |
154 | |
155 USED(base); | |
156 USED(port); | |
157 | |
158 filec = xstrdup(file); | |
159 scriptc = xstrdup(file); | |
160 path = dirname(filec); | |
161 script = basename(scriptc); | |
162 | |
163 if (sear == NULL) | |
164 sear = ""; | |
165 if (args == NULL) | |
166 args = ""; | |
167 | |
168 while (dup2(sock, 0) < 0 && errno == EINTR); | |
169 while (dup2(sock, 1) < 0 && errno == EINTR); | |
170 while (dup2(sock, 2) < 0 && errno == EINTR); | |
171 switch (fork()) { | |
172 case 0: | |
173 if (path != NULL) { | |
174 if (chdir(path) < 0) | |
175 break; | |
176 } | |
177 | |
178 setcgienviron(script, file, port, base, args, sear, ohos… | |
179 bhost, istls, sel, traverse); | |
180 | |
181 if (execl(file, script, sear, args, ohost, port, travers… | |
182 (char *)NULL) == -1) { | |
183 perror("execl"); | |
184 _exit(1); | |
185 } | |
186 case -1: | |
187 perror("fork"); | |
188 break; | |
189 default: | |
190 wait(NULL); | |
191 free(filec); | |
192 free(scriptc); | |
193 break; | |
194 } | |
195 } | |
196 | |
197 /* | |
198 * This is RFC3875 NPH Scripts | |
199 * plus parsing of GPH syntax for easier gophermap portability. | |
200 */ | |
201 void | |
202 handledcgi(int sock, char *file, char *port, char *base, char *args, | |
203 char *sear, char *ohost, char *chost, char *bhost, int i… | |
204 char *sel, char *traverse) | |
205 { | |
206 FILE *fp; | |
207 char *script, *path, *filec, *scriptc, *ln = NULL; | |
208 size_t linesiz = 0; | |
209 ssize_t n; | |
210 int outsocks[2], ret = 0; | |
211 gphelem *el; | |
212 | |
213 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, outsocks) < 0) | |
214 return; | |
215 | |
216 filec = xstrdup(file); | |
217 scriptc = xstrdup(file); | |
218 path = dirname(filec); | |
219 script = basename(scriptc); | |
220 | |
221 if (sear == NULL) | |
222 sear = ""; | |
223 if (args == NULL) | |
224 args = ""; | |
225 | |
226 while (dup2(sock, 0) < 0 && errno == EINTR); | |
227 while (dup2(sock, 2) < 0 && errno == EINTR); | |
228 switch (fork()) { | |
229 case 0: | |
230 while (dup2(outsocks[1], 1) < 0 && errno == EINTR); | |
231 close(outsocks[0]); | |
232 if (path != NULL) { | |
233 if (chdir(path) < 0) | |
234 break; | |
235 } | |
236 | |
237 setcgienviron(script, file, port, base, args, sear, ohos… | |
238 bhost, istls, sel, traverse); | |
239 | |
240 if (execl(file, script, sear, args, ohost, port, travers… | |
241 (char *)NULL) == -1) { | |
242 perror("execl"); | |
243 _exit(1); | |
244 } | |
245 break; | |
246 case -1: | |
247 perror("fork"); | |
248 break; | |
249 default: | |
250 while (dup2(sock, 1) < 0 && errno == EINTR); | |
251 close(outsocks[1]); | |
252 | |
253 if (!(fp = fdopen(outsocks[0], "r"))) { | |
254 perror("fdopen"); | |
255 close(outsocks[0]); | |
256 break; | |
257 } | |
258 | |
259 while ((n = getline(&ln, &linesiz, fp)) > 0 && ret >= 0)… | |
260 if (ln[n - 1] == '\n') | |
261 ln[--n] = '\0'; | |
262 | |
263 el = gph_getadv(ln); | |
264 if (el == NULL) | |
265 continue; | |
266 | |
267 ret = gph_printelem(sock, el, file, base, ohost,… | |
268 gph_freeelem(el); | |
269 } | |
270 if (ferror(fp)) | |
271 perror("getline"); | |
272 dprintf(sock, ".\r\n"); | |
273 | |
274 free(ln); | |
275 fclose(fp); | |
276 wait(NULL); | |
277 free(filec); | |
278 free(scriptc); | |
279 break; | |
280 } | |
281 } | |
282 |