/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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\ \n\ \n\ \n\ \n\ \n\ index of directory at " #define HEADER2 "\n\ \n\ \n\ \n\ \n\

Directory entries for " #define HEADER3 "

\n
    \n" #define FOOTER "
\n\n\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, "
  • ") == -1 || buffer_puts(buffer_1, name) == -1 || (S_ISDIR(st.st_mode) && buffer_put(buffer_1, "/", 1) == -1) || buffer_puts(buffer_1, " ") == -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, "
  • \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 ; }