summaryrefslogtreecommitdiffstats
path: root/web/util_cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'web/util_cache.c')
-rwxr-xr-xweb/util_cache.c516
1 files changed, 516 insertions, 0 deletions
diff --git a/web/util_cache.c b/web/util_cache.c
new file mode 100755
index 00000000..5178dad5
--- /dev/null
+++ b/web/util_cache.c
@@ -0,0 +1,516 @@
+/* $Id: util_cache.c,v 1.1 2002/10/18 14:43:58 ptt Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+#ifdef __FreeBSD__
+#include <machine/param.h>
+#endif
+
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+/* the reason for "safe_sleep" is that we may call sleep during
+ SIGALRM handler routine, while SIGALRM is blocked.
+ if we use the original sleep, we'll never wake up. */
+unsigned int safe_sleep(unsigned int seconds) {
+ /* jochang sleep有問題時用*/
+ sigset_t set,oldset;
+
+ sigemptyset(&set);
+ sigprocmask(SIG_BLOCK, &set, &oldset);
+ if(sigismember(&oldset, SIGALRM)) {
+ unsigned long retv;
+ sigemptyset(&set);
+ sigaddset(&set,SIGALRM);
+ sigprocmask(SIG_UNBLOCK,&set,NULL);
+ retv=sleep(seconds);
+ sigprocmask(SIG_BLOCK,&set,NULL);
+ return retv;
+ }
+ return sleep(seconds);
+}
+
+void setapath(char *buf, char *boardname) {
+ sprintf(buf, "man/boards/%c/%s", boardname[0], boardname);
+}
+
+static char *str_dotdir = ".DIR";
+
+void setadir(char *buf, char *path) {
+ sprintf(buf, "%s/%s", path, str_dotdir);
+}
+
+static void attach_err(int shmkey, char *name) {
+ fprintf(stderr, "[%s error] key = %x\n", name, shmkey);
+ fprintf(stderr, "errno = %d: %s\n", errno, strerror(errno));
+ exit(1);
+}
+
+void *attach_shm(int shmkey, int shmsize) {
+ void *shmptr;
+ int shmid;
+
+ char *empty_addr;
+ /* set up one page in-accessible -- jochang */
+ {
+ int fd = open("/dev/zero",O_RDONLY);
+ int size = ((shmsize + 4095) / 4096) * 4096;
+
+ munmap(
+ (empty_addr=mmap(0,4096+size,PROT_NONE,MAP_PRIVATE,fd,0))+4096
+ ,size);
+
+ close(fd);
+ }
+
+ shmid = shmget(shmkey, shmsize, 0);
+ if(shmid < 0) {
+ shmid = shmget(shmkey, shmsize, IPC_CREAT | 0600);
+ if(shmid < 0)
+ attach_err(shmkey, "shmget");
+ shmptr = (void *)shmat(shmid, NULL, 0);
+ if(shmptr == (void *)-1)
+ attach_err(shmkey, "shmat");
+ } else {
+ shmptr = (void *)shmat(shmid, NULL, 0);
+ if(shmptr == (void *)-1)
+ attach_err(shmkey, "shmat");
+ }
+
+ /* unmap the page -- jochang */
+ {
+ munmap(empty_addr,4096);
+ }
+ return shmptr;
+}
+
+#ifndef __FreeBSD__
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
+ unsigned short int *array; /* array for GETALL, SETALL */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
+#endif
+
+#define SEM_FLG 0600 /* semaphore mode */
+
+/* ----------------------------------------------------- */
+/* semaphore : for critical section */
+/* ----------------------------------------------------- */
+void sem_init(int semkey,int *semid) {
+ union semun s;
+
+ s.val=1;
+ *semid = semget(semkey, 1, 0);
+ if(*semid == -1) {
+ *semid = semget(semkey, 1, IPC_CREAT | SEM_FLG);
+ if(*semid == -1)
+ attach_err(semkey, "semget");
+ semctl(*semid, 0, SETVAL, s);
+ }
+}
+
+void sem_lock(int op,int semid) {
+ struct sembuf sops;
+
+ sops.sem_num = 0;
+ sops.sem_flg = SEM_UNDO;
+ sops.sem_op = op;
+ semop(semid, &sops, 1);
+}
+
+SHM_t *SHM;
+int *GLOBALVAR;
+boardheader_t *bcache;
+int numboards = -1;
+
+void attach_SHM(void)
+{
+ SHM = attach_shm(SHM_KEY, sizeof(SHM_t));
+ if( !SHM->loaded ) /* (uhash) assume fresh shared memory is zeroed */
+ exit(1);
+ if( SHM->Btouchtime == 0 )
+ SHM->Btouchtime = 1;
+ bcache = SHM->bcache;
+
+ GLOBALVAR = SHM->GLOBALVAR;
+ if( SHM->Ptouchtime == 0 )
+ SHM->Ptouchtime = 1;
+
+ if( SHM->Ftouchtime == 0 )
+ SHM->Ftouchtime = 1;
+
+ bcache = SHM->bcache;
+ numboards = SHM->Bnumber;
+}
+
+int setumoney(int uid, int money) {
+ SHM->money[uid-1]=money;
+ passwd_update_money(uid);
+ return SHM->money[uid-1];
+}
+
+int deumoney(int uid, int money) {
+ if(money<0 && SHM->money[uid-1]<-money)
+ return setumoney(uid,0);
+ else
+ return setumoney(uid,SHM->money[uid-1]+money);
+}
+int moneyof(int uid){ /* ptt 改進金錢處理效率 */
+ return SHM->money[uid-1];
+}
+
+static unsigned string_hash(unsigned char *s) {
+ unsigned int v=0;
+ while(*s) {
+ v = (v << 8) | (v >> 24);
+ v ^= toupper(*s++); /* note this is case insensitive */
+ }
+ return (v * 2654435769UL) >> (32 - HASH_BITS);
+}
+
+void add_to_uhash(int n, char *id) {
+ int *p, h = string_hash(id);
+ strcpy(SHM->userid[n], id);
+
+ p = &(SHM->hash_head[h]);
+
+ while(*p != -1)
+ p = &(SHM->next_in_hash[*p]);
+
+ SHM->next_in_hash[*p = n] = -1;
+}
+
+/* note: after remove_from_uhash(), you should add_to_uhash()
+ (likely with a different name) */
+void remove_from_uhash(int n) {
+ int h = string_hash(SHM->userid[n]);
+ int *p = &(SHM->hash_head[h]);
+
+ while(*p != -1 && *p != n)
+ p = &(SHM->next_in_hash[*p]);
+ if(*p == n)
+ *p = SHM->next_in_hash[n];
+}
+
+int searchuser(char *userid) {
+ int h,p;
+
+ if(SHM == NULL)
+ attach_SHM(); /* for sloopy util programs */
+
+ h = string_hash(userid);
+ p = SHM->hash_head[h];
+
+ while(p != -1) {
+ if(strcasecmp(SHM->userid[p],userid) == 0) {
+ strcpy(userid,SHM->userid[p]);
+ return p + 1;
+ }
+ p = SHM->next_in_hash[p];
+ }
+ return 0;
+}
+userec_t xuser;
+
+int getuser(char *userid) {
+ int uid;
+ if((uid = searchuser(userid)))
+ passwd_query(uid, &xuser);
+ return uid;
+}
+
+void setuserid(int num, char *userid) {
+ if(num > 0 && num <= MAX_USERS) {
+ if(num > SHM->number)
+ SHM->number = num;
+ else
+ remove_from_uhash(num-1);
+ add_to_uhash(num-1,userid);
+ }
+}
+
+/*-------------------------------------------------------*/
+/* .UTMP cache */
+/*-------------------------------------------------------*/
+void resolve_utmp() {
+ if(SHM == NULL) {
+ attach_SHM();
+ if(SHM->UTMPuptime == 0)
+ SHM->UTMPuptime = SHM->UTMPnumber = 1;
+ }
+}
+
+userinfo_t *currutmp = NULL;
+
+void getnewutmpent(userinfo_t *up) {
+ extern int errno;
+ register int i;
+ register userinfo_t *uentp;
+
+ resolve_utmp();
+
+ for(i = 0; i < USHM_SIZE; i++) {
+ uentp = &(SHM->uinfo[i]);
+ if(!(uentp->pid)) {
+ memcpy(uentp, up, sizeof(userinfo_t));
+ currutmp = uentp;
+ SHM->number++;
+ return;
+ }
+ }
+ exit(1);
+}
+
+int apply_ulist(int (*fptr)(userinfo_t *)) {
+ register userinfo_t *uentp;
+ register int i, state;
+
+ resolve_utmp();
+ for(i = 0; i < USHM_SIZE; i++) {
+ uentp = &(SHM->uinfo[i]);
+ if(uentp->pid && (PERM_HIDE(currutmp) || !PERM_HIDE(uentp)))
+ if((state = (*fptr) (uentp)))
+ return state;
+ }
+ return 0;
+}
+
+userinfo_t *search_ulist(int uid) {
+ register int i;
+ register userinfo_t *uentp;
+
+ resolve_utmp();
+ for(i = 0; i < USHM_SIZE; i++) {
+ uentp = &(SHM->uinfo[i]);
+ if(uid==uentp->uid)
+ return uentp;
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------*/
+/* .BOARDS cache */
+/*-------------------------------------------------------*/
+char *fn_board=BBSHOME"/"FN_BOARD;
+static void reload_bcache() {
+ if(SHM->Bbusystate) {
+ safe_sleep(1);
+ }
+}
+
+void resolve_boards() {
+ if(SHM == NULL) {
+ attach_SHM();
+ if(SHM->Btouchtime == 0)
+ SHM->Btouchtime = 1;
+ }
+
+ while(SHM->Buptime < SHM->Btouchtime)
+ reload_bcache();
+ numboards = SHM->Bnumber;
+}
+
+void touch_boards() {
+ time(&(SHM->Btouchtime));
+ numboards = -1;
+ resolve_boards();
+}
+void reset_board(int bid)
+{
+ int fd;
+ boardheader_t bh;
+ if(--bid<0)return;
+ if(SHM->Bbusystate==0)
+ {
+ SHM->Bbusystate = 1;
+ if((fd = open(fn_board, O_RDONLY)) > 0) {
+ lseek(fd, (off_t)(bid * sizeof(boardheader_t)), SEEK_SET);
+ read(fd, &bh , sizeof(boardheader_t));
+ close(fd);
+ if(bh.brdname[0] && !strcmp(bh.brdname,bcache[bid].brdname))
+ memcpy(&bcache[bid],&bh, sizeof(boardheader_t));
+ }
+ SHM->Bbusystate = 0;
+ }
+}
+boardheader_t *getbcache(int bid) { /* Ptt改寫 */
+ return bcache + bid - 1;
+}
+
+void touchbtotal(int bid) {
+ SHM->total[bid - 1] = 0;
+ SHM->lastposttime[bid - 1] = 0;
+}
+
+
+int getbnum(char *bname) {
+ register int i;
+ register boardheader_t *bhdr;
+
+ for(i = 0, bhdr = bcache; i++ < numboards; bhdr++)
+ if(
+ !strcasecmp(bname, bhdr->brdname))
+ return i;
+ return 0;
+}
+
+/*-------------------------------------------------------*/
+/* PTT cache */
+/*-------------------------------------------------------*/
+/* cachefor 動態看版 */
+void reload_pttcache(void)
+{
+ if(SHM->Pbusystate)
+ safe_sleep(1);
+ else { /* jochang: temporary workaround */
+ fileheader_t item, subitem;
+ char pbuf[256], buf[256], *chr;
+ FILE *fp, *fp1, *fp2;
+ int id, section = 0;
+
+ SHM->Pbusystate = 1;
+ SHM->max_film = 0;
+ bzero(SHM->notes, sizeof SHM->notes);
+ setapath(pbuf, "Note");
+ setadir(buf, pbuf);
+ id = 0;
+ if((fp = fopen(buf, "r"))) {
+ while(fread(&item, sizeof(item), 1, fp)) {
+ if(item.title[3]=='<' && item.title[8]=='>') {
+ sprintf(buf,"%s/%s", pbuf, item.filename);
+ setadir(buf, buf);
+ if(!(fp1 = fopen(buf, "r")))
+ continue;
+ SHM->next_refresh[section] = SHM->n_notes[section] = id;
+ section ++;
+ while(fread(&subitem, sizeof(subitem), 1, fp1)) {
+ sprintf(buf,"%s/%s/%s", pbuf, item.filename ,
+ subitem.filename);
+ if(!(fp2=fopen(buf,"r")))
+ continue;
+ fread(SHM->notes[id],sizeof(char), 200*11, fp2);
+ SHM->notes[id][200*11 - 1]=0;
+ id++;
+ fclose(fp2);
+ if(id >= MAX_MOVIE)
+ break;
+ }
+ fclose(fp1);
+ if(id >= MAX_MOVIE || section >= MAX_MOVIE_SECTION)
+ break;
+ }
+ }
+ fclose(fp);
+ }
+ SHM->next_refresh[section] = -1;
+ SHM->n_notes[section] = SHM->max_film = id-1;
+ SHM->max_history = SHM->max_film - 2;
+ if(SHM->max_history > MAX_HISTORY - 1)
+ SHM->max_history = MAX_HISTORY - 1;
+ if(SHM->max_history <0) SHM->max_history=0;
+
+ fp = fopen("etc/today_is","r");
+ if(fp) {
+ fgets(SHM->today_is,15,fp);
+ if((chr = strchr(SHM->today_is,'\n')))
+ *chr = 0;
+ SHM->today_is[15] = 0;
+ fclose(fp);
+ }
+
+ /* 等所有資料更新後再設定 uptime */
+
+ SHM->Puptime = SHM->Ptouchtime ;
+ SHM->Pbusystate = 0;
+ }
+}
+
+void resolve_garbage() {
+ int count=0;
+
+ if(SHM == NULL) {
+ attach_SHM();
+ if(SHM->Ptouchtime == 0)
+ SHM->Ptouchtime = 1;
+ }
+ while(SHM->Puptime < SHM->Ptouchtime) { /* 不用while等 */
+ reload_pttcache();
+ if(count ++ > 10 && SHM->Pbusystate) {
+/* Ptt: 這邊會有問題 load超過10 秒會所有進loop的process都讓 busystate = 0
+ 這樣會所有prcosee都會在load 動態看板 會造成load大增
+ 但沒有用這個function的話 萬一load passwd檔的process死了 又沒有人把他
+ 解開 同樣的問題發生在reload passwd
+*/
+ SHM->Pbusystate = 0;
+ }
+ }
+}
+
+/*-------------------------------------------------------*/
+/* PTT's cache */
+/*-------------------------------------------------------*/
+/* cachefor from host 與最多上線人數 */
+static void reload_fcache() {
+ if(SHM->Fbusystate)
+ safe_sleep(1);
+ else {
+ FILE *fp;
+
+ SHM->Fbusystate = 1;
+ bzero(SHM->domain, sizeof SHM->domain);
+ if((fp = fopen("etc/domain_name_query","r"))) {
+ char buf[101],*po;
+
+ SHM->top=0;
+ while(fgets(buf,100,fp)) {
+ if(buf[0] && buf[0] != '#' && buf[0] != ' ' &&
+ buf[0] != '\n') {
+ sscanf(buf,"%s",SHM->domain[SHM->top]);
+ po = buf + strlen(SHM->domain[SHM->top]);
+ while(*po == ' ')
+ po++;
+ strncpy(SHM->replace[SHM->top],po,49);
+ SHM->replace[SHM->top]
+ [strlen(SHM->replace[SHM->top])-1] = 0;
+ (SHM->top)++;
+ }
+ }
+ }
+
+ SHM->max_user=0;
+
+ /* 等所有資料更新後再設定 uptime */
+ SHM->Fuptime = SHM->Ftouchtime;
+ SHM->Fbusystate = 0;
+ }
+}
+
+void resolve_fcache() {
+ if(SHM == NULL) {
+ attach_SHM();
+ if(SHM->Ftouchtime == 0)
+ SHM->Ftouchtime = 1;
+ }
+ while(SHM->Fuptime < SHM->Ftouchtime)
+ reload_fcache();
+}