Back to index

avfs  1.0.1
dispatch.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 1998-2001  Miklos Szeredi <miklos@szeredi.hu>
00004 
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 */
00008 
00009 #include "avfscoda.h"
00010 
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <unistd.h>
00015 #include <time.h>
00016 #include <signal.h>
00017 #include <stdarg.h>
00018 #include <errno.h>
00019 #include <fcntl.h>
00020 #include <grp.h>
00021 #include <pwd.h>
00022 #include <sys/time.h>
00023 #include <sys/stat.h>
00024 #include <syslog.h>
00025 
00026 /* #include "KERNINCLUDE/linux/coda.h" */
00027 #include CODAINCLUDE
00028 
00029 /* Keep file lookups cached for at least this many seconds: */
00030 #define KEEPTIME 600
00031 
00032 /* Flush attribute caches after this many seconds */
00033 #define FLUSHTIME 2
00034 
00035 /* Keep at most this many looked up files cached: */
00036 #define MAXFILES 5000
00037 
00038 /* Check looked up files after this many operations: */
00039 #define CHECKNUM 1000
00040 
00041 /* Maximum number of child processes running: */
00042 #define MAXUSERS 10
00043 
00044 #define MAXMSGLEN 1045
00045 
00046 
00047 struct operation {
00048     struct operation *next;
00049     union inputArgs *req;
00050        
00051     char ibuf[MAXMSGLEN];
00052 };
00053 
00054 struct userinfo {
00055     uid_t uid;
00056     gid_t gid;
00057     volatile pid_t serverpid;
00058     int pipout;
00059     int pipin;
00060     time_t lastuse;
00061     int terminated;
00062     struct operation *ops;
00063 };
00064 
00065 static struct userinfo currusers[MAXUSERS];
00066 
00067 static int codafd;
00068 static const char *codadir;
00069 static FILE *logfile;
00070 
00071 static int numfids;
00072 static int checknum;
00073 
00074 static int debugmode;
00075 
00076 struct openfile {
00077     pid_t pid;
00078     char *tmpfile;
00079     int fd;
00080     int use;
00081     int wuse;
00082        
00083     struct openfile *next;
00084 };
00085 
00086 struct fileinfo {
00087     struct fileinfo *prev;
00088     struct fileinfo *next;
00089        
00090     char *name;
00091     char *path;
00092     unsigned int unique;
00093     unsigned int parunique;
00094        
00095     time_t lasttime;
00096     int use;
00097        
00098     struct openfile *ofs;
00099 };
00100 
00101 #define FMAPSIZE 65536
00102 static struct fileinfo *fmap[FMAPSIZE];
00103 static unsigned int nextunique = 0;
00104 
00105 #define HASHSIZE 6247
00106 static struct fileinfo *fhash[HASHSIZE];
00107 
00108 static int needflush;
00109 
00110 static struct fileinfo unused_files;
00111 
00112 static void log(const char *, ...) __attribute__ ((format (printf, 1, 2)));
00113 static void log(const char *fmt, ...)
00114 {
00115     if(debugmode) {
00116        va_list ap;
00117        
00118        va_start(ap, fmt);
00119        vfprintf(logfile, fmt, ap);
00120        va_end(ap);
00121     }
00122 }
00123 
00124 static void log_date()
00125 {
00126     if(debugmode) {
00127         struct tm tm;
00128         struct timeval tv;
00129 
00130         gettimeofday(&tv, NULL);
00131         localtime_r(&tv.tv_sec, &tm);        
00132         log("%02i/%02i %02i:%02i:%02i.%03i\n", 
00133             tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
00134             (int) (tv.tv_usec / 1000));
00135     }
00136 }
00137 
00138 #define LOGMSG_SIZE 1024
00139 static void logerr(const char *, ...) __attribute__ ((format (printf, 1, 2)));
00140 static void logerr(const char *fmt, ...)
00141 {
00142     char buf[LOGMSG_SIZE + 1];
00143     va_list ap;
00144 
00145     va_start(ap, fmt);
00146     vsnprintf(buf, LOGMSG_SIZE, fmt, ap);
00147     va_end(ap);
00148 
00149     buf[LOGMSG_SIZE] = '\0';
00150     syslog(LOG_INFO, "%s", buf);
00151     log(buf);
00152 }
00153 
00154 static unsigned int fi_hash(unsigned int unique, const char *name)
00155 {
00156     unsigned int hash = unique;
00157 
00158     for(; *name != 0; name++) {
00159        hash = (hash << 4) | (hash >> 28);
00160        hash ^= (unsigned int) *name;
00161     }
00162     return hash % HASHSIZE;
00163 }
00164 
00165 static struct fileinfo *remove_name(struct fileinfo *parentdir,
00166                                 const char *name)
00167 {
00168     struct fileinfo **fip;
00169     unsigned int hash = fi_hash(parentdir->unique, name);
00170     
00171     for(fip = &fhash[hash]; *fip != NULL; fip = &(*fip)->next) {
00172        struct fileinfo *fi = *fip;
00173        if(fi->parunique == parentdir->unique && strcmp(fi->name, name) == 0) {
00174            *fip = fi->next;
00175            return fi;
00176        }
00177     }
00178 
00179     return NULL;
00180 }
00181 
00182 
00183 static void add_name(struct fileinfo *fi, struct fileinfo *parentdir,
00184                      const char *name, int hash)
00185 {
00186     fi->next = fhash[hash];
00187     fhash[hash] = fi;
00188 
00189     fi->name = strdup(name);
00190     fi->parunique = parentdir->unique;
00191     fi->path = (char *) malloc(strlen(parentdir->path) + 1 + strlen(name) + 1);
00192     sprintf(fi->path, "%s/%s", parentdir->path, name);
00193 }
00194 
00195 static void rename_file(struct fileinfo *oldfi, const char *oldname,
00196                      struct fileinfo *newfi, const char *newname)
00197 {
00198     struct fileinfo *fi;
00199 
00200     fi = remove_name(oldfi, oldname);
00201     if(fi != NULL) {
00202        unsigned int hash = fi_hash(newfi->unique, newname);
00203        
00204        free(fi->name);
00205        free(fi->path);
00206        add_name(fi, newfi, newname, hash);
00207     }
00208 
00209 }
00210 
00211 static struct fileinfo *get_file(struct fileinfo *parentdir, const char *name)
00212 {
00213     unsigned int hash = fi_hash(parentdir->unique, name);
00214     struct fileinfo *fi;
00215     int i;
00216 
00217     for(fi = fhash[hash]; fi != NULL; fi = fi->next)
00218        if(fi->parunique == parentdir->unique && strcmp(fi->name, name) == 0)
00219            return fi;
00220 
00221     fi = malloc(sizeof(*fi));
00222     if(fi == NULL) {
00223         logerr("Out of memory");
00224         clean_exit(1);
00225     }
00226     
00227     for(i = 0; i < FMAPSIZE; i++) {
00228         unsigned int index;
00229 
00230         nextunique ++;
00231         if(nextunique == 0)
00232             nextunique = 1;
00233 
00234         index = nextunique % FMAPSIZE;
00235         if(fmap[index] == NULL) {
00236             fmap[index] = fi;
00237             fi->unique = nextunique;
00238             break;
00239         }
00240     }
00241 
00242     if(i == FMAPSIZE) {
00243         logerr("fmap full\n");
00244         clean_exit(1);
00245     }
00246 
00247     log("New fid: 0x%x\n", fi->unique);
00248 
00249     numfids ++;
00250 
00251     fi->lasttime = time(NULL);
00252     fi->ofs = NULL;
00253     fi->use = 0;
00254 
00255     add_name(fi, parentdir, name, hash);
00256 
00257     return fi;
00258 }
00259 
00260 
00261 static void put_file(struct fileinfo *fi)
00262 {
00263     struct fileinfo *prev;
00264     struct fileinfo *next;
00265 
00266     log("Put fid: 0x%x\n", fi->unique);
00267 
00268     prev = unused_files.prev;
00269     next = &unused_files;
00270     prev->next = fi;
00271     next->prev = fi;
00272     fi->next = next;
00273     fi->prev = prev;
00274 
00275     free(fi->name);
00276     fi->name = NULL;
00277 }
00278 
00279 static void remove_file(struct fileinfo *parentdir, const char *name)
00280 {
00281     struct fileinfo *fi;
00282 
00283     fi = remove_name(parentdir, name);
00284     if(fi != NULL)
00285        put_file(fi);
00286 }
00287 
00288 
00289 static void delete_file(struct fileinfo *fi)
00290 {
00291     unsigned int index;
00292     struct fileinfo *prev = fi->prev;
00293     struct fileinfo *next = fi->next;
00294 
00295     log("Delete fid: 0x%x\n", fi->unique);
00296 
00297     prev->next = next;
00298     next->prev = prev;
00299 
00300     index = fi->unique % FMAPSIZE;
00301     fmap[index] = NULL;
00302 
00303     free(fi->name);
00304     free(fi->path);
00305     free(fi);
00306     numfids --;
00307 }
00308 
00309 static struct fileinfo *get_info(unsigned int unique)
00310 {
00311     struct fileinfo *fi;
00312     unsigned int index = (unique % FMAPSIZE);
00313 
00314     fi = fmap[index];
00315     if(fi == NULL || fi->unique != unique) {
00316         logerr("Deleted Fid: 0x%x\n", unique);
00317         return NULL;
00318     }
00319     return fi;
00320 }
00321 
00322 static struct fileinfo *look_info(ViceFid *id)
00323 {
00324     struct fileinfo *fi;
00325        
00326     if ((id->Volume != 0) || (id->Vnode != 0)) {
00327         logerr("Bad handle passed %lx/%lx/%lx\n", 
00328             id->Volume, id->Vnode, id->Unique );
00329         clean_exit(1);
00330     }
00331        
00332     log("unique: 0x%x\n", (unsigned int) id->Unique);
00333        
00334     if(id->Unique == 0) {
00335        static struct fileinfo rootinfo;
00336        rootinfo.path = "/";
00337         return &rootinfo;
00338     }
00339     else {
00340         fi = get_info(id->Unique);
00341         if(fi != NULL)
00342             fi->lasttime = time(NULL);
00343               
00344         return fi;
00345     }
00346 }
00347 
00348 static char *look_name(ViceFid *id)
00349 {
00350     struct fileinfo *fi;
00351        
00352     fi = look_info(id);
00353     if(fi == NULL)
00354         return NULL;
00355 
00356     log("path: %s\n", fi->path);
00357        
00358     return fi->path;
00359 }
00360 
00361 static void ref_fid(ViceFid *fid)
00362 {
00363     struct fileinfo *fi = look_info(fid);
00364 
00365     if(fi != NULL)
00366         fi->use ++;
00367 }
00368 
00369 static void unref_fid(ViceFid *fid)
00370 {
00371     struct fileinfo *fi = look_info(fid);
00372 
00373     if(fi != NULL)
00374         fi->use --;
00375 }
00376 
00377 static void reset_signal_handlers()
00378 {
00379     struct sigaction sa;
00380        
00381     sa.sa_handler = SIG_DFL;
00382     sigemptyset(&(sa.sa_mask));
00383     sa.sa_flags = 0;
00384        
00385     sigaction(SIGPIPE, &sa, NULL);
00386     sigaction(SIGCHLD, &sa, NULL);
00387 }
00388 
00389 
00390 static void send_to_kernel(union outputArgs *rep, int size)
00391 {
00392     int ret;
00393        
00394     log("%i bytes\n",  size);
00395     ret = write(codafd, rep, size);
00396     if(ret == -1 || ret != size) {
00397         logerr("Error writing to device: %s\n", strerror(errno));
00398     }
00399 }
00400 
00401 static struct fileinfo *create_file(const char *filename, ViceFid *parentid,
00402                                     ViceFid *newid)
00403 {
00404     struct fileinfo *fi;
00405 
00406     fi = look_info(parentid);
00407     if(fi == NULL)
00408         return NULL;
00409     fi = get_file(fi, filename);
00410 
00411     newid->Volume = 0;
00412     newid->Vnode = 0;
00413     newid->Unique = fi->unique;
00414 
00415     return fi;
00416 }
00417 
00418 static void purge_file(struct fileinfo *fi)
00419 {
00420     union outputArgs rep;
00421 
00422     log("=================================================================\n");
00423     log_date();
00424     log("Cleaning out 0x%x\n", fi->unique);
00425     log("CODA_PURGEFID\n");
00426     
00427     rep.oh.opcode = CODA_PURGEFID;
00428     rep.oh.result = 0;
00429     rep.oh.unique = 0;
00430     rep.coda_purgefid.CodaFid.Volume = 0;
00431     rep.coda_purgefid.CodaFid.Vnode  = 0;
00432     rep.coda_purgefid.CodaFid.Unique = fi->unique;
00433     
00434     send_to_kernel(&rep, sizeof(rep.coda_purgefid));
00435 }
00436 
00437 static void zap_file(struct fileinfo *fi)
00438 {
00439     union outputArgs rep;
00440 
00441     log("=================================================================\n");
00442     log_date();
00443     log("Cleaning out 0x%x\n", fi->unique);
00444     log("CODA_ZAPFILE\n");
00445     
00446     rep.oh.opcode = CODA_ZAPFILE;
00447     rep.oh.result = 0;
00448     rep.oh.unique = 0;
00449     rep.coda_zapfile.CodaFid.Volume = 0;
00450     rep.coda_zapfile.CodaFid.Vnode  = 0;
00451     rep.coda_zapfile.CodaFid.Unique = fi->unique;
00452     
00453     send_to_kernel(&rep, sizeof(rep.coda_zapfile));
00454 }
00455 
00456 #if 0
00457 static void zap_dir(struct fileinfo *fi)
00458 {
00459     union outputArgs rep;
00460 
00461     log("=================================================================\n");
00462     log_date();
00463     log("Cleaning out 0x%x\n", fi->unique);
00464     log("CODA_ZAPDIR\n");
00465     
00466     rep.oh.opcode = CODA_ZAPDIR;
00467     rep.oh.result = 0;
00468     rep.oh.unique = 0;
00469     rep.coda_zapdir.CodaFid.Volume = 0;
00470     rep.coda_zapdir.CodaFid.Vnode  = 0;
00471     rep.coda_zapdir.CodaFid.Unique = fi->unique;
00472     
00473     send_to_kernel(&rep, sizeof(rep.coda_zapdir));
00474 }
00475 #endif
00476 
00477 static void clean_up(time_t oldtime)
00478 {
00479     int i;
00480 
00481     for(i = 0; i < HASHSIZE; i++) {
00482        struct fileinfo **fip = &fhash[i];
00483 
00484        while(*fip != NULL) {
00485            struct fileinfo *fi = *fip;
00486               
00487            if((!oldtime || fi->lasttime < oldtime) && fi->use == 0) {
00488               *fip = fi->next;
00489               purge_file(fi);
00490               put_file(fi);
00491            }
00492            else
00493               fip = &fi->next;        
00494        }
00495     }
00496 }
00497 
00498 static void clean_up_unused()
00499 {
00500     struct fileinfo *fi;
00501 
00502     for(fi = unused_files.next; fi != &unused_files;) {
00503         struct fileinfo *nextfi = fi->next;
00504         if(fi->use == 0)
00505             delete_file(fi);
00506 
00507         fi = nextfi;
00508     }
00509 }
00510 
00511 
00512 static void clean_up_names()
00513 {
00514     clean_up_unused();
00515 
00516     if(numfids > FMAPSIZE / 2)
00517         clean_up(0);
00518     else
00519         clean_up(time(NULL) - KEEPTIME);
00520 }
00521 
00522 static void open_file(union inputArgs *req, struct openfile *of)
00523 {
00524     int ret;
00525     union outputArgs rep;
00526     struct stat stbuf;
00527        
00528     rep.oh.opcode = req->ih.opcode;
00529     rep.oh.unique = req->ih.unique;
00530        
00531     if(req->ih.opcode == CODA_OPEN) {
00532         ret = stat(of->tmpfile, &stbuf);
00533         if(ret == -1) 
00534             rep.oh.result = errno;
00535         else {
00536             rep.oh.result = 0;
00537             rep.coda_open.dev = stbuf.st_dev;
00538             rep.coda_open.inode = stbuf.st_ino;
00539             
00540             log("dev: %lli, ino: %lli\n", rep.coda_open.dev,
00541                 rep.coda_open.inode);
00542             log("size: %lli\n", stbuf.st_size);
00543             of->use ++;
00544             if((req->coda_open.flags & (C_O_WRITE | C_O_TRUNC)) != 0)
00545                 of->wuse ++;
00546         }
00547        
00548         send_to_kernel(&rep, sizeof(rep.coda_open));
00549     }
00550 #ifdef CODA_OPEN_BY_FD
00551     else {
00552         if(of->fd == -1) {
00553             of->fd = open(of->tmpfile, O_RDONLY);
00554             if(of->fd == -1)
00555                 rep.oh.result = errno;
00556         }
00557         if(of->fd != -1) {
00558             rep.oh.result = 0;
00559             rep.coda_open_by_fd.fd =  of->fd;
00560             
00561             log("fd: %i\n", of->fd);
00562 
00563             of->use ++;
00564             if((req->coda_open.flags & (C_O_WRITE | C_O_TRUNC)) != 0)
00565                 of->wuse ++;
00566         }
00567         send_to_kernel(&rep, sizeof(rep.coda_open_by_fd));
00568     }
00569 #endif
00570 }
00571 
00572 static void del_file(const char *tmpname)
00573 {
00574     int res;
00575        
00576     /* Coda holds on to the inode, so to free up space: */
00577     truncate(tmpname, 0);
00578     res = unlink(tmpname);
00579     if(res == -1)
00580         fprintf(stderr, "unlink(%s) failed (%s)\n", 
00581                 tmpname, strerror(errno));
00582 }
00583 
00584 static void close_file(struct openfile *of, struct openfile **ofp,
00585                        ViceFid *fid)
00586 {
00587     
00588     if(of->use > 0) of->use --;
00589     if(of->use == 0 && of->tmpfile != NULL) {
00590         if(of->fd != -1)
00591             close(of->fd);
00592         del_file(of->tmpfile);
00593         free(of->tmpfile);
00594         *ofp = of->next;
00595         free(of);
00596         unref_fid(fid);
00597     }
00598 }
00599 
00600 static void reply(union inputArgs *req, int res)
00601 {
00602     union outputArgs rep;
00603        
00604     rep.oh.opcode = req->ih.opcode;
00605     rep.oh.unique = req->ih.unique;
00606     rep.oh.result = res;
00607        
00608     send_to_kernel(&rep, sizeof(rep.oh));
00609 }
00610 
00611 static void check_servers()
00612 {
00613     int i;
00614               
00615     for(i = 0; i < MAXUSERS; i++) {
00616         if(currusers[i].serverpid == 0) {
00617             /* FIXME: reply to the pending messages */
00618                      
00619             close(currusers[i].pipout);
00620             close(currusers[i].pipin);
00621                      
00622             currusers[i].serverpid = -1;
00623         }
00624     }
00625 }
00626 
00627 static void grab_fids(union inputArgs *req)
00628 {
00629     /* All have first VFid in the same place */
00630     ref_fid(&req->coda_getattr.VFid);
00631     
00632     if(req->ih.opcode == CODA_LINK)
00633         ref_fid(&req->coda_link.destFid);
00634     if(req->ih.opcode == CODA_RENAME)
00635         ref_fid(&req->coda_rename.destFid);
00636 }
00637 
00638 static void release_fids(union inputArgs *req)
00639 {
00640     /* All have first VFid in the same place */
00641     unref_fid(&req->coda_getattr.VFid);
00642     
00643     if(req->ih.opcode == CODA_LINK)
00644         unref_fid(&req->coda_link.destFid);
00645     if(req->ih.opcode == CODA_RENAME)
00646         unref_fid(&req->coda_rename.destFid);
00647 }
00648 
00649 static void process_answer(struct userinfo *user)
00650 {
00651     int numread;
00652     char obuf[MAXMSGLEN];
00653     union outputArgs *rep = (union outputArgs *) obuf;
00654     struct operation *op, **opp;
00655     struct fileinfo *fi;
00656     struct openfile *of, **ofp;
00657     char *filename;
00658     int insize;
00659 
00660     if(!needflush)
00661         needflush = time(NULL);
00662 
00663     numread = read(user->pipin, &insize, sizeof(insize));
00664     if(numread == -1) {
00665         logerr("Error reading from device: %s\n", strerror(errno));
00666         return;
00667     }
00668     if(insize > MAXMSGLEN || insize <= 0) {
00669         logerr("Error: illegal size");
00670         return;
00671     }
00672        
00673     numread = read(user->pipin, obuf, insize);
00674     if(numread == -1) {
00675         logerr("Error reading from child [%i/%i]: %s\n", 
00676             user->uid, user->gid, strerror(errno));
00677         return;
00678     }
00679        
00680     log("+ %i/%i [%i] +++++++++++++++++++++++++++++++++++++++++++++++++++\n",
00681         user->uid, user->gid, user->serverpid);
00682     log_date();
00683     log("%i (%i) bytes: opcode: %li, result: %i, unique: %li\n", 
00684         numread, insize, rep->oh.opcode, (int) rep->oh.result, rep->oh.unique);
00685        
00686     for(opp = &user->ops; *opp != NULL; opp = &(*opp)->next) 
00687         if((*opp)->req->ih.unique == rep->oh.unique) break;
00688        
00689     op = *opp;
00690        
00691     if(op == NULL)
00692         logerr("Operation not found!!!!\n");
00693     else {
00694         log("Found operation: %li\n", op->req->ih.unique);
00695               
00696         switch(rep->oh.opcode) {
00697 #ifdef CODA_OPEN_BY_FD
00698         case CODA_OPEN_BY_FD:
00699 #endif
00700         case CODA_OPEN:
00701             fi = look_info(&op->req->coda_open.VFid);
00702 
00703             for(ofp = &fi->ofs; *ofp != NULL; ofp = &(*ofp)->next)
00704                 if((*ofp)->pid == op->req->ih.pid) break;
00705                             
00706             of = *ofp;
00707 
00708             if(of == NULL) {
00709                 logerr("Output file not found!!!\n");
00710                 reply(op->req, ENOENT);
00711             }
00712             else {
00713                 if(rep->oh.result == 0) {
00714                     open_file(op->req, of);
00715                 }
00716                 else {
00717                     close_file(of, ofp, &op->req->coda_open.VFid);
00718                     send_to_kernel(rep, numread);
00719                 }
00720             }
00721             break;
00722         
00723         case CODA_CLOSE:
00724             fi = look_info(&op->req->coda_close.VFid);
00725             
00726             for(ofp = &fi->ofs; *ofp != NULL; ofp = &(*ofp)->next)
00727                 if((*ofp)->pid == op->req->ih.pid) break;
00728             
00729             of = *ofp;
00730 
00731             if(of == NULL) {
00732                 logerr("Output file not found!!!\n");
00733                 reply(op->req, ENOENT);
00734             }
00735             else
00736                 close_file(of, ofp, &op->req->coda_close.VFid);
00737 
00738             send_to_kernel(rep, numread);
00739            zap_file(fi);
00740             break;
00741                      
00742         case CODA_LOOKUP:
00743             if(rep->oh.result == 0) {
00744                 filename = (char *) op->req + op->req->coda_lookup.name;
00745                 fi = create_file(filename, &op->req->coda_lookup.VFid,
00746                                  &rep->coda_lookup.VFid);
00747                 if(fi == NULL)
00748                     rep->oh.result = ENOENT;
00749             }
00750             send_to_kernel(rep, numread);
00751             break;
00752 
00753         case CODA_CREATE:
00754             if(rep->oh.result == 0) {
00755                 filename = (char *) op->req + op->req->coda_create.name;
00756                 fi = create_file(filename, &op->req->coda_create.VFid,
00757                                  &rep->coda_create.VFid);
00758                 if(fi == NULL)
00759                     rep->oh.result = ENOENT;
00760             }
00761             send_to_kernel(rep, numread);
00762             break;
00763 
00764         case CODA_MKDIR:
00765             if(rep->oh.result == 0) {
00766                 filename = (char *) op->req + op->req->coda_mkdir.name;
00767                 fi = create_file(filename, &op->req->coda_mkdir.VFid,
00768                                  &rep->coda_mkdir.VFid);
00769                 if(fi == NULL)
00770                     rep->oh.result = ENOENT;
00771             }
00772             send_to_kernel(rep, numread);
00773             break;
00774 
00775         case CODA_REMOVE:
00776             if(rep->oh.result == 0) {
00777                 filename = (char *) op->req + op->req->coda_remove.name;
00778                 fi = look_info(&op->req->coda_remove.VFid);
00779               remove_file(fi, filename);
00780             }
00781             send_to_kernel(rep, numread);
00782             break;
00783 
00784         case CODA_RMDIR:
00785             if(rep->oh.result == 0) {
00786                 filename = (char *) op->req + op->req->coda_rmdir.name;
00787                 fi = look_info(&op->req->coda_rmdir.VFid);
00788               remove_file(fi, filename);
00789             }
00790             send_to_kernel(rep, numread);
00791             break;
00792             
00793         case CODA_RENAME:
00794             if(rep->oh.result == 0) {
00795                 char *newname;
00796                 struct fileinfo *newfi;
00797 
00798                 newname = (char *) op->req + op->req->coda_rename.destname;
00799                 newfi = look_info(&op->req->coda_rename.destFid);
00800               remove_file(newfi, newname);
00801 
00802                 filename = (char *) op->req + op->req->coda_rename.srcname;
00803                 fi = look_info(&op->req->coda_rename.sourceFid);
00804               rename_file(fi, filename, newfi, newname);
00805             }
00806             send_to_kernel(rep, numread);
00807             break;
00808 
00809         default:
00810             send_to_kernel(rep, numread);
00811                      
00812         }
00813         
00814         release_fids(op->req);
00815         *opp = op->next;
00816         free(op);
00817     }
00818        
00819     if(user->ops != NULL) {
00820         log("Remaining operations: ");
00821         for(op = user->ops; op != NULL; op = op->next)
00822             log("%li ", op->req->ih.unique);
00823         log("\n");
00824     }  
00825 }
00826 
00827 static void process_child_answer()
00828 {
00829     fd_set rfds;
00830     int ret;
00831     int maxfd;
00832     int i;
00833        
00834     check_servers();
00835        
00836     FD_ZERO(&rfds);
00837        
00838     maxfd = 0;
00839        
00840     for(i = 0; i < MAXUSERS; i++) {
00841         if(currusers[i].serverpid > 0) {
00842             int pipfd = currusers[i].pipin;
00843                      
00844             FD_SET(pipfd, &rfds);
00845             if(pipfd > maxfd) maxfd = pipfd;
00846         }
00847     }
00848        
00849     ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
00850     if(ret == -1) {
00851         if(errno != EINTR) 
00852             logerr("Select failed: %s\n", strerror(errno));
00853     }
00854     else {
00855         for(i = 0; i < MAXUSERS; i++) {
00856             if(currusers[i].serverpid > 0) {
00857                 int pipfd = currusers[i].pipin;
00858                             
00859                 if(FD_ISSET(pipfd, &rfds)) 
00860                     process_answer(&currusers[i]);
00861             }
00862         }
00863     }
00864 }
00865 
00866 static void kill_child()
00867 {
00868     struct userinfo *user;
00869     time_t oldesttime;
00870     int oldesti;
00871     int i;
00872     pid_t pid;
00873        
00874     oldesttime = 0;
00875     oldesti = -1;
00876        
00877     do {
00878         for(i = 0; i < MAXUSERS; i++) {
00879             user = currusers + i;
00880             if(user->serverpid == -1) return;
00881             if(user->serverpid == 0) {
00882                 check_servers();
00883                 return;
00884             }
00885                      
00886             if(user->ops == NULL) {
00887                 if(oldesti == -1 || 
00888                    user->lastuse < oldesttime) {
00889                     oldesttime = user->lastuse;
00890                     oldesti = i;
00891                 }
00892             }
00893         }
00894               
00895         if(oldesti == -1) {
00896             /* If every child is busy then block */
00897             process_child_answer();
00898         }
00899     } while(oldesti == -1);
00900        
00901     user = currusers + oldesti;
00902        
00903     /* FIXME: This is a mess, because user->serverpid can change to 0 
00904        when SIGCHLD is received */
00905     pid = user->serverpid;
00906     if(pid > 0) {
00907         if(!user->terminated) {
00908             kill(pid, SIGTERM);
00909             user->terminated = 1;
00910         }
00911         else {
00912             log("kill(%i, SIGKILL)\n", pid);
00913             kill(pid, SIGKILL);
00914         }
00915     }
00916        
00917     /* FIXME: Need to wait for the death of the child or max 1 second. 
00918        How can this be done? */
00919     if(user->serverpid > 0)
00920         sleep(1);
00921        
00922     check_servers();
00923 }
00924 
00925 static int new_child(struct userinfo *user, uid_t uid, gid_t gid)
00926 {
00927     int pipout[2];
00928     int pipin[2];
00929     int pid;
00930     int i;
00931     gid_t list[32];
00932     int num;
00933        
00934     if(pipe(pipout) == -1) {
00935         logerr("Could not open pipe for child: %s\n", strerror(errno));
00936         return -1;
00937     }
00938     if(pipe(pipin) == -1) {
00939         close(pipout[0]);
00940         close(pipout[1]);
00941         return -1;
00942     }
00943        
00944     user->serverpid = pid = fork();
00945     if(pid == -1) {
00946         close(pipout[0]);
00947         close(pipout[1]);
00948         close(pipin[0]);
00949         close(pipin[1]);
00950         logerr("Could not fork child: %s\n", strerror(errno));
00951         return -1;
00952     }
00953        
00954     user->pipout = pipout[1];
00955     user->pipin = pipin[0];
00956        
00957     if(pid == 0) {
00958         /* Child */
00959               
00960         reset_signal_handlers();
00961               
00962         /* Close everything, except the current pipes */
00963         for(i = 0; i < MAXUSERS; i++) 
00964             if(currusers[i].serverpid >= 0) {
00965                 close(currusers[i].pipout);
00966                 close(currusers[i].pipin);
00967             }
00968               
00969         close(codafd);
00970 #if 0
00971         fclose(logfile);
00972 #endif
00973         /* Don't want any troublesome signals from the child */
00974         setsid(); 
00975               
00976         /* FIXME: What is the proper way of dealing with
00977            supplementary groups? */
00978         list[0] = gid;
00979         num = 1;
00980         setgroups(num, list);
00981               
00982 #if 1
00983         {
00984             struct passwd *pwbuf;
00985                      
00986             /* FIXME: This messes up gdb. Why? */
00987             pwbuf = getpwuid(uid);
00988             if(pwbuf != NULL)
00989                 initgroups(pwbuf->pw_name, gid);
00990         }
00991 #endif
00992               
00993         setgid(gid);
00994         setuid(uid);
00995               
00996         fprintf(stderr, "Child process: %i/%i\n", getuid(), getgid());
00997               
00998         num = getgroups(32, list);
00999         fprintf(stderr, "Supplementary groups: ");
01000         for(i = 0; i < num; i++) fprintf(stderr, "%i, ", list[i]);
01001         fprintf(stderr, "\n");
01002               
01003         child_process(pipout[0], pipin[1]);
01004         exit(0);
01005     }
01006        
01007     /* Parent */
01008        
01009     close(pipout[0]);
01010     close(pipin[1]);
01011        
01012     user->uid = uid;
01013     user->gid = gid;
01014     user->terminated = 0;
01015     user->lastuse = 0;
01016     user->ops = NULL;
01017        
01018     return 0;
01019 }
01020 
01021 static struct userinfo *get_user(uid_t uid, gid_t gid)
01022 {
01023     int i;
01024     struct userinfo *user = NULL;
01025        
01026     for(i = 0; i < MAXUSERS; i++) {
01027         if(currusers[i].serverpid > 0 && currusers[i].uid == uid &&
01028            currusers[i].gid == gid) {
01029             user = &currusers[i];
01030             break;
01031         }
01032     }
01033        
01034     if(user == NULL) {
01035         /* Create child */
01036         do {
01037             /* Find a free slot */
01038             for(i = 0; i < MAXUSERS; i++)
01039                 if(currusers[i].serverpid == -1) break;
01040                      
01041             if(i == MAXUSERS) {
01042                 /* No free slots, must kill a child */
01043                 kill_child();
01044             }
01045         } while(i == MAXUSERS);
01046               
01047         user = currusers + i;
01048         if(new_child(user, uid, gid) == -1)
01049             return NULL;
01050     }
01051        
01052     user->lastuse = time(NULL);
01053     return user;
01054 }
01055 
01056 
01057 static void send_to_child(union inputArgs *req, int reqsize, char *path1,
01058                        char *path2)
01059 {
01060     struct operation *op;
01061     uid_t uid = req->ih.cred.cr_fsuid;
01062     gid_t gid = req->ih.cred.cr_fsgid;
01063     struct userinfo *user;
01064     int msgsize;
01065     struct child_message msg;
01066     char *message, *mp;
01067     int msgoff;
01068     int res;
01069     
01070 
01071     user = get_user(uid, gid);
01072     if(user == NULL) {
01073         reply(req, ENOMEM);
01074         return;
01075     }
01076        
01077     msg.reqsize = reqsize;
01078     msg.path1size = path1 ? strlen(path1) + 1 : 0;
01079     msg.path2size = path2 ? strlen(path2) + 1 : 0;
01080     msgoff = sizeof(struct child_message);
01081        
01082     msgsize = sizeof(int) + msgoff + msg.reqsize + msg.path1size + 
01083         msg.path2size;
01084        
01085     message = malloc(msgsize);
01086     if(message == NULL) {
01087         reply(req, ENOMEM);
01088         return;
01089     }
01090        
01091     op = malloc(sizeof(struct operation));
01092     if(op == NULL) {
01093         free(message);
01094         reply(req, ENOMEM);
01095         return;
01096     }
01097        
01098     memcpy(op->ibuf, req, reqsize);
01099     op->req = (union inputArgs *) op->ibuf;
01100        
01101     mp = message;
01102        
01103     *(int *) mp = (msgsize - sizeof(int));
01104     mp += sizeof(int);
01105        
01106     memcpy(mp, &msg, msgoff);
01107     mp += msgoff;
01108        
01109     memcpy(mp, req, msg.reqsize);
01110     mp += msg.reqsize;
01111        
01112     log("****** opcode: %li\n", req->ih.opcode);
01113     log("****** msgsize: %i, msgoff: %i, msg.reqsize: %i, \n", 
01114         msgsize, msgoff, msg.reqsize);
01115        
01116     if(path1) {
01117         memcpy(mp, path1, msg.path1size);
01118         mp += msg.path1size;
01119     }
01120        
01121     if(path2) {
01122         memcpy(mp, path2, msg.path2size);
01123         mp += msg.path2size;
01124     }
01125        
01126     res = write(user->pipout, message, msgsize);
01127     free(message);
01128        
01129     if(res != msgsize) {
01130         free(op);
01131         logerr("Error writing to child: %s\n", strerror(errno));
01132               
01133         reply(req, errno);
01134     }
01135     else {
01136         grab_fids(req);
01137         op->next = user->ops;
01138         user->ops = op;
01139     }
01140 }
01141 
01142 static void send_with_path(union inputArgs *req, int reqsize, char *filename,
01143                            ViceFid *id, char *path2)
01144 {
01145     char pathbuf[1024];
01146     struct fileinfo *fi;
01147     char *path;
01148 
01149     fi = look_info(id);
01150     if(fi == NULL) {
01151         reply(req, ENOENT);
01152         return;
01153     }
01154 
01155     path = fi->path;
01156               
01157     sprintf(pathbuf, "%s/%s", path, filename);
01158 
01159     log("path1: %s, path2: %s\n", pathbuf, path2 ? path2 : "(null)");
01160 
01161     /* FIXME: */
01162     if(strcmp(pathbuf+1, codadir) == 0) 
01163             reply(req, ENOENT);
01164     else 
01165             send_to_child(req, reqsize, pathbuf, path2);
01166 }
01167 
01168 static void coda_flush()
01169 {
01170     union outputArgs rep;
01171        
01172     log("=================================================================\n");
01173     log_date();
01174     log("CODA_FLUSH\n");
01175        
01176     rep.oh.opcode = CODA_FLUSH;
01177     rep.oh.result = 0;
01178     rep.oh.unique = 0;
01179        
01180     send_to_kernel(&rep, sizeof(rep.oh));
01181 }
01182 
01183 void run_exit()
01184 {
01185     int i;
01186        
01187     for(i = 0; i < MAXUSERS; i++) {
01188         if(currusers[i].serverpid > 0) {
01189             kill(currusers[i].serverpid, SIGTERM);
01190         }
01191     }
01192        
01193     /* FIXME: should wait until the children are all dead */
01194        
01195     coda_flush();
01196     close(codafd);
01197     unmount_coda(codadir, 0);
01198 }
01199 
01200 void user_child(pid_t pid)
01201 {
01202     int i;
01203        
01204     for(i = 0; i < MAXUSERS; i++) {
01205         if(currusers[i].serverpid == pid) {
01206             log("Child %i (%i/%i) exited\n", 
01207                 pid, currusers[i].uid, 
01208                 currusers[i].gid);
01209                      
01210             currusers[i].serverpid = 0;
01211                      
01212             return;
01213         }
01214     }
01215        
01216     logerr("Unknown child %i exited\n", pid);
01217 }
01218 
01219 static void process_kernel_req()
01220 {
01221     char ibuf[MAXMSGLEN];
01222     char pathbuf[1024];
01223     union inputArgs *req = (union inputArgs *) ibuf;
01224     union outputArgs rep;
01225     struct openfile *of, **ofp;
01226     int numread;
01227     char *path;
01228     char *filename, *filename2;
01229     struct fileinfo *fi;
01230     struct operation **opp, *op;
01231     int i;
01232        
01233     numread = read(codafd, ibuf, MAXMSGLEN);
01234     if(numread == -1) {
01235         logerr("Error reading from device: %s\n", strerror(errno));
01236         clean_exit(1);
01237     }
01238        
01239     log("=================================================================\n");
01240     log_date();
01241     log("%i bytes: opcode: %li, unique: %li\n", 
01242         numread, req->ih.opcode, req->ih.unique);
01243        
01244     switch (req->ih.opcode) {
01245     case CODA_ROOT:
01246         log("CODA_ROOT\n");
01247               
01248         rep.oh.opcode = req->ih.opcode;
01249         rep.oh.unique = req->ih.unique;
01250         rep.oh.result = 0;
01251         rep.coda_root.VFid.Volume = 0;
01252         rep.coda_root.VFid.Vnode  = 0;
01253         rep.coda_root.VFid.Unique = 0;           /* 0 means root */
01254               
01255         send_to_kernel(&rep, sizeof(rep.coda_root));
01256         break;
01257               
01258     case CODA_GETATTR:
01259         log("CODA_GETATTR\n");
01260         path = look_name(&req->coda_getattr.VFid);
01261         if(path == NULL)
01262             reply(req, ENOENT);
01263         else
01264             send_to_child(req, numread, path, NULL); 
01265         break;
01266               
01267     case CODA_ACCESS:
01268         log("CODA_ACCESS, flags: 0x%04x\n", req->coda_access.flags);
01269               
01270         path = look_name(&req->coda_access.VFid);
01271         if(path == NULL)
01272             reply(req, ENOENT);
01273         else
01274             send_to_child(req, numread, path, NULL);
01275         break;
01276               
01277 #ifdef CODA_OPEN_BY_FD
01278     case CODA_OPEN_BY_FD:
01279         log("CODA_OPEN_BY_FD, flags: 0x%04x\n", req->coda_open.flags);
01280 #endif
01281     case CODA_OPEN:
01282         if(req->ih.opcode == CODA_OPEN)
01283             log("CODA_OPEN, flags: 0x%04x\n", req->coda_open.flags);
01284         
01285         fi = look_info(&req->coda_open.VFid);
01286         if(fi == NULL) {
01287             reply(req, ENOENT);
01288             break;
01289         }
01290 
01291         path = fi->path;
01292         log("path: %s\n", path);
01293               
01294         for(of = fi->ofs; of != NULL; of = of->next) 
01295             if(of->pid == req->ih.pid) break;
01296               
01297         if(of != NULL) {
01298             if((req->coda_open.flags & C_O_TRUNC) != 0) 
01299                 truncate(of->tmpfile, 0);
01300 
01301             open_file(req, of);
01302         }
01303         else {
01304             char tmpname[64];
01305             int fd;
01306                      
01307             strcpy(tmpname, "/tmp/.avfs_coda_XXXXXX");
01308             fd = mkstemp(tmpname);
01309                      
01310             if(fd == -1) {
01311                 logerr("Could not make temporary file: %s\n", strerror(errno));
01312                 reply(req, ENFILE);
01313             }
01314             else {
01315                 fchown(fd, req->ih.cred.cr_fsuid, req->ih.cred.cr_fsgid);
01316                 close(fd);
01317 
01318                 of = malloc(sizeof(struct openfile));
01319                 if(of == NULL) {
01320                     reply(req, ENOMEM);
01321                 }
01322                 else {
01323                     of->use = 0;
01324                     of->wuse = 0;
01325                     of->pid = req->ih.pid;
01326                     of->tmpfile = strdup(tmpname);
01327                     of->fd = -1;
01328                     of->next = fi->ofs;
01329                     fi->ofs = of;
01330                     ref_fid(&req->coda_open.VFid);
01331 
01332                     log("tmpfile: %s\n", of->tmpfile);
01333                     send_to_child(req, numread, path, tmpname);
01334                 }
01335             }
01336         }
01337         break;
01338               
01339     case CODA_CLOSE:
01340         log("CODA_CLOSE, flags: 0x%04x\n", req->coda_close.flags);
01341               
01342         fi = look_info(&req->coda_close.VFid);
01343         if(fi == NULL) {
01344             reply(req, ENOENT);
01345             break;
01346         }
01347 
01348         path = fi->path;
01349         log("path: %s\n", path);
01350               
01351         for(ofp = &fi->ofs; *ofp != NULL; ofp = &(*ofp)->next)
01352             if((*ofp)->pid == req->ih.pid) break;
01353               
01354         of = *ofp;
01355               
01356         if(of == NULL) {
01357             logerr("File not found\n");
01358             reply(req, ENOENT);
01359         }
01360         else {
01361             int dowrite = 0;
01362 
01363             log("use: %i\n", of->use);
01364             log("wuse: %i\n", of->wuse);
01365             if(of->wuse > 0 &&
01366                (req->coda_close.flags & (C_O_WRITE | C_O_TRUNC)) != 0) {
01367                 of->wuse --;
01368                 
01369                 if(of->wuse == 0 && of->tmpfile != NULL) {
01370                     log("tmpfile: %s\n", of->tmpfile);
01371                     dowrite = 1;
01372                     send_to_child(req, numread, path, of->tmpfile);
01373                 }
01374             }
01375             if(!dowrite) {
01376                 close_file(of, ofp, &req->coda_close.VFid);
01377                 reply(req, 0);
01378             }
01379         }
01380         break;
01381               
01382     case CODA_LOOKUP:
01383         /* It is not clear to me, whether lookups should be
01384            done as 'user' or as 'root' */
01385               
01386         filename = ibuf + req->coda_lookup.name;
01387               
01388         log("CODA_LOOKUP, name: '%s', flags: 0x%04x\n", 
01389             filename, req->coda_lookup.flags);
01390               
01391         send_with_path(req, numread, filename, &req->coda_lookup.VFid, NULL);
01392         break;
01393 
01394     case CODA_CREATE:
01395         filename = ibuf + req->coda_create.name;
01396               
01397         log("CODA_CREATE, name: '%s', mode: 0%o, rdev: 0x%04x\n", 
01398             filename, req->coda_create.mode,
01399             (int) req->coda_create.attr.va_rdev);
01400               
01401         send_with_path(req, numread, filename, &req->coda_create.VFid, NULL);
01402         break;
01403               
01404     case CODA_READLINK:
01405         log("CODA_READLINK\n");
01406               
01407         path = look_name(&req->coda_readlink.VFid);
01408         if(path == NULL)
01409             reply(req, ENOENT);
01410         else
01411             send_to_child(req, numread, path, NULL);
01412         break;
01413 
01414     case CODA_SETATTR:
01415         log("CODA_SETATTR\n");
01416 
01417         path = look_name(&req->coda_setattr.VFid);
01418         if(path == NULL)
01419             reply(req, ENOENT);
01420         else
01421             send_to_child(req, numread, path, NULL);
01422         break;
01423 
01424     case CODA_REMOVE:
01425         filename = ibuf + req->coda_remove.name;
01426               
01427         log("CODA_REMOVE, name: '%s'\n", filename);
01428               
01429         send_with_path(req, numread, filename, &req->coda_remove.VFid, NULL);
01430         break;
01431 
01432     case CODA_RMDIR:
01433         filename = ibuf + req->coda_rmdir.name;
01434         
01435         log("CODA_RMDIR, name: '%s'\n", filename);
01436               
01437         send_with_path(req, numread, filename, &req->coda_rmdir.VFid, NULL);
01438         break;
01439         
01440     case CODA_MKDIR:
01441         filename = ibuf + req->coda_mkdir.name;
01442         
01443         log("CODA_MKDIR, name: '%s', mode: 0%o\n", filename, 
01444             req->coda_mkdir.attr.va_mode);
01445               
01446         send_with_path(req, numread, filename, &req->coda_mkdir.VFid, NULL);
01447         break;
01448 
01449     case CODA_RENAME:
01450         filename = ibuf + req->coda_rename.srcname;
01451         filename2 = ibuf + req->coda_rename.destname;
01452 
01453         log("CODA_RENAME, name1: '%s', name2: '%s'\n", filename, filename2); 
01454 
01455         fi = look_info(&req->coda_rename.destFid);
01456         if(fi == NULL) {
01457             reply(req, ENOENT);
01458             break;
01459         }
01460         sprintf(pathbuf, "%s/%s", fi->path, filename2);
01461         
01462         send_with_path(req, numread, filename, &req->coda_rename.sourceFid,
01463                        pathbuf);
01464         break;
01465 
01466     case CODA_SYMLINK:
01467         filename = ibuf + req->coda_symlink.srcname;
01468         filename2 = ibuf + req->coda_symlink.tname;
01469 
01470         log("CODA_SYMLINK, src: '%s', tname: '%s'\n", filename, filename2); 
01471         
01472         send_with_path(req, numread, filename2, &req->coda_symlink.VFid,
01473                        filename);
01474         break;
01475 
01476     case CODA_LINK:
01477         fi = look_info(&req->coda_link.sourceFid);
01478         if(fi == NULL) {
01479             reply(req, ENOENT);
01480             break;
01481         }
01482         filename = fi->path;
01483         filename2 = ibuf + req->coda_link.tname;        
01484         
01485         log("CODA_LINK, src: '%s', tname: '%s'\n", filename, filename2);
01486 
01487         send_with_path(req, numread, filename2, &req->coda_link.destFid,
01488                        filename);
01489         break;
01490 
01491     case CODA_SIGNAL:
01492         log("CODA_SIGNAL\n");
01493         for(i = 0; i < MAXUSERS; i++) {
01494             for(opp = &currusers[i].ops; *opp != NULL; 
01495                 opp = &(*opp)->next) 
01496                 if((*opp)->req->ih.unique == req->ih.unique) 
01497                     break;
01498                      
01499             if(*opp != NULL) break;
01500         }
01501         op = *opp;
01502               
01503         if(op == NULL) 
01504             logerr("Operation not found!!!!\n");
01505         else {
01506             /* FIXME: Inform the child that the operation
01507                is interrupted */
01508 
01509             switch(op->req->ih.opcode) {
01510 #ifdef CODA_OPEN_BY_FD
01511             case CODA_OPEN_BY_FD:
01512 #endif
01513             case CODA_OPEN:
01514                 fi = look_info(&op->req->coda_open.VFid);
01515 
01516                 for(ofp = &fi->ofs; *ofp != NULL; ofp = &(*ofp)->next)
01517                     if((*ofp)->pid == op->req->ih.pid) break;
01518                             
01519                 of = *ofp;
01520                 if(of != NULL)
01521                     close_file(of, ofp, &op->req->coda_open.VFid);
01522 
01523                 break;
01524 
01525             default:;
01526             }
01527 
01528             release_fids(op->req);
01529             *opp = op->next;
01530             free(op);
01531         }
01532         break;
01533               
01534     default:
01535         reply(req, EOPNOTSUPP);
01536               
01537         log("========================================\n");
01538         log("     N o t   I m p l e m e n t e d      \n");
01539         log("========================================\n");
01540     }  
01541 }
01542 
01543 static void process()
01544 {
01545     fd_set rfds;
01546     int ret;
01547     int maxfd;
01548     int i;
01549 
01550     unused_files.prev = &unused_files;
01551     unused_files.next = &unused_files;
01552        
01553     while(1) {
01554         struct timeval timeout;
01555 
01556         check_servers();
01557 
01558         checknum ++;
01559         if(numfids > MAXFILES && checknum > CHECKNUM) {
01560             clean_up_names();
01561             checknum = 0;
01562        }
01563               
01564         FD_ZERO(&rfds);            
01565         FD_SET(codafd, &rfds);
01566         maxfd = codafd;
01567               
01568         for(i = 0; i < MAXUSERS; i++) {
01569             if(currusers[i].serverpid > 0) {
01570                 int pipfd = currusers[i].pipin;
01571                             
01572                 FD_SET(pipfd, &rfds);
01573                 if(pipfd > maxfd) maxfd = pipfd;
01574             }
01575         }
01576 
01577         timeout.tv_sec = 2;
01578         timeout.tv_usec = 0;
01579               
01580         ret = select(maxfd+1, &rfds, NULL, NULL, &timeout);
01581         if(ret == -1) {
01582             if(errno == EINTR)
01583                 continue;
01584             logerr("Select failed: %s\n", strerror(errno));
01585             continue;
01586         }
01587         
01588         if(needflush && needflush + FLUSHTIME <= time(NULL)) {
01589             coda_flush();
01590             needflush = 0;
01591         }
01592 
01593         if(ret == 0)
01594             continue;
01595 
01596         log("Numfids: %i\n", numfids);
01597 
01598         if(FD_ISSET(codafd, &rfds))
01599             process_kernel_req();
01600               
01601         for(i = 0; i < MAXUSERS; i++) {
01602             if(currusers[i].serverpid > 0) {
01603                 int pipfd = currusers[i].pipin;
01604                             
01605                 if(FD_ISSET(pipfd, &rfds))
01606                     process_answer(&currusers[i]);
01607             }
01608         }
01609     }
01610 }
01611 
01612 
01613 void run(int cfs, const char *dir, int dm)
01614 {
01615     int i;
01616 
01617     openlog("avfscoda", LOG_CONS, LOG_USER);
01618        
01619     codafd = cfs;
01620     codadir = dir;
01621     logfile = stderr;
01622     numfids = 0;
01623     checknum = 0;
01624     debugmode = dm;
01625        
01626     for(i = 0; i < MAXUSERS; i++)
01627         currusers[i].serverpid = -1;
01628        
01629     set_signal_handlers();
01630        
01631     process();
01632 }