ref: 8fa9d99424da17b8ac3e67fb6d5563bf71f51e56
parent: c7abd2e7be5f3f9aff60f18121d47da13e5b279d
author: moody <moody@remilia>
date: Tue Oct 22 00:38:59 EDT 2024
add torrent seeds and tracker for releases
--- /dev/null
+++ b/bin/trackerc
@@ -1,0 +1,116 @@
+#!/bin/rc
+
+# worst bittorrent tacker ever written... in rc.
+dir=/tmp/tracker
+cd $dir || exit 'no tracker directory'
+
+cr=' '
+
+ipv=ip
+ipv6=()
+if(! ~ $#net 1) net=$$#*
+ip=`'!'{cat $net/remote}
+ip=$ip(1)
+~ $#ip 1 || exit 'no remote ip'
+
+if(~ $ip *:*){
+ ipv=ipv6
+ ipv6=$ip
+ ip=()
+}
+
+req=`{read}
+
+q=`'?'{echo -n $req(2)}
+q=`'&'{echo -n $q(2)}
+
+for(i in $q){
+ v=`'='{echo -n $i}
+ k=$v(1)
+ v=$v(2)
+ switch($k){
+ case info_hash peer_id port
+ $k=$v
+ }
+}
+
+# sanity
+~ $#info_hash 1 || exit 'no info hash'
+
+fn hex {
+ xd -x1 | sed 's/^[^ ]+//g;s/[ ]//g;' | sed '{N;s/\n//;}'
+}
+info_hash=`{echo -n $info_hash | urlencode -d | hex}
+
+# sanity
+~ $info_hash ???????????????????????????????????????? || exit 'bad info hash format'
+
+fn respond {
+ echo $ip $req $* >[1=2]
+
+ echo 'HTTP/1.1' $* $cr
+ echo $cr
+}
+
+# is this a scrape?
+if(! ~ $#peer_id 1){
+ if(! test -d $info_hash){
+ respond 404 'Not Found'
+ exit ''
+ }
+}
+
+fn str {
+ n=`{echo -n $1 | wc -c}
+ echo -n $n:$1
+}
+fn int {
+ echo -n i^$1^e
+}
+
+if(~ $#peer_id 1){
+ echo -n $peer_id | urlencode -d > /env/peer_id.bin
+ peer_id=`{hex < /env/peer_id.bin}
+
+ # sanity
+ ~ $peer_id ???????????????????????????????????????? || exit 'bad peer id format'
+
+ port=`{echo $port | sed 's/[^0-9]//g'}
+ ~ $#port 1 || exit 'no port port'
+ ~ $port [0-9]* || exit 'bad port format'
+
+ mkdir -p $info_hash || exit 'mkdir info hash directory'
+
+ # write dict file for classic mode
+ > $info_hash/$peer_id.$ipv.dict {
+ echo -n d
+ str 'peer id'
+ echo -n '20:'
+ cat /env/peer_id.bin
+ str ip
+ str $$ipv
+ str port
+ int $port
+ echo -n e
+ }
+}
+
+cd $info_hash || exit 'cd info hash directory'
+
+# cleanup old files
+for(i in *){
+ test $i -older 5m && rm -f $i
+}
+
+respond 200 OK
+
+echo -n d
+str interval
+int 120
+str peers
+echo -n l
+cat *.dict >[2] /dev/null
+echo -n e
+echo -n e
+
+exit ''
--- a/cpustart
+++ b/cpustart
@@ -3,4 +3,8 @@
if(test -r $key){
cat $key >/mnt/factotum/ctl
}
+releases='/usr/build/www/release'
+if(test -d $releases){
+ ip/seedbox $releases
+}
auth/cron
--- a/mkfile
+++ b/mkfile
@@ -3,6 +3,7 @@
SRC=\
tcp80\
execfs\
+ seedbox\
all:V:
# nothing
--- /dev/null
+++ b/service/tcp1337
@@ -1,0 +1,3 @@
+#!/bin/rc
+exec alarm 2000 /bin/trackerc $* >>[2]/sys/log/tracker
+
--- /dev/null
+++ b/service/tcp1337.namespace
@@ -1,0 +1,37 @@
+# kernel devices
+bind #c /dev
+bind #d /fd
+bind -c #e /env
+bind #p /proc
+bind -c #s$srvspec /srv
+bind -a #¤ /dev
+bind -qa #¶ /dev
+
+# root
+mount -C /srv/boot /root $rootspec
+bind -a $rootdir /
+
+# mount points
+mount -a /srv/slashn /n
+mount -a /srv/slashmnt /mnt
+mount -a /srv/mntexport /mnt/exportfs
+
+# standard bin
+bind /$cputype/bin /bin
+bind $rootdir/rc /rc
+bind -a /rc/bin /bin
+
+bind -a #l /net
+bind -a #I /net
+bind -a #a /net
+mount -a /srv/cs /net
+mount -a /srv/dns /net
+mount -a /srv/net /net
+
+bind -c /sys/lib/tracker /tmp
+
+. /lib/namespace.local
+. /lib/namespace.$sysname
+. /cfg/$sysname/namespace
+
+chdev Mcde|pslI/
--- /dev/null
+++ b/src/seedbox/mkfile
@@ -1,0 +1,11 @@
+</$objtype/mkfile
+
+TARG=seedbox
+BIN=/$objtype/bin/ip
+CFLAGS=-FTVw
+
+HFILES=
+
+OFILES=seedbox.$O
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/src/seedbox/seedbox.c
@@ -1,0 +1,167 @@
+#include <u.h>
+#include <libc.h>
+
+typedef struct Seed Seed;
+struct Seed {
+ int pid;
+ char *torrent;
+ int seen;
+};
+static Seed *seeds;
+static int nseeds;
+static char *ddir, *tdir;
+static int tfd;
+
+static void
+spawn(Seed *s, char *t)
+{
+ int p;
+
+ if(t != nil && (s->torrent = strdup(t)) == nil)
+ sysfatal("strdup: %r");
+ switch(p = fork()){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ if(chdir(ddir ? ddir : tdir) < 0)
+ sysfatal("chdir: %r");
+ execl("/bin/ip/torrent", "torrent", "-s", smprint("%s/%s", tdir, s->torrent), nil);
+ sysfatal("exec: %r");
+ default:
+ s->pid = p;
+ return;
+ }
+}
+
+static void
+kill(Seed *s)
+{
+ assert(s->pid != 0);
+ postnote(PNPROC, s->pid, "kill");
+ s->pid = 0;
+ free(s->torrent);
+ s->torrent = nil;
+}
+
+static void
+scandir(void)
+{
+ Dir *d;
+ char **new, *s;
+ int i, j, n, o, p;
+
+ for(j = 0; j < nseeds; j++)
+ seeds[j].seen = 0;
+ if(seek(tfd, 0, 0) != 0)
+ sysfatal("seek: %r");
+ n = dirreadall(tfd, &d);
+ if(n < 0)
+ sysfatal("dirreadall: %r");
+ new = mallocz(sizeof(char*)*n, 1);
+ if(new == nil)
+ sysfatal("malloc: %r");
+ o = 0;
+ for(i = 0; i < n; i++){
+ if((s = strstr(d[i].name, ".torrent")) == nil)
+ continue;
+ if(s[strlen(".torrent")] != '\0')
+ continue;
+ for(j = 0; j < nseeds; j++){
+ if(strcmp(seeds[j].torrent, d[i].name) != 0)
+ continue;
+ if(seeds[j].pid == 0)
+ spawn(seeds+j, nil);
+ seeds[j].seen = 1;
+ break;
+ }
+ if(j == nseeds)
+ new[o++] = d[i].name;
+ }
+ for(j = 0; o > 0 && j < nseeds; j++){
+ if(seeds[j].seen == 1)
+ continue;
+ kill(seeds+j);
+ spawn(seeds+j, new[--o]);
+ seeds[j].seen = 1;
+ }
+ if(o > 0){
+ seeds = realloc(seeds, sizeof(Seed) * (nseeds + o));
+ if(seeds == nil)
+ sysfatal("realloc: %r");
+ for(p = o, j = nseeds; j < nseeds + o; j++){
+ seeds[j].seen = 1;
+ spawn(seeds+j, new[--p]);
+ }
+ nseeds = nseeds + o;
+ }
+ for(j = 0; j < nseeds; j++)
+ if(seeds[j].seen == 0)
+ kill(seeds+j);
+ free(new);
+ free(d);
+}
+
+static int
+catch(void*, char*)
+{
+ int j;
+
+ for(j = 0; j < nseeds; j++)
+ kill(seeds+j);
+ return 0;
+}
+
+_Noreturn void
+usage(void)
+{
+ fprint(2, "%s: tdir <ddir>\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int sec;
+ char *n, *r;
+ char buf[128];
+
+ sec = 30;
+ ARGBEGIN{
+ case 'w':
+ n = EARGF(usage());
+ sec = strtol(n, &r, 0);
+ if(n == r)
+ sysfatal("invalid number");
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ switch(argc){
+ default:
+ usage();
+ case 2:
+ ddir = argv[1];
+ case 1:
+ tfd = open(argv[0], OREAD);
+ if(tfd < 0)
+ sysfatal("open: %r");
+ if(fd2path(tfd, buf, sizeof buf) != 0)
+ sysfatal("fd2path: %r");
+ tdir = strdup(buf);
+ if(tdir == nil)
+ sysfatal("tdir: %r");
+ }
+
+ switch(fork()){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ break;
+ default:
+ exits(0);
+ }
+
+ for(atnotify(catch, 1); ; sleep(sec * 1000))
+ scandir();
+}