/* * spool.c: Handle disk-cache for videotext-pages * * $Id: spool.c,v 1.5 1997/09/14 01:39:54 mb Exp mb $ * * Copyright (c) 1994-96 Martin Buck * Read COPYING for more information * */ #include #include #include #include #include #include #include #include #include #include #include #include "safe_malloc.h" #include "tilde.h" #include "misc.h" #include "config.h" #include "hotlist.h" #include "vtxqueue.h" #include "cache.h" #include "vtxtools.h" #include "xinit.h" #include "spool.h" #define NICE_VAL 5 static char * public_spooldir(void) { static char *dir; if (!dir && !(dir = getenv("VTX_SPOOLDIR"))) { dir = VTX_SPOOLDIR; } return dir; } static int write_spooldir(const char *basedir, int private) { char *ch, *dirname, *fname_offs, station_name[STATIONNAME_MAXLEN + 1], buffer[VTX_PAGESIZE]; int oldumask; cache_loop_t last; vtx_pageinfo_t info; FILE *file; dirname = sstrdup(basedir); dirname = sstrapp(dirname, "/"); strcpy(station_name, hotlist_get_name()); for (ch = station_name; *ch; ch++) { if (*ch == '/') { *ch = '_'; } } dirname = sstrapp(dirname, station_name); oldumask = umask(0); if (private) { mkdir(dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); } else { mkdir(dirname, S_IRWXU | S_IRWXG | S_IRWXO); } umask(0022); if (access(dirname, R_OK | W_OK | X_OK) < 0) { umask(oldumask); free(dirname); return -1; } dirname = sstrapp(dirname, "/??????????"); fname_offs = dirname + strlen(dirname) - 10; last.page = -1; while (cache_loop(&last, buffer, &info)) { if (hotlist_check_spool(info.pagenum)) { sprintf(fname_offs, "%X_%02X.vtx", info.pagenum, info.minute); unlink(dirname); if ((file = fopen(dirname, "w"))) { save_vtx(file, buffer, &info, FALSE); fclose(file); } } } umask(oldumask); free(dirname); return 0; } void write_cache(void) { int fd, maxopen; pid_t pid; const char *privdir; if (!hotlist_get_current() || !vtx_dev_open) return; if ((pid = fork()) < 0) { /* ignore failure because writing the cache to disk is not vital */ return; } else if (pid == 0) { /* this is the new process */ if ((maxopen = sysconf(_SC_OPEN_MAX)) < 0) { maxopen = 256; /* hopefully enough */ } for (fd = 0; fd < maxopen; fd++) { close(fd); } nice(NICE_VAL); /* No need to hurry */ notify_set_signal_func(frame, NOTIFY_FUNC_NULL, SIGHUP, NOTIFY_SYNC); if (hotlist_get_spoolflag(TRUE, FALSE) && strcmp(privdir = config_get_spooldir(), "") && (privdir = tilde_expand(privdir))) { write_spooldir(privdir, TRUE); } if (hotlist_get_spoolflag(FALSE, FALSE)) { write_spooldir(public_spooldir(), FALSE); } _exit(0); } notify_set_wait3_func(frame, notify_default_wait3, pid); /* reap child when finished */ } static char * mkdirname(char *stname) { static char dirname[STATIONNAME_MAXLEN + 1]; char *dirptr; for (dirptr = dirname; *stname; stname++, dirptr++) { if (*stname == '/') { *dirptr = '_'; } else { *dirptr = *stname; } } *dirptr = '\0'; return dirname; } static int read_spool(const char *basedir, int page, int subpage, byte_t *buffer, vtx_pageinfo_t *info) { FILE *file; struct stat st; char *fname, *fname_offs, *dirname; int retval = FALSE; dirname = sstrdup(basedir); dirname = sstrapp(dirname, "/"); dirname = sstrapp(dirname, mkdirname(hotlist_get_name())); if (access(dirname, R_OK | X_OK) < 0) { free(dirname); return FALSE; } fname = NULL; if (subpage == -1) { /* Find the first subpage */ DIR *dir; struct dirent *de; char fntempl[11]; int f_sub; if ((dir = opendir(dirname))) { sprintf(fntempl, "%X_%%d.vtx", page); while ((de = readdir(dir))) { if (sscanf(de->d_name, fntempl, &f_sub) == 1 && (subpage < 0 || f_sub < subpage)) { subpage = f_sub; if (subpage == 0 || subpage == 1) break; } } closedir(dir); } } if (subpage < 0) { free(dirname); return FALSE; } fname = sstrdup(dirname); fname = sstrapp(fname, "/??????????"); fname_offs = fname + strlen(fname) - 10; sprintf(fname_offs, "%X_%02X.vtx", page, subpage); if ((file = fopen(fname, "r"))) { if (!fstat(fileno(file), &st) && (!vtx_dev_open || st.st_mtime / 3600 + hotlist_get_expire() >= time(NULL) / 3600) && load_vtx(file, buffer, info, NULL) >= 0) { retval = TRUE; } fclose(file); } else { /* Single-digit subpages for compatibility with version 0.6 * FIXME: Remove before version 0.8 */ sprintf(fname_offs, "%X_%X.vtx", page, subpage); if ((file = fopen(fname, "r"))) { if (!fstat(fileno(file), &st) && (!vtx_dev_open || st.st_mtime / 3600 + hotlist_get_expire() >= time(NULL) / 3600) && load_vtx(file, buffer, info, NULL) >= 0) { retval = TRUE; } fclose(file); } } free(fname); free(dirname); return retval; } int query_spool(int page, int subpage, byte_t *buffer, vtx_pageinfo_t *info) { const char *privdir; if (!vtx_chkpgnum(page, FALSE) || !hotlist_check_spool(page)) return FALSE; if (((!vtx_dev_open || hotlist_get_spoolflag(TRUE, TRUE)) && strcmp(privdir = config_get_spooldir(), "") && (privdir = tilde_expand(privdir)) && read_spool(privdir, page, subpage, buffer, info)) || ((!vtx_dev_open || hotlist_get_spoolflag(FALSE, TRUE)) && read_spool(public_spooldir(), page, subpage, buffer, info))) { return TRUE; } return FALSE; } spool_dirent_t * parsedir(const char *basedir, int dirnum, int *count) { DIR *dir; struct dirent *de; char *dirname; spool_dirent_t *dlist; int max; unsigned int page, subpage; dirname = sstrdup(basedir); dirname = sstrapp(dirname, "/"); dirname = sstrapp(dirname, mkdirname(hotlist_get_name())); *count = max = 0; dlist = NULL; if ((dir = opendir(dirname))) { while ((de = readdir(dir))) { if (sscanf(de->d_name, "%3x_%2x.vtx", &page, &subpage) == 2 && vtx_chkpgnum(page, TRUE) && subpage <= 0x7f) { if (max <= *count + 1) { max += 100; dlist = srealloc(dlist, max * sizeof(spool_dirent_t)); } dlist[*count].page = page; dlist[*count].subpage = subpage; dlist[*count].dirnum = dirnum; (*count)++; dlist[*count].page = 0; } } closedir(dir); } free(dirname); return dlist; } static int dirent_cmp_fn(const void *ent1, const void *ent2) { const spool_dirent_t *de1, *de2; de1 = ent1; de2 = ent2; if (de1->page < de2->page) return -1; if (de1->page > de2->page) return 1; if (de1->subpage < de2->subpage) return -1; if (de1->subpage > de2->subpage) return 1; if (de1->dirnum < de2->dirnum) return -1; if (de1->dirnum > de2->dirnum) return 1; return 0; } spool_dirent_t * spool_getlist(int use_pub, int use_priv) { spool_dirent_t *dlist, *dlist1, *dlist2, *ent; int count, count1, count2, new_count; const char *privdir; dlist1 = dlist2 = NULL; count1 = count2 = 0; if (use_priv && strcmp(privdir = config_get_spooldir(), "") && (privdir = tilde_expand(privdir))) { dlist1 = parsedir(privdir, 1, &count1); } if (use_pub) { dlist2 = parsedir(public_spooldir(), 2, &count2); } if (!dlist1 && !dlist2) { return NULL; } count = count1 + count2; dlist = smalloc((count + 1) * sizeof(spool_dirent_t)); if (dlist1) { memcpy(dlist, dlist1, count1 * sizeof(spool_dirent_t)); } if (dlist2) { memcpy(dlist + count1, dlist2, count2 * sizeof(spool_dirent_t)); } dlist[count].page = 0; free(dlist1); free(dlist2); qsort(dlist, count, sizeof(spool_dirent_t), dirent_cmp_fn); ent = dlist; new_count = count; while (ent->page) { if (ent->page == (ent + 1)->page && ent->subpage == (ent + 1)->subpage) { memmove(ent + 1, ent + 2, --count * sizeof(spool_dirent_t)); new_count--; } else { ent++; count--; } } dlist = srealloc(dlist, (new_count + 1) * sizeof(spool_dirent_t)); return dlist; }