summaryrefslogtreecommitdiff
path: root/src/misc
diff options
context:
space:
mode:
Diffstat (limited to 'src/misc')
-rw-r--r--src/misc/deps-exe/ls.cgi2
-rw-r--r--src/misc/ls.cgi.c154
2 files changed, 156 insertions, 0 deletions
diff --git a/src/misc/deps-exe/ls.cgi b/src/misc/deps-exe/ls.cgi
new file mode 100644
index 0000000..8ecd888
--- /dev/null
+++ b/src/misc/deps-exe/ls.cgi
@@ -0,0 +1,2 @@
+libtipidee.a.xyzzy
+-lskarnet
diff --git a/src/misc/ls.cgi.c b/src/misc/ls.cgi.c
new file mode 100644
index 0000000..d72ae10
--- /dev/null
+++ b/src/misc/ls.cgi.c
@@ -0,0 +1,154 @@
+/* ISC license. */
+
+#include <skalibs/bsdsnowflake.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <skalibs/gccattributes.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stat.h>
+#include <skalibs/direntry.h>
+#include <skalibs/strerr.h>
+#include <skalibs/tai.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-transactional.h>
+
+#include <tipidee/response.h>
+#include <tipidee/util.h>
+
+#define USAGE "ls.cgi is meant to be used as a CGI script invoked by tipideed"
+#define dieusage() strerr_dieusage(100, USAGE)
+#define dienomem() strerr_diefu1sys(111, "stralloc_catb")
+#define dieout() strerr_diefu1sys(111, "write to stdout")
+
+#define HEADER1 "Status: 200\nContent-Type: text/html\n\n\
+<html>\n\
+<head>\n\
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n\
+ <meta http-equiv=\"Content-Language\" content=\"en\" />\n\
+ <title>index of directory at "
+
+#define HEADER2 "</title>\n\
+ <meta name=\"Description\" content=\"directory entries list, generated by index.cgi\" />\n\
+ <meta name=\"Keywords\" content=\"tipideed index index.cgi CGI directory web server skarnet.org skarnet software\" />\n\
+ </head>\n\
+<body>\n\
+<h1> Directory entries for "
+
+#define HEADER3 " </h1>\n<ul>\n"
+
+#define FOOTER "</ul>\n</body>\n</html>\n"
+
+static void print_one_entry (int dfd, char const *path, char const *name)
+{
+ struct stat st ;
+ if (stat_at(dfd, name, &st) == -1) strerr_diefu4sys(111, "stat ", path, "/", name) ;
+ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) return ;
+ if (buffer_puts(buffer_1, " <li> <a href=\"") == -1
+ || buffer_puts(buffer_1, name) == -1
+ || (S_ISDIR(st.st_mode) && buffer_put(buffer_1, "/", 1) == -1)
+ || buffer_puts(buffer_1, "\"> ") == -1
+ || buffer_puts(buffer_1, name) == -1
+ || (S_ISDIR(st.st_mode) && buffer_put(buffer_1, "/", 1) == -1)
+ || buffer_puts(buffer_1, " </a>") == -1) dieout() ;
+ if (!S_ISDIR(st.st_mode))
+ {
+ int iskB = st.st_size >= 1024 ;
+ char lmdate[128] ;
+ char fmt[UINT64_FMT] ;
+ tain t ;
+ size_t l ;
+ if (!tain_from_timespec(&t, &st.st_mtim))
+ strerr_diefu4sys(111, "convert st_mtim for ", path, "/", name) ;
+ l = tipidee_response_header_date_fmt(lmdate, 128, &t) ;
+ if (!l) strerr_diefu4sys(111, "convert st_mtim for ", path, "/", name) ;
+ lmdate[l++] = 0 ;
+ fmt[uint64_fmt(fmt, iskB ? st.st_size / 1024 : st.st_size)] = 0 ;
+ if (buffer_put(buffer_1, " (", 2) == -1
+ || buffer_puts(buffer_1, fmt) == -1
+ || buffer_put(buffer_1, " ", 1) == -1
+ || buffer_puts(buffer_1, iskB ? "kB" : "bytes") == -1
+ || buffer_puts(buffer_1, ", last modified ") == -1
+ || buffer_put(buffer_1, lmdate, l) == -1
+ || buffer_put(buffer_1, ")", 1) == -1) dieout() ;
+ }
+ if (buffer_puts(buffer_1, " </li>\n") == -1) dieout() ;
+}
+
+static void html_escape (stralloc *sa, char const *s)
+{
+ size_t len = strlen(s) ;
+ char cc[2] = "\0" ;
+ for (size_t i = 0 ; i < len ; i++)
+ {
+ cc[0] = s[i] ;
+ if (!stralloc_cats(sa, tipidee_util_htmlescape(cc))) dienomem() ;
+ }
+ if (!stralloc_0(sa)) dienomem() ;
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ stralloc sa = STRALLOC_ZERO ;
+ stralloc tmp = STRALLOC_ZERO ;
+ size_t dirlen ;
+ char const *x ;
+ DIR *dir ;
+ int dfd ;
+ PROG = "ls.cgi" ;
+
+ x = getenv("SERVER_PROTOCOL") ;
+ if (!x) strerr_dienotset(100, "SERVER_PROTOCOL") ;
+ if (strncmp(x, "HTTP/1.", 7))
+ strerr_diefu1x(100, "SERVER_PROTOCOL isn't HTTP") ;
+ x = getenv("REQUEST_METHOD") ;
+ if (!x) strerr_dienotset(100, "REQUEST_METHOD") ;
+ if (strcmp(x, "GET") && strcmp(x, "HEAD"))
+ strerr_diefu1x(100, "ls.cgi can only be used with the GET or HEAD methods") ;
+
+ x = getenv("SERVER_NAME") ;
+ if (!x) strerr_dienotset(100, "SERVER_NAME") ;
+ if (!stralloc_cats(&sa, x)) dienomem() ;
+ if (!stralloc_catb(&sa, ":", 1)) dienomem() ;
+ x = getenv("SERVER_PORT") ;
+ if (!x) strerr_dienotset(100, "SERVER_PORT") ;
+ if (!stralloc_cats(&sa, x)) dienomem() ;
+ x = getenv("SCRIPT_NAME") ;
+ if (!x) strerr_dienotset(100, "SCRIPT_NAME") ;
+ if (*x != '/') strerr_diefu2x(100, "SCRIPT_NAME", " must be absolute") ;
+ if (!stralloc_cats(&sa, x)) dienomem() ;
+ while (sa.s[sa.len - 1] != '/') sa.len-- ;
+ sa.s[--sa.len] = 0 ;
+ html_escape(&tmp, sa.s) ;
+ dirlen = tmp.len - 1 ;
+
+ dir = opendir(sa.s) ;
+ if (!dir) strerr_diefu2sys(111, "opendir ", sa.s) ;
+ dfd = dir_fd(dir) ;
+
+ if (buffer_puts(buffer_1, HEADER1) == -1
+ || buffer_put(buffer_1, tmp.s, dirlen) == -1
+ || buffer_puts(buffer_1, HEADER2) == -1
+ || buffer_put(buffer_1, tmp.s, dirlen) == -1
+ || buffer_puts(buffer_1, HEADER3) == -1) dieout() ;
+
+ for (;;)
+ {
+ direntry *d ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (d->d_name[0] == '.') continue ;
+ html_escape(&tmp, d->d_name) ;
+ print_one_entry(dfd, tmp.s, tmp.s + dirlen + 1) ;
+ tmp.len = dirlen + 1 ;
+ }
+ if (errno) strerr_diefu2sys(111, "readdir ", sa.s) ;
+ dir_close(dir) ;
+
+ if (buffer_putsflush(buffer_1, FOOTER) == -1) dieout() ;
+ return 0 ;
+}