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 istls, 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%s\r\n", 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 istls, 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, ohost, port); 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 istls, 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 istls, 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, ohost, chost, 179 bhost, istls, sel, traverse); 180 181 if (execl(file, script, sear, args, ohost, port, traverse, sel, 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 istls, 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, ohost, chost, 238 bhost, istls, sel, traverse); 239 240 if (execl(file, script, sear, args, ohost, port, traverse, sel, 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, port); 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