summaryrefslogblamecommitdiffstats
path: root/util/util_cache.c
blob: a8dd6b71df1f03d3b397768a0a3027395d0b1f62 (plain) (tree)
1
                                                            


























                          





















                                                               
                                                              
























































































                                                                          


                        
                       















                                                                         


                             
 

                                   
                           
                            
                            


                                  
                                          

                               
                                                     

                                                  
                            

 










                                                                   
                               
    
                             

                        
                                     
                                
                                   




                                                             

                                        

                              
                                     
               
                                  




                              

                                                      

                            
                          

                    

                                                    

                         
                                 










                                  
 

                                       

                              








                                                           
                     



                                                  












                                    
                                 


                                                  
                          











                                            
                                 












                                                                    
                                 








                                                           
                                  



















                                                                                
     






























                                                                     
     

 
                       



                                

     
                                      
                        
                             


                     
                             





                         
                   
                    
                        
    
                        

                                                                 
                                            
                

                                                                  
     
                        






                                                 

                                   

















                                                           


                          






                                                                           


                                             









                                                              
                                                                            





                                                                     

                                                                        











                                                                       





                                                     


                                       

                                                  
                         
                                  




                                           

                                        





                        



                                
     
                                                             
                          
                                              




                                                                          
                                







                                                           
                             
                       



                      

                                               


                                                       
                       


                                                              

                                                             

                                     



                                                               



                        
                        

                                           

                                       



                       



                                
     
                                         

                        
/* $Id: util_cache.c,v 1.11 2003/05/16 18:58:49 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 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 \xa4\xa3\xaf\xe0\xb3\xe6\xbfW\xa9I\xa5s \xa9I\xa5sreload
_bcache or reset_board */
    for (i = 0; i < SHM->Bnumber; i++) {
        SHM->bsorted[1][i] = SHM->bsorted[0][i] = &bcache[i];
    }
    qsort(SHM->bsorted[0], SHM->Bnumber, sizeof(boardheader_t *),
          (QCAST) cmpboardname);
    qsort(SHM->bsorted[1], SHM->Bnumber, sizeof(boardheader_t *),
          (QCAST) cmpboardclass);
}


static void
reload_bcache()
{
    if (SHM->Bbusystate) {
        safe_sleep(1);
    }
    else {
        int             fd, i;

        SHM->Bbusystate = 1;
        if ((fd = open(fn_board, O_RDONLY)) > 0) {
            SHM->Bnumber =
                read(fd, bcache, MAX_BOARD * sizeof(boardheader_t)) /
                sizeof(boardheader_t);
            close(fd);
        }
        memset(SHM->lastposttime, 0, MAX_BOARD * sizeof(time_t));
        SHM->Buptime = SHM->Btouchtime;
        sort_bcache();
        for (i = 0; i < SHM->Bnumber; ++i) {
            bcache[i].firstchild[0] = NULL;
            bcache[i].firstchild[1] = NULL;
        }
        SHM->Bbusystate = 0;
    }
}

void resolve_boards() {
    if(SHM == NULL) {
    attach_SHM();
    if(SHM->Btouchtime == 0)
        SHM->Btouchtime = 1;
    }

    if(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();
}