git.strcat.st

/strcat/filebin.git/ - summarytreelogarchive

subject
add flags -m, -n, -s and -t
commit
311580634cc9ec421bb13791bc8c227c3761a807
date
2026-05-28T17:45:42Z
message
diff
 filebin.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 106 insertions(+), 31 deletions(-)

diff --git a/filebin.c b/filebin.c
index b2ac476..04b03f8 100644
--- a/filebin.c
+++ b/filebin.c
@@ -21,15 +21,15 @@
 #include <unistd.h>
 
 #define	PORT			8080
-#define	MAX_REQ			(16 * 1024 * 1024)
+#define	DEFAULT_MAX_REQ		(16 * 1024 * 1024)
 #define	ENABLE_INDEX		0
 #define	DEFAULT_TTL_SEC		(3 * 24 * 60 * 60)
 #define	MAX_TTL_SEC		(3 * 24 * 60 * 60)
 #define	CLEANUP_INTERVAL_SEC	60
 #define	CLIENT_IDLE_TIMEOUT_SEC	30
 #define	INITIAL_REQ_CAP		8192
-#define	MAX_CLIENTS		128
-#define	STORAGE_CAP_GB		100
+#define	DEFAULT_MAX_CLIENTS	128
+#define	DEFAULT_STORAGE_CAP_GB	100
 
 #if defined(__OpenBSD__) || defined(__linux__) || defined(__FreeBSD__) || \
     defined(__NetBSD__) || defined(__DragonFly__)
@@ -37,9 +37,9 @@
 #endif
 
 #ifdef HAVE_CHROOT
-#define	OPTSTR			"dc:p:u:"
+#define	OPTSTR			"dc:m:n:p:s:t:u:"
 #else
-#define	OPTSTR			"dp:u:"
+#define	OPTSTR			"dm:n:p:s:t:u:"
 #endif
 
 #ifdef HAVE_CHROOT
@@ -74,6 +74,12 @@ static const char *html_index =
     "</select> "
     "<button>Upload</button></form></div>";
 
+static size_t g_max_req = DEFAULT_MAX_REQ;
+static int g_max_clients = DEFAULT_MAX_CLIENTS;
+static off_t g_storage_cap_bytes = (off_t)DEFAULT_STORAGE_CAP_GB *
+    1024 * 1024 * 1024;
+static long g_default_ttl_sec = DEFAULT_TTL_SEC;
+
 static int	has_suffix(const char *, const char *);
 static int	grow_reqbuf(struct client *);
 static int	hdr_get(const char *, const char *, char *, size_t);
@@ -83,6 +89,8 @@ static int	isimg_ext(const char *);
 static int	req_done(const char *, size_t);
 static int	mk_fdir(void);
 static int	parse_uint(const char *, unsigned int *);
+static int	parse_size_mb(const char *, size_t *);
+static int	parse_size_gb(const char *, off_t *);
 static int	parse_ttl(const char *, long *);
 static int	parse_ug(const char *, uid_t *, gid_t *);
 static int	meta_read(const char *, time_t *);
@@ -403,13 +411,7 @@ meta_read(const char *name, time_t *exp)
 static off_t
 cap_bytes(void)
 {
-	off_t cap;
-
-	cap = (off_t)STORAGE_CAP_GB;
-	cap *= 1024;
-	cap *= 1024;
-	cap *= 1024;
-	return cap;
+	return g_storage_cap_bytes;
 }
 
 static off_t
@@ -474,7 +476,7 @@ cleanup_expired(void)
 	        continue;
 	    }
 	    if (meta_read(e->d_name, &exp) == 0)
-	        exp = st.st_mtime + DEFAULT_TTL_SEC;
+	        exp = st.st_mtime + (time_t)g_default_ttl_sec;
 	    if (now < exp)
 	        continue;
 	    snprintf(path, sizeof(path), "f/%s", e->d_name);
@@ -548,6 +550,40 @@ hdr_has_chunked(const char *hdr)
 	return 0;
 }
 
+static int
+parse_size_mb(const char *s, size_t *out)
+{
+	unsigned long v;
+	char *end;
+
+	errno = 0;
+	v = strtoul(s, &end, 10);
+	if (s[0] == '\0' || *end != '\0' || errno != 0)
+	    return 0;
+	if (v == 0 || v > (unsigned long)((size_t)-1 / (1024UL * 1024UL)))
+	    return 0;
+	*out = (size_t)v * 1024UL * 1024UL;
+	return 1;
+}
+
+static int
+parse_size_gb(const char *s, off_t *out)
+{
+	unsigned long v;
+	char *end;
+	off_t gb;
+
+	errno = 0;
+	v = strtoul(s, &end, 10);
+	if (s[0] == '\0' || *end != '\0' || errno != 0)
+	    return 0;
+	gb = (off_t)v;
+	if (gb <= 0 || gb > (off_t)-1 / (1024 * 1024 * 1024))
+	    return 0;
+	*out = gb * 1024 * 1024 * 1024;
+	return 1;
+}
+
 static int
 parse_hex_size(const char *p, size_t len, size_t *out)
 {
@@ -619,7 +655,7 @@ decode_chunked_body(const char *in, size_t inlen, char **out, size_t *outlen)
 	        }
 	        break;
 	    }
-	    if (chunk > inlen - off || woff > MAX_REQ - chunk) {
+	    if (chunk > inlen - off || woff > g_max_req - chunk) {
 	        free(buf);
 	        return 0;
 	    }
@@ -816,7 +852,7 @@ serve_upload(int fd, char *req, size_t req_len)
 	unsigned char r[12];
 	FILE *fp;
 
-	ttl_sec = DEFAULT_TTL_SEC;
+	ttl_sec = g_default_ttl_sec;
 	dec_body = NULL;
 	filename[0] = '\0';
 	file_body = NULL;
@@ -850,7 +886,7 @@ serve_upload(int fd, char *req, size_t req_len)
 
 	    raw_len = req_len - (size_t)(body - req);
 	    if (decode_chunked_body(body, raw_len, &dec_body, &dec_len) == 0 ||
-	        dec_len == 0 || dec_len > MAX_REQ) {
+	        dec_len == 0 || dec_len > g_max_req) {
 	        free(dec_body);
 	        sendtxt(fd, "400 Bad Request", "bad chunked body\n");
 	        return;
@@ -859,7 +895,7 @@ serve_upload(int fd, char *req, size_t req_len)
 	    body_len = (long)dec_len;
 	} else {
 	    body_len = atol(cl);
-	    if (body_len <= 0 || body_len > MAX_REQ) {
+	    if (body_len <= 0 || (size_t)body_len > g_max_req) {
 	        sendtxt(fd, "413 Payload Too Large", "bad size\n");
 	        return;
 	    }
@@ -1105,11 +1141,11 @@ grow_reqbuf(struct client *cl)
 
 	if (cl->off < cl->cap)
 	    return 1;
-	if (cl->cap >= MAX_REQ)
+	if (cl->cap >= g_max_req)
 	    return 0;
 	newcap = cl->cap == 0 ? INITIAL_REQ_CAP : cl->cap * 2;
-	if (newcap > MAX_REQ)
-	    newcap = MAX_REQ;
+	if (newcap > g_max_req)
+	    newcap = g_max_req;
 	p = realloc(cl->req, newcap + 1);
 	if (p == NULL)
 	    return 0;
@@ -1183,9 +1219,12 @@ usage(void)
 {
 #ifdef HAVE_CHROOT
 	fprintf(stderr,
-	    "usage: filebin [-d] [-c chrootdir] [-p port] [-u user:group]\n");
+	    "usage: filebin [-d] [-c chrootdir] [-m maxmb] [-n maxclients] "
+	    "[-p port] [-s storagegb] [-t ttl] [-u user:group]\n");
 #else
-	fprintf(stderr, "usage: filebin [-d] [-p port] [-u user:group]\n");
+	fprintf(stderr,
+	    "usage: filebin [-d] [-m maxmb] [-n maxclients] [-p port] "
+	    "[-s storagegb] [-t ttl] [-u user:group]\n");
 #endif
 	exit(1);
 }
@@ -1291,13 +1330,13 @@ main(int argc, char *argv[])
 	const char *chroot_dir;
 #endif
 	char *end;
-	struct client clients[MAX_CLIENTS];
-	struct pollfd pfds[MAX_CLIENTS + 1];
+	struct client *clients;
+	struct pollfd *pfds;
 	struct sockaddr_in sin;
 	time_t last_cleanup;
 	uid_t run_uid;
 	gid_t run_gid;
-	int map[MAX_CLIENTS + 1];
+	int *map;
 	int c;
 	int ch;
 	int do_daemon;
@@ -1308,10 +1347,18 @@ main(int argc, char *argv[])
 	int port;
 	int pr;
 	int s;
+	size_t max_req_mb;
+	off_t storage_cap_bytes;
+	unsigned int max_clients;
+	long ttl_cfg;
 
 	port = PORT;
 	do_daemon = 0;
 	do_drop = 0;
+	max_req_mb = DEFAULT_MAX_REQ / (1024 * 1024);
+	max_clients = DEFAULT_MAX_CLIENTS;
+	storage_cap_bytes = (off_t)DEFAULT_STORAGE_CAP_GB * 1024 * 1024 * 1024;
+	ttl_cfg = DEFAULT_TTL_SEC;
 	run_uid = 0;
 	run_gid = 0;
 #ifdef HAVE_CHROOT
@@ -1334,6 +1381,27 @@ main(int argc, char *argv[])
 		        port <= 0 || port > 65535)
 			    usage();
 		    break;
+		case 'm':
+		    if (parse_size_mb(optarg, &g_max_req) == 0)
+		        usage();
+		    break;
+		case 'n':
+		    if (parse_uint(optarg, &max_clients) == 0 || max_clients == 0)
+		        usage();
+		    if (max_clients > INT_MAX - 1)
+		        usage();
+		    g_max_clients = (int)max_clients;
+		    break;
+		case 's':
+		    if (parse_size_gb(optarg, &storage_cap_bytes) == 0)
+		        usage();
+		    g_storage_cap_bytes = storage_cap_bytes;
+		    break;
+		case 't':
+		    if (parse_ttl(optarg, &ttl_cfg) == 0)
+		        usage();
+		    g_default_ttl_sec = ttl_cfg;
+		    break;
 		case 'u':
 		    if (parse_ug(optarg, &run_uid, &run_gid) == 0)
 		        diex("invalid user:group", optarg);
@@ -1347,6 +1415,13 @@ main(int argc, char *argv[])
 	argv += optind;
 	if (argc != 0)
 	    usage();
+	(void)max_req_mb;
+
+	clients = calloc((size_t)g_max_clients, sizeof(*clients));
+	pfds = calloc((size_t)g_max_clients + 1, sizeof(*pfds));
+	map = calloc((size_t)g_max_clients + 1, sizeof(*map));
+	if (clients == NULL || pfds == NULL || map == NULL)
+	    die("calloc");
 
 	s = socket(AF_INET, SOCK_STREAM, 0);
 	if (s < 0)
@@ -1375,7 +1450,7 @@ main(int argc, char *argv[])
 	    die("set_nb");
 	if (do_daemon != 0)
 	    daemonize_self();
-	for (i = 0; i < MAX_CLIENTS; i++) {
+	for (i = 0; i < g_max_clients; i++) {
 	    clients[i].req = NULL;
 	    clients[i].off = 0;
 	    clients[i].cap = 0;
@@ -1394,7 +1469,7 @@ main(int argc, char *argv[])
 	        cleanup_expired();
 	        last_cleanup = now;
 	    }
-	    for (i = 0; i < MAX_CLIENTS; i++) {
+	    for (i = 0; i < g_max_clients; i++) {
 	        if (clients[i].fd >= 0 &&
 	            now - clients[i].last_active >= CLIENT_IDLE_TIMEOUT_SEC)
 	            client_close(&clients[i]);
@@ -1405,7 +1480,7 @@ main(int argc, char *argv[])
 	    pfds[0].revents = 0;
 	    map[0] = -1;
 	    nfds = 1;
-	    for (i = 0; i < MAX_CLIENTS; i++) {
+	    for (i = 0; i < g_max_clients; i++) {
 	        if (clients[i].fd < 0)
 	            continue;
 	        pfds[nfds].fd = clients[i].fd;
@@ -1434,11 +1509,11 @@ main(int argc, char *argv[])
 	                close(c);
 	                continue;
 	            }
-	            for (i = 0; i < MAX_CLIENTS; i++) {
+	            for (i = 0; i < g_max_clients; i++) {
 	                if (clients[i].fd < 0)
 	                    break;
 	            }
-	            if (i == MAX_CLIENTS) {
+	            if (i == g_max_clients) {
 	                close(c);
 	                continue;
 	            }
@@ -1481,7 +1556,7 @@ main(int argc, char *argv[])
 	                    client_close(cl);
 	                    break;
 	                }
-	                if (cl->off >= MAX_REQ) {
+	                if (cl->off >= g_max_req) {
 	                    sendtxt(cl->fd, "413 Payload Too Large", "bad size\n");
 	                    client_close(cl);
 	                    break;