common.c
c858e9b6
 /*
  * common.c
e6a800d5
  * Copyright (C) 2008-2012 KLab Inc.
c858e9b6
  */
86badd32
 #include "makuosan.h"
 
 mopt moption;
46e655e5
 mfile *mftop[2]  = {NULL,NULL};
 mfile *mfreeobj  = NULL;
 mhost *members   = NULL;
 int send_rate    = 0;
 int view_rate    = 0;
 time_t send_time = 0;
86badd32
 struct timeval curtime;
d38d0833
 struct timeval lastpong;
86badd32
 BF_KEY EncKey;
e6a800d5
 volatile sig_atomic_t log_level = 0;
 volatile sig_atomic_t loop_flag = 1;
86badd32
 
38605fc1
 char *yesno(int n)
 {
   static char *YES="yes";
   static char *NO="no";
   if(n){
     return(YES);
   }
   return(NO);
 }
 
86badd32
 /*
3434d319
  *  タイムアウト時間が経過しているかどうかを判断する
  *   - 現在時刻がtfからmsec[ms]経過していれば1を返す
d38d0833
  *   - 経過していなければ0を返す
86badd32
  */
 int mtimeout(struct timeval *tf, uint32_t msec)
 {
   struct timeval tv;
   struct timeval tr;
aa2b6bc8
   
   if((tf->tv_sec == 0) && (tf->tv_usec == 0)){
     return(0);
   }
86badd32
   tv.tv_sec  = msec / 1000;
   tv.tv_usec = (msec % 1000) * 1000;
   timeradd(tf, &tv, &tr);
   return(timercmp(&tr, &curtime, <));
 }
 
 /*
3434d319
  *  現在時刻を取得する
e396e004
  *  (といってもcurtimeをコピーするだけだけど)
86badd32
  */
 int mtimeget(struct timeval *tv)
 {
   memcpy(tv, &curtime, sizeof(curtime));
   return(0);
 }
 
 /*
3434d319
  *  ファイル名がexcludeリストにマッチするかどうかを調べる
  *   - マッチした場合はそのexcludeitem構造体のポインタを返す
  *   - マッチしない場合はNULLを返す
86badd32
  */
 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);
 }
 
686a33f7
 int isexclude(char *fn, excludeitem *exclude, int dir)
17b77ef8
 {
686a33f7
   char path[PATH_MAX];
8e09e847
   if(!strcmp(fn, ".")){
     fn = "";
686a33f7
   }
8e09e847
   if(!memcmp(fn, "./", 2)){
     fn += 2;
686a33f7
   }
8e09e847
   while(*fn == '/'){
     fn++;
686a33f7
   }
8e09e847
   if(dir){
     sprintf(path, "%s/%s/", moption.real_dir, fn);
   }else{
     sprintf(path, "%s/%s" , moption.real_dir, fn);
   }
   if(mfnmatch(path, exclude)){
     return(1);
686a33f7
   }
   return(0);
17b77ef8
 }
 
fc430629
 uint32_t getrid()
86badd32
 {
fc430629
   static uint32_t rid=0;
86badd32
   return(rid++);
 }
 
 int workend(mcomm *c)
 {
f73d92fa
   char *m;
   if(!c){
     return(0);
   }
   if(!c->working){
     return(0);
   }
   if(c->cpid){
     return(0);
   }
   if(moption.commpass && !c->authchk){
     m = "password: \x1b]E";
   }else{
     if(c->logover && strcmp("dsync", c->parse[0][0])){
6640e404
       if(cprintf(0, c, "[error] Log lost: %d lines\n", c->logover) == 0){
f73d92fa
         c->logover = 0;
25108556
       }else{
         c->logover--;
86badd32
       }
     }
83082c34
     if(c->logfail){
       m = "\n> ";
     }else{
       m = "> ";
     }
86badd32
   }
f73d92fa
   if(cprintf(0, c, m) == 0){
     c->working = 0;
25108556
   }else{
     c->logover--;
f73d92fa
   }
86badd32
   return(0);
 }
 
af8d11e0
 mfile *mfalloc()
 {
   mfile *m = mfreeobj;
   if(m){
     mfreeobj = m->next;
   }else{
     m = (mfile *)malloc(sizeof(mfile));
   }
   return(m);
 }
 
 void mfree(mfile *m){
   m->prev  = NULL;
   m->next  = mfreeobj;
   mfreeobj = m;
 }
 
86badd32
 void mfdel(mfile *m)
 {
   mfile *p;
   mfile *n;
   if(m){
1b4c64d4
     if((p = (mfile *)m->prev)){
86badd32
       p->next = m->next;
1b4c64d4
     }
     if((n = (mfile *)m->next)){
86badd32
       n->prev = m->prev;
1b4c64d4
     }
     if(mftop[0] == m){
86badd32
       mftop[0] = n;
1b4c64d4
     }
     if(mftop[1] == m){
86badd32
       mftop[1] = n;
1b4c64d4
     }
af8d11e0
     mfree(m);
86badd32
   }
 }
 
 mfile *mfnew()
 {
   mfile *m;
1b4c64d4
   if((m = mfalloc())){
86badd32
     memset(m, 0, sizeof(mfile));
326703dc
     m->mdata.head.maddr  = moption.maddr.sin_addr.s_addr;
     m->mdata.head.mport  = moption.maddr.sin_port;
86badd32
     m->mdata.head.vproto = PROTOCOL_VERSION;
806dbe3b
     m->fd   = -1;
     m->pipe = -1;
86badd32
     m->retrycnt = MAKUO_SEND_RETRYCNT;
     memcpy(&(m->addr), &(moption.maddr), sizeof(m->addr));
   }
   return(m);
 }
 
 mfile *mfadd(int n)
 {
   mfile *m;
1b4c64d4
   if((m = mfnew())){
86badd32
     if(!mftop[n]){
       mftop[n] =m;
     }else{
       mfile *l;
       for(l=mftop[n];l->next;l=l->next);
806dbe3b
       l->next = m;
       m->prev = l;
86badd32
       m->next = NULL;
     }
   }
   return(m);
 }
 
 mfile *mfins(int n)
 {
   mfile *m;
1b4c64d4
   if((m = mfnew())){
86badd32
     if(mftop[n]){
       mftop[n]->prev = m;
       m->next = mftop[n];
     }
     mftop[n] =m;
   }
   return(m);
 }
 
aa2b6bc8
 mhost *member_get(struct in_addr *addr)
 {
   mhost *t;
   for(t=members;t;t=t->next){
     if(!memcmp(&t->ad, addr, sizeof(t->ad))){
3b736b7c
       return(t);
aa2b6bc8
     }
   }
3b736b7c
   return(NULL); 
aa2b6bc8
 }
 
86badd32
 mhost *member_add(struct in_addr *addr, mdata *data)
 {
aa2b6bc8
   int f = 0;
a80ad51a
   int l = 0;
86badd32
   mping *p = NULL;
aa2b6bc8
   mhost *t = member_get(addr);
 
86badd32
   if(!t){
aa2b6bc8
     f = 1;
86badd32
     t = malloc(sizeof(mhost));
     if(!t){
a80ad51a
       lprintf(0, "%s: out of memory\n", __func__);
86badd32
       return(NULL);
     }
abce546a
     memset(t, 0, sizeof(mhost));
86badd32
     memcpy(&t->ad, addr, sizeof(t->ad));
     if(members){
       members->prev = t;
       t->next = members;
     }
     members = t;
     t->hostname[0] = 0;
   }
   if(data){
634a23d7
     if(data->head.opcode == MAKUO_OP_PING){
86badd32
       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){
a80ad51a
     lprintf(0, "%s: %s (%s)\n", __func__, inet_ntoa(t->ad), t->hostname);
86badd32
   }
   mtimeget(&(t->lastrecv));
   return(t);
 }
 
 void member_del(mhost *t)
 {
   mhost *p;
   mhost *n;
fc430629
   if(!t){
86badd32
     return;
fc430629
   }
a80ad51a
   lprintf(0, "%s: %s (%s)\n", __func__, inet_ntoa(t->ad), t->hostname);
1b4c64d4
   if((p = (mhost *)t->prev)){
86badd32
     p->next = t->next;
fc430629
   }
1b4c64d4
   if((n = (mhost *)t->next)){
86badd32
     n->prev = t->prev;
fc430629
   }
   if(members == t){
86badd32
     members = n;
fc430629
   }
86badd32
   free(t);
 }
 
eeef442d
 void member_del_message(int err, mhost *t, char *mess)
fc430629
 {
   int i;
69d91074
   mfile *m;
 
69b027c3
   if(!t || !mess){
     return;
   }
69d91074
   for(i=0;i<MAKUO_HOSTSTATE_SIZE;i++){
1b4c64d4
     if((m = t->mflist[i])){
69d91074
       if(m->comm){
         if(m->comm->working){
           cprintf(0, m->comm, "error: %s: %s\n", mess, m->cmdline);
eeef442d
           if(err){
             lprintf(0, "[error] %s: %s: ST=%s RC=%02d: %s\n", 
               __func__, 
               mess, 
               strmstate(&(m->mdata)),
               m->retrycnt,
               m->cmdline);
           }
69d91074
         }
       }
     }
   }
fc430629
   for(i=0;i<MAX_COMM;i++){
     if(moption.comm[i].working){
69d91074
       cprintf(0, &(moption.comm[i]), "error: %s: %s(%s)\n", mess, inet_ntoa(t->ad), t->hostname);
fc430629
     }
   }
eeef442d
   if(err){
     lprintf(0, "[error] %s: %s: %s(%s)\n", __func__, mess, inet_ntoa(t->ad), t->hostname);
   }
fc430629
 }
 
f31a5410
 mmark *markalloc()
86badd32
 {
f31a5410
   mmark *mm = calloc(1, sizeof(mmark));
   return(mm);
 }
 
 void markfree(mmark *mm)
 {
   free(mm);
 }
 
 mmark *addmark(mmark *mm, uint32_t l, uint32_t h)
 {
   mmark *nn = markalloc();
   nn->l = l;
   nn->h = h;
   if(mm){
     nn->next = mm;
     nn->prev = mm->prev;
     mm->prev = nn;
     if(nn->prev){
       nn->prev->next = nn;
abce546a
     }
86badd32
   }
f31a5410
   return(nn);
 }
 
 mmark *delmark(mmark *mm)
 {
   mmark *nn = NULL;
   if(mm){
     if(mm->prev){
       mm->prev->next = mm->next;
     }
     if(mm->next){
       mm->next->prev = mm->prev;
abce546a
     }
f31a5410
     nn = mm->next;
     markfree(mm);
86badd32
   }
f31a5410
   return(nn);
 }
a80ad51a
 
f31a5410
 void seq_addmark(mfile *m, uint32_t l, uint32_t h)
 {
69b027c3
   if(!m || (h == l)){
f31a5410
     return;
a80ad51a
   }
f31a5410
   m->markcount += (h - l);
   m->mark = addmark(m->mark, l, h);
86badd32
 }
 
 int seq_delmark(mfile *m, uint32_t seq)
 {
f31a5410
   uint32_t l;
   uint32_t h;
   mmark  *mm;
69b027c3
 
f31a5410
   if(!m){
     return(0);
   }
 
   for(mm=m->mark;mm;mm=mm->next){
     l = mm->l;
     h = mm->h - 1;
     if(seq == l){
       mm->l++;
       if(mm->l == mm->h){
         if(mm == m->mark){
           m->mark = mm->next;
         }
         delmark(mm);
       }
86badd32
       m->markcount--;
f31a5410
       return(1);
     }
     if(seq == h){
       mm->h--;
       if(mm->l == mm->h){
         if(mm == m->mark){
           m->mark = mm->next;
         }
         delmark(mm);
       }
       m->markcount--;
       return(1);
     }
     if((seq>l) && (seq<h)){
       if(mm == m->mark){
         m->mark = addmark(mm, mm->l, seq);
       }else{
         addmark(mm, mm->l, seq);
       }
       mm->l = seq + 1;
       m->markcount--;
       return(1);
86badd32
     }
   }
f31a5410
   return(0);
86badd32
 }
 
f31a5410
 void seq_setmark(mfile *m, uint32_t l, uint32_t h)
86badd32
 {
f31a5410
   mmark *mm;
   mmark *mn;
 
   if(!m){
     return;
   }
   mm = m->mark;
   mn = addmark(NULL, l, h);
   while(mm){
     if((mn->h < mm->l) || (mn->l > mm->h)){
       mm = mm->next;
       continue;
     }
     if(mn->l > mm->l){
       mn->l = mm->l;
     }
     if(mn->h < mm->h){
       mn->h = mm->h;
     }
     if(mm == m->mark){
       m->mark = mm->next;
     }
     mm = delmark(mm);
   }
1b4c64d4
   if((mn->next = m->mark)){
f31a5410
     m->mark->prev = mn;
   }
   m->mark = mn;
   m->markcount = 0;
   for(mm=m->mark;mm;mm=mm->next){
     m->markcount += (mm->h - mm->l);
86badd32
   }
 }
 
f31a5410
 uint32_t seq_getmark(mfile *m)
 {
   uint32_t seq;
   if(!m){
     return(0);
   }
   if(!m->mark){
     return(0);
   }
   seq = m->mark->l;
   m->markcount--;
   m->mark->l++;
   if(m->mark->l == m->mark->h){
     m->mark = delmark(m->mark);
   }  
   return(seq);
 }
 
abce546a
 void clr_hoststate(mfile *m)
 {
a80ad51a
   int i;
abce546a
   mhost *t;
   for(t=members;t;t=t->next){
3b736b7c
     for(i=0;i<MAKUO_HOSTSTATE_SIZE;i++){
abce546a
       if(t->mflist[i] == m){
         t->mflist[i] = NULL;
         t->state[i]  = 0;
       }
     }
   }
 }
 
5fe10f4f
 void dump_hoststate(mfile *m, char *func)
 {
   mhost   *t;
   uint8_t *r;
   for(t=members;t;t=t->next){
1b4c64d4
     if((r=get_hoststate(t,m))){
17b77ef8
       lprintf(9,"%s: %s from %s %s\n", func, strrstate(*r), t->hostname, m->fn);
5fe10f4f
     }
   }
 }
 
abce546a
 uint8_t *get_hoststate(mhost *t, mfile *m)
 {
   int i;
   int r;
   if(!t || !m){
     return(NULL);
   }
   r = -1;
3b736b7c
   for(i=0;i<MAKUO_HOSTSTATE_SIZE;i++){
abce546a
     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);
 }
 
aa2b6bc8
 uint8_t *set_hoststate(mhost *t, mfile *m, uint8_t state)
 {
   uint8_t *s;
1b4c64d4
   if((s = get_hoststate(t,m))){
aa2b6bc8
     *s = state;
   }
   return(s);
 }
 
86badd32
 int ack_clear(mfile *m, int state)
 {
abce546a
   uint8_t *s;
   mhost   *t;
   for(t=members;t;t=t->next){
86badd32
     if(!m->sendto){
1b4c64d4
       if((s = get_hoststate(t, m))){
abce546a
         if(state == -1 || *s == state){
           *s = MAKUO_RECVSTATE_NONE;
         }
       }
86badd32
     }else{
abce546a
       if(!memcmp(&(m->addr.sin_addr), &(t->ad), sizeof(m->addr.sin_addr))){
1b4c64d4
         if((s = get_hoststate(t, m))){
abce546a
           if(state == -1 || *s == state){
             *s = MAKUO_RECVSTATE_NONE;
             return(1);
           }else{
             return(0);
           }
86badd32
         }
       }
     }
   }
   if(m->sendto)
     return(-1);
   return(0);
 }
 
3434d319
 /* 指定したステータスを持つ応答メッセージがあるかをチェックする
  * 引数  :
  *      m: 送信対象のファイルオブジェクト
  *  state: 検索するステータス
86badd32
  *
3434d319
  * 戻り値:
  *      0: 見つからなかった
  *      1: 見つかった
  *     -1: ホスト指定転送なのにホストオブジェクトが見つからない
86badd32
 */
 int ack_check(mfile *m, int state)
 {
abce546a
   uint8_t *s;
   mhost   *t;
   for(t=members;t;t=t->next){
86badd32
     if(!m->sendto){
e42e0b01
       s = get_hoststate(t,m);
       if(!s){
05348f1d
         lprintf(0,"[error] %s: can't get state area host=%s fn=%s\n", __func__, t->hostname, m->fn);
e42e0b01
       }else{
abce546a
         if(*s == state){
           return(1);
         }
86badd32
       }
     }else{
abce546a
       if(!memcmp(&(m->addr.sin_addr), &(t->ad), sizeof(m->addr.sin_addr))){
e42e0b01
         s = get_hoststate(t,m);
         if(!s){
05348f1d
           lprintf(0,"[error] %s: can't get state area host=%s fn=%s\n", __func__, t->hostname, m->fn);
e42e0b01
         }else{
abce546a
           if(*s == state){
             return(1);
           }else{
             return(0);
           }
86badd32
         }
       }
     }
   }
69b027c3
   if(m->sendto){
86badd32
     return(-1);
69b027c3
   }
86badd32
   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)
 {
7680186f
   if(s1->st_mtime != s2->st_mtime){
57179b09
     return(MAKUO_RECVSTATE_UPDATE);
7680186f
   }
7b348a67
   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);
     }
   }
86badd32
   if((S_ISDIR(s1->st_mode)) && (S_ISDIR(s2->st_mode))){
57179b09
     if(s1->st_mode != s2->st_mode)
86badd32
       return(MAKUO_RECVSTATE_UPDATE);
     return(MAKUO_RECVSTATE_SKIP);
   }
   if((S_ISREG(s1->st_mode)) && (S_ISREG(s2->st_mode))){
e5b6322e
     if(s1->st_mode != s2->st_mode)
       return(MAKUO_RECVSTATE_UPDATE);
86badd32
     if(s1->st_size != s2->st_size)
       return(MAKUO_RECVSTATE_UPDATE);
     return(MAKUO_RECVSTATE_SKIP);
   }
57179b09
   if(s1->st_mode == s2->st_mode){
     if(s1->st_rdev == s2->st_rdev){
       return(MAKUO_RECVSTATE_SKIP);
     }
   }
86badd32
   return(MAKUO_RECVSTATE_UPDATE);
 } 
 
 int is_dir(char *path)
 {
   struct stat mstat;
69b027c3
   if(!lstat(path,&mstat)){
86badd32
     return(S_ISDIR(mstat.st_mode));
69b027c3
   }
86badd32
   return(0);
 }
 
 int is_reg(char *path)
 {
   struct stat mstat;
69b027c3
   if(!lstat(path,&mstat)){
86badd32
     return(S_ISREG(mstat.st_mode));
69b027c3
   }
86badd32
   return(0);
 }
 
05348f1d
 int set_guid(uid_t uid, gid_t gid, size_t gidn, gid_t *gids)
e5b6322e
 {
   /*----- setgids -----*/
05348f1d
   if(gidn && gids){
     if(setgroups(gidn, gids) == -1){
       return(-1);
e5b6322e
     }
   }else{
     if(gid != getegid()){
       if(setgroups(1, &gid) == -1){
         return(-1);
       }
     }
   }
 
   /*----- setgid -----*/
   if(gid != getegid()){
     if(setegid(gid) == -1){
       return(-1);
     }
   }
69b027c3
 
e5b6322e
   /*----- setuid -----*/
   if(uid != geteuid()){
     if(seteuid(uid) == -1){
       return(-1);
     }
   }  
   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);
 }
 
86badd32
 void mtempname(char *base, char *fn, char *tn)
 {
b60b392c
   struct stat    st;
   struct timeval tv;
86badd32
   char path[PATH_MAX];
   do{
b60b392c
     gettimeofday(&tv, NULL);
     sprintf(tn, "%s.makuo%03u%03u", fn, getrid() % 1000,  (int)tv.tv_usec);
86badd32
     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{
a80ad51a
     sprintf(path, "%s/%s", base, name);
86badd32
   }
   if(is_dir(path)){
1b4c64d4
     if((d = opendir(path))){
       while((dent=readdir(d))){
86badd32
         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);
1b4c64d4
     if((p = strtok(NULL,"/"))){
86badd32
       if(!is_dir(path)){
         remove(path);
         if(mkdir(path,mode) == -1){
           return(-1);
         }
       }
     }
   }
   return(0);
 }
 
57179b09
 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);
 }
 
abce546a
 int mcreatefile(char *base, char *name, mode_t mode)
86badd32
 {
   int fd = -1;
57179b09
   mode_t u = umask(0);
86badd32
   char path[PATH_MAX];
   if(!mcreatedir(base,name,0755)){
     sprintf(path,"%s/%s",base,name);
facf6c53
     fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode & 0xFFF);
86badd32
   }
57179b09
   umask(u);
86badd32
   return(fd);
 }
 
abce546a
 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);
 }
 
86badd32
 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);
 }
 
874955ec
 mfile *mkreq(mdata *data, struct sockaddr_in *addr, uint8_t state)
 {
   mfile *a;
1b4c64d4
   if((a = mfins(MFSEND))){
874955ec
     a->mdata.head.opcode = data->head.opcode;
     a->mdata.head.reqid  = data->head.reqid;
     a->mdata.head.seqno  = data->head.seqno;
     a->mdata.head.nstate = state;
     memcpy(&(a->addr), addr, sizeof(a->addr));
   }
   return(a);
 }
 
 mfile *mkack(mdata *data, struct sockaddr_in *addr, uint8_t state)
 {
   mfile *a;
3b736b7c
   for(a=mftop[MFSEND];a;a=a->next){
f31a5410
     if((a->mdata.head.flags & MAKUO_FLAG_ACK)      &&
        (a->mdata.head.opcode == data->head.opcode) &&
        (a->mdata.head.reqid  == data->head.reqid)  &&
        (a->mdata.head.seqno  == data->head.seqno)  &&
        (a->mdata.head.nstate == state)             &&
        (!memcmp(&(a->addr), addr, sizeof(a->addr)))){
       return(a);
     }
   }
1b4c64d4
   if((a = mfins(MFSEND))){
874955ec
     a->mdata.head.flags |= MAKUO_FLAG_ACK;
     a->mdata.head.opcode = data->head.opcode;
     a->mdata.head.reqid  = data->head.reqid;
     a->mdata.head.seqno  = data->head.seqno;
1ed29a26
     a->mdata.head.ostate = data->head.ostate;
874955ec
     a->mdata.head.nstate = state;
1ed29a26
     a->mdata.head.error  = data->head.error;
874955ec
     memcpy(&(a->addr), addr, sizeof(a->addr));
   }
   return(a);
 }
 
eeef442d
 int atomic_read(int fd, void *buff, int size, int nb)
686a33f7
 {
eeef442d
   int e;
686a33f7
   int r;
eeef442d
   int s;
   int f;
 
   s = size;
   f = fcntl(fd, F_GETFL, 0);
   if(nb){
     fcntl(fd, F_SETFL, f | O_NONBLOCK);
   }else{
     fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
   }
686a33f7
 
   while(size){
     r = read(fd, buff, size);
eeef442d
     e = errno;
     /* EOF */
     if(r == 0){
       fcntl(fd, F_SETFL, f);
       return(1);
     }
     /* ERROR */
686a33f7
     if(r == -1){
eeef442d
       if(e == EINTR){
686a33f7
         continue;
       }
eeef442d
       fcntl(fd, F_SETFL, f);
       errno = e;
686a33f7
       return(-1);
     }
eeef442d
     /* SUCCESS */
686a33f7
     size -= r;
     buff += r;
eeef442d
     fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
686a33f7
   }
eeef442d
   fcntl(fd, F_SETFL, f);
686a33f7
   return(0);
 }
 
442bde46
 int data_safeget(mdata *data, void *buff, size_t size)
 {
   if(data->p + size > data->data + data->head.szdata){
     return(-1);
   }
   memcpy(buff, data->p, size);
   data->p += size;
   return(0);
 }
 
 int data_safeget16(mdata *data, uint16_t *buff)
 {
   int r = data_safeget(data, buff, sizeof(uint16_t));
   if(!r){
     *buff = ntohs(*buff);
   }
   return(r);
 }
 
 int data_safeget32(mdata *data, uint32_t *buff)
 {
   int r = data_safeget(data, buff, sizeof(uint32_t));
   if(!r){
     *buff = ntohl(*buff);
   }
   return(r);
 }
 
 int data_safeset(mdata *data, void *buff, size_t size)
 {
   if(data->head.szdata + size > MAKUO_BUFFER_SIZE){
     return(-1);
   }
   memcpy(data->data + data->head.szdata, buff, size);
   data->head.szdata += size;
   return(0);
 }
 
 int data_safeset16(mdata *data, uint16_t val)
 {
   if(data->head.szdata + sizeof(uint16_t) > MAKUO_BUFFER_SIZE){
     return(-1);
   }
36959136
   val = htons(val);
   memcpy((void *)(data->data + data->head.szdata), (void *)(&val), sizeof(val));
442bde46
   data->head.szdata += sizeof(uint16_t);
   return(0);
 }
 
 int data_safeset32(mdata *data, uint32_t val)
 {
   if(data->head.szdata + sizeof(uint32_t) > MAKUO_BUFFER_SIZE){
     return(-1);
   }
36959136
   val = htonl(val);
   memcpy((void *)(data->data + data->head.szdata), (void *)(&val), sizeof(val));
442bde46
   data->head.szdata += sizeof(uint32_t);
   return(0);
 }
 
8e09e847
 excludeitem *exclude_add(excludeitem *exclude, char *pattern)
 {
   excludeitem *e = malloc(sizeof(excludeitem));
   e->prev = NULL;
   e->next = NULL;
   if(exclude){
     e->next = exclude;
     e->prev = exclude->prev;
     exclude->prev = e;
     if(e->prev){
       e->prev->next = e;
     }
   }
   e->pattern = malloc(strlen(pattern)+1);
   strcpy(e->pattern, pattern);
   return(e);
 }
 
 excludeitem *exclude_del(excludeitem *e)
 {
   excludeitem *r = NULL;
   excludeitem *p = NULL;
   excludeitem *n = NULL;
 
   if(!e){
     return(NULL);
   }
   p = e->prev;
   n = e->next;
   if(p){
     p->next=n;
   }
   if(n){
     n->prev=p;
     r = n;
   }
   free(e->pattern);
   e->pattern = NULL;
   e->prev = NULL;
   e->next = NULL;
   free(e);
   return(r);
 }