Back to index

avfs  1.0.1
Classes | Defines | Functions | Variables
dispatch.c File Reference
#include "avfscoda.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <syslog.h>

Go to the source code of this file.

Classes

struct  operation
struct  userinfo
struct  openfile
struct  fileinfo

Defines

#define KEEPTIME   600
#define FLUSHTIME   2
#define MAXFILES   5000
#define CHECKNUM   1000
#define MAXUSERS   10
#define MAXMSGLEN   1045
#define FMAPSIZE   65536
#define HASHSIZE   6247
#define LOGMSG_SIZE   1024

Functions

static void log (const char *,...)
static void log_date ()
static void logerr (const char *,...)
static unsigned int fi_hash (unsigned int unique, const char *name)
static struct fileinforemove_name (struct fileinfo *parentdir, const char *name)
static void add_name (struct fileinfo *fi, struct fileinfo *parentdir, const char *name, int hash)
static void rename_file (struct fileinfo *oldfi, const char *oldname, struct fileinfo *newfi, const char *newname)
static struct fileinfoget_file (struct fileinfo *parentdir, const char *name)
static void put_file (struct fileinfo *fi)
static void remove_file (struct fileinfo *parentdir, const char *name)
static void delete_file (struct fileinfo *fi)
static struct fileinfoget_info (unsigned int unique)
static struct fileinfolook_info (ViceFid *id)
static char * look_name (ViceFid *id)
static void ref_fid (ViceFid *fid)
static void unref_fid (ViceFid *fid)
static void reset_signal_handlers ()
static void send_to_kernel (union outputArgs *rep, int size)
static struct fileinfocreate_file (const char *filename, ViceFid *parentid, ViceFid *newid)
static void purge_file (struct fileinfo *fi)
static void zap_file (struct fileinfo *fi)
static void clean_up (time_t oldtime)
static void clean_up_unused ()
static void clean_up_names ()
static void open_file (union inputArgs *req, struct openfile *of)
static void del_file (const char *tmpname)
static void close_file (struct openfile *of, struct openfile **ofp, ViceFid *fid)
static void reply (union inputArgs *req, int res)
static void check_servers ()
static void grab_fids (union inputArgs *req)
static void release_fids (union inputArgs *req)
static void process_answer (struct userinfo *user)
static void process_child_answer ()
static void kill_child ()
static int new_child (struct userinfo *user, uid_t uid, gid_t gid)
static struct userinfoget_user (uid_t uid, gid_t gid)
static void send_to_child (union inputArgs *req, int reqsize, char *path1, char *path2)
static void send_with_path (union inputArgs *req, int reqsize, char *filename, ViceFid *id, char *path2)
static void coda_flush ()
void run_exit ()
void user_child (pid_t pid)
static void process_kernel_req ()
static void process ()
void run (int cfs, const char *dir, int dm)

Variables

static struct userinfo [MAXUSERS]
static int codafd
static const char * codadir
static FILE * logfile
static int numfids
static int checknum
static int debugmode
static struct fileinfofmap [FMAPSIZE]
static unsigned int nextunique = 0
static struct fileinfofhash [HASHSIZE]
static int needflush
static struct fileinfo

Class Documentation

struct operation

Definition at line 47 of file dispatch.c.

Collaboration diagram for operation:
Class Members
char ibuf
struct operation * next
union inputArgs * req
struct userinfo

Definition at line 54 of file dispatch.c.

Collaboration diagram for userinfo:
Class Members
gid_t gid
time_t lastuse
struct operation * ops
int pipin
int pipout
volatile pid_t serverpid
int terminated
uid_t uid
struct openfile

Definition at line 76 of file dispatch.c.

Collaboration diagram for openfile:
Class Members
int fd
struct openfile * next
pid_t pid
char * tmpfile
int use
int wuse
struct fileinfo

Definition at line 86 of file dispatch.c.

Collaboration diagram for fileinfo:
Class Members
int holderfd
int isvirtual
time_t lasttime
char * name
struct fileinfo * next
struct openfile * ofs
unsigned int parunique
char * path
struct fileinfo * prev
int serverfh
unsigned int unique
int use

Define Documentation

#define CHECKNUM   1000

Definition at line 39 of file dispatch.c.

#define FLUSHTIME   2

Definition at line 33 of file dispatch.c.

#define FMAPSIZE   65536

Definition at line 101 of file dispatch.c.

#define HASHSIZE   6247

Definition at line 105 of file dispatch.c.

#define KEEPTIME   600

Definition at line 30 of file dispatch.c.

#define LOGMSG_SIZE   1024

Definition at line 138 of file dispatch.c.

#define MAXFILES   5000

Definition at line 36 of file dispatch.c.

#define MAXMSGLEN   1045

Definition at line 44 of file dispatch.c.

#define MAXUSERS   10

Definition at line 42 of file dispatch.c.


Function Documentation

static void add_name ( struct fileinfo fi,
struct fileinfo parentdir,
const char *  name,
int  hash 
) [static]

Definition at line 183 of file dispatch.c.

{
    fi->next = fhash[hash];
    fhash[hash] = fi;

    fi->name = strdup(name);
    fi->parunique = parentdir->unique;
    fi->path = (char *) malloc(strlen(parentdir->path) + 1 + strlen(name) + 1);
    sprintf(fi->path, "%s/%s", parentdir->path, name);
}

Here is the caller graph for this function:

static void check_servers ( ) [static]

Definition at line 611 of file dispatch.c.

{
    int i;
              
    for(i = 0; i < MAXUSERS; i++) {
        if(currusers[i].serverpid == 0) {
            /* FIXME: reply to the pending messages */
                     
            close(currusers[i].pipout);
            close(currusers[i].pipin);
                     
            currusers[i].serverpid = -1;
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void clean_up ( time_t  oldtime) [static]

Definition at line 477 of file dispatch.c.

{
    int i;

    for(i = 0; i < HASHSIZE; i++) {
       struct fileinfo **fip = &fhash[i];

       while(*fip != NULL) {
           struct fileinfo *fi = *fip;
              
           if((!oldtime || fi->lasttime < oldtime) && fi->use == 0) {
              *fip = fi->next;
              purge_file(fi);
              put_file(fi);
           }
           else
              fip = &fi->next;        
       }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void clean_up_names ( ) [static]

Definition at line 512 of file dispatch.c.

{
    clean_up_unused();

    if(numfids > FMAPSIZE / 2)
        clean_up(0);
    else
        clean_up(time(NULL) - KEEPTIME);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void clean_up_unused ( ) [static]

Definition at line 498 of file dispatch.c.

{
    struct fileinfo *fi;

    for(fi = unused_files.next; fi != &unused_files;) {
        struct fileinfo *nextfi = fi->next;
        if(fi->use == 0)
            delete_file(fi);

        fi = nextfi;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void close_file ( struct openfile of,
struct openfile **  ofp,
ViceFid *  fid 
) [static]

Definition at line 584 of file dispatch.c.

{
    
    if(of->use > 0) of->use --;
    if(of->use == 0 && of->tmpfile != NULL) {
        if(of->fd != -1)
            close(of->fd);
        del_file(of->tmpfile);
        free(of->tmpfile);
        *ofp = of->next;
        free(of);
        unref_fid(fid);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void coda_flush ( ) [static]

Definition at line 1168 of file dispatch.c.

{
    union outputArgs rep;
       
    log("=================================================================\n");
    log_date();
    log("CODA_FLUSH\n");
       
    rep.oh.opcode = CODA_FLUSH;
    rep.oh.result = 0;
    rep.oh.unique = 0;
       
    send_to_kernel(&rep, sizeof(rep.oh));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct fileinfo* create_file ( const char *  filename,
ViceFid *  parentid,
ViceFid *  newid 
) [static, read]

Definition at line 401 of file dispatch.c.

{
    struct fileinfo *fi;

    fi = look_info(parentid);
    if(fi == NULL)
        return NULL;
    fi = get_file(fi, filename);

    newid->Volume = 0;
    newid->Vnode = 0;
    newid->Unique = fi->unique;

    return fi;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void del_file ( const char *  tmpname) [static]

Definition at line 572 of file dispatch.c.

{
    int res;
       
    /* Coda holds on to the inode, so to free up space: */
    truncate(tmpname, 0);
    res = unlink(tmpname);
    if(res == -1)
        fprintf(stderr, "unlink(%s) failed (%s)\n", 
                tmpname, strerror(errno));
}

Here is the caller graph for this function:

static void delete_file ( struct fileinfo fi) [static]

Definition at line 289 of file dispatch.c.

{
    unsigned int index;
    struct fileinfo *prev = fi->prev;
    struct fileinfo *next = fi->next;

    log("Delete fid: 0x%x\n", fi->unique);

    prev->next = next;
    next->prev = prev;

    index = fi->unique % FMAPSIZE;
    fmap[index] = NULL;

    free(fi->name);
    free(fi->path);
    free(fi);
    numfids --;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned int fi_hash ( unsigned int  unique,
const char *  name 
) [static]

Definition at line 154 of file dispatch.c.

{
    unsigned int hash = unique;

    for(; *name != 0; name++) {
       hash = (hash << 4) | (hash >> 28);
       hash ^= (unsigned int) *name;
    }
    return hash % HASHSIZE;
}

Here is the caller graph for this function:

static struct fileinfo* get_file ( struct fileinfo parentdir,
const char *  name 
) [static, read]

Definition at line 211 of file dispatch.c.

{
    unsigned int hash = fi_hash(parentdir->unique, name);
    struct fileinfo *fi;
    int i;

    for(fi = fhash[hash]; fi != NULL; fi = fi->next)
       if(fi->parunique == parentdir->unique && strcmp(fi->name, name) == 0)
           return fi;

    fi = malloc(sizeof(*fi));
    if(fi == NULL) {
        logerr("Out of memory");
        clean_exit(1);
    }
    
    for(i = 0; i < FMAPSIZE; i++) {
        unsigned int index;

        nextunique ++;
        if(nextunique == 0)
            nextunique = 1;

        index = nextunique % FMAPSIZE;
        if(fmap[index] == NULL) {
            fmap[index] = fi;
            fi->unique = nextunique;
            break;
        }
    }

    if(i == FMAPSIZE) {
        logerr("fmap full\n");
        clean_exit(1);
    }

    log("New fid: 0x%x\n", fi->unique);

    numfids ++;

    fi->lasttime = time(NULL);
    fi->ofs = NULL;
    fi->use = 0;

    add_name(fi, parentdir, name, hash);

    return fi;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct fileinfo* get_info ( unsigned int  unique) [static, read]

Definition at line 309 of file dispatch.c.

{
    struct fileinfo *fi;
    unsigned int index = (unique % FMAPSIZE);

    fi = fmap[index];
    if(fi == NULL || fi->unique != unique) {
        logerr("Deleted Fid: 0x%x\n", unique);
        return NULL;
    }
    return fi;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct userinfo* get_user ( uid_t  uid,
gid_t  gid 
) [static, read]

Definition at line 1021 of file dispatch.c.

{
    int i;
    struct userinfo *user = NULL;
       
    for(i = 0; i < MAXUSERS; i++) {
        if(currusers[i].serverpid > 0 && currusers[i].uid == uid &&
           currusers[i].gid == gid) {
            user = &currusers[i];
            break;
        }
    }
       
    if(user == NULL) {
        /* Create child */
        do {
            /* Find a free slot */
            for(i = 0; i < MAXUSERS; i++)
                if(currusers[i].serverpid == -1) break;
                     
            if(i == MAXUSERS) {
                /* No free slots, must kill a child */
                kill_child();
            }
        } while(i == MAXUSERS);
              
        user = currusers + i;
        if(new_child(user, uid, gid) == -1)
            return NULL;
    }
       
    user->lastuse = time(NULL);
    return user;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void grab_fids ( union inputArgs *  req) [static]

Definition at line 627 of file dispatch.c.

{
    /* All have first VFid in the same place */
    ref_fid(&req->coda_getattr.VFid);
    
    if(req->ih.opcode == CODA_LINK)
        ref_fid(&req->coda_link.destFid);
    if(req->ih.opcode == CODA_RENAME)
        ref_fid(&req->coda_rename.destFid);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void kill_child ( ) [static]

Definition at line 866 of file dispatch.c.

{
    struct userinfo *user;
    time_t oldesttime;
    int oldesti;
    int i;
    pid_t pid;
       
    oldesttime = 0;
    oldesti = -1;
       
    do {
        for(i = 0; i < MAXUSERS; i++) {
            user = currusers + i;
            if(user->serverpid == -1) return;
            if(user->serverpid == 0) {
                check_servers();
                return;
            }
                     
            if(user->ops == NULL) {
                if(oldesti == -1 || 
                   user->lastuse < oldesttime) {
                    oldesttime = user->lastuse;
                    oldesti = i;
                }
            }
        }
              
        if(oldesti == -1) {
            /* If every child is busy then block */
            process_child_answer();
        }
    } while(oldesti == -1);
       
    user = currusers + oldesti;
       
    /* FIXME: This is a mess, because user->serverpid can change to 0 
       when SIGCHLD is received */
    pid = user->serverpid;
    if(pid > 0) {
        if(!user->terminated) {
            kill(pid, SIGTERM);
            user->terminated = 1;
        }
        else {
            log("kill(%i, SIGKILL)\n", pid);
            kill(pid, SIGKILL);
        }
    }
       
    /* FIXME: Need to wait for the death of the child or max 1 second. 
       How can this be done? */
    if(user->serverpid > 0)
        sleep(1);
       
    check_servers();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void log ( const char *  ,
  ... 
) [static]

Definition at line 112 of file dispatch.c.

{
    if(debugmode) {
       va_list ap;
       
       va_start(ap, fmt);
       vfprintf(logfile, fmt, ap);
       va_end(ap);
    }
}

Here is the caller graph for this function:

static void log_date ( ) [static]

Definition at line 124 of file dispatch.c.

{
    if(debugmode) {
        struct tm tm;
        struct timeval tv;

        gettimeofday(&tv, NULL);
        localtime_r(&tv.tv_sec, &tm);        
        log("%02i/%02i %02i:%02i:%02i.%03i\n", 
            tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
            (int) (tv.tv_usec / 1000));
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void logerr ( const char *  ,
  ... 
) [static]

Definition at line 139 of file dispatch.c.

{
    char buf[LOGMSG_SIZE + 1];
    va_list ap;

    va_start(ap, fmt);
    vsnprintf(buf, LOGMSG_SIZE, fmt, ap);
    va_end(ap);

    buf[LOGMSG_SIZE] = '\0';
    syslog(LOG_INFO, "%s", buf);
    log(buf);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct fileinfo* look_info ( ViceFid *  id) [static, read]

Definition at line 322 of file dispatch.c.

{
    struct fileinfo *fi;
       
    if ((id->Volume != 0) || (id->Vnode != 0)) {
        logerr("Bad handle passed %lx/%lx/%lx\n", 
            id->Volume, id->Vnode, id->Unique );
        clean_exit(1);
    }
       
    log("unique: 0x%x\n", (unsigned int) id->Unique);
       
    if(id->Unique == 0) {
       static struct fileinfo rootinfo;
       rootinfo.path = "/";
        return &rootinfo;
    }
    else {
        fi = get_info(id->Unique);
        if(fi != NULL)
            fi->lasttime = time(NULL);
              
        return fi;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* look_name ( ViceFid *  id) [static]

Definition at line 348 of file dispatch.c.

{
    struct fileinfo *fi;
       
    fi = look_info(id);
    if(fi == NULL)
        return NULL;

    log("path: %s\n", fi->path);
       
    return fi->path;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int new_child ( struct userinfo user,
uid_t  uid,
gid_t  gid 
) [static]

Definition at line 925 of file dispatch.c.

{
    int pipout[2];
    int pipin[2];
    int pid;
    int i;
    gid_t list[32];
    int num;
       
    if(pipe(pipout) == -1) {
        logerr("Could not open pipe for child: %s\n", strerror(errno));
        return -1;
    }
    if(pipe(pipin) == -1) {
        close(pipout[0]);
        close(pipout[1]);
        return -1;
    }
       
    user->serverpid = pid = fork();
    if(pid == -1) {
        close(pipout[0]);
        close(pipout[1]);
        close(pipin[0]);
        close(pipin[1]);
        logerr("Could not fork child: %s\n", strerror(errno));
        return -1;
    }
       
    user->pipout = pipout[1];
    user->pipin = pipin[0];
       
    if(pid == 0) {
        /* Child */
              
        reset_signal_handlers();
              
        /* Close everything, except the current pipes */
        for(i = 0; i < MAXUSERS; i++) 
            if(currusers[i].serverpid >= 0) {
                close(currusers[i].pipout);
                close(currusers[i].pipin);
            }
              
        close(codafd);
#if 0
        fclose(logfile);
#endif
        /* Don't want any troublesome signals from the child */
        setsid(); 
              
        /* FIXME: What is the proper way of dealing with
           supplementary groups? */
        list[0] = gid;
        num = 1;
        setgroups(num, list);
              
#if 1
        {
            struct passwd *pwbuf;
                     
            /* FIXME: This messes up gdb. Why? */
            pwbuf = getpwuid(uid);
            if(pwbuf != NULL)
                initgroups(pwbuf->pw_name, gid);
        }
#endif
              
        setgid(gid);
        setuid(uid);
              
        fprintf(stderr, "Child process: %i/%i\n", getuid(), getgid());
              
        num = getgroups(32, list);
        fprintf(stderr, "Supplementary groups: ");
        for(i = 0; i < num; i++) fprintf(stderr, "%i, ", list[i]);
        fprintf(stderr, "\n");
              
        child_process(pipout[0], pipin[1]);
        exit(0);
    }
       
    /* Parent */
       
    close(pipout[0]);
    close(pipin[1]);
       
    user->uid = uid;
    user->gid = gid;
    user->terminated = 0;
    user->lastuse = 0;
    user->ops = NULL;
       
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void open_file ( union inputArgs *  req,
struct openfile of 
) [static]

Definition at line 522 of file dispatch.c.

{
    int ret;
    union outputArgs rep;
    struct stat stbuf;
       
    rep.oh.opcode = req->ih.opcode;
    rep.oh.unique = req->ih.unique;
       
    if(req->ih.opcode == CODA_OPEN) {
        ret = stat(of->tmpfile, &stbuf);
        if(ret == -1) 
            rep.oh.result = errno;
        else {
            rep.oh.result = 0;
            rep.coda_open.dev = stbuf.st_dev;
            rep.coda_open.inode = stbuf.st_ino;
            
            log("dev: %lli, ino: %lli\n", rep.coda_open.dev,
                rep.coda_open.inode);
            log("size: %lli\n", stbuf.st_size);
            of->use ++;
            if((req->coda_open.flags & (C_O_WRITE | C_O_TRUNC)) != 0)
                of->wuse ++;
        }
       
        send_to_kernel(&rep, sizeof(rep.coda_open));
    }
#ifdef CODA_OPEN_BY_FD
    else {
        if(of->fd == -1) {
            of->fd = open(of->tmpfile, O_RDONLY);
            if(of->fd == -1)
                rep.oh.result = errno;
        }
        if(of->fd != -1) {
            rep.oh.result = 0;
            rep.coda_open_by_fd.fd =  of->fd;
            
            log("fd: %i\n", of->fd);

            of->use ++;
            if((req->coda_open.flags & (C_O_WRITE | C_O_TRUNC)) != 0)
                of->wuse ++;
        }
        send_to_kernel(&rep, sizeof(rep.coda_open_by_fd));
    }
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void process ( ) [static]

Definition at line 1543 of file dispatch.c.

{
    fd_set rfds;
    int ret;
    int maxfd;
    int i;

    unused_files.prev = &unused_files;
    unused_files.next = &unused_files;
       
    while(1) {
        struct timeval timeout;

        check_servers();

        checknum ++;
        if(numfids > MAXFILES && checknum > CHECKNUM) {
            clean_up_names();
            checknum = 0;
       }
              
        FD_ZERO(&rfds);            
        FD_SET(codafd, &rfds);
        maxfd = codafd;
              
        for(i = 0; i < MAXUSERS; i++) {
            if(currusers[i].serverpid > 0) {
                int pipfd = currusers[i].pipin;
                            
                FD_SET(pipfd, &rfds);
                if(pipfd > maxfd) maxfd = pipfd;
            }
        }

        timeout.tv_sec = 2;
        timeout.tv_usec = 0;
              
        ret = select(maxfd+1, &rfds, NULL, NULL, &timeout);
        if(ret == -1) {
            if(errno == EINTR)
                continue;
            logerr("Select failed: %s\n", strerror(errno));
            continue;
        }
        
        if(needflush && needflush + FLUSHTIME <= time(NULL)) {
            coda_flush();
            needflush = 0;
        }

        if(ret == 0)
            continue;

        log("Numfids: %i\n", numfids);

        if(FD_ISSET(codafd, &rfds))
            process_kernel_req();
              
        for(i = 0; i < MAXUSERS; i++) {
            if(currusers[i].serverpid > 0) {
                int pipfd = currusers[i].pipin;
                            
                if(FD_ISSET(pipfd, &rfds))
                    process_answer(&currusers[i]);
            }
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void process_answer ( struct userinfo user) [static]

Definition at line 649 of file dispatch.c.

{
    int numread;
    char obuf[MAXMSGLEN];
    union outputArgs *rep = (union outputArgs *) obuf;
    struct operation *op, **opp;
    struct fileinfo *fi;
    struct openfile *of, **ofp;
    char *filename;
    int insize;

    if(!needflush)
        needflush = time(NULL);

    numread = read(user->pipin, &insize, sizeof(insize));
    if(numread == -1) {
        logerr("Error reading from device: %s\n", strerror(errno));
        return;
    }
    if(insize > MAXMSGLEN || insize <= 0) {
        logerr("Error: illegal size");
        return;
    }
       
    numread = read(user->pipin, obuf, insize);
    if(numread == -1) {
        logerr("Error reading from child [%i/%i]: %s\n", 
            user->uid, user->gid, strerror(errno));
        return;
    }
       
    log("+ %i/%i [%i] +++++++++++++++++++++++++++++++++++++++++++++++++++\n",
        user->uid, user->gid, user->serverpid);
    log_date();
    log("%i (%i) bytes: opcode: %li, result: %i, unique: %li\n", 
        numread, insize, rep->oh.opcode, (int) rep->oh.result, rep->oh.unique);
       
    for(opp = &user->ops; *opp != NULL; opp = &(*opp)->next) 
        if((*opp)->req->ih.unique == rep->oh.unique) break;
       
    op = *opp;
       
    if(op == NULL)
        logerr("Operation not found!!!!\n");
    else {
        log("Found operation: %li\n", op->req->ih.unique);
              
        switch(rep->oh.opcode) {
#ifdef CODA_OPEN_BY_FD
        case CODA_OPEN_BY_FD:
#endif
        case CODA_OPEN:
            fi = look_info(&op->req->coda_open.VFid);

            for(ofp = &fi->ofs; *ofp != NULL; ofp = &(*ofp)->next)
                if((*ofp)->pid == op->req->ih.pid) break;
                            
            of = *ofp;

            if(of == NULL) {
                logerr("Output file not found!!!\n");
                reply(op->req, ENOENT);
            }
            else {
                if(rep->oh.result == 0) {
                    open_file(op->req, of);
                }
                else {
                    close_file(of, ofp, &op->req->coda_open.VFid);
                    send_to_kernel(rep, numread);
                }
            }
            break;
        
        case CODA_CLOSE:
            fi = look_info(&op->req->coda_close.VFid);
            
            for(ofp = &fi->ofs; *ofp != NULL; ofp = &(*ofp)->next)
                if((*ofp)->pid == op->req->ih.pid) break;
            
            of = *ofp;

            if(of == NULL) {
                logerr("Output file not found!!!\n");
                reply(op->req, ENOENT);
            }
            else
                close_file(of, ofp, &op->req->coda_close.VFid);

            send_to_kernel(rep, numread);
           zap_file(fi);
            break;
                     
        case CODA_LOOKUP:
            if(rep->oh.result == 0) {
                filename = (char *) op->req + op->req->coda_lookup.name;
                fi = create_file(filename, &op->req->coda_lookup.VFid,
                                 &rep->coda_lookup.VFid);
                if(fi == NULL)
                    rep->oh.result = ENOENT;
            }
            send_to_kernel(rep, numread);
            break;

        case CODA_CREATE:
            if(rep->oh.result == 0) {
                filename = (char *) op->req + op->req->coda_create.name;
                fi = create_file(filename, &op->req->coda_create.VFid,
                                 &rep->coda_create.VFid);
                if(fi == NULL)
                    rep->oh.result = ENOENT;
            }
            send_to_kernel(rep, numread);
            break;

        case CODA_MKDIR:
            if(rep->oh.result == 0) {
                filename = (char *) op->req + op->req->coda_mkdir.name;
                fi = create_file(filename, &op->req->coda_mkdir.VFid,
                                 &rep->coda_mkdir.VFid);
                if(fi == NULL)
                    rep->oh.result = ENOENT;
            }
            send_to_kernel(rep, numread);
            break;

        case CODA_REMOVE:
            if(rep->oh.result == 0) {
                filename = (char *) op->req + op->req->coda_remove.name;
                fi = look_info(&op->req->coda_remove.VFid);
              remove_file(fi, filename);
            }
            send_to_kernel(rep, numread);
            break;

        case CODA_RMDIR:
            if(rep->oh.result == 0) {
                filename = (char *) op->req + op->req->coda_rmdir.name;
                fi = look_info(&op->req->coda_rmdir.VFid);
              remove_file(fi, filename);
            }
            send_to_kernel(rep, numread);
            break;
            
        case CODA_RENAME:
            if(rep->oh.result == 0) {
                char *newname;
                struct fileinfo *newfi;

                newname = (char *) op->req + op->req->coda_rename.destname;
                newfi = look_info(&op->req->coda_rename.destFid);
              remove_file(newfi, newname);

                filename = (char *) op->req + op->req->coda_rename.srcname;
                fi = look_info(&op->req->coda_rename.sourceFid);
              rename_file(fi, filename, newfi, newname);
            }
            send_to_kernel(rep, numread);
            break;

        default:
            send_to_kernel(rep, numread);
                     
        }
        
        release_fids(op->req);
        *opp = op->next;
        free(op);
    }
       
    if(user->ops != NULL) {
        log("Remaining operations: ");
        for(op = user->ops; op != NULL; op = op->next)
            log("%li ", op->req->ih.unique);
        log("\n");
    }  
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void process_child_answer ( ) [static]

Definition at line 827 of file dispatch.c.

{
    fd_set rfds;
    int ret;
    int maxfd;
    int i;
       
    check_servers();
       
    FD_ZERO(&rfds);
       
    maxfd = 0;
       
    for(i = 0; i < MAXUSERS; i++) {
        if(currusers[i].serverpid > 0) {
            int pipfd = currusers[i].pipin;
                     
            FD_SET(pipfd, &rfds);
            if(pipfd > maxfd) maxfd = pipfd;
        }
    }
       
    ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
    if(ret == -1) {
        if(errno != EINTR) 
            logerr("Select failed: %s\n", strerror(errno));
    }
    else {
        for(i = 0; i < MAXUSERS; i++) {
            if(currusers[i].serverpid > 0) {
                int pipfd = currusers[i].pipin;
                            
                if(FD_ISSET(pipfd, &rfds)) 
                    process_answer(&currusers[i]);
            }
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void process_kernel_req ( ) [static]

Definition at line 1219 of file dispatch.c.

{
    char ibuf[MAXMSGLEN];
    char pathbuf[1024];
    union inputArgs *req = (union inputArgs *) ibuf;
    union outputArgs rep;
    struct openfile *of, **ofp;
    int numread;
    char *path;
    char *filename, *filename2;
    struct fileinfo *fi;
    struct operation **opp, *op;
    int i;
       
    numread = read(codafd, ibuf, MAXMSGLEN);
    if(numread == -1) {
        logerr("Error reading from device: %s\n", strerror(errno));
        clean_exit(1);
    }
       
    log("=================================================================\n");
    log_date();
    log("%i bytes: opcode: %li, unique: %li\n", 
        numread, req->ih.opcode, req->ih.unique);
       
    switch (req->ih.opcode) {
    case CODA_ROOT:
        log("CODA_ROOT\n");
              
        rep.oh.opcode = req->ih.opcode;
        rep.oh.unique = req->ih.unique;
        rep.oh.result = 0;
        rep.coda_root.VFid.Volume = 0;
        rep.coda_root.VFid.Vnode  = 0;
        rep.coda_root.VFid.Unique = 0;           /* 0 means root */
              
        send_to_kernel(&rep, sizeof(rep.coda_root));
        break;
              
    case CODA_GETATTR:
        log("CODA_GETATTR\n");
        path = look_name(&req->coda_getattr.VFid);
        if(path == NULL)
            reply(req, ENOENT);
        else
            send_to_child(req, numread, path, NULL); 
        break;
              
    case CODA_ACCESS:
        log("CODA_ACCESS, flags: 0x%04x\n", req->coda_access.flags);
              
        path = look_name(&req->coda_access.VFid);
        if(path == NULL)
            reply(req, ENOENT);
        else
            send_to_child(req, numread, path, NULL);
        break;
              
#ifdef CODA_OPEN_BY_FD
    case CODA_OPEN_BY_FD:
        log("CODA_OPEN_BY_FD, flags: 0x%04x\n", req->coda_open.flags);
#endif
    case CODA_OPEN:
        if(req->ih.opcode == CODA_OPEN)
            log("CODA_OPEN, flags: 0x%04x\n", req->coda_open.flags);
        
        fi = look_info(&req->coda_open.VFid);
        if(fi == NULL) {
            reply(req, ENOENT);
            break;
        }

        path = fi->path;
        log("path: %s\n", path);
              
        for(of = fi->ofs; of != NULL; of = of->next) 
            if(of->pid == req->ih.pid) break;
              
        if(of != NULL) {
            if((req->coda_open.flags & C_O_TRUNC) != 0) 
                truncate(of->tmpfile, 0);

            open_file(req, of);
        }
        else {
            char tmpname[64];
            int fd;
                     
            strcpy(tmpname, "/tmp/.avfs_coda_XXXXXX");
            fd = mkstemp(tmpname);
                     
            if(fd == -1) {
                logerr("Could not make temporary file: %s\n", strerror(errno));
                reply(req, ENFILE);
            }
            else {
                fchown(fd, req->ih.cred.cr_fsuid, req->ih.cred.cr_fsgid);
                close(fd);

                of = malloc(sizeof(struct openfile));
                if(of == NULL) {
                    reply(req, ENOMEM);
                }
                else {
                    of->use = 0;
                    of->wuse = 0;
                    of->pid = req->ih.pid;
                    of->tmpfile = strdup(tmpname);
                    of->fd = -1;
                    of->next = fi->ofs;
                    fi->ofs = of;
                    ref_fid(&req->coda_open.VFid);

                    log("tmpfile: %s\n", of->tmpfile);
                    send_to_child(req, numread, path, tmpname);
                }
            }
        }
        break;
              
    case CODA_CLOSE:
        log("CODA_CLOSE, flags: 0x%04x\n", req->coda_close.flags);
              
        fi = look_info(&req->coda_close.VFid);
        if(fi == NULL) {
            reply(req, ENOENT);
            break;
        }

        path = fi->path;
        log("path: %s\n", path);
              
        for(ofp = &fi->ofs; *ofp != NULL; ofp = &(*ofp)->next)
            if((*ofp)->pid == req->ih.pid) break;
              
        of = *ofp;
              
        if(of == NULL) {
            logerr("File not found\n");
            reply(req, ENOENT);
        }
        else {
            int dowrite = 0;

            log("use: %i\n", of->use);
            log("wuse: %i\n", of->wuse);
            if(of->wuse > 0 &&
               (req->coda_close.flags & (C_O_WRITE | C_O_TRUNC)) != 0) {
                of->wuse --;
                
                if(of->wuse == 0 && of->tmpfile != NULL) {
                    log("tmpfile: %s\n", of->tmpfile);
                    dowrite = 1;
                    send_to_child(req, numread, path, of->tmpfile);
                }
            }
            if(!dowrite) {
                close_file(of, ofp, &req->coda_close.VFid);
                reply(req, 0);
            }
        }
        break;
              
    case CODA_LOOKUP:
        /* It is not clear to me, whether lookups should be
           done as 'user' or as 'root' */
              
        filename = ibuf + req->coda_lookup.name;
              
        log("CODA_LOOKUP, name: '%s', flags: 0x%04x\n", 
            filename, req->coda_lookup.flags);
              
        send_with_path(req, numread, filename, &req->coda_lookup.VFid, NULL);
        break;

    case CODA_CREATE:
        filename = ibuf + req->coda_create.name;
              
        log("CODA_CREATE, name: '%s', mode: 0%o, rdev: 0x%04x\n", 
            filename, req->coda_create.mode,
            (int) req->coda_create.attr.va_rdev);
              
        send_with_path(req, numread, filename, &req->coda_create.VFid, NULL);
        break;
              
    case CODA_READLINK:
        log("CODA_READLINK\n");
              
        path = look_name(&req->coda_readlink.VFid);
        if(path == NULL)
            reply(req, ENOENT);
        else
            send_to_child(req, numread, path, NULL);
        break;

    case CODA_SETATTR:
        log("CODA_SETATTR\n");

        path = look_name(&req->coda_setattr.VFid);
        if(path == NULL)
            reply(req, ENOENT);
        else
            send_to_child(req, numread, path, NULL);
        break;

    case CODA_REMOVE:
        filename = ibuf + req->coda_remove.name;
              
        log("CODA_REMOVE, name: '%s'\n", filename);
              
        send_with_path(req, numread, filename, &req->coda_remove.VFid, NULL);
        break;

    case CODA_RMDIR:
        filename = ibuf + req->coda_rmdir.name;
        
        log("CODA_RMDIR, name: '%s'\n", filename);
              
        send_with_path(req, numread, filename, &req->coda_rmdir.VFid, NULL);
        break;
        
    case CODA_MKDIR:
        filename = ibuf + req->coda_mkdir.name;
        
        log("CODA_MKDIR, name: '%s', mode: 0%o\n", filename, 
            req->coda_mkdir.attr.va_mode);
              
        send_with_path(req, numread, filename, &req->coda_mkdir.VFid, NULL);
        break;

    case CODA_RENAME:
        filename = ibuf + req->coda_rename.srcname;
        filename2 = ibuf + req->coda_rename.destname;

        log("CODA_RENAME, name1: '%s', name2: '%s'\n", filename, filename2); 

        fi = look_info(&req->coda_rename.destFid);
        if(fi == NULL) {
            reply(req, ENOENT);
            break;
        }
        sprintf(pathbuf, "%s/%s", fi->path, filename2);
        
        send_with_path(req, numread, filename, &req->coda_rename.sourceFid,
                       pathbuf);
        break;

    case CODA_SYMLINK:
        filename = ibuf + req->coda_symlink.srcname;
        filename2 = ibuf + req->coda_symlink.tname;

        log("CODA_SYMLINK, src: '%s', tname: '%s'\n", filename, filename2); 
        
        send_with_path(req, numread, filename2, &req->coda_symlink.VFid,
                       filename);
        break;

    case CODA_LINK:
        fi = look_info(&req->coda_link.sourceFid);
        if(fi == NULL) {
            reply(req, ENOENT);
            break;
        }
        filename = fi->path;
        filename2 = ibuf + req->coda_link.tname;        
        
        log("CODA_LINK, src: '%s', tname: '%s'\n", filename, filename2);

        send_with_path(req, numread, filename2, &req->coda_link.destFid,
                       filename);
        break;

    case CODA_SIGNAL:
        log("CODA_SIGNAL\n");
        for(i = 0; i < MAXUSERS; i++) {
            for(opp = &currusers[i].ops; *opp != NULL; 
                opp = &(*opp)->next) 
                if((*opp)->req->ih.unique == req->ih.unique) 
                    break;
                     
            if(*opp != NULL) break;
        }
        op = *opp;
              
        if(op == NULL) 
            logerr("Operation not found!!!!\n");
        else {
            /* FIXME: Inform the child that the operation
               is interrupted */

            switch(op->req->ih.opcode) {
#ifdef CODA_OPEN_BY_FD
            case CODA_OPEN_BY_FD:
#endif
            case CODA_OPEN:
                fi = look_info(&op->req->coda_open.VFid);

                for(ofp = &fi->ofs; *ofp != NULL; ofp = &(*ofp)->next)
                    if((*ofp)->pid == op->req->ih.pid) break;
                            
                of = *ofp;
                if(of != NULL)
                    close_file(of, ofp, &op->req->coda_open.VFid);

                break;

            default:;
            }

            release_fids(op->req);
            *opp = op->next;
            free(op);
        }
        break;
              
    default:
        reply(req, EOPNOTSUPP);
              
        log("========================================\n");
        log("     N o t   I m p l e m e n t e d      \n");
        log("========================================\n");
    }  
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void purge_file ( struct fileinfo fi) [static]

Definition at line 418 of file dispatch.c.

{
    union outputArgs rep;

    log("=================================================================\n");
    log_date();
    log("Cleaning out 0x%x\n", fi->unique);
    log("CODA_PURGEFID\n");
    
    rep.oh.opcode = CODA_PURGEFID;
    rep.oh.result = 0;
    rep.oh.unique = 0;
    rep.coda_purgefid.CodaFid.Volume = 0;
    rep.coda_purgefid.CodaFid.Vnode  = 0;
    rep.coda_purgefid.CodaFid.Unique = fi->unique;
    
    send_to_kernel(&rep, sizeof(rep.coda_purgefid));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void put_file ( struct fileinfo fi) [static]

Definition at line 261 of file dispatch.c.

{
    struct fileinfo *prev;
    struct fileinfo *next;

    log("Put fid: 0x%x\n", fi->unique);

    prev = unused_files.prev;
    next = &unused_files;
    prev->next = fi;
    next->prev = fi;
    fi->next = next;
    fi->prev = prev;

    free(fi->name);
    fi->name = NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ref_fid ( ViceFid *  fid) [static]

Definition at line 361 of file dispatch.c.

{
    struct fileinfo *fi = look_info(fid);

    if(fi != NULL)
        fi->use ++;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void release_fids ( union inputArgs *  req) [static]

Definition at line 638 of file dispatch.c.

{
    /* All have first VFid in the same place */
    unref_fid(&req->coda_getattr.VFid);
    
    if(req->ih.opcode == CODA_LINK)
        unref_fid(&req->coda_link.destFid);
    if(req->ih.opcode == CODA_RENAME)
        unref_fid(&req->coda_rename.destFid);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void remove_file ( struct fileinfo parentdir,
const char *  name 
) [static]

Definition at line 279 of file dispatch.c.

{
    struct fileinfo *fi;

    fi = remove_name(parentdir, name);
    if(fi != NULL)
       put_file(fi);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct fileinfo* remove_name ( struct fileinfo parentdir,
const char *  name 
) [static, read]

Definition at line 165 of file dispatch.c.

{
    struct fileinfo **fip;
    unsigned int hash = fi_hash(parentdir->unique, name);
    
    for(fip = &fhash[hash]; *fip != NULL; fip = &(*fip)->next) {
       struct fileinfo *fi = *fip;
       if(fi->parunique == parentdir->unique && strcmp(fi->name, name) == 0) {
           *fip = fi->next;
           return fi;
       }
    }

    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void rename_file ( struct fileinfo oldfi,
const char *  oldname,
struct fileinfo newfi,
const char *  newname 
) [static]

Definition at line 195 of file dispatch.c.

{
    struct fileinfo *fi;

    fi = remove_name(oldfi, oldname);
    if(fi != NULL) {
       unsigned int hash = fi_hash(newfi->unique, newname);
       
       free(fi->name);
       free(fi->path);
       add_name(fi, newfi, newname, hash);
    }

}

Here is the call graph for this function:

Here is the caller graph for this function:

static void reply ( union inputArgs *  req,
int  res 
) [static]

Definition at line 600 of file dispatch.c.

{
    union outputArgs rep;
       
    rep.oh.opcode = req->ih.opcode;
    rep.oh.unique = req->ih.unique;
    rep.oh.result = res;
       
    send_to_kernel(&rep, sizeof(rep.oh));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void reset_signal_handlers ( ) [static]

Definition at line 377 of file dispatch.c.

{
    struct sigaction sa;
       
    sa.sa_handler = SIG_DFL;
    sigemptyset(&(sa.sa_mask));
    sa.sa_flags = 0;
       
    sigaction(SIGPIPE, &sa, NULL);
    sigaction(SIGCHLD, &sa, NULL);
}

Here is the caller graph for this function:

void run ( int  cfs,
const char *  dir,
int  dm 
)

Definition at line 1613 of file dispatch.c.

{
    int i;

    openlog("avfscoda", LOG_CONS, LOG_USER);
       
    codafd = cfs;
    codadir = dir;
    logfile = stderr;
    numfids = 0;
    checknum = 0;
    debugmode = dm;
       
    for(i = 0; i < MAXUSERS; i++)
        currusers[i].serverpid = -1;
       
    set_signal_handlers();
       
    process();
}

Here is the call graph for this function:

Here is the caller graph for this function:

void run_exit ( )

Definition at line 1183 of file dispatch.c.

{
    int i;
       
    for(i = 0; i < MAXUSERS; i++) {
        if(currusers[i].serverpid > 0) {
            kill(currusers[i].serverpid, SIGTERM);
        }
    }
       
    /* FIXME: should wait until the children are all dead */
       
    coda_flush();
    close(codafd);
    unmount_coda(codadir, 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void send_to_child ( union inputArgs *  req,
int  reqsize,
char *  path1,
char *  path2 
) [static]

Definition at line 1057 of file dispatch.c.

{
    struct operation *op;
    uid_t uid = req->ih.cred.cr_fsuid;
    gid_t gid = req->ih.cred.cr_fsgid;
    struct userinfo *user;
    int msgsize;
    struct child_message msg;
    char *message, *mp;
    int msgoff;
    int res;
    

    user = get_user(uid, gid);
    if(user == NULL) {
        reply(req, ENOMEM);
        return;
    }
       
    msg.reqsize = reqsize;
    msg.path1size = path1 ? strlen(path1) + 1 : 0;
    msg.path2size = path2 ? strlen(path2) + 1 : 0;
    msgoff = sizeof(struct child_message);
       
    msgsize = sizeof(int) + msgoff + msg.reqsize + msg.path1size + 
        msg.path2size;
       
    message = malloc(msgsize);
    if(message == NULL) {
        reply(req, ENOMEM);
        return;
    }
       
    op = malloc(sizeof(struct operation));
    if(op == NULL) {
        free(message);
        reply(req, ENOMEM);
        return;
    }
       
    memcpy(op->ibuf, req, reqsize);
    op->req = (union inputArgs *) op->ibuf;
       
    mp = message;
       
    *(int *) mp = (msgsize - sizeof(int));
    mp += sizeof(int);
       
    memcpy(mp, &msg, msgoff);
    mp += msgoff;
       
    memcpy(mp, req, msg.reqsize);
    mp += msg.reqsize;
       
    log("****** opcode: %li\n", req->ih.opcode);
    log("****** msgsize: %i, msgoff: %i, msg.reqsize: %i, \n", 
        msgsize, msgoff, msg.reqsize);
       
    if(path1) {
        memcpy(mp, path1, msg.path1size);
        mp += msg.path1size;
    }
       
    if(path2) {
        memcpy(mp, path2, msg.path2size);
        mp += msg.path2size;
    }
       
    res = write(user->pipout, message, msgsize);
    free(message);
       
    if(res != msgsize) {
        free(op);
        logerr("Error writing to child: %s\n", strerror(errno));
              
        reply(req, errno);
    }
    else {
        grab_fids(req);
        op->next = user->ops;
        user->ops = op;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void send_to_kernel ( union outputArgs *  rep,
int  size 
) [static]

Definition at line 390 of file dispatch.c.

{
    int ret;
       
    log("%i bytes\n",  size);
    ret = write(codafd, rep, size);
    if(ret == -1 || ret != size) {
        logerr("Error writing to device: %s\n", strerror(errno));
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void send_with_path ( union inputArgs *  req,
int  reqsize,
char *  filename,
ViceFid *  id,
char *  path2 
) [static]

Definition at line 1142 of file dispatch.c.

{
    char pathbuf[1024];
    struct fileinfo *fi;
    char *path;

    fi = look_info(id);
    if(fi == NULL) {
        reply(req, ENOENT);
        return;
    }

    path = fi->path;
              
    sprintf(pathbuf, "%s/%s", path, filename);

    log("path1: %s, path2: %s\n", pathbuf, path2 ? path2 : "(null)");

    /* FIXME: */
    if(strcmp(pathbuf+1, codadir) == 0) 
            reply(req, ENOENT);
    else 
            send_to_child(req, reqsize, pathbuf, path2);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void unref_fid ( ViceFid *  fid) [static]

Definition at line 369 of file dispatch.c.

{
    struct fileinfo *fi = look_info(fid);

    if(fi != NULL)
        fi->use --;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void user_child ( pid_t  pid)

Definition at line 1200 of file dispatch.c.

{
    int i;
       
    for(i = 0; i < MAXUSERS; i++) {
        if(currusers[i].serverpid == pid) {
            log("Child %i (%i/%i) exited\n", 
                pid, currusers[i].uid, 
                currusers[i].gid);
                     
            currusers[i].serverpid = 0;
                     
            return;
        }
    }
       
    logerr("Unknown child %i exited\n", pid);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void zap_file ( struct fileinfo fi) [static]

Definition at line 437 of file dispatch.c.

{
    union outputArgs rep;

    log("=================================================================\n");
    log_date();
    log("Cleaning out 0x%x\n", fi->unique);
    log("CODA_ZAPFILE\n");
    
    rep.oh.opcode = CODA_ZAPFILE;
    rep.oh.result = 0;
    rep.oh.unique = 0;
    rep.coda_zapfile.CodaFid.Volume = 0;
    rep.coda_zapfile.CodaFid.Vnode  = 0;
    rep.coda_zapfile.CodaFid.Unique = fi->unique;
    
    send_to_kernel(&rep, sizeof(rep.coda_zapfile));
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

int checknum [static]

Definition at line 72 of file dispatch.c.

const char* codadir [static]

Definition at line 68 of file dispatch.c.

int codafd [static]

Definition at line 67 of file dispatch.c.

int debugmode [static]

Definition at line 74 of file dispatch.c.

struct fileinfo* fhash[HASHSIZE] [static]

Definition at line 106 of file dispatch.c.

struct fileinfo [static]

Definition at line 110 of file dispatch.c.

struct fileinfo* fmap[FMAPSIZE] [static]

Definition at line 102 of file dispatch.c.

FILE* logfile [static]

Definition at line 69 of file dispatch.c.

int needflush [static]

Definition at line 108 of file dispatch.c.

unsigned int nextunique = 0 [static]

Definition at line 103 of file dispatch.c.

int numfids [static]

Definition at line 71 of file dispatch.c.

struct userinfo[MAXUSERS] [static]

Definition at line 65 of file dispatch.c.