/* * common.c * Copyright (C) 2008 KLab Inc. */ #include "makuosan.h" mopt moption; mfile *mftop[2] = {NULL,NULL}; mhost *members = NULL; int loop_flag = 1; struct timeval curtime; BF_KEY EncKey; char *sstatestrlist[9]={"SEND_STAT", "SEND_OPEN", "SEND_DATA", "SEND_MARK", "SEND_CLOSE", "SEND_LAST", "SEND_ERROR", "SEND_BREAK" "SEND_UNKNOWN"}; uint8_t sstatenumlist[9]={MAKUO_SENDSTATE_STAT, MAKUO_SENDSTATE_OPEN, MAKUO_SENDSTATE_DATA, MAKUO_SENDSTATE_MARK, MAKUO_SENDSTATE_CLOSE, MAKUO_SENDSTATE_LAST, MAKUO_SENDSTATE_ERROR, MAKUO_SENDSTATE_BREAK, MAKUO_STATE_MAX}; char *rstatestrlist[16] = {"RECV_NONE", "RECV_UPDATE", "RECV_SKIP", "RECV_OPEN", "RECV_MARK", "RECV_CLOSE", "RECV_IGNORE", "RECV_READONLY", "RECV_RETRY", "RECV_MD5OK", "RECV_MD5NG", "RECV_OPENERR", "RECV_READERR", "RECV_WRITEERR", "RECV_CLOSEERR", "RECV_UNKNOWN"}; uint8_t rstatenumlist[16]={MAKUO_RECVSTATE_NONE, MAKUO_RECVSTATE_UPDATE, MAKUO_RECVSTATE_SKIP, MAKUO_RECVSTATE_OPEN, MAKUO_RECVSTATE_MARK, MAKUO_RECVSTATE_CLOSE, MAKUO_RECVSTATE_IGNORE, MAKUO_RECVSTATE_READONLY, MAKUO_RECVSTATE_RETRY, MAKUO_RECVSTATE_MD5OK, MAKUO_RECVSTATE_MD5NG, MAKUO_RECVSTATE_OPENERROR, MAKUO_RECVSTATE_READERROR, MAKUO_RECVSTATE_WRITEERROR, MAKUO_RECVSTATE_CLOSEERROR, MAKUO_STATE_MAX}; char *SSTATE(uint8_t n) { int i; for(i=0;sstatenumlist[i] != MAKUO_STATE_MAX;i++){ if(sstatenumlist[i] == n){ break; } } return(sstatestrlist[i]); } char *RSTATE(uint8_t n) { int i; for(i=0;rstatenumlist[i] != MAKUO_STATE_MAX;i++){ if(rstatenumlist[i] == n){ break; } } return(rstatestrlist[i]); } int md5sum(int fd, unsigned char *digest) { int rd; char buff[1024]; MD5_CTX ctx; MD5_Init(&ctx); while(rd = read(fd, buff, sizeof(buff))){ if(rd == -1){ return(-1); } MD5_Update(&ctx, buff, rd); } MD5_Final(digest, &ctx); return(0); } /* * ã¿ã¤ã ã¢ã¦ãæéãçµéãã¦ãããã©ãããå¤æãã * - ç¾å¨æå»ãtfããmsec[ms]çµéãã¦ããã°1ãè¿ã * - ãã以å¤ã¯0ãè¿ã */ int mtimeout(struct timeval *tf, uint32_t msec) { struct timeval tv; struct timeval tr; tv.tv_sec = msec / 1000; tv.tv_usec = (msec % 1000) * 1000; timeradd(tf, &tv, &tr); return(timercmp(&tr, &curtime, <)); } /* * ç¾å¨æå»ãåå¾ãã * ï¼ã¨ãã£ã¦ãcurtimeãã³ãã¼ããã ãã ãã©ï¼ */ int mtimeget(struct timeval *tv) { memcpy(tv, &curtime, sizeof(curtime)); return(0); } /* * ãã¡ã¤ã«åãexcludeãªã¹ãã«ããããããã©ããã調ã¹ã * - ãããããå ´åã¯ãã®excludeitemæ§é ä½ã®ãã¤ã³ã¿ãè¿ã * - ãããããªãå ´åã¯NULLãè¿ã */ excludeitem *mfnmatch(char *str, excludeitem *exclude) { char *p; excludeitem *e; for(e=exclude;e;e=e->next){ p=str; while(*p){ if(strlen(p) < strlen(e->pattern)){ break; } if(!fnmatch(e->pattern, p, FNM_PATHNAME)){ return(e); } while(*p){ if(*(p++) == '/'){ break; } } } } return(NULL); } void fdprintf(int s, char *fmt, ...) { char m[2048]; va_list arg; if(s != -1){ va_start(arg, fmt); vsprintf(m, fmt, arg); va_end(arg); write(s, m, strlen(m)); } } void lprintf(int l, char *fmt, ...) { va_list arg; char msg[2048]; if(moption.loglevel >= l){ va_start(arg, fmt); vsprintf(msg, fmt, arg); va_end(arg); fprintf(stderr, "%s", msg); syslog(LOG_ERR, "%s: %s", moption.user_name, msg); } } void cprintf(int l, mcomm *c, char *fmt, ...) { char m[2048]; va_list arg; if(!c) return; if(c->fd[0] == -1) return; if(c->loglevel >= l){ va_start(arg, fmt); vsprintf(m, fmt, arg); va_end(arg); write(c->fd[0], m, strlen(m)); fsync(c->fd[0]); } } int getrid() { static int rid=0; return(rid++); } int workend(mcomm *c) { if(c){ if(c->working && !c->cpid){ c->working = 0; if(moption.commpass && !c->authchk){ cprintf(0, c, "password: \x1b]E"); }else{ cprintf(0,c,"> "); lprintf(1,"mexec: ======= separator =======\n"); } } } return(0); } void mfdel(mfile *m) { mfile *p; mfile *n; if(m){ if(p = (mfile *)m->prev) p->next = m->next; if(n = (mfile *)m->next) n->prev = m->prev; if(mftop[0] == m) mftop[0] = n; if(mftop[1] == m) mftop[1] = n; free(m); } } mfile *mfnew() { mfile *m; if(m = (mfile *)malloc(sizeof(mfile))){ memset(m, 0, sizeof(mfile)); m->mdata.head.vproto = PROTOCOL_VERSION; m->fd = -1; m->retrycnt = MAKUO_SEND_RETRYCNT; memcpy(&(m->addr), &(moption.maddr), sizeof(m->addr)); } return(m); } mfile *mfadd(int n) { mfile *m; if(m = mfnew()){ if(!mftop[n]){ mftop[n] =m; }else{ mfile *l; for(l=mftop[n];l->next;l=l->next); l->next = (void *)m; m->prev = (void *)l; m->next = NULL; } } return(m); } mfile *mfins(int n) { mfile *m; if(m = mfnew()){ if(mftop[n]){ mftop[n]->prev = m; m->next = mftop[n]; } mftop[n] =m; } return(m); } mhost *member_add(struct in_addr *addr, mdata *data) { int f = 1; int l = 0; mhost *t = NULL; mping *p = NULL; for(t=members;t;t=t->next) if(!(f=memcmp(&t->ad, addr, sizeof(t->ad)))) break; if(!t){ t = malloc(sizeof(mhost)); if(!t){ lprintf(0, "%s: out of memory\n", __func__); return(NULL); } memset(t, 0, sizeof(mhost)); memcpy(&t->ad, addr, sizeof(t->ad)); if(members){ members->prev = t; t->next = members; } members = t; t->hostname[0] = 0; } if(data){ if(data->head.opcode == MAKUO_OP_PING){ p = (mping *)data->data; l = ntohs(p->hostnamelen); data->p = p->data; memcpy(t->hostname, data->p, l); t->hostname[l] = 0; data->p += l; l = ntohs(p->versionlen); memcpy(t->version, data->p, l); t->version[l] = 0; } } if(f){ lprintf(0, "%s: %s (%s)\n", __func__, inet_ntoa(t->ad), t->hostname); } mtimeget(&(t->lastrecv)); return(t); } void member_del(mhost *t) { mfile *m; mhost *p; mhost *n; if(!t) return; lprintf(0, "%s: %s (%s)\n", __func__, inet_ntoa(t->ad), t->hostname); if(p = (mhost *)t->prev) p->next = t->next; if(n = (mhost *)t->next) n->prev = t->prev; if(members == t) members = n; free(t); } int seq_addmark(mfile *m, uint32_t lseq, uint32_t useq) { int i, j; int size = 0; void *n = NULL; mfile *a = NULL; if(!m->mark){ m->markcount = 0; m->marksize = 1024; m->mark = malloc(sizeof(uint32_t) * m->marksize); if(!m->mark){ lprintf(0, "%s: out of memory(mark)\n", __func__); return(-1); } } size = m->marksize; while(size < m->markcount + useq - lseq) size += 1024; if(size != m->marksize){ n = realloc(m->mark, sizeof(uint32_t) * size); if(!n){ lprintf(0, "%s: out of memory(realloc)\n", __func__); return(-1); } a = mfins(0); m->mark = n; m->marksize = size; } /***** mark ******/ for(i=lseq;i<useq;i++){ for(j=0;j<m->markcount;j++) if(i == m->mark[j]) break; if(j == m->markcount){ m->mark[m->markcount++] = i; } } /***** complaint *****/ if(a){ lprintf(2,"%s: complaint (%d/%d) %s\n", __func__, m->markcount, m->marksize, m->fn); a->mdata.head.flags |= MAKUO_FLAG_ACK; a->mdata.head.opcode = m->mdata.head.opcode; a->mdata.head.reqid = m->mdata.head.reqid; a->mdata.head.szdata = 0; a->mdata.head.seqno = m->mdata.head.seqno; a->mdata.head.nstate = MAKUO_RECVSTATE_RETRY; memcpy(&(a->addr), &(m->addr), sizeof(a->addr)); } return(0); } int seq_delmark(mfile *m, uint32_t seq) { int i; int r = 0; for(i=0;i<m->markcount;i++){ if(m->mark[i] == seq){ r = 1; m->markcount--; m->mark[i] = m->mark[m->markcount]; } } return(r); } int seq_popmark(mfile *m, int n) { char *s; char *d; int size = m->markcount - n; if(size > 0){ s = (char *)(m->mark + n); d = (char *)(m->mark + 0); memmove(d, s, size * sizeof(uint32_t)); m->markcount = size; }else{ m->markcount = 0; } } void clr_hoststate(mfile *m) { int i; mhost *t; for(t=members;t;t=t->next){ for(i=0;i<MAKUO_PARALLEL_MAX;i++){ if(t->mflist[i] == m){ t->mflist[i] = NULL; t->state[i] = 0; } } } } void dump_hoststate(mfile *m, char *func) { mhost *t; uint8_t *r; for(t=members;t;t=t->next){ if(r=get_hoststate(t,m)){ lprintf(9,"%s: rstate=%s from %s %s\n", func, RSTATE(*r), t->hostname, m->fn); } } } uint8_t *get_hoststate(mhost *t, mfile *m) { int i; int r; if(!t || !m){ return(NULL); } r = -1; for(i=0;i<MAKUO_PARALLEL_MAX;i++){ if(t->mflist[i] == m){ return(&(t->state[i])); }else{ if((r == -1) && !(t->mflist[i])){ r = i; } } } if(r != -1){ t->mflist[r] = m; return(&(t->state[r])); } return(NULL); } int ack_clear(mfile *m, int state) { uint8_t *s; mhost *t; for(t=members;t;t=t->next){ if(!m->sendto){ if(s = get_hoststate(t, m)){ if(state == -1 || *s == state){ *s = MAKUO_RECVSTATE_NONE; } } }else{ if(!memcmp(&(m->addr.sin_addr), &(t->ad), sizeof(m->addr.sin_addr))){ if(s = get_hoststate(t, m)){ if(state == -1 || *s == state){ *s = MAKUO_RECVSTATE_NONE; return(1); }else{ return(0); } } } } } if(m->sendto) return(-1); return(0); } /* æå®ããã¹ãã¼ã¿ã¹ãæã¤å¿çã¡ãã»ã¼ã¸ããããããã§ãã¯ãã * å¼æ° : * m: é信対象ã®ãã¡ã¤ã«ãªãã¸ã§ã¯ã * state: æ¤ç´¢ããã¹ãã¼ã¿ã¹ * * æ»ãå¤: * 0: è¦ã¤ãããªãã£ã * 1: è¦ã¤ãã£ã * -1: ãã¹ãæå®è»¢éãªã®ã«ãã¹ããªãã¸ã§ã¯ããè¦ã¤ãããªã */ int ack_check(mfile *m, int state) { uint8_t *s; mhost *t; for(t=members;t;t=t->next){ if(!m->sendto){ if(s=get_hoststate(t,m)){ if(*s == state){ return(1); } } }else{ if(!memcmp(&(m->addr.sin_addr), &(t->ad), sizeof(m->addr.sin_addr))){ if(s=get_hoststate(t,m)){ if(*s == state){ return(1); }else{ return(0); } } } } } if(m->sendto) return(-1); return(0); } int linkcmp(mfile *m) { ssize_t size; char ln[PATH_MAX]; if(m){ size = readlink(m->fn, ln, PATH_MAX); if(size != -1 && size < PATH_MAX){ ln[size] = 0; if(!strcmp(m->ln, ln)){ return(MAKUO_RECVSTATE_SKIP); } } } return(MAKUO_RECVSTATE_UPDATE); } int statcmp(struct stat *s1, struct stat *s2) { if(s1->st_mtime != s2->st_mtime) return(MAKUO_RECVSTATE_UPDATE); if(!geteuid() || !getegid()){ if(s1->st_uid != s2->st_uid){ return(MAKUO_RECVSTATE_UPDATE); } if(s1->st_gid != s2->st_gid){ return(MAKUO_RECVSTATE_UPDATE); } } if((S_ISDIR(s1->st_mode)) && (S_ISDIR(s2->st_mode))){ if(s1->st_mode != s2->st_mode) return(MAKUO_RECVSTATE_UPDATE); return(MAKUO_RECVSTATE_SKIP); } if((S_ISREG(s1->st_mode)) && (S_ISREG(s2->st_mode))){ if(s1->st_mode != s2->st_mode) return(MAKUO_RECVSTATE_UPDATE); if(s1->st_size != s2->st_size) return(MAKUO_RECVSTATE_UPDATE); return(MAKUO_RECVSTATE_SKIP); } if(s1->st_mode == s2->st_mode){ if(s1->st_rdev == s2->st_rdev){ return(MAKUO_RECVSTATE_SKIP); } } return(MAKUO_RECVSTATE_UPDATE); } int is_dir(char *path) { struct stat mstat; if(!lstat(path,&mstat)) return(S_ISDIR(mstat.st_mode)); return(0); } int is_reg(char *path) { struct stat mstat; if(!lstat(path,&mstat)) return(S_ISREG(mstat.st_mode)); return(0); } int set_guid(int uid, int gid, gid_t *gids) { size_t num; /*----- setgids -----*/ if(gids){ for(num=0;gids[num];num++); if(num){ if(setgroups(num,gids) == -1){ return(-1); } } }else{ if(gid != getegid()){ if(setgroups(1, &gid) == -1){ return(-1); } } } /*----- setgid -----*/ if(gid != getegid()){ if(setegid(gid) == -1){ return(-1); } } /*----- setuid -----*/ if(uid != geteuid()){ if(seteuid(uid) == -1){ return(-1); } } return(0); } int set_gids(char *groups) { char *p; size_t num; struct group *g; char buff[1024]; num = 0; strcpy(buff, groups); p = strtok(buff,","); while(p){ p = strtok(NULL,","); num++; } if(moption.gids){ free(moption.gids); } moption.gids = malloc(sizeof(gid_t) * (num + 1)); num = 0; strcpy(buff, groups); p = strtok(buff,","); while(p){ if(*p >= '0' && *p <= '9'){ moption.gids[num] = atoi(p); }else{ if(g = getgrnam(p)){ moption.gids[num] = g->gr_gid; } } p = strtok(NULL,","); num++; } moption.gids[num] = 0; return(0); } void set_filestat(char *path, uid_t uid, gid_t gid, mode_t mode) { struct stat fs; if(lstat(path, &fs) == -1){ return; } if(fs.st_uid != uid){ lchown(path, uid, -1); } if(fs.st_gid != gid){ lchown(path, -1, gid); } chmod(path, mode & 07777); } void mtempname(char *base, char *fn, char *tn) { struct stat st; struct timeb tb; char path[PATH_MAX]; do{ ftime(&tb); sprintf(tn, "%s.makuo%03u%03u", fn, getrid() % 1000, (int)tb.millitm); sprintf(path, "%s/%s", base, tn); }while(lstat(tn, &st) != -1); } int mremove(char *base, char *name) { DIR *d; struct dirent *dent; char path[PATH_MAX]; if(!base){ strcpy(path,name); }else{ sprintf(path, "%s/%s", base, name); lprintf(0, "%s: %s\n", __func__, path); } if(is_dir(path)){ if(d = opendir(path)){ while(dent=readdir(d)){ if(!strcmp(dent->d_name, ".")) continue; if(!strcmp(dent->d_name, "..")) continue; mremove(path, dent->d_name); } closedir(d); } } return(remove(path)); } int mrename(char *base, char *oldname, char *newname) { char oldpath[PATH_MAX]; char newpath[PATH_MAX]; char tmppath[PATH_MAX]; sprintf(oldpath,"%s/%s", base, oldname); sprintf(newpath,"%s/%s", base, newname); mtempname(base, newname, tmppath); rename(newpath,tmppath); if(rename(oldpath,newpath) == -1){ rename(tmppath, newpath); return(-1); } mremove(NULL,tmppath); return(0); } int mcreatedir(char *base, char *name, mode_t mode) { char *p; char buff[PATH_MAX]; char path[PATH_MAX]; strcpy(buff, name); strcpy(path, base); p = strtok(buff, "/"); while(p){ strcat(path, "/"); strcat(path, p); if(p = strtok(NULL,"/")){ if(!is_dir(path)){ remove(path); if(mkdir(path,mode) == -1){ return(-1); } } } } return(0); } int mcreatenode(char *base, char *name, mode_t mode, dev_t dev) { int r = -1; mode_t u = umask(0); char path[PATH_MAX]; if(!mcreatedir(base, name, 0755)){ sprintf(path,"%s/%s",base,name); r = mknod(path, mode, dev); } umask(u); return(r); } int mcreatefile(char *base, char *name, mode_t mode) { int fd = -1; mode_t u = umask(0); char path[PATH_MAX]; if(!mcreatedir(base,name,0755)){ sprintf(path,"%s/%s",base,name); fd = open(path, O_RDWR | O_CREAT | O_TRUNC, mode & 0xFFF); } umask(u); return(fd); } int mcreatelink(char *base, char *name, char *link) { char path[PATH_MAX]; if(!mcreatedir(base,name,0755)){ sprintf(path,"%s/%s",base,name); return(symlink(link,path)); } return(-1); } int space_escape(char *str) { int r = 0; char buff[PATH_MAX]; char *s = str; char *d = buff; while(*s){ if(*s == ' '){ r++; *(d++) = '\\'; } *(d++) = *(s++); } *d = 0; strcpy(str, buff); return(r); } void chexit() { char cwd[PATH_MAX]; if(moption.chroot){ /*----- chroot exit -----*/ mtempname("",".MAKUOWORK",cwd); mkdir(cwd,0700); chroot(cwd); rmdir(cwd); chdir(".."); getcwd(cwd,PATH_MAX); while(strcmp("/", cwd)){ chdir(".."); getcwd(cwd,PATH_MAX); } chroot("."); } return(0); } void restoreguid() { if(getuid() != geteuid()) seteuid(getuid()); if(getgid() != getegid()) setegid(getgid()); }