void resolve_utmp() { int iscreate; if (utmpshm == NULL) { utmpshm = (struct UTMPFILE *) attach_shm("UTMP_SHMKEY", 3699, sizeof(*utmpshm), &iscreate); /*attach user tmp cache */ if (iscreate) { int i, utmpfd; utmphead = (struct UTMPHEAD *) attach_shm("UTMPHEAD_SHMKEY", 3698, sizeof(struct UTMPHEAD), &iscreate); /*attach user tmp cache */ utmpfd = utmp_lock(); bzero(utmpshm, sizeof(struct UTMPFILE)); bzero(utmphead, sizeof(struct UTMPHEAD)); utmphead->number = 0; utmphead->hashhead[0] = 1; for (i = 0; i < USHM_SIZE - 1; i++) utmphead->next[i] = i + 2; utmphead->next[USHM_SIZE - 1] = 0; /* utmphead->listhead=0; */ utmp_unlock(utmpfd); } else utmphead = (struct UTMPHEAD *) attach_shm1("UTMPHEAD_SHMKEY", 3698, sizeof(struct UTMPHEAD), &iscreate, 0, NULL); /*attach user tmp head */ } }
// Refreshes utmp(cache for online users.) int refresh_utmp(void) { int utmpfd, ucachefd; struct user_info *uentp; int n; int count = 0; // Online users count. time_t now; resolve_utmp(); if (resolve_ucache() == -1) return -1; now = time(NULL); // Lock caches. utmpfd = utmp_lock(); if (utmpfd == -1) return -1; ucachefd = ucache_lock(); if (ucachefd == -1) return -1; memset(uidshm->status, 0, sizeof(uidshm->status)); for (n = 0; n < USHM_SIZE; n++) { uentp = &(utmpshm->uinfo[n]); if (uentp->active && uentp->pid) { // See if pid exists. if (bbskill(uentp, 0) == -1) { memset(uentp, 0, sizeof(struct user_info)); continue; } else { // Kick idle users out. if (uentp->mode != BBSNET && now - uentp->idle_time > IDLE_TIMEOUT) { bbskill(uentp, SIGHUP); memset(uentp, 0, sizeof(struct user_info)); } else { // Increase status. uidshm->status[uentp->uid - 1]++; // Count online users. ++count; } } } } utmpshm->total_num = count; // Get count of all users from ucache. utmpshm->usersum = allusers(); // Unlock caches. ucache_unlock(ucachefd); utmp_unlock(utmpfd); return count; }
void clear_utmp(int uent, int useridx, int pid) { int lockfd; /* ulock todo: use user lock */ lockfd = utmp_lock(); utmp_setreadonly(0); if (((useridx == 0) || (utmpshm->uinfo[uent - 1].uid == useridx)) && pid == utmpshm->uinfo[uent - 1].pid) clear_utmp2(uent); utmp_setreadonly(1); utmp_unlock(lockfd); }
int getnewutmpent(struct user_info *up) { int utmpfd, ucachefd; struct user_info *uentp; int i; resolve_utmp(); if (resolve_ucache() == -1) return -1; utmpfd=utmp_lock(); if (utmpfd == -1) { return -1; } if (utmpshm->max_login_num < get_online()) utmpshm->max_login_num = get_online(); for (i = 0; i < USHM_SIZE; i++) { uentp = &(utmpshm->uinfo[i]); if (!uentp->active || !uentp->pid) break; } if (i >= USHM_SIZE) { utmp_unlock(utmpfd); return -2; } utmpshm->uinfo[i] = *up; utmpshm->total_num++; utmp_unlock(utmpfd); ucachefd=ucache_lock(); uidshm->status[up->uid-1]++; ucache_unlock(ucachefd); return i + 1; }
/* same as getnewutmpent() except no updating of utmpshm * only called in www */ int getnewutmpent2(struct user_info *up, int is_www) { int pos, i,ret; int utmpfd, hashkey; utmpfd = utmp_lock(); utmp_setreadonly(0); up->utmpkey = rand() % 100000000; pos = utmphead->hashhead[0] - 1; if (pos == -1) { ret=-1; } else { /* add to sorted list */ if (!utmphead->listhead) { /* init the list head */ utmphead->list_prev[pos] = pos + 1; utmphead->list_next[pos] = pos + 1; utmphead->listhead = pos + 1; } else { int i; i = utmphead->listhead; if (strcasecmp(utmpshm->uinfo[i - 1].userid, up->userid) >= 0) { /* add to head */ utmphead->list_prev[pos] = utmphead->list_prev[i - 1]; utmphead->list_next[pos] = i; utmphead->list_prev[i - 1] = pos + 1; utmphead->list_next[utmphead->list_prev[pos] - 1] = pos + 1; utmphead->listhead = pos + 1; } else { int count; count = 0; i = utmphead->list_next[i - 1]; while ((strcasecmp(utmpshm->uinfo[i - 1].userid, up->userid) < 0) && (i != utmphead->listhead)) { i = utmphead->list_next[i - 1]; count++; if (count > USHM_SIZE) { utmphead->listhead = 0; bbslog("3system", "UTMP:maybe loop rebuild..!"); apply_ulist((APPLY_UTMP_FUNC) rebuild_list, NULL); utmp_setreadonly(1); utmp_unlock(utmpfd); exit(-1); } } utmphead->list_prev[pos] = utmphead->list_prev[i - 1]; utmphead->list_next[pos] = i; utmphead->list_prev[i - 1] = pos + 1; utmphead->list_next[utmphead->list_prev[pos] - 1] = pos + 1; } } utmphead->hashhead[0] = utmphead->next[pos]; if (utmpshm->uinfo[pos].active) if (utmpshm->uinfo[pos].pid) { bbslog("3system", "utmp: alloc a active utmp! old:%s new:%s", utmpshm->uinfo[pos].userid, up->userid); kill(utmpshm->uinfo[pos].pid, SIGHUP); } utmpshm->uinfo[pos] = *up; hashkey = utmp_hash(up->userid); i = utmphead->hashhead[hashkey]; /* not need sort */ utmphead->next[pos] = i; utmphead->hashhead[hashkey] = pos + 1; utmphead->number++; setpublicshmreadonly(0); if (!is_www) { get_publicshm()->logincount ++; } else { get_publicshm()->wwwlogincount ++; } setpublicshmreadonly(1); ret=pos+1; } utmp_setreadonly(1); utmp_unlock(utmpfd); return ret; }
int getnewutmpent(struct user_info *up, int is_www) { struct user_info *uentp; time_t now; int pos, n, i,ret; int utmpfd, hashkey; utmpfd = utmp_lock(); utmp_setreadonly(0); up->utmpkey=rand() % 100000000; pos = utmphead->hashhead[0] - 1; if (pos == -1) { ret=-1; } else { /* add to sorted list */ if (!utmphead->listhead) { /* init the list head */ utmphead->list_prev[pos] = pos + 1; utmphead->list_next[pos] = pos + 1; utmphead->listhead = pos + 1; } else { int i; i = utmphead->listhead; if (strcasecmp(utmpshm->uinfo[i - 1].userid, up->userid) >= 0) { /* add to head */ utmphead->list_prev[pos] = utmphead->list_prev[i - 1]; utmphead->list_next[pos] = i; utmphead->list_prev[i - 1] = pos + 1; utmphead->list_next[utmphead->list_prev[pos] - 1] = pos + 1; utmphead->listhead = pos + 1; } else { int count; count = 0; i = utmphead->list_next[i - 1]; while ((strcasecmp(utmpshm->uinfo[i - 1].userid, up->userid) < 0) && (i != utmphead->listhead)) { i = utmphead->list_next[i - 1]; count++; if (count > USHM_SIZE) { utmphead->listhead = 0; bbslog("3system", "UTMP:maybe loop rebuild!"); apply_ulist((APPLY_UTMP_FUNC) rebuild_list, NULL); utmp_setreadonly(1); utmp_unlock(utmpfd); exit(-1); } } utmphead->list_prev[pos] = utmphead->list_prev[i - 1]; utmphead->list_next[pos] = i; utmphead->list_prev[i - 1] = pos + 1; utmphead->list_next[utmphead->list_prev[pos] - 1] = pos + 1; } } /* */ utmphead->hashhead[0] = utmphead->next[pos]; if (utmpshm->uinfo[pos].active) if (utmpshm->uinfo[pos].pid) { bbslog("3system", "utmp: alloc a active utmp! old:%s new:%s", utmpshm->uinfo[pos].userid, up->userid); kill(utmpshm->uinfo[pos].pid, SIGHUP); } utmpshm->uinfo[pos] = *up; hashkey = utmp_hash(up->userid); i = utmphead->hashhead[hashkey]; /* not need sort */ utmphead->next[pos] = i; utmphead->hashhead[hashkey] = pos + 1; utmphead->number++; setpublicshmreadonly(0); if (!is_www) { get_publicshm()->logincount ++; } else { get_publicshm()->wwwlogincount ++; } setpublicshmreadonly(1); if (get_utmp_number() + getwwwguestcount()>get_publicshm()->max_user) { setpublicshmreadonly(0); save_maxuser(); setpublicshmreadonly(1); } now = time(NULL); if ((now > utmphead->uptime + 120) || (now < utmphead->uptime - 120)) { utmphead->uptime = now; newbbslog(BBSLOG_USIES, "UTMP:Clean user utmp cache"); for (n = 0; n < USHM_SIZE; n++) { utmphead->uptime = now; uentp = &(utmpshm->uinfo[n]); if ((uentp->pid == 1) && ((now - uentp->freshtime) < IDLE_TIMEOUT)) { continue; } if (uentp->active && uentp->pid && kill(uentp->pid, 0) == -1) { /*uentp检查 */ char buf[STRLEN]; strncpy(buf, uentp->userid, IDLEN + 2); clear_utmp2(n + 1); /* 不需要再lock了 */ RemoveMsgCountFile(buf); } } } ret=pos+1; } utmp_setreadonly(1); utmp_unlock(utmpfd); return ret; }
int main(void) { int n,prev,pos,next,nn,ppd; int pig=0; int i,j;//,k; //int inlist=0; int utmpfd;//, hashkey; init_all(); pos=-1; #if 1 utmpfd = utmp_lock(); utmphead->hashhead[0]=0; for (i = 0; i <= USHM_SIZE - 1; i++) { if (!utmpshm->uinfo[i].active) { add_empty(i+1); } } utmp_unlock(utmpfd); printf("end\n"); // return; #endif j=0; for(i = utmphead->hashhead[0]; i; i = utmphead->next[i - 1]) j++; printf("items on hashhead[0] chain:%d\n",j); j=0; pig=0; for(i=0;i<USHM_SIZE;i++){ if (!utmpshm->uinfo[i].active) j++; else pig++; } printf("direct iteration: inactive:%d, active:%d\n",j,pig); pig=0; for(n=1;n<=UTMP_HASHSIZE;n++) { ppd=false; next = utmphead->hashhead[n]; prev = -1; while(next) { nn = utmphead->next[next - 1]; if (!utmpshm->uinfo[next - 1].active) { if (pos==-1) pos=prev; //printf("%d, %d, %s\n", next, nn, utmpshm->uinfo[next - 1].userid); ppd=true; } else { int hash = utmp_hash(getuserid2(utmpshm->uinfo[next - 1].uid)); if (hash!=n) { printf("utmp_hash err: %d %d %d %d %s\n", n, next, utmphead->hashhead[n], nn, getuserid2(utmpshm->uinfo[next - 1].uid)); if (0) { if (utmphead->hashhead[n] == next) { utmphead->hashhead[n] = nn; } else { utmphead->next[prev - 1] = nn; } } } } prev = next; next = nn; pig++; } if(ppd) printf("ERROR:%d,%d,%d\n", n, utmphead->hashhead[n], pos); } printf("active: %d, total: %d\n", pig, pig+j); n=utmphead->listhead; pig=0; prev=-1; while(n) { pig++; if (prev>0) { if (strcasecmp(utmpshm->uinfo[prev-1].userid, utmpshm->uinfo[n-1].userid) > 0) { printf("list chain error: %d %d\n", prev, n); } } prev=n; n=utmphead->list_next[n-1]; if (utmphead->list_prev[n-1]!=prev) { printf("list chain list_prev error: %d %d\n", prev, n); } if (n==utmphead->listhead) { break; } } printf("active on list chain: %d\n", pig); // return 0; #if 0 for (i = 0; i <= USHM_SIZE - 1; i++) { if (!utmpshm->uinfo[i].active) { if(!in_hash(i+1)){ //printf("%d empty but not in hash\n", i); pig ++; if(in_list(i)) inlist++; //if(pig >=40) break; } } } printf("%d total,%d inlist\n", pig, inlist); if(i==USHM_SIZE) return; return; k=utmphead->listhead; for(j=utmphead->list_next[k-1]; j!=k && j; j=utmphead->list_next[j-1]){ if(j==i+1) printf("in listhead\n"); } return; #endif pig=0; next = utmphead->hashhead[0]; while(next) { if (pos!=-1 &&pos==next) { printf("%d: on empty list\n", pos); return 0; } nn = utmphead->next[next - 1]; next = nn; pig++; } printf("%d %ld %ld\n", pig, utmphead->uptime, time(NULL)); time_t now = time(NULL); int web=0;int kick=0; pig=0; for (n = 0; n < USHM_SIZE; n++) { struct user_info *uentp = &(utmpshm->uinfo[n]); //printf("%d, %d\n", n, uentp->pid); if ((uentp->pid == 1) && ((now - uentp->freshtime) < IDLE_TIMEOUT)) { continue; } if (uentp->pid==0 && uentp->active) kick++; if (/*uentp->active &&*/ uentp->pid && kill(uentp->pid, 0) == -1) { /*uentp¼ì²é */ pig++; if(uentp->pid==1) web++; } } printf("killable: %d, web: %d, pid0: %d\n", pig, web, kick); return 0; }