/* * Print a list of available virtual hosts */ void vhostlist(state *st) { sdirent dir[MAX_SDIRENT]; struct tm *ltime; char timestr[20]; char buf[BUFSIZE]; int width; int num; int i; /* Scan the root dir for vhost dirs */ num = sortdir(st->server_root, dir, MAX_SDIRENT); if (num < 0) die(st, ERR_NOTFOUND, "WTF?"); /* Width of filenames for fancy listing */ width = st->out_width - DATE_WIDTH - 15; /* Loop through the directory entries */ for (i = 0; i < num; i++) { /* Skip dotfiles */ if (dir[i].name[0] == '.') continue; /* Require FQDN */ if (!strchr(dir[i].name, '.')) continue; /* We only want world-readable directories */ if ((dir[i].mode & S_IROTH) == 0) continue; if ((dir[i].mode & S_IFMT) != S_IFDIR) continue; /* Generate display string for vhost */ snprintf(buf, sizeof(buf), VHOST_FORMAT, dir[i].name); /* Fancy listing */ if (st->opt_date) { ltime = localtime(&dir[i].mtime); strftime(timestr, sizeof(timestr), DATE_FORMAT, ltime); printf("1%-*.*s %s - \t/;%s\t%s\t%i" CRLF, width, width, buf, timestr, dir[i].name, dir[i].name, st->server_port); } /* Teh boring version */ else { printf("1%.*s\t/;%s\t%s\t%i" CRLF, st->out_width, buf, dir[i].name, dir[i].name, st->server_port); } } }
static int check_dir(uint32_t ino, uint32_t parentino, const char *pathsofar) { struct sfs_inode sfi; struct sfs_dir *direntries; int *sortvector; uint32_t dirsize, ndirentries, maxdirentries, subdircount, i; int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0; diskread(&sfi, ino); swapinode(&sfi); if (remember_dir(ino, pathsofar)) { /* crosslinked dir */ return 1; } bitmap_mark(ino, B_INODE, ino); count_dirs++; if (sfi.sfi_size % sizeof(struct sfs_dir) != 0) { setbadness(EXIT_RECOV); warnx("Directory /%s has illegal size %lu (fixed)", pathsofar, (unsigned long) sfi.sfi_size); sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size, sizeof(struct sfs_dir)); ichanged = 1; } if (check_inode_blocks(ino, &sfi, 1)) { ichanged = 1; } ndirentries = sfi.sfi_size/sizeof(struct sfs_dir); maxdirentries = SFS_ROUNDUP(ndirentries, SFS_BLOCKSIZE/sizeof(struct sfs_dir)); dirsize = maxdirentries * sizeof(struct sfs_dir); direntries = domalloc(dirsize); sortvector = domalloc(ndirentries * sizeof(int)); dirread(&sfi, direntries, ndirentries); for (i=ndirentries; i<maxdirentries; i++) { direntries[i].sfd_ino = SFS_NOINO; bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name)); } for (i=0; i<ndirentries; i++) { if (check_dir_entry(pathsofar, i, &direntries[i])) { dchanged = 1; } sortvector[i] = i; } sortdir(sortvector, direntries, ndirentries); /* don't use ndirentries-1 here in case ndirentries == 0 */ for (i=0; i+1<ndirentries; i++) { struct sfs_dir *d1 = &direntries[sortvector[i]]; struct sfs_dir *d2 = &direntries[sortvector[i+1]]; assert(d1 != d2); if (d1->sfd_ino == SFS_NOINO) { continue; } if (!strcmp(d1->sfd_name, d2->sfd_name)) { if (d1->sfd_ino == d2->sfd_ino) { setbadness(EXIT_RECOV); warnx("Directory /%s: Duplicate entries for " "%s (merged)", pathsofar, d1->sfd_name); d1->sfd_ino = SFS_NOINO; d1->sfd_name[0] = 0; } else { snprintf(d1->sfd_name, sizeof(d1->sfd_name), "FSCK.%lu.%lu", (unsigned long) d1->sfd_ino, (unsigned long) uniquecounter++); setbadness(EXIT_RECOV); warnx("Directory /%s: Duplicate names %s " "(one renamed: %s)", pathsofar, d2->sfd_name, d1->sfd_name); } dchanged = 1; } } for (i=0; i<ndirentries; i++) { if (!strcmp(direntries[i].sfd_name, ".")) { if (direntries[i].sfd_ino != ino) { setbadness(EXIT_RECOV); warnx("Directory /%s: Incorrect `.' entry " "(fixed)", pathsofar); direntries[i].sfd_ino = ino; dchanged = 1; } assert(dotseen==0); /* due to duplicate checking */ dotseen = 1; } else if (!strcmp(direntries[i].sfd_name, "..")) { if (direntries[i].sfd_ino != parentino) { setbadness(EXIT_RECOV); warnx("Directory /%s: Incorrect `..' entry " "(fixed)", pathsofar); direntries[i].sfd_ino = parentino; dchanged = 1; } assert(dotdotseen==0); /* due to duplicate checking */ dotdotseen = 1; } } if (!dotseen) { if (dir_tryadd(direntries, ndirentries, ".", ino)==0) { setbadness(EXIT_RECOV); warnx("Directory /%s: No `.' entry (added)", pathsofar); dchanged = 1; } else if (dir_tryadd(direntries, maxdirentries, ".", ino)==0) { setbadness(EXIT_RECOV); warnx("Directory /%s: No `.' entry (added)", pathsofar); ndirentries++; dchanged = 1; sfi.sfi_size += sizeof(struct sfs_dir); ichanged = 1; } else { setbadness(EXIT_UNRECOV); warnx("Directory /%s: No `.' entry (NOT FIXED)", pathsofar); } } if (!dotdotseen) { if (dir_tryadd(direntries, ndirentries, "..", parentino)==0) { setbadness(EXIT_RECOV); warnx("Directory /%s: No `..' entry (added)", pathsofar); dchanged = 1; } else if (dir_tryadd(direntries, maxdirentries, "..", parentino)==0) { setbadness(EXIT_RECOV); warnx("Directory /%s: No `..' entry (added)", pathsofar); ndirentries++; dchanged = 1; sfi.sfi_size += sizeof(struct sfs_dir); ichanged = 1; } else { setbadness(EXIT_UNRECOV); warnx("Directory /%s: No `..' entry (NOT FIXED)", pathsofar); } } subdircount=0; for (i=0; i<ndirentries; i++) { if (!strcmp(direntries[i].sfd_name, ".")) { /* nothing */ } else if (!strcmp(direntries[i].sfd_name, "..")) { /* nothing */ } else if (direntries[i].sfd_ino == SFS_NOINO) { /* nothing */ } else { char path[strlen(pathsofar)+SFS_NAMELEN+1]; struct sfs_inode subsfi; diskread(&subsfi, direntries[i].sfd_ino); swapinode(&subsfi); snprintf(path, sizeof(path), "%s/%s", pathsofar, direntries[i].sfd_name); switch (subsfi.sfi_type) { case SFS_TYPE_FILE: if (check_inode_blocks(direntries[i].sfd_ino, &subsfi, 0)) { swapinode(&subsfi); diskwrite(&subsfi, direntries[i].sfd_ino); } observe_filelink(direntries[i].sfd_ino); break; case SFS_TYPE_DIR: if (check_dir(direntries[i].sfd_ino, ino, path)) { setbadness(EXIT_RECOV); warnx("Directory /%s: Crosslink to " "other directory (removed)", path); direntries[i].sfd_ino = SFS_NOINO; direntries[i].sfd_name[0] = 0; dchanged = 1; } else { subdircount++; } break; default: setbadness(EXIT_RECOV); warnx("Object /%s: Invalid inode type " "(removed)", path); direntries[i].sfd_ino = SFS_NOINO; direntries[i].sfd_name[0] = 0; dchanged = 1; break; } } } if (sfi.sfi_linkcount != subdircount+2) { setbadness(EXIT_RECOV); warnx("Directory /%s: Link count %lu should be %lu (fixed)", pathsofar, (unsigned long) sfi.sfi_linkcount, (unsigned long) subdircount+2); sfi.sfi_linkcount = subdircount+2; ichanged = 1; } if (dchanged) { dirwrite(&sfi, direntries, ndirentries); } if (ichanged) { swapinode(&sfi); diskwrite(&sfi, ino); } free(direntries); free(sortvector); return 0; }
/* * Handle gopher menus */ void gopher_menu(state *st) { FILE *fp; sdirent dir[MAX_SDIRENT]; struct tm *ltime; struct stat file; char buf[BUFSIZE]; char pathname[BUFSIZE]; char displayname[BUFSIZE]; char encodedname[BUFSIZE]; char timestr[20]; char sizestr[20]; char *parent; char *c; char type; int width; int num; int i; int n; /* Check for a gophermap */ snprintf(pathname, sizeof(pathname), "%s/%s", st->req_realpath, st->map_file); if (stat(pathname, &file) == OK && (file.st_mode & S_IFMT) == S_IFREG) { /* Parse gophermap */ if (gophermap(st, pathname, 0) == QUIT) { footer(st); return; } } else { /* Check for a gophertag */ snprintf(pathname, sizeof(pathname), "%s/%s", st->req_realpath, st->tag_file); if (stat(pathname, &file) == OK && (file.st_mode & S_IFMT) == S_IFREG) { /* Read & output gophertag */ if ((fp = fopen(pathname , "r"))) { fgets(buf, sizeof(buf), fp); chomp(buf); info(st, buf, TYPE_TITLE); info(st, EMPTY, TYPE_INFO); fclose(fp); } } /* No gophermap or tag found - print default header */ else if (st->opt_header) { /* Use the selector as menu title */ sstrlcpy(displayname, st->req_selector); /* Shorten too long titles */ while (strlen(displayname) > (st->out_width - sizeof(HEADER_FORMAT))) { if ((c = strchr(displayname, '/')) == NULL) break; if (!*++c) break; sstrlcpy(displayname, c); } /* Output menu title */ snprintf(buf, sizeof(buf), HEADER_FORMAT, displayname); info(st, buf, TYPE_TITLE); info(st, EMPTY, TYPE_INFO); } } /* Scan the directory */ num = sortdir(st->req_realpath, dir, MAX_SDIRENT); if (num < 0) die(st, ERR_NOTFOUND, "WTF?"); /* Create link to parent directory */ if (st->opt_parent) { sstrlcpy(buf, st->req_selector); parent = dirname(buf); /* Root has no parent */ if (strcmp(st->req_selector, ROOT) != MATCH) { /* Prevent double-slash */ if (strcmp(parent, ROOT) == MATCH) parent++; /* Print link */ printf("1%-*s\t%s/\t%s\t%i" CRLF, st->opt_date ? (st->out_width - 1) : (int) strlen(PARENT), PARENT, parent, st->server_host, st->server_port); } } /* Width of filenames for fancy listing */ width = st->out_width - DATE_WIDTH - 15; /* Loop through the directory entries */ for (i = 0; i < num; i++) { /* Get full path+name */ snprintf(pathname, sizeof(pathname), "%s/%s", st->req_realpath, dir[i].name); /* Skip dotfiles and non world-readables */ if (dir[i].name[0] == '.') continue; if ((dir[i].mode & S_IROTH) == 0) continue; /* Skip gophermaps and tags (but not dirs) */ if ((dir[i].mode & S_IFMT) != S_IFDIR) { if (strcmp(dir[i].name, st->map_file) == MATCH) continue; if (strcmp(dir[i].name, st->tag_file) == MATCH) continue; } /* Skip files marked for hiding */ for (n = 0; n < st->hidden_count; n++) if (strcmp(dir[i].name, st->hidden[n]) == MATCH) break; if (n < st->hidden_count) continue; /* Cruel hack... */ /* Generate display name with correct output charset */ if (st->opt_iconv) sstrniconv(st->out_charset, displayname, dir[i].name); else sstrlcpy(displayname, dir[i].name); /* #OCT-encode filename */ strnencode(encodedname, dir[i].name, sizeof(encodedname)); /* Handle inline .gophermap */ if (strstr(displayname, st->map_file) > displayname) { gophermap(st, pathname, 0); continue; } /* Handle directories */ if ((dir[i].mode & S_IFMT) == S_IFDIR) { /* Check for a gophertag */ snprintf(buf, sizeof(buf), "%s/%s", pathname, st->tag_file); if (stat(buf, &file) == OK && (file.st_mode & S_IFMT) == S_IFREG) { /* Use the gophertag as displayname */ if ((fp = fopen(buf , "r"))) { fgets(buf, sizeof(buf), fp); chomp(buf); fclose(fp); /* Skip empty gophertags */ if (*buf) { /* Convert to output charset */ if (st->opt_iconv) sstrniconv(st->out_charset, displayname, buf); else sstrlcpy(displayname, buf); } } } /* Dir listing with dates */ if (st->opt_date) { ltime = localtime(&dir[i].mtime); strftime(timestr, sizeof(timestr), DATE_FORMAT, ltime); /* Hack to get around UTF-8 byte != char */ n = width - strcut(displayname, width); strrepeat(buf, ' ', n); printf("1%s%s %s - \t%s%s/\t%s\t%i" CRLF, displayname, buf, timestr, st->req_selector, encodedname, st->server_host, st->server_port); } /* Regular dir listing */ else { strcut(displayname, st->out_width); printf("1%s\t%s%s/\t%s\t%i" CRLF, displayname, st->req_selector, encodedname, st->server_host, st->server_port); } continue; } /* Skip special files (sockets, fifos etc) */ if ((dir[i].mode & S_IFMT) != S_IFREG) continue; /* Get file type */ type = gopher_filetype(st, pathname, st->opt_magic); /* File listing with dates & sizes */ if (st->opt_date) { ltime = localtime(&dir[i].mtime); strftime(timestr, sizeof(timestr), DATE_FORMAT, ltime); strfsize(sizestr, dir[i].size, sizeof(sizestr)); /* Hack to get around UTF-8 byte != char */ n = width - strcut(displayname, width); strrepeat(buf, ' ', n); printf("%c%s%s %s %s\t%s%s\t%s\t%i" CRLF, type, displayname, buf, timestr, sizestr, st->req_selector, encodedname, st->server_host, st->server_port); } /* Regular file listing */ else { strcut(displayname, st->out_width); printf("%c%s\t%s%s\t%s\t%i" CRLF, type, displayname, st->req_selector, encodedname, st->server_host, st->server_port); } } /* Print footer */ footer(st); }
/* * Get suffices of all sub-mandir directories in a mandir. */ static void get_all_sect(struct man_node *manp) { DIR *dp; char **dirv; char **dv; char **p; char *prev = NULL; char *tmp = NULL; int maxentries = MAXTOKENS; int entries = 0; if ((dp = opendir(manp->path)) == 0) return; sortdir(dp, &dirv); (void) closedir(dp); if (manp->secv == NULL) { if ((manp->secv = malloc(maxentries * sizeof (char *))) == NULL) err(1, "malloc"); } for (dv = dirv, p = manp->secv; *dv; dv++) { if (strcmp(*dv, CONFIG) == 0) { free(*dv); continue; } free(tmp); if ((tmp = strdup(*dv + 3)) == NULL) err(1, "strdup"); if (prev != NULL && strcmp(prev, tmp) == 0) { free(*dv); continue; } free(prev); if ((prev = strdup(*dv + 3)) == NULL) err(1, "strdup"); if ((*p = strdup(*dv + 3)) == NULL) err(1, "strdup"); p++; entries++; if (entries == maxentries) { maxentries += MAXTOKENS; if ((manp->secv = realloc(manp->secv, sizeof (char *) * maxentries)) == NULL) err(1, "realloc"); p = manp->secv + entries; } free(*dv); } free(tmp); free(prev); *p = NULL; free(dirv); }
/* * For a specified manual directory, read, store and sort section subdirs. * For each section specified, find and search matching subdirs. */ static void mandir(char **secv, char *path, char *name, int lspec) { DIR *dp; char **dirv; char **dv, **pdv; int len, dslen; if ((dp = opendir(path)) == NULL) return; if (lspec) DPRINTF("-- Searching mandir: %s\n", path); sortdir(dp, &dirv); /* Search in the order specified by MANSECTS */ for (; *secv; secv++) { len = strlen(*secv); for (dv = dirv; *dv; dv++) { dslen = strlen(*dv + 3); if (dslen > len) len = dslen; if (**secv == '\\') { if (strcmp(*secv + 1, *dv + 3) != 0) continue; } else if (strncasecmp(*secv, *dv + 3, len) != 0) { if (!all && (newsection = map_section(*secv, path)) == NULL) { continue; } if (newsection == NULL) newsection = ""; if (strncmp(newsection, *dv + 3, len) != 0) { continue; } } if (searchdir(path, *dv, name) == 0) continue; if (!all) { pdv = dirv; while (*pdv) { free(*pdv); pdv++; } (void) closedir(dp); free(dirv); return; } if (all && **dv == 'm' && *(dv + 1) && strcmp(*(dv + 1) + 3, *dv + 3) == 0) dv++; } } pdv = dirv; while (*pdv != NULL) { free(*pdv); pdv++; } free(dirv); (void) closedir(dp); }