精華區beta SetupBBS 關於我們 聯絡資訊
/*-------------------------------------------------------*/ /* cache.c ( NTHU CS MapleBBS Ver 2.36 ) */ /*-------------------------------------------------------*/ /* target : cache up data by shared memory */ /* create : 95/03/29 */ /* update : 95/12/15 */ /*-------------------------------------------------------*/ #include "bbs.h" #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #ifdef HAVE_MMAP #include <sys/mman.h> #else int usernumber; #endif struct UCACHE *uidshm; #if defined(_BBS_UTIL_C_) void setapath(buf, boardname) char *buf, *boardname; { sprintf(buf, "man/boards/%s", boardname); } char *str_dotdir = ".DIR"; void setadir(buf, path) char *buf, *path; { sprintf(buf, "%s/%s", path, str_dotdir); } #endif static void attach_err(shmkey, name) int shmkey; char *name; { fprintf(stderr, "[%s error] key = %x\n", name, shmkey); exit(1); } static void * attach_shm(shmkey, shmsize) int shmkey, shmsize; { void *shmptr; int shmid; 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"); memset(shmptr, 0, shmsize); } else { shmptr = (void *) shmat(shmid, NULL, 0); if (shmptr == (void *) -1) attach_err(shmkey, "shmat"); } return shmptr; } /* ----------------------------------------------------- */ /* semaphore : for critical section */ /* ----------------------------------------------------- */ #define SEM_FLG 0600 /* semaphore mode */ void /* sem_init(BSEM_KEY,&ap_semid) */ sem_init(int semkey,int *semid) { *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, 1); } } void sem_lock(int op,int semid) /* sem_lock(SEM_LEAVE,ap_semid) */ { struct sembuf sops; sops.sem_num = 0; sops.sem_flg = SEM_UNDO; sops.sem_op = op; semop(semid, &sops, 1); } /*-------------------------------------------------------*/ /* .PASSWDS cache */ /*-------------------------------------------------------*/ #ifndef HAVE_MMAP static int fillucache(uentp) userec *uentp; { if (usernumber < MAXUSERS) { strncpy(uidshm->userid[usernumber], uentp->userid, IDLEN + 1); uidshm->userid[usernumber++][IDLEN] = '\0'; } return 0; } #endif /* -------------------------------------- */ /* (1) 系統啟動後,第一個 BBS user 剛進來 */ /* (2) .PASSWDS 更新時 */ /* -------------------------------------- */ reload_ucache() { if (uidshm->busystate) { /* ------------------------------------------ */ /* 其他 user 正在 flushing ucache ==> CSMA/CD */ /* ------------------------------------------ */ if (uidshm->touchtime - uidshm->uptime > 30) { uidshm->busystate = 0; /* leave busy state */ #if !defined(_BBS_UTIL_C_) log_usies("CACHE", "refork token"); #endif } else sleep(1); } else { uidshm->busystate = 1; /* enter busy state */ #ifdef HAVE_MMAP { register int fd, usernumber; usernumber = 0; if ((fd = open(".PASSWDS", O_RDONLY)) > 0) { caddr_t fimage, mimage; struct stat stbuf; fstat(fd, &stbuf); fimage = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); if (fimage == (char *) -1) exit(-1); close(fd); fd = stbuf.st_size / sizeof(userec); if (fd > MAXUSERS) fd = MAXUSERS; for (mimage = fimage; usernumber < fd; mimage += sizeof(userec)) { memcpy(uidshm->userid[usernumber++], mimage, IDLEN); } munmap(fimage, stbuf.st_size); } uidshm->number = usernumber; } #else usernumber = 0; apply_record(".PASSWDS", fillucache, sizeof(userec)); uidshm->number = usernumber; #endif /* 等 user 資料更新後再設定 uptime */ uidshm->uptime = uidshm->touchtime; #if !defined(_BBS_UTIL_C_) log_usies("CACHE", "reload ucache"); #endif uidshm->busystate = 0; /* leave busy state */ } } void resolve_ucache() { if (uidshm == NULL) { uidshm = attach_shm(UIDSHM_KEY, sizeof(*uidshm)); if (uidshm->touchtime == 0) uidshm->touchtime = 1; } while (uidshm->uptime < uidshm->touchtime) reload_ucache(); } int ci_strcmp(s1, s2) register char *s1, *s2; { register int c1, c2, diff; do { c1 = *s1++; c2 = *s2++; if (c1 >= 'A' && c1 <= 'Z') c1 |= 32; if (c2 >= 'A' && c2 <= 'Z') c2 |= 32; if (diff = c1 - c2) return (diff); } while (c1); return 0; } int searchuser(userid) char *userid; { register char *ptr; register int i, j; resolve_ucache(); i = 0; j = uidshm->number; while (i < j) { ptr = uidshm->userid[i++]; if (!ci_strcmp(ptr, userid)) { strcpy(userid, ptr); return i; } } return 0; } #if !defined(_BBS_UTIL_C_) int getuser(userid) char *userid; { int uid; if (uid = searchuser(userid)) get_record(fn_passwd, &xuser, sizeof(xuser), uid); return uid; } char * getuserid(num) int num; { if (--num >= 0 && num < MAXUSERS) { return ((char *) uidshm->userid[num]); } return NULL; } void setuserid(num, userid) int num; char *userid; { if (num > 0 && num <= MAXUSERS) { if (num > uidshm->number) uidshm->number = num; strncpy(uidshm->userid[num - 1], userid, IDLEN + 1); } } int searchnewuser(mode) int mode; /* 0 ==> 找過期帳號 */ /* 1 ==> 建立新帳號 */ { register int i, num; resolve_ucache(); num = uidshm->number; i = 0; while (i < num) { if (!uidshm->userid[i++][0]) return (i); } if (mode && (num < MAXUSERS)) return (num + 1); return 0; } #if 0 int apply_users(func) void (*func) (); { register int i, num; resolve_ucache(); num = uidshm->number; for (i = 0; i < num; i++) (*func) (uidshm->userid[i], i + 1); return 0; } #endif char * u_namearray(buf, pnum, tag) char buf[][IDLEN + 1], *tag; int *pnum; { register struct UCACHE *reg_ushm = uidshm; register char *ptr, tmp; register int n, total; char tagbuf[STRLEN]; int ch, ch2, num; resolve_ucache(); 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]; } /*-------------------------------------------------------*/ /* .UTMP cache */ /*-------------------------------------------------------*/ struct UTMPFILE *utmpshm; user_info *currutmp; void resolve_utmp() { if (utmpshm == NULL) { utmpshm = attach_shm(UTMPSHM_KEY, sizeof(*utmpshm)); if (utmpshm->uptime == 0) utmpshm->uptime = utmpshm->number = 1; } } void setutmpmode(mode) int mode; { if (currstat != mode) currutmp->mode = currstat = mode; } /* woju */ resetutmpent() { extern int errno; register time_t now; register int i; register pid_t pid; register user_info *uentp; resolve_utmp(); now = time(NULL) - 79; if (now > utmpshm->uptime) utmpshm->busystate = 0; while (utmpshm->busystate) { sleep(1); } utmpshm->busystate = 1; /* ------------------------------ */ /* for 幽靈傳說: 每 79 秒更新一次 */ /* ------------------------------ */ for (i = now = 0; i < USHM_SIZE; i++) { uentp = &(utmpshm->uinfo[i]); if (pid = uentp->pid) { if ((kill(pid, 0) == -1) && (errno == ESRCH)) memset(uentp, 0, sizeof(user_info)); else now++; } } utmpshm->number = now; time(&utmpshm->uptime); utmpshm->busystate = 0; } void getnewutmpent(up) user_info *up; { extern int errno; register time_t now; register int i; register pid_t pid; register user_info *uentp; resolve_utmp(); now = time(NULL) - 79; if (now > utmpshm->uptime) utmpshm->busystate = 0; while (utmpshm->busystate) { sleep(1); } utmpshm->busystate = 1; /* ------------------------------ */ /* for 幽靈傳說: 每 79 秒更新一次 */ /* ------------------------------ */ if (now > utmpshm->uptime) { for (i = now = 0; i < USHM_SIZE; i++) { uentp = &(utmpshm->uinfo[i]); if (pid = uentp->pid) { if ((kill(pid, 0) == -1) && (errno == ESRCH)) memset(uentp, 0, sizeof(user_info)); else now++; } } utmpshm->number = now; time(&utmpshm->uptime); } for (i = 0; i < USHM_SIZE; i++) { uentp = &(utmpshm->uinfo[i]); if (!(uentp->pid)) { memcpy(uentp, up, sizeof(user_info)); currutmp = uentp; utmpshm->number++; utmpshm->busystate = 0; return; } } utmpshm->busystate = 0; sleep(1); exit(1); } int apply_ulist(fptr) int (*fptr) (); { register user_info *uentp; register int i, state; resolve_utmp(); 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; } user_info * search_ulist(fptr, farg) int (*fptr) (); int farg; { register int i; register user_info *uentp; resolve_utmp(); for (i = 0; i < USHM_SIZE; i++) { uentp = &(utmpshm->uinfo[i]); if ((*fptr) (farg, uentp)) return uentp; } return 0; } int count_multi() { register int i, j; register user_info *uentp; resolve_utmp(); for (i = j = 0; i < USHM_SIZE; i++) { uentp = &(utmpshm->uinfo[i]); if (uentp->uid == usernum) j++; } return j; } /* -------------------- */ /* for multi-login talk */ /* -------------------- */ user_info * search_ulistn(fptr, farg, unum) int (*fptr) (); int farg; int unum; { register int i, j; register user_info *uentp; resolve_utmp(); for (i = j = 0; i < USHM_SIZE; i++) { uentp = &(utmpshm->uinfo[i]); if ((*fptr) (farg, uentp)) { if (++j == unum) return uentp; } } return 0; } int count_logins(fptr, farg, show) int (*fptr) (); int farg; int show; { register user_info *uentp; register int i, j; resolve_utmp(); for (i = j = 0; i < USHM_SIZE; i++) { uentp = &(utmpshm->uinfo[i]); if ((*fptr) (farg, uentp)) { j++; if (show) { prints("(%d) 目前狀態為: %-17.16s(來自 %s)\n", j, modestring(uentp, 0), uentp->from); } } } return j; } void purge_utmp(uentp) user_info *uentp; { memset(uentp, 0, sizeof(user_info)); if (utmpshm->number) utmpshm->number--; } int count_ulist() { int ans = utmpshm->number; register user_info *uentp; int ch = 0; while (ch < USHM_SIZE) { uentp = &(utmpshm->uinfo[ch++]); if (uentp->pid && ( is_rejected(uentp) & 2 && !HAS_PERM(PERM_SYSOP) || uentp->invisible && !HAS_PERM(PERM_SEECLOAK) &!HAS_PERM(PERM_SYSOP) || !PERM_HIDE(currutmp) && PERM_HIDE(uentp) || cuser.uflag & FRIEND_FLAG && !is_friend(uentp) )) --ans; } return ans; } /*-------------------------------------------------------*/ /* .BOARDS cache */ /*-------------------------------------------------------*/ struct BCACHE *brdshm; boardheader *bcache; int numboards = -1; /* force re-caching */ void touch_boards() { time(&(brdshm->touchtime)); numboards = -1; } reload_bcache() { if (brdshm->busystate) { sleep(1); } else { int fd; brdshm->busystate = 1; if ((fd = open(fn_board, O_RDONLY)) > 0) { brdshm->number = read(fd, bcache, MAXBOARD * sizeof(boardheader)) / sizeof(boardheader); close(fd); } /* 等所有 boards 資料更新後再設定 uptime */ brdshm->uptime = brdshm->touchtime; #if !defined(_BBS_UTIL_C_) log_usies("CACHE", "reload bcache"); #endif brdshm->busystate = 0; } } 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; } int apply_boards(func) int (*func) (); { register int i; register boardheader *bhdr; resolve_boards(); for (i = 0, bhdr = bcache; i < numboards; i++, bhdr++) { if (Ben_Perm(bhdr)) if ((*func) (bhdr) == QUIT) return QUIT; } return 0; } boardheader * getbcache(bname) char *bname; { register int i; register boardheader *bhdr; resolve_boards(); for (i = 0, bhdr = bcache; i < numboards; i++, bhdr++) /* if (Ben_Perm(bhdr)) */ if (!ci_strcmp(bname, bhdr->brdname)) return bhdr; return NULL; } int getbnum(bname) char *bname; { register int i; register boardheader *bhdr; resolve_boards(); for (i = 0, bhdr = bcache; i++ < numboards; bhdr++) /* if (Ben_Perm(bhdr)) */ if (!ci_strcmp(bname, bhdr->brdname)) return i; return 0; } int haspostperm(bname) char *bname; { register int i; char buf[200]; /* if (currmode & MODE_DIGEST || currmode & MODE_ETC) return 0; */ setbfile(buf, bname, fn_water); if (belong(buf, cuser.userid)) return 0; if (!ci_strcmp(bname, DEFAULT_BOARD)) return 1; if (!cuser.userlevel) { char *ptr; if (belong("etc/anonymous", cuser.userid)) { while (ptr = strtok(NULL, str_space)) { if (!ci_strcmp(bname, ptr)) return 1; } } return 0; } if (!HAS_PERM(PERM_POST)) return 0; if (!(i = getbnum(bname))) return 0; i = bcache[i - 1].level; /* 秘密看板特別處理 */ if ((i & 0xffff) == PERM_SYSOP) return 1; return (HAS_PERM(i & ~PERM_POSTMASK & ~PERM_POST)); } /*-------------------------------------------------------*/ /* PTT cache */ /*-------------------------------------------------------*/ /* cachefor 動態看版 */ struct PTTCACHE *ptt; int ptt_semid; void reload_pttcache() { if (ptt->busystate) { sleep(1); } else { int fd; fileheader item; char pbuf[256], buf[256]; FILE *fp; int num, id, j; sem_init(PTTSEM_KEY,&ptt_semid); sem_lock(SEM_ENTER,ptt_semid); ptt->busystate = 1; ptt->max_film = 0; bzero(ptt->notes, sizeof ptt->notes); setapath(pbuf, "Note"); setadir(buf, pbuf); num = get_num_records(buf, sizeof item); for (j = 0; j <= num; j++) if (get_record(buf, &item, sizeof item, j) != -1) if (item.title[3] == '<' && item.title[7] == '>' ) { id = (item.title[4] - '0') * 100 + (item.title[5] - '0') * 10 + item.title[6] - '0'; if (id < MAX_MOVIE) { if (ptt->max_film < id) ptt->max_film = id; strcpy(ptt->notes[id], item.filename); } } ptt->max_history = ptt->max_film - 2; if (ptt->max_history > MAX_HISTORY - 1) ptt->max_history = MAX_HISTORY - 1; { FILE *fp=fopen("etc/today_is","r"); char *chr; 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 sem_lock(SEM_LEAVE,ptt_semid); ptt->busystate = 0; } } void resolve_garbage() { if (ptt == NULL) { ptt = attach_shm(PTTSHM_KEY, sizeof(*ptt)); if (ptt->touchtime == 0) ptt->touchtime = 1; } while (ptt->uptime < ptt->touchtime) reload_pttcache(); } /*-------------------------------------------------------*/ /* PTT's cache */ /*-------------------------------------------------------*/ /* cachefor from host 與最多上線人數 */ struct FROMCACHE *fcache; int fcache_semid; reload_fcache() { if (fcache->busystate) { sleep(1); } else { FILE *fp; sem_init(FROMSEM_KEY,&fcache_semid); sem_lock(SEM_ENTER,fcache_semid); fcache->busystate = 1; bzero(fcache->domain, sizeof fcache->domain); if(fp=fopen("etc/domain_name_query","r")) { char buf[101],*po; fcache->top=0; while (fgets(buf,100,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)++; } } } fcache->max_user=0; /* 等所有資料更新後再設定 uptime */ fcache->uptime = fcache->touchtime; #if !defined(_BBS_UTIL_C_) log_usies("CACHE", "reload fcache"); #endif sem_lock(SEM_LEAVE,fcache_semid); 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(); } /*-------------------------------------------------------*/ /* PTT's cache userlink */ /*-------------------------------------------------------*/ /* cachefor from host 與最多上線人數 */ struct LINKUSER *luser; void resolve_luser() { if (luser == NULL) { luser = attach_shm(LINKSHM_KEY, sizeof(*luser)); if (luser->touchtime == 0) luser->touchtime = 1; } } #endif !defined(_BBS_UTIL_C_)