geomyidae

A small C-based gopherd. (gopher://bitreich.org/1/scm/geomyidae)
git clone git://r-36.net/geomyidae
Log | Files | Refs | 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 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