diff options
author | in2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2002-03-07 23:13:44 +0800 |
---|---|---|
committer | in2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2002-03-07 23:13:44 +0800 |
commit | ae31e19f92e717919ac8e3db9039eb38d2b89aae (patch) | |
tree | c70164d6a1852344f44b04a653ae2815043512af /mbbsd/cache.c | |
download | pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.gz pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.bz2 pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.lz pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.xz pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.tar.zst pttbbs-ae31e19f92e717919ac8e3db9039eb38d2b89aae.zip |
Initial revision
git-svn-id: http://opensvn.csie.org/pttbbs/pttbbs/trunk/pttbbs@1 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'mbbsd/cache.c')
-rw-r--r-- | mbbsd/cache.c | 1053 |
1 files changed, 1053 insertions, 0 deletions
diff --git a/mbbsd/cache.c b/mbbsd/cache.c new file mode 100644 index 00000000..73f8ac5b --- /dev/null +++ b/mbbsd/cache.c @@ -0,0 +1,1053 @@ +/* $Id: cache.c,v 1.1 2002/03/07 15:13:48 in2 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/mman.h> +#include <sys/stat.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" + +#ifndef __FreeBSD__ +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 + +int fcache_semid; + +/* 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; +#if !defined(_BBS_UTIL_C_) + log_usies("SAFE_SLEEP ", "avoid hang"); +#endif + sigemptyset(&set); + sigaddset(&set,SIGALRM); + sigprocmask(SIG_UNBLOCK,&set,NULL); + retv=sleep(seconds); + sigprocmask(SIG_BLOCK,&set,NULL); + return retv; + } + return sleep(seconds); +} + +#if defined(_BBS_UTIL_C_) +static void setapath(char *buf, char *boardname) { + sprintf(buf, "man/boards/%s", boardname); +} + +static char *str_dotdir = ".DIR"; + +static void setadir(char *buf, char *path) { + sprintf(buf, "%s/%s", path, str_dotdir); +} +#endif + +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); +} + +static 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; +} + + +#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); +} + +/* uhash *******************************************/ +/* the design is this: + we use another stand-alone program to create and load data into the hash. + (that program could be run in rc-scripts or something like that) + after loading completes, the stand-alone program sets loaded to 1 and exits. + + the bbs exits if it can't attach to the shared memory or + the hash is not loaded yet. +*/ +uhash_t *uhash; + +/* attach_uhash should be called before using uhash */ +void attach_uhash() { + uhash = attach_shm(UHASH_KEY, sizeof(*uhash)); + if(!uhash->loaded) /* assume fresh shared memory is zeroed */ + exit(1); +} + +void add_to_uhash(int n, char *id) { + int *p, h = StringHash(id); + strcpy(uhash->userid[n], id); + + p = &(uhash->hash_head[h]); + + while(*p != -1) + p = &(uhash->next_in_hash[*p]); + + uhash->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 = StringHash(uhash->userid[n]); + int *p = &(uhash->hash_head[h]); + + while(*p != -1 && *p != n) + p = &(uhash->next_in_hash[*p]); + if(*p == n) + *p = uhash->next_in_hash[n]; +} + +int setumoney(int uid, int money) { + uhash->money[uid-1]=money; + passwd_update_money(uid); + return uhash->money[uid-1]; +} + +int deumoney(int uid, int money) { + if(money<0 && uhash->money[uid-1]<-money) + return setumoney(uid,0); + else + return setumoney(uid,uhash->money[uid-1]+money); +} +int demoney(int money) { + extern int usernum; + return deumoney(usernum,money); +} +int moneyof(int uid){ /* ptt 改進金錢處理效率 */ + return uhash->money[uid-1]; +} +int searchuser(char *userid) { + int h,p; + + h = StringHash(userid); + p = uhash->hash_head[h]; + + while(p != -1) { + if(strcasecmp(uhash->userid[p],userid) == 0) { + strcpy(userid,uhash->userid[p]); + return p + 1; + } + p = uhash->next_in_hash[p]; + } + return 0; +} + +#if !defined(_BBS_UTIL_C_) +extern userec_t xuser; + +int getuser(char *userid) { + int uid; + + if((uid = searchuser(userid))) + passwd_query(uid, &xuser); + return uid; +} + +char *getuserid(int num) { + if(--num >= 0 && num < MAX_USERS) + return ((char *) uhash->userid[num]); + return NULL; +} + +void setuserid(int num, char *userid) { + if(num > 0 && num <= MAX_USERS) { + if(num > uhash->number) + uhash->number = num; + else + remove_from_uhash(num-1); + add_to_uhash(num-1,userid); + } +} + +/* 0 ==> 找過期帳號 */ +/* 1 ==> 建立新帳號 */ +/* should do it by searching "" in the hash */ +int searchnewuser(int mode) { + register int i, num; + + num = uhash->number; + i = 0; + + /* 為什麼這邊不用 hash table 去找而要用 linear search? */ + while(i < num) { + if(!uhash->userid[i++][0]) + return i; + } + if(mode && (num < MAX_USERS)) + return num + 1; + return 0; +} + +char *u_namearray(char buf[][IDLEN + 1], int *pnum, char *tag) { + register struct uhash_t *reg_ushm = uhash; + register char *ptr, tmp; + register int n, total; + char tagbuf[STRLEN]; + int ch, ch2, num; + + if(*tag == '\0') { + *pnum = reg_ushm->number; + return reg_ushm->userid[0]; + } + for(n = 0; tag[n]; n++) + tagbuf[n] = chartoupper(tag[n]); + tagbuf[n] = '\0'; + ch = tagbuf[0]; + ch2 = ch - 'A' + 'a'; + total = reg_ushm->number; + for(n = num = 0; n < total; n++) { + ptr = reg_ushm->userid[n]; + tmp = *ptr; + if(tmp == ch || tmp == ch2) { + if(chkstr(tag, tagbuf, ptr)) + strcpy(buf[num++], ptr); + } + } + *pnum = num; + return buf[0]; +} +#endif + +/*-------------------------------------------------------*/ +/* .UTMP cache */ +/*-------------------------------------------------------*/ +struct utmpfile_t *utmpshm=NULL; + +void resolve_utmp() { + if(utmpshm == NULL) { + utmpshm = attach_shm(UTMPSHM_KEY, sizeof(*utmpshm)); + } +} + +userinfo_t *currutmp = NULL; + +#if !defined(_BBS_UTIL_C_) +extern unsigned int currstat; +extern userec_t cuser; + +void setutmpmode(int mode) { + if(currstat != mode) + currutmp->mode = currstat = mode; + + /* 追蹤使用者 */ + if(HAS_PERM(PERM_LOGUSER)) { + time_t now = time(NULL); + char msg[200]; + sprintf(msg, "%s setutmpmode to %s(%d) at %s", + cuser.userid, modestring(currutmp, 0), mode, Cdate(&now)); + log_user(msg); + } +} +#endif +/* +static int cmputmpuserid(userinfo_t ** i, userinfo_t ** j) { + return strcasecmp((*i)->userid, (*j)->userid); +} + +static int cmputmpmode(userinfo_t ** i, userinfo_t ** j) { + return (*i)->mode-(*j)->mode; +} + +static int cmputmpidle(userinfo_t ** i, userinfo_t ** j) { + return (*i)->lastact-(*j)->lastact; +} + +static int cmputmpfrom(userinfo_t ** i, userinfo_t ** j) { + return strcasecmp((*i)->from, (*j)->from); +} + +static int cmputmpfive(userinfo_t ** i, userinfo_t ** j) { + int type; + if((type=(*j)->five_win - (*i)->five_win)) + return type; + if((type=(*i)->five_lose - (*j)->five_lose)) + return type; + return (*i)->five_tie-(*j)->five_tie; +} +static int cmputmpsex(userinfo_t ** i, userinfo_t ** j) { + static int ladyfirst[]={1,0,1,0,1,0,3,3}; + return ladyfirst[(*i)->sex]-ladyfirst[(*j)->sex]; +} +static int cmputmppid(userinfo_t ** i, userinfo_t ** j) { + return (*i)->pid-(*j)->pid; +} +static int cmputmpuid(userinfo_t ** i, userinfo_t ** j) { + return (*i)->uid-(*j)->uid; +} +*/ +static int cmputmpuserid(const void *i, const void *j){ + return strcasecmp((*((userinfo_t**)i))->userid, (*((userinfo_t**)j))->userid); +} + +static int cmputmpmode(const void *i, const void *j){ + return (*((userinfo_t**)i))->mode-(*((userinfo_t**)j))->mode; +} + +static int cmputmpidle(const void *i, const void *j){ + return (*((userinfo_t**)i))->lastact-(*((userinfo_t**)j))->lastact; +} + +static int cmputmpfrom(const void *i, const void *j){ + return strcasecmp((*((userinfo_t**)i))->from, (*((userinfo_t**)j))->from); +} + +static int cmputmpfive(const void *i, const void *j){ + int type; + if((type=(*((userinfo_t**)j))->five_win - (*((userinfo_t**)i))->five_win)) + return type; + if((type=(*((userinfo_t**)i))->five_lose - (*((userinfo_t**)j))->five_lose)) + return type; + return (*((userinfo_t**)i))->five_tie-(*((userinfo_t**)j))->five_tie; +} + +static int cmputmpsex(const void *i, const void *j){ + static int ladyfirst[]={1,0,1,0,1,0,3,3}; + return ladyfirst[(*((userinfo_t**)i))->sex]-ladyfirst[(*((userinfo_t**)j))->sex]; +} +static int cmputmppid(const void *i, const void *j){ + return (*((userinfo_t**)i))->pid-(*((userinfo_t**)j))->pid; +} +static int cmputmpuid(const void *i, const void *j){ + return (*((userinfo_t**)i))->uid-(*((userinfo_t**)j))->uid; +} +void sort_utmp() +{ + time_t now=time(NULL); + int count, i, ns; + userinfo_t *uentp; + + if(now-utmpshm->uptime<60 && (now==utmpshm->uptime || utmpshm->busystate)) + return; /* lazy sort */ + utmpshm->busystate=1; + utmpshm->uptime = now; + ns=(utmpshm->currsorted?0:1); + + for(uentp = &utmpshm->uinfo[0], count=0, i=0; + i< USHM_SIZE; i++,uentp = &utmpshm->uinfo[i]) + if(uentp->pid) + { + utmpshm->sorted[ns][0][count++]= uentp; + } + utmpshm->number = count; + qsort(utmpshm->sorted[ns][0],count,sizeof(userinfo_t*),cmputmpuserid); + memcpy(utmpshm->sorted[ns][1],utmpshm->sorted[ns][0], + sizeof(userinfo_t *)*count); + memcpy(utmpshm->sorted[ns][2],utmpshm->sorted[ns][0], + sizeof(userinfo_t *)*count); + memcpy(utmpshm->sorted[ns][3],utmpshm->sorted[ns][0], + sizeof(userinfo_t *)*count); + memcpy(utmpshm->sorted[ns][4],utmpshm->sorted[ns][0], + sizeof(userinfo_t *)*count); + memcpy(utmpshm->sorted[ns][5],utmpshm->sorted[ns][0], + sizeof(userinfo_t *)*count); + memcpy(utmpshm->sorted[ns][6],utmpshm->sorted[ns][0], + sizeof(userinfo_t *)*count); + memcpy(utmpshm->sorted[ns][7],utmpshm->sorted[ns][0], + sizeof(userinfo_t *)*count); + qsort(utmpshm->sorted[ns][1], count, sizeof(userinfo_t *), cmputmpmode ); + qsort(utmpshm->sorted[ns][2], count, sizeof(userinfo_t *), cmputmpidle ); + qsort(utmpshm->sorted[ns][3], count, sizeof(userinfo_t *), cmputmpfrom ); + qsort(utmpshm->sorted[ns][4], count, sizeof(userinfo_t *), cmputmpfive ); + qsort(utmpshm->sorted[ns][5], count, sizeof(userinfo_t *), cmputmpsex ); + qsort(utmpshm->sorted[ns][6], count, sizeof(userinfo_t *), cmputmpuid ); + qsort(utmpshm->sorted[ns][7], count, sizeof(userinfo_t *), cmputmppid ); + utmpshm->currsorted=ns; + utmpshm->busystate=0; +} +// Ptt:這邊加入hash觀念 找空的utmp +void getnewutmpent(userinfo_t *up) { + extern int errno; + register int i, p ; + register userinfo_t *uentp; + for(i = 0, p=StringHash(up->userid)%USHM_SIZE; i < USHM_SIZE; i++, p++) { + if(p==USHM_SIZE) p=0; + uentp = &(utmpshm->uinfo[p]); + if(!(uentp->pid)) { + memcpy(uentp, up, sizeof(userinfo_t)); + currutmp = uentp; + sort_utmp(); + return; + } + } + exit(1); +} + +int apply_ulist(int (*fptr)(userinfo_t *)) { + register userinfo_t *uentp; + register int i, state; + + for(i = 0; i < USHM_SIZE; i++) { + uentp = &(utmpshm->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) { + return search_ulistn(uid,1); +} + +#if !defined(_BBS_UTIL_C_) +extern int usernum; + +userinfo_t *search_ulist_pid(int pid) { + register int i=0, j, start = 0, end = utmpshm->number - 1; + register userinfo_t **ulist; + ulist=utmpshm->sorted[utmpshm->currsorted][7]; + for(i=((start+end)/2); ;i=(start+end)/2) + { + j=pid-ulist[i]->pid; + if(!j) + { + return (userinfo_t *) (ulist[i]); + } + if(end==start) + { + break; + } + else if(i==start) + { + i=end; + start=end; + } + else if(j>0) start = i; + else end = i; + } + return 0; +} +userinfo_t *search_ulistn(int uid, int unum) { + register int i=0, j, start = 0, end = utmpshm->number - 1; + register userinfo_t **ulist; + ulist=utmpshm->sorted[utmpshm->currsorted][6]; + for(i=((start+end)/2); ;i=(start+end)/2) + { + j= uid - ulist[i]->uid; + if(!j) + { + for(;i>0 && uid==ulist[i-1]->uid;i--);/* 指到第一筆 */ + if(uid==ulist[i+unum-1]->uid) + return (userinfo_t *) (ulist[i+unum-1]); + break; /* 超過範圍 */ + } + if(end==start) + { + break; + } + else if(i==start) + { + i=end; + start=end; + } + else if(j>0) start = i; + else end = i; + } + return 0; +} + +int count_logins(int uid, int show) { + register int i=0, j, start = 0, end = utmpshm->number - 1, count; + register userinfo_t **ulist; + ulist=utmpshm->sorted[utmpshm->currsorted][6]; + for(i=((start+end)/2); ;i=(start+end)/2) + { + j = uid-ulist[i]->uid; + if(!j) + { + for(;i>0 && uid==ulist[i-1]->uid;i--);/* 指到第一筆 */ + for(count=0;uid==ulist[i+count]->uid;count++) + { + if(show) + prints("(%d) 目前狀態為: %-17.16s(來自 %s)\n", + count+1, modestring(ulist[i+count], 0), + ulist[i+count]->from); + } + return count; + } + if(end==start) + { + break; + } + else if(i==start) + { + i=end; + start=end; + } + else if(j>0) start = i; + else end = i; + } + return 0; +} + + +void purge_utmp(userinfo_t *uentp) { + logout_friend_online(); + memset(uentp, 0, sizeof(userinfo_t)); +} + +#endif + +/*-------------------------------------------------------*/ +/* .BOARDS cache */ +/*-------------------------------------------------------*/ +extern char *fn_board; +extern int currbid; +bcache_t *brdshm; +boardheader_t *bcache; + +void touchdircache(int bid) +{ + int *i= (int *)&brdshm->dircache[bid - 1][0].filename[0]; + *i=0; +} + +void load_fileheader_cache(int bid, char *direct) +{ + int num=getbtotal(bid); + int n = num-DIRCACHESIZE+1; + if (brdshm->busystate!=1) + { + brdshm->busystate = 1; + get_records(direct, brdshm->dircache[bid - 1] , + sizeof(fileheader_t),n<1?1:n, DIRCACHESIZE); + brdshm->cachetotal[bid-1]=num; // cachetotal先設 以後再改不用全部load + brdshm->busystate = 0; + } + else + {safe_sleep(1);} +} + +int get_fileheader_cache(int bid, char *direct, fileheader_t *headers, + int recbase, int nlines) +{ + int ret, n,num; + + num=getbtotal(bid); + + ret = num-recbase+1, + n = (num - DIRCACHESIZE+1); + + + if(brdshm->dircache[bid - 1][0].filename[0]=='\0') + load_fileheader_cache(bid, direct); + if (n<1) + n=recbase-1; + else + n=recbase-n; + if(n<0) n=0; + if (ret>nlines) ret=nlines; + memcpy(headers, &(brdshm->dircache[bid - 1][n]),sizeof(fileheader_t)*ret); + return ret; +} +static int cmpboardname(boardheader_t **brd, boardheader_t **tmp) { + return strcasecmp((*brd)->brdname, (*tmp)->brdname); +} +static int cmpboardclass(boardheader_t **brd, boardheader_t **tmp) { + return (strncmp((*brd)->title, (*tmp)->title, 4)<<8)+ + strcasecmp((*brd)->brdname, (*tmp)->brdname); +} +static void sort_bcache(){ + int i;/*critical section 不能單獨呼叫 呼叫reload_bcache or reset_board */ + for(i=0;i<brdshm->number;i++) + { + brdshm->sorted[1][i]=brdshm->sorted[0][i]=&bcache[i]; + } + qsort(brdshm->sorted[0], brdshm->number, sizeof(boardheader_t *), + (QCAST)cmpboardname); + qsort(brdshm->sorted[1], brdshm->number, sizeof(boardheader_t *), + (QCAST)cmpboardclass); +} +static void reload_bcache() { + if(brdshm->busystate) { + safe_sleep(1); + } +#if !defined(_BBS_UTIL_C_) + else { + int fd,i; + + brdshm->busystate = 1; + if((fd = open(fn_board, O_RDONLY)) > 0) { + brdshm->number = + read(fd, bcache, MAX_BOARD * sizeof(boardheader_t)) / + sizeof(boardheader_t); + close(fd); + } + memset(brdshm->lastposttime, 0, MAX_BOARD * sizeof(time_t)); + /* 等所有 boards 資料更新後再設定 uptime */ + brdshm->uptime = brdshm->touchtime; + log_usies("CACHE", "reload bcache"); + sort_bcache(); + for(i=0;i<brdshm->number;i++) + { + bcache[i].firstchild[0]=NULL; + bcache[i].firstchild[1]=NULL; + } + brdshm->busystate = 0; + } +#endif +} + +int numboards = -1; + +void resolve_boards() { + if(brdshm == NULL) { + brdshm = attach_shm(BRDSHM_KEY, sizeof(*brdshm)); + if(brdshm->touchtime == 0) + brdshm->touchtime = 1; + bcache = brdshm->bcache; + } + + while(brdshm->uptime < brdshm->touchtime) + {reload_bcache();} + numboards = brdshm->number; +} + +void touch_boards() { + time(&(brdshm->touchtime)); + numboards = -1; + resolve_boards(); +} +void addbrd_touchcache() +{ + brdshm->number++; + numboards=brdshm->number; + reset_board(numboards); +} +#if !defined(_BBS_UTIL_C_) +void reset_board(int bid) { /* Ptt: 這樣就不用老是touch board了 */ + int fd,i; + boardheader_t *bhdr; + + if(--bid < 0) + return; + if(brdshm->busystate) { + safe_sleep(1); + } else { + brdshm->busystate = 1; + bhdr = bcache; + bhdr += bid; + if((fd = open(fn_board, O_RDONLY)) > 0) { + lseek(fd, (off_t)(bid * sizeof(boardheader_t)), SEEK_SET); + read(fd, bhdr, sizeof(boardheader_t)); + close(fd); + } + sort_bcache(); + for(i=0;i<brdshm->number;i++) + { + bcache[i].firstchild[0]=NULL; + bcache[i].firstchild[1]=NULL; + } + brdshm->busystate = 0; + } +} + +int apply_boards(int (*func)(boardheader_t *)) { + register int i; + register boardheader_t *bhdr; + + for(i = 0, bhdr = bcache; i < numboards; i++, bhdr++) { + if(!(bhdr->brdattr & BRD_GROUPBOARD) && Ben_Perm(bhdr) && + (*func)(bhdr) == QUIT) + return QUIT; + } + return 0; +} +#endif + +boardheader_t *getbcache(int bid) { /* Ptt改寫 */ + return bcache + bid - 1; +} +int getbtotal(int bid) +{ + return brdshm->total[bid - 1]; +} +void setbtotal(int bid) { + boardheader_t *bh = getbcache(bid); + struct stat st; + char genbuf[256]; + int num,fd; + + sprintf(genbuf, "boards/%s/.DIR", bh->brdname); + + if((fd = open(genbuf, O_RDWR)) < 0) + return; /* .DIR掛了 */ + fstat(fd, &st); + num = st.st_size / sizeof(fileheader_t); + brdshm->total[bid - 1] = num; + + if(num>0) + { + lseek(fd, (off_t) (num - 1) * sizeof(fileheader_t), SEEK_SET); + if(read(fd, genbuf, FNLEN)>=0) + { + brdshm->lastposttime[bid - 1]=(time_t) atoi(&genbuf[2]); + } + } + else + brdshm->lastposttime[bid - 1] = 0; + close(fd); + if(num) + touchdircache(bid); +} + +void +touchbpostnum(int bid, int delta) { + int *total = &brdshm->total[bid - 1]; + if (*total) *total += delta; +} + + +int getbnum(char *bname) { + register int i=0, j, start = 0, end = brdshm->number - 1; + register boardheader_t **bhdr; + bhdr=brdshm->sorted[0]; + for(i=((start+end)/2); ;i=(start+end)/2) + { + if(! (j=strcasecmp(bname,bhdr[i]->brdname))) + return (int) (bhdr[i] - bcache +1); + if(end==start) + { + break; + } + else if(i==start) + { + i=end; + start=end; + } + else if(j>0) start = i; + else end = i; + } + return 0; +} + +#if !defined(_BBS_UTIL_C_) +extern char *fn_water; +extern char *str_sysop; + +int haspostperm(char *bname) { + register int i; + char buf[200]; + + setbfile(buf, bname, fn_water); + if(belong(buf, cuser.userid)) + return 0; + + if(!strcasecmp(bname, DEFAULT_BOARD)) + return 1; + + if (!strcasecmp(bname, "PttLaw")) + return 1; + + if(!HAS_PERM(PERM_POST)) + return 0; + + if(!(i = getbnum(bname))) + return 0; + + /* 秘密看板特別處理 */ + if(bcache[i - 1].brdattr & BRD_HIDE) + return 1; + + i = bcache[i - 1].level; + + if (HAS_PERM(PERM_VIOLATELAW) && (i & PERM_VIOLATELAW)) + return 1; + else if (HAS_PERM(PERM_VIOLATELAW)) + return 0; + + return HAS_PERM(i & ~PERM_POST); +} +#endif + +/*-------------------------------------------------------*/ +/* PTT cache */ +/*-------------------------------------------------------*/ +/* cachefor 動態看版 */ +struct pttcache_t *ptt; + +static void reload_pttcache() { + if(ptt->busystate) + 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; + + ptt->busystate = 1; + ptt->max_film = 0; + bzero(ptt->notes, sizeof ptt->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; + ptt->next_refresh[section] = ptt->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(ptt->notes[id],sizeof(char), 200*11, fp2); + ptt->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); + } + ptt->next_refresh[section] = -1; + ptt->n_notes[section] = ptt->max_film = id-1; + ptt->max_history = ptt->max_film - 2; + if(ptt->max_history > MAX_HISTORY - 1) + ptt->max_history = MAX_HISTORY - 1; + if(ptt->max_history <0) ptt->max_history=0; + + fp = fopen("etc/today_is","r"); + if(fp) { + fgets(ptt->today_is,15,fp); + if((chr = strchr(ptt->today_is,'\n'))) + *chr = 0; + ptt->today_is[15] = 0; + fclose(fp); + } + + /* 等所有資料更新後再設定 uptime */ + + ptt->uptime = ptt->touchtime ; +#if !defined(_BBS_UTIL_C_) + log_usies("CACHE", "reload pttcache"); +#endif + ptt->busystate = 0; + } +} + +void resolve_garbage() { + int count=0; + + if(ptt == NULL) { + ptt = attach_shm(PTTSHM_KEY, sizeof(*ptt)); + if(ptt->touchtime == 0) + ptt->touchtime = 1; + } + while(ptt->uptime < ptt->touchtime) { /* 不用while等 */ + reload_pttcache(); + if(count ++ > 10 && ptt->busystate) { +/* Ptt: 這邊會有問題 load超過10 秒會所有進loop的process都讓 busystate = 0 + 這樣會所有prcosee都會在load 動態看板 會造成load大增 + 但沒有用這個function的話 萬一load passwd檔的process死了 又沒有人把他 + 解開 同樣的問題發生在reload passwd +*/ + ptt->busystate = 0; +#ifndef _BBS_UTIL_C_ + log_usies("CACHE", "refork Ptt dead lock"); +#endif + } + } +} + +/*-------------------------------------------------------*/ +/* PTT's cache */ +/*-------------------------------------------------------*/ +/* cachefor from host 與最多上線人數 */ +struct fromcache_t *fcache; + +static void reload_fcache() { + if(fcache->busystate) + safe_sleep(1); + else { + FILE *fp; + + fcache->busystate = 1; + bzero(fcache->domain, sizeof fcache->domain); + if((fp = fopen("etc/domain_name_query","r"))) { + char buf[256],*po; + + fcache->top=0; + while(fgets(buf, sizeof(buf),fp)) { + if(buf[0] && buf[0] != '#' && buf[0] != ' ' && + buf[0] != '\n') { + sscanf(buf,"%s",fcache->domain[fcache->top]); + po = buf + strlen(fcache->domain[fcache->top]); + while(*po == ' ') + po++; + strncpy(fcache->replace[fcache->top],po,49); + fcache->replace[fcache->top] + [strlen(fcache->replace[fcache->top])-1] = 0; + (fcache->top)++; + if(fcache->top == MAX_FROM) + break; + } + } + } + + fcache->max_user=0; + + /* 等所有資料更新後再設定 uptime */ + fcache->uptime = fcache->touchtime; +#if !defined(_BBS_UTIL_C_) + log_usies("CACHE", "reload fcache"); +#endif + fcache->busystate = 0; + } +} + +void resolve_fcache() { + if(fcache == NULL) { + fcache = attach_shm(FROMSHM_KEY, sizeof(*fcache)); + if(fcache->touchtime == 0) + fcache->touchtime = 1; + } + while(fcache->uptime < fcache->touchtime) + reload_fcache(); +} + +extern time_t login_start_time; +extern char *fn_visable; +FILE *DEBUG = NULL; + +void hbflreload(int bid) +{ + int hbfl[MAX_FRIEND + 1], i, num, uid; + char buf[128]; + FILE *fp; + + memset(hbfl, 0, sizeof(hbfl)); + setbfile(buf, bcache[bid-1].brdname, fn_visable); + if( (fp = fopen(buf, "r")) != NULL ){ + for( num = 1 ; num <= MAX_FRIEND ; ++num ){ + if( fgets(buf, sizeof(buf), fp) == NULL ) + break; + for( i = 0 ; buf[i] != 0 ; ++i ) + if( buf[i] == ' ' ){ + buf[i] = 0; + break; + } + if( strcasecmp("guest", buf) == 0 || + (uid = searchuser(buf)) == 0 ) { + --num; + continue; + } + hbfl[num] = uid; + } + fclose(fp); + } + hbfl[0] = time(NULL); + memcpy(uhash->hbfl[bid], hbfl, sizeof(hbfl)); +} + +int hbflcheck(int bid, int uid) +{ + int i; + + if( uhash->hbfl[bid][0] < login_start_time - HBFLexpire ) + hbflreload(bid); + for( i = 1 ; uhash->hbfl[bid][i] != 0 && i <= MAX_FRIEND ; ++i ){ + if( uhash->hbfl[bid][i] == uid ) + return 0; + } + return 1; +} |