beans

simple pastebin server
git clone git://git.bitsmanent.org/beans
Log | Files | Refs | LICENSE

beans.c (3886B)


      1 /* beans is a simple pastebin server */
      2 
      3 #include <errno.h>
      4 #include <netdb.h>
      5 #include <stdarg.h>
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 #include <sys/socket.h>
     10 #include <sys/stat.h>
     11 #include <sys/types.h>
     12 #include <unistd.h>
     13 #include <signal.h>
     14 
     15 #include "arg.h"
     16 
     17 #define BACKLOG 32
     18 #define MAXSIZE 32000 /* in bytes */
     19 
     20 /* function declarations */
     21 void die(const char *errstr, ...);
     22 int bindon(char *port);
     23 void *ecalloc(size_t nmemb, size_t size);
     24 char *readall(int sd, int *len, int limit);
     25 void run(void);
     26 void serve(int sd);
     27 void sout(int sd, char *fmt, ...);
     28 
     29 /* variables */
     30 char *argv0;
     31 char port[8] = "2023";
     32 char base[256] = "";
     33 char path[256] = "/tmp";
     34 char mode[8] = "0600";
     35 int sockd;
     36 
     37 /* function implementations */
     38 void
     39 die(const char *errstr, ...) {
     40 	va_list ap;
     41 
     42 	va_start(ap, errstr);
     43 	vfprintf(stderr, errstr, ap);
     44 	va_end(ap);
     45 	exit(1);
     46 }
     47 
     48 int
     49 bindon(char *port) {
     50 	struct addrinfo hints, *res;
     51 	int sd = 0, e;
     52 
     53 	memset(&hints, 0, sizeof hints);
     54 	hints.ai_family = AF_UNSPEC;
     55 	hints.ai_socktype = SOCK_STREAM;
     56 	hints.ai_flags = AI_PASSIVE;
     57 
     58 	if((e = getaddrinfo(NULL, port, &hints, &res)))
     59 		die("getaddrinfo(): %s\n", gai_strerror(e));
     60 	if((sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1)
     61 		die("socket(): %s\n", strerror(errno));
     62 	if(bind(sd, res->ai_addr, res->ai_addrlen) == -1)
     63 		die("bind(): %s\n", strerror(errno));
     64 	if(listen(sd, BACKLOG) == -1)
     65 		die("listen(): %s\n", strerror(errno));
     66 	return sd;
     67 }
     68 
     69 void *
     70 ecalloc(size_t nmemb, size_t size) {
     71 	void *p;
     72 
     73 	if(!(p = calloc(nmemb, size)))
     74 		die("Cannot allocate memory.\n");
     75 	return p;
     76 }
     77 
     78 char *
     79 readall(int sd, int *len, int limit) {
     80 	char *buf;
     81 	int sz = 512, r, l = 0;
     82 
     83 	if(limit && sz > limit)
     84 		sz = limit;
     85 
     86 	buf = ecalloc(1, sz);
     87 	while((r = read(sd, &buf[l], sz - l)) != -1) {
     88 		if(!r)
     89 			break;
     90 		l += r;
     91 		if(limit && l == limit)
     92 			break;
     93 		if(l == sz) {
     94 			sz *= 2;
     95 			if(limit && sz > limit)
     96 				sz = limit;
     97 			if(!(buf = realloc(buf, sz)))
     98 				die("realloc()\n");
     99 		}
    100 	}
    101 	if(r == -1) {
    102 		free(buf);
    103 		return NULL;
    104 	}
    105 	if(len)
    106 		*len = l;
    107 	buf[l] = '\0';
    108 	return buf;
    109 }
    110 
    111 void
    112 run(void) {
    113 	struct sockaddr_storage conn;
    114 	socklen_t size;
    115 	int csd;
    116 	pid_t pid;
    117 
    118 	while(1) {
    119 		size = sizeof conn;
    120 		csd = accept(sockd, (struct sockaddr *)&conn, &size);
    121 		if(csd == -1) {
    122 			fprintf(stderr, "accept(): %s", strerror(errno));
    123 			continue;
    124 		}
    125 		pid = fork();
    126 		if(pid) {
    127 			if(pid == -1)
    128 				fprintf(stderr, "fork(): %s\n", strerror(errno));
    129 			close(csd);
    130 			continue;
    131 		}
    132 		serve(csd);
    133 		close(csd);
    134 		break;
    135 	}
    136 }
    137 
    138 void
    139 serve(int sd) {
    140 	int len, tmpsd;
    141 	char *buf, *code;
    142 	char tmpfn[320] = {0};
    143 
    144 	buf = readall(sd, &len, MAXSIZE);
    145 	if(!(buf && len)) {
    146 		sout(sd, "Nothing pasted.\n");
    147 		return;
    148 	}
    149 	snprintf(tmpfn, sizeof tmpfn, "%s/beans.XXXXXX", path);
    150 	tmpsd = mkstemp(tmpfn);
    151 	if(tmpsd == -1) {
    152 		fprintf(stderr, "mkstemp()\n");
    153 		free(buf);
    154 		return;
    155 	}
    156 	if(write(tmpsd, buf, len) == -1)
    157 		fprintf(stderr, "write(): %s\n", strerror(errno));
    158 	code = strchr(tmpfn, '.')+1;
    159 	if(*base)
    160 		sout(sd, "%s%s\n", base, code);
    161 	else
    162 		sout(sd, "%s\n", code);
    163 	fchmod(tmpsd, strtol(mode, 0, 8));
    164 	close(tmpsd);
    165 	free(buf);
    166 }
    167 
    168 void
    169 sout(int sd, char *fmt, ...) {
    170 	va_list ap;
    171 	char buf[4096];
    172 	int sz;
    173 
    174 	va_start(ap, fmt);
    175 	sz = vsnprintf(buf, sizeof buf, fmt, ap);
    176 	va_end(ap);
    177 	send(sd, buf, sz, 0);
    178 }
    179 
    180 int
    181 main(int argc, char *argv[]) {
    182 	ARGBEGIN {
    183 	case 'b': strncpy(base, EARGF(die("%s: missing base URL\n", argv0)), sizeof base); break;
    184 	case 'd': strncpy(path, EARGF(die("%s: missing path\n", argv0)), sizeof path); break;
    185 	case 'm': strncpy(mode, EARGF(die("%s: missing mode\n", argv0)), sizeof mode); break;
    186 	case 'p': strncpy(port, EARGF(die("%s: missing port\n", argv0)), sizeof port); break;
    187 	case 'v': die("beans-"VERSION"\n");
    188 	} ARGEND
    189 
    190 	sockd = bindon(port);
    191 	signal(SIGCHLD, SIG_IGN); /* cleanup zombies */
    192 	run();
    193 	close(sockd);
    194 	return 0;
    195 }