/* * MAKUOSAN * multicast file synchronization system */ #include "makuosan.h" void usage() { printf("makuosan (Multicast Advance Keep Update Overwrite Synchronization Always Network)\n"); printf("version %s\n\n", MAKUOSAN_VERSION); printf("usage: makuosan [OPTION]\n"); printf(" -d num # loglevel(0-9)\n"); printf(" -u uid # user\n"); printf(" -g gid # group\n"); printf(" -b dir # base dir\n"); printf(" -p port # port number (default: 5000)\n"); printf(" -m addr # multicast address (default: 224.0.0.108)\n"); printf(" -l addr # listen address (default: 127.0.0.1)\n"); printf(" -U path # unix domain socket\n"); printf(" -k file # key file (encrypt password)\n"); printf(" -K file # key file (console password)\n"); printf(" -c # chroot to base dir\n"); printf(" -n # don't fork\n"); printf(" -r # don't recv\n"); printf(" -s # don't send\n"); printf(" -o # don't listen (console off mode)\n"); printf(" -O # owner match limitation mode\n"); printf(" -h # help\n\n"); exit(0); } int 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); } int setguid(int uid, int gid) { /*----- setgid -----*/ if(gid != getegid()){ if(setgroups(1, &gid) == -1){ return(-1); } if(setegid(gid) == -1){ return(-1); } } /*----- setuid -----*/ if(uid != geteuid()){ if(seteuid(uid) == -1){ return(-1); } } return(0); } int restoreguid() { if(getuid() != geteuid()) seteuid(getuid()); if(getgid() != getegid()) setegid(getgid()); return(0); } void recv_timeout(mfile *m) { mhost *h; if(m){ m->retrycnt = MAKUO_SEND_RETRYCNT; do{ for(h=members;h;h=h->next){ if(h->state == MAKUO_RECVSTATE_NONE){ lprintf(0,"%s: %s(%s) timeout\n", __func__, inet_ntoa(h->ad), h->hostname); member_del(h); break; } } }while(h); } } struct timeval *pingpong(int n) { static struct timeval tv; mfile *m = mfins(0); mping *p = NULL; char buff[MAKUO_HOSTNAME_MAX + 1]; if(!m){ lprintf(0, "%s: out of memmory\r\n", __func__); return(0); } switch(n){ case 0: m->mdata.head.opcode = MAKUO_OP_PING; break; case 1: m->mdata.head.opcode = MAKUO_OP_PING; m->mdata.head.flags |= MAKUO_FLAG_ACK; break; case 2: m->mdata.head.opcode = MAKUO_OP_EXIT; break; } m->mdata.head.reqid = getrid(); m->mdata.head.seqno = 0; m->mdata.head.szdata = 0; m->sendwait = 0; if(gethostname(buff, sizeof(buff)) == -1){ buff[0] = 0; } p = (mping *)(m->mdata.data); p->hostnamelen = strlen(buff); p->versionlen = strlen(MAKUOSAN_VERSION); m->mdata.head.szdata = sizeof(mping) + p->hostnamelen + p->versionlen; m->mdata.p = p->data; memcpy(m->mdata.p, buff, p->hostnamelen); m->mdata.p += p->hostnamelen; memcpy(m->mdata.p, MAKUOSAN_VERSION, p->versionlen); m->mdata.p += p->versionlen; p->hostnamelen = htons(p->hostnamelen); p->versionlen = htons(p->versionlen); gettimeofday(&tv,NULL); return(&tv); } int cleanup() { mfile *m; socklen_t namelen; struct sockaddr_un addr; /*----- send object -----*/ while(m=mftop[0]) mfdel(m); /*----- recv object -----*/ while(m=mftop[1]){ if(m->mdata.head.nstate == MAKUO_RECVSTATE_OPEN){ if(m->fd != -1){ close(m->fd); m->fd = -1; } if(S_ISREG(m->fs.st_mode)){ mremove(moption.base_dir,m->tn); } } mfdel(m); } /*----- exit notify -----*/ pingpong(2); msend(moption.mcsocket, mftop[0]); /*----- unlink unix domain socket -----*/ namelen=sizeof(addr); if(!getsockname(moption.lisocket, (struct sockaddr *)&addr, &namelen)){ if(addr.sun_family == AF_UNIX){ unlink(addr.sun_path); } } /*----- close -----*/ close(moption.mcsocket); close(moption.lisocket); return(0); } int mcomm_accept(mcomm *c, fd_set *fds, int s) { int i; if(s == -1) return(0); if(!FD_ISSET(s,fds)) return(0); for(i=0;i<MAX_COMM;i++) if(c[i].fd[0] == -1) break; if(i==MAX_COMM){ close(accept(s, NULL, 0)); return(0); } c[i].addrlen = sizeof(c[i].addr); c[i].fd[0] = accept(s, (struct sockaddr *)(&c[i].addr), &(c[i].addrlen)); lprintf(2, "%s: accept from %s i=%d fd=%d\n", __func__, inet_ntoa(c[i].addr.sin_addr), i, c[i].fd[0]); /*cprintf(0, &(c[i]),"\xff\xfd\x18\r");*/ c[i].working = 1; return(0); } int mcomm_read(mcomm *c, fd_set *fds){ int i, j; mfile *m; for(i=0;i<MAX_COMM;i++){ for(j=0;j<2;j++){ if(c[i].fd[j] != -1){ if(FD_ISSET(c[i].fd[j], fds) || c[i].check[j]){ mexec(&c[i], j); } } } if(c[i].fd[1] == -1){ for(m=mftop[0];m;m=m->next){ if(m->comm == &c[i]){ break; } } if(!m){ if(c[i].working && !c[i].cpid){ lprintf(9,"************* work end **************\n"); workend(&c[i]); } } } } return(0); } int mcomm_fdset(mcomm *c, fd_set *fds) { int i; for(i=0;i<MAX_COMM;i++){ if(c[i].fd[0] != -1){ FD_SET(c[i].fd[0], fds); } if(c[i].fd[1] != -1){ FD_SET(c[i].fd[1], fds); }else{ if(c[i].cpid){ if(waitpid(c[i].cpid, NULL, WNOHANG) == c[i].cpid){ lprintf(0, "%s: send complete\n", __func__); c[i].cpid = 0; } } } } return(0); } int ismsend(mfile *m) { int r; if(!m) return(0); if(!m->sendwait){ return(1); } r = ack_check(m,MAKUO_RECVSTATE_NONE); if(r == -1){ m->mdata.head.seqno = 0; m->mdata.head.nstate = MAKUO_SENDSTATE_BREAK; return(1); } if(!r){ m->sendwait = 0; return(1); } if(mtimeout(&(m->lastsend), MAKUO_SEND_TIMEOUT)){ if(m->retrycnt){ return(1); }else{ recv_timeout(m); } } return(0); } /***** main loop *****/ int mloop() { fd_set rfds; fd_set wfds; struct timeval *lastpong; struct timeval tv; gettimeofday(&curtime,NULL); lastpong = pingpong(0); while(loop_flag){ tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&rfds); FD_ZERO(&wfds); gettimeofday(&curtime,NULL); if(mtimeout(lastpong, MAKUO_PONG_INTERVAL)) lastpong = pingpong(1); FD_SET(moption.mcsocket, &rfds); if(moption.lisocket != -1) FD_SET(moption.lisocket, &rfds); if(mftop[0]){ tv.tv_sec = 0; tv.tv_usec = 10000; if(ismsend(mftop[0])) FD_SET(moption.mcsocket, &wfds); } mcomm_fdset(moption.comm, &rfds); if(select(1024, &rfds, &wfds, NULL, &tv) < 0) continue; gettimeofday(&curtime,NULL); if(FD_ISSET(moption.mcsocket,&wfds)) msend(moption.mcsocket, mftop[0]); if(FD_ISSET(moption.mcsocket,&rfds)) mrecv(moption.mcsocket); mrecv_gc(); mcomm_accept(moption.comm, &rfds, moption.lisocket); /* new console */ mcomm_read(moption.comm, &rfds); /* command exec */ } return(0); } void mexit() { lprintf(0, "%s: shutdown start\n", __func__); restoreguid(); /* euid,egidãåã«æ»ã */ chexit(); /* chrootããè±åº */ cleanup(); /* ãã£ã¹ã¯ãªãã¿ã®éæ¾ãªã© */ lprintf(0, "%s: shutdown complete\n", __func__); } int main(int argc, char *argv[]) { minit(argc,argv); mloop(); mexit(); return(0); }