Add tested Alpine-derived distroless rTorrent variant
Build and Push Docker Image / build (push) Successful in 38s
Build and Push Docker Image / build (push) Successful in 38s
This commit is contained in:
1 parent
4ac29238fe
commit
8b88089cb4
7 files changed
+307
No files matched your search
@@ -0,0 +1,107 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void pause_tick(void) {
|
||||
struct timespec delay = {0, 100000000};
|
||||
nanosleep(&delay, NULL);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
const char *forbidden[] = {"/bin/sh", "/bin/bash", "/bin/busybox", "/sbin/apk", NULL};
|
||||
for (int i = 0; forbidden[i]; ++i) {
|
||||
if (access(forbidden[i], F_OK) == 0) {
|
||||
fprintf(stderr, "Unexpected runtime tool: %s\n", forbidden[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
const char *config = "/tmp/rtorrent-smoke.rc";
|
||||
const char *lock = "/home/nfs_download/rsession/rtorrent.lock";
|
||||
FILE *f = fopen(config, "w");
|
||||
if (!f) return 1;
|
||||
fputs("system.daemon.set = true\nnetwork.bind_address.set = 0.0.0.0\n"
|
||||
"network.scgi.open_port = 127.0.0.1:5001\n", f);
|
||||
fclose(f);
|
||||
f = fopen(lock, "w");
|
||||
if (!f) return 1;
|
||||
fputs("stale smoke-test lock", f);
|
||||
fclose(f);
|
||||
pid_t child = fork();
|
||||
if (child < 0) return 1;
|
||||
if (child == 0) {
|
||||
execl("/usr/local/bin/rtorrent-entrypoint", "rtorrent-entrypoint", "-n", "-o",
|
||||
"import=/tmp/rtorrent-smoke.rc", (char *)NULL);
|
||||
_exit(127);
|
||||
}
|
||||
int result = 1, fd = -1, status;
|
||||
for (int attempt = 0; attempt < 300; ++attempt) {
|
||||
if (waitpid(child, &status, WNOHANG) == child) {
|
||||
fprintf(stderr, "rTorrent exited before SCGI became ready\n");
|
||||
child = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) goto cleanup;
|
||||
struct sockaddr_in addr = {0};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(5001);
|
||||
if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) goto cleanup;
|
||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) break;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
pause_tick();
|
||||
}
|
||||
if (fd < 0 || access(lock, F_OK) == 0) goto cleanup;
|
||||
struct timeval timeout = {5, 0};
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
const char *body = "<?xml version=\"1.0\"?><methodCall><methodName>system.client_version</methodName><params/></methodCall>";
|
||||
char headers[128], request[512], response[8192];
|
||||
int hlen = snprintf(headers, sizeof(headers), "CONTENT_LENGTH%c%zu%cSCGI%c1%c", 0, strlen(body), 0, 0, 0);
|
||||
int prefix = snprintf(request, sizeof(request), "%d:", hlen);
|
||||
memcpy(request + prefix, headers, (size_t)hlen);
|
||||
size_t length = (size_t)prefix + (size_t)hlen;
|
||||
request[length++] = ',';
|
||||
memcpy(request + length, body, strlen(body));
|
||||
length += strlen(body);
|
||||
if (send(fd, request, length, 0) != (ssize_t)length) goto cleanup;
|
||||
size_t used = 0;
|
||||
ssize_t n;
|
||||
while (used < sizeof(response) - 1 && (n = recv(fd, response + used, sizeof(response) - 1 - used, 0)) > 0)
|
||||
used += (size_t)n;
|
||||
response[used] = '\0';
|
||||
if (!strstr(response, "<methodResponse>") || strstr(response, "<fault>")) {
|
||||
fprintf(stderr, "SCGI test failed: %s\n", response);
|
||||
goto cleanup;
|
||||
}
|
||||
pid_t health = fork();
|
||||
if (health < 0) goto cleanup;
|
||||
if (health == 0) {
|
||||
execl("/usr/local/bin/rtorrent-entrypoint", "rtorrent-entrypoint", "--healthcheck", (char *)NULL);
|
||||
_exit(127);
|
||||
}
|
||||
if (waitpid(health, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) goto cleanup;
|
||||
puts("Distroless rTorrent: startup, stale lock cleanup, SCGI and healthcheck passed");
|
||||
result = 0;
|
||||
cleanup:
|
||||
if (fd >= 0) close(fd);
|
||||
if (child > 0) {
|
||||
kill(child, SIGTERM);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
if (waitpid(child, &status, WNOHANG) == child) { child = -1; break; }
|
||||
pause_tick();
|
||||
}
|
||||
if (child > 0) { kill(child, SIGKILL); waitpid(child, &status, 0); }
|
||||
}
|
||||
unlink(config);
|
||||
unlink(lock);
|
||||
return result;
|
||||
}
|
||||
Reference in new issue
Block a user