/* This file deals with protection in the file system. It contains the code * for four system calls that relate to protection. * * The entry points into this file are * do_chmod: perform the CHMOD and FCHMOD system calls * do_chown: perform the CHOWN and FCHOWN system calls * do_umask: perform the UMASK system call * do_access: perform the ACCESS system call * * Changes for VFS: * Jul 2006 (Balazs Gerofi) */ #include "fs.h" #include #include #include "file.h" #include "fproc.h" #include "param.h" #include #include "vnode.h" #include "vmnt.h" /*===========================================================================* * do_chmod * *===========================================================================*/ PUBLIC int do_chmod() { struct filp *flp; struct vnode *vp; int r; uid_t uid; gid_t gid; mode_t new_mode; if (call_nr == CHMOD) { /* Perform the chmod(name, mode) system call. */ if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); /* Request lookup */ r = lookup_vp(0 /*flags*/, 0 /*!use_realuid*/, &vp); if (r != OK) return r; } else if (call_nr == FCHMOD) { if (!(flp = get_filp(m_in.m3_i1))) return err_code; vp= flp->filp_vno; dup_vnode(vp); } else panic(__FILE__, "do_chmod called with strange call_nr", call_nr); uid= fp->fp_effuid; gid= fp->fp_effgid; /* Only the owner or the super_user may change the mode of a file. * No one may change the mode of a file on a read-only file system. */ if (vp->v_uid != uid && uid != SU_UID) r = EPERM; else r = read_only(vp); /* If error, return inode. */ if (r != OK) { put_vnode(vp); return(r); } /* Now make the change. Clear setgid bit if file is not in caller's grp */ if (uid != SU_UID && vp->v_gid != gid) m_in.mode &= ~I_SET_GID_BIT; /* Issue request */ r = req_chmod(vp->v_fs_e, vp->v_inode_nr, m_in.mode, &new_mode); if (r == OK) vp->v_mode = new_mode; put_vnode(vp); return OK; } /*===========================================================================* * do_chown * *===========================================================================*/ PUBLIC int do_chown() { int inode_nr; int fs_e; struct filp *flp; struct vnode *vp; int r; uid_t uid; gid_t gid; mode_t new_mode; if (call_nr == CHOWN) { /* Perform the chmod(name, mode) system call. */ if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); /* Request lookup */ r = lookup_vp(0 /*flags*/, 0 /*!use_realuid*/, &vp); if (r != OK) return r; } else if (call_nr == FCHOWN) { if (!(flp = get_filp(m_in.m1_i1))) return err_code; vp= flp->filp_vno; dup_vnode(vp); } else panic(__FILE__, "do_chmod called with strange call_nr", call_nr); uid= fp->fp_effuid; gid= fp->fp_effgid; r= OK; if (uid == SU_UID) { /* The super user can do anything. */ } else { /* Regular users can only change groups of their own files. */ if (vp->v_uid != uid) r = EPERM; /* File does not belong to the caller */ if (vp->v_uid != m_in.owner) r = EPERM; /* no giving away */ if (gid != m_in.group) r = EPERM; /* only change to the current gid */ } if (r != OK) { put_vnode(vp); return r; } /* Issue request */ r = req_chown(vp->v_fs_e, vp->v_inode_nr, m_in.owner, m_in.group, &new_mode); if(r == OK) { vp->v_uid = m_in.owner; vp->v_gid = m_in.group; vp->v_mode = new_mode; } put_vnode(vp); return r; } /*===========================================================================* * do_umask * *===========================================================================*/ PUBLIC int do_umask() { /* Perform the umask(co_mode) system call. */ register mode_t r; r = ~fp->fp_umask; /* set 'r' to complement of old mask */ fp->fp_umask = ~(m_in.co_mode & RWX_MODES); return(r); /* return complement of old mask */ } /*===========================================================================* * do_access * *===========================================================================*/ PUBLIC int do_access() { /* Perform the access(name, mode) system call. */ int r; struct vnode *vp; /* First check to see if the mode is correct. */ if ( (m_in.mode & ~(R_OK | W_OK | X_OK)) != 0 && m_in.mode != F_OK) return(EINVAL); if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); /* Request lookup */ r = lookup_vp(0 /*flags*/, TRUE /*use_realuid*/, &vp); if (r != OK) return r; r= forbidden(vp, m_in.mode, 1 /*use_realuid*/); put_vnode(vp); return r; } /*===========================================================================* * forbidden * *===========================================================================*/ PUBLIC int forbidden(struct vnode *vp, mode_t access_desired, int use_realuid) { /* Given a pointer to an inode, 'rip', and the access desired, determine * if the access is allowed, and if not why not. The routine looks up the * caller's uid in the 'fproc' table. If access is allowed, OK is returned * if it is forbidden, EACCES is returned. */ register struct super_block *sp; register mode_t bits, perm_bits; uid_t uid; gid_t gid; int r, shift, type; if (vp->v_uid == (uid_t)-1 || vp->v_gid == (gid_t)-1) { printf("forbidden: bad uid/gid in vnode: inode %d on dev 0x%x\n", vp->v_inode_nr, vp->v_dev); printf("forbidden: last allocated at %s, %d\n", vp->v_file, vp->v_line); return EACCES; } /* Isolate the relevant rwx bits from the mode. */ bits = vp->v_mode; if (use_realuid) { uid= fp->fp_realuid; gid= fp->fp_realgid; } else { uid= fp->fp_effuid; gid= fp->fp_effgid; } if (uid == SU_UID) { /* Grant read and write permission. Grant search permission for * directories. Grant execute permission (for non-directories) if * and only if one of the 'X' bits is set. */ if ( (bits & I_TYPE) == I_DIRECTORY || bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT)) perm_bits = R_BIT | W_BIT | X_BIT; else perm_bits = R_BIT | W_BIT; } else { if (uid == vp->v_uid) shift = 6; /* owner */ else if (gid == vp->v_gid ) shift = 3; /* group */ else shift = 0; /* other */ perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT); } /* If access desired is not a subset of what is allowed, it is refused. */ r = OK; if ((perm_bits | access_desired) != perm_bits) { r = EACCES; } /* Check to see if someone is trying to write on a file system that is * mounted read-only. */ if (r == OK) if (access_desired & W_BIT) r = read_only(vp); return(r); } /*===========================================================================* * read_only * *===========================================================================*/ PUBLIC int read_only(vp) struct vnode *vp; /* ptr to inode whose file sys is to be cked */ { /* Check to see if the file system on which the inode 'ip' resides is mounted * read only. If so, return EROFS, else return OK. */ register struct vmnt *mp; mp = vp->v_vmnt; return(mp->m_flags ? EROFS : OK); } /* This file contains the wrapper functions for issueing a request * and receiving response from FS processes. * Each function builds a request message according to the request * parameter, calls the most low-level fs_sendrec and copies * back the response. * The low-level fs_sendrec handles the recovery mechanism from * a dead driver and reissues the request. * * Sep 2006 (Balazs Gerofi) */ #include "fs.h" #include #include #include #include #include #include #include #include #include #include #include #include "fproc.h" #include "vmnt.h" #include "vnode.h" #include "param.h" FORWARD _PROTOTYPE(int fs_sendrec_f, (char *file, int line, endpoint_t fs_e, message *reqm)); #define fs_sendrec(e, m) fs_sendrec_f(__FILE__, __LINE__, (e), (m)) /*===========================================================================* * req_breadwrite * *===========================================================================*/ PUBLIC int req_breadwrite(fs_e, user_e, dev, pos, num_of_bytes, user_addr, rw_flag, new_posp, cum_iop) endpoint_t fs_e; endpoint_t user_e; dev_t dev; u64_t pos; unsigned int num_of_bytes; char *user_addr; int rw_flag; u64_t *new_posp; unsigned int *cum_iop; { int r; cp_grant_id_t gid; message m; gid= cpf_grant_magic(fs_e, user_e, (vir_bytes)user_addr, num_of_bytes, (rw_flag == READING ? CPF_WRITE : CPF_READ)); if (gid == -1) panic(__FILE__, "req_breadwrite: cpf_grant_magic failed", NO_NUM); /* Fill in request message */ m.m_type = rw_flag == READING ? REQ_BREAD_S : REQ_BWRITE_S; m.REQ_XFD_BDEV = dev; m.REQ_XFD_GID = gid; m.REQ_XFD_POS_LO = ex64lo(pos); m.REQ_XFD_POS_HI = ex64hi(pos); m.REQ_XFD_NBYTES = num_of_bytes; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(gid); if (r != OK) return r; /* Fill in response structure */ *new_posp = make64(m.RES_XFD_POS_LO, m.RES_XFD_POS_HI); *cum_iop = m.RES_XFD_CUM_IO; return OK; } /*===========================================================================* * req_chmod * *===========================================================================*/ PUBLIC int req_chmod(fs_e, inode_nr, rmode, new_modep) int fs_e; ino_t inode_nr; mode_t rmode; mode_t *new_modep; { message m; int r; /* Fill in request message */ m.m_type = REQ_CHMOD; m.REQ_INODE_NR = inode_nr; m.REQ_MODE = rmode; m.REQ_UID = fp->fp_effuid; m.REQ_GID = fp->fp_effgid; /* Send/rec request */ r = fs_sendrec(fs_e, &m); /* Copy back actual mode. */ if (r == OK) *new_modep = m.RES_MODE; return r; } /* Structure for REQ_CHOWN request */ typedef struct chown_req { int fs_e; ino_t inode_nr; uid_t uid; gid_t gid; uid_t newuid; gid_t newgid; } chown_req_t; /*===========================================================================* * req_chown * *===========================================================================*/ PUBLIC int req_chown(fs_e, inode_nr, newuid, newgid, new_modep) endpoint_t fs_e; ino_t inode_nr; uid_t newuid; gid_t newgid; mode_t *new_modep; { message m; int r; /* Fill in request message */ m.m_type = REQ_CHOWN; m.REQ_INODE_NR = inode_nr; m.REQ_UID = fp->fp_effuid; m.REQ_GID = fp->fp_effgid; m.REQ_NEW_UID = newuid; m.REQ_NEW_GID = newgid; /* Send/rec request */ r = fs_sendrec(fs_e, &m); /* Return new mode to caller. */ *new_modep = m.RES_MODE; return r; } /*===========================================================================* * req_create * *===========================================================================*/ int req_create(fs_e, inode_nr, omode, uid, gid, path, res) int fs_e; ino_t inode_nr; int omode; uid_t uid; gid_t gid; char *path; node_details_t *res; { int r; cp_grant_id_t grant_id; size_t len; message m; len= strlen(path) + 1; grant_id= cpf_grant_direct(fs_e, (vir_bytes)path, len, CPF_READ); if (grant_id == -1) panic(__FILE__, "req_create: cpf_grant_direct failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_CREATE_S; m.REQ_INODE_NR = inode_nr; m.REQ_MODE = omode; m.REQ_UID = uid; m.REQ_GID = gid; m.REQ_GRANT = grant_id; m.REQ_PATH_LEN = len; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); if (r != OK) return r; /* Fill in response structure */ res->fs_e = m.m_source; res->inode_nr = m.RES_INODE_NR; res->fmode = m.RES_MODE; res->fsize = m.RES_FILE_SIZE; res->uid = m.RES_UID; res->gid = m.RES_GID; res->dev = m.RES_DEV; res->inode_index = m.RES_INODE_INDEX; return OK; } /*===========================================================================* * req_flush * *===========================================================================*/ PUBLIC int req_flush(fs_e, dev) endpoint_t fs_e; dev_t dev; { message m; /* Fill in request message */ m.m_type = REQ_FLUSH; m.REQ_DEV = dev; /* Send/rec request */ return fs_sendrec(fs_e, &m); } /*===========================================================================* * req_fstatfs * *===========================================================================*/ PUBLIC int req_fstatfs(fs_e, inode_nr, who_e, buf) int fs_e; ino_t inode_nr; int who_e; char *buf; { int r; cp_grant_id_t gid; message m; gid= cpf_grant_magic(fs_e, who_e, (vir_bytes)buf, sizeof(struct statfs), CPF_WRITE); if (gid < 0) return gid; /* Fill in request message */ m.m_type = REQ_FSTATFS; m.REQ_INODE_NR = inode_nr; m.REQ_GRANT = gid; /* Send/rec request */ r= fs_sendrec(fs_e, &m); cpf_revoke(gid); return r; } /*===========================================================================* * req_ftrunc * *===========================================================================*/ PUBLIC int req_ftrunc(fs_e, inode_nr, start, end) endpoint_t fs_e; ino_t inode_nr; off_t start; off_t end; { message m; /* Fill in request message */ m.m_type = REQ_FTRUNC; m.REQ_FD_INODE_NR = inode_nr; m.REQ_FD_START = start; m.REQ_FD_END = end; /* Send/rec request */ return fs_sendrec(fs_e, &m); } /*===========================================================================* * req_getdents * *===========================================================================*/ PUBLIC int req_getdents(fs_e, inode_nr, pos, gid, size, pos_change) endpoint_t fs_e; ino_t inode_nr; off_t pos; cp_grant_id_t gid; size_t size; off_t *pos_change; { int r; message m; m.m_type= REQ_GETDENTS; m.REQ_GDE_INODE= inode_nr; m.REQ_GDE_GRANT= gid; m.REQ_GDE_SIZE= size; m.REQ_GDE_POS= pos; r = fs_sendrec(fs_e, &m); *pos_change= m.RES_GDE_POS_CHANGE; return r; } /*===========================================================================* * req_inhibread * *===========================================================================*/ PUBLIC int req_inhibread(fs_e, inode_nr) endpoint_t fs_e; ino_t inode_nr; { message m; /* Fill in request message */ m.m_type = REQ_INHIBREAD; m.REQ_INODE_NR = inode_nr; /* Send/rec request */ return fs_sendrec(fs_e, &m); } /*===========================================================================* * req_link * *===========================================================================*/ PUBLIC int req_link(fs_e, link_parent, lastc, linked_file) endpoint_t fs_e; ino_t link_parent; char *lastc; ino_t linked_file; { int r; cp_grant_id_t gid; size_t len; message m; len= strlen(lastc) + 1; gid= cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); if (gid == -1) panic(__FILE__, "req_link: cpf_grant_direct failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_LINK_S; m.REQ_LINKED_FILE = linked_file; m.REQ_LINK_PARENT = link_parent; m.REQ_GRANT = gid; m.REQ_PATH_LEN = len; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(gid); return r; } /*===========================================================================* * req_lookup * *===========================================================================*/ PUBLIC int req_lookup(fs_e, path_off, dir_ino, root_ino, uid, gid, flags, res) endpoint_t fs_e; size_t path_off; ino_t dir_ino; ino_t root_ino; uid_t uid; gid_t gid; int flags; lookup_res_t *res; { int r; size_t len; cp_grant_id_t grant_id; message m; #if 0 printf("req_lookup_s: fs %d, ino %d, root %d, string (off %d) '%s'\n", fs_e, dir_ino, root_ino, path_off, user_fullpath+path_off); #endif grant_id= cpf_grant_direct(fs_e, (vir_bytes)user_fullpath, sizeof(user_fullpath), CPF_READ|CPF_WRITE); if (grant_id == -1) panic(__FILE__, "req_lookup_s: cpf_grant_direct failed", NO_NUM); len= strlen(user_fullpath+path_off) + 1; /* Fill in request message */ m.m_type = REQ_LOOKUP_S; m.REQ_L_GRANT = grant_id; m.REQ_L_PATH_LEN = len; m.REQ_L_PATH_SIZE = sizeof(user_fullpath); m.REQ_L_PATH_OFF = path_off; m.REQ_L_DIR_INO = dir_ino; m.REQ_L_ROOT_INO = root_ino; m.REQ_L_FLAGS = flags; m.REQ_L_UID = uid; m.REQ_L_GID = gid; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); /* Fill in response according to the return value */ res->fs_e = m.m_source; switch (r) { case OK: res->inode_nr = m.RES_INODE_NR; res->fmode = m.RES_MODE; res->fsize = m.RES_FILE_SIZE; res->dev = m.RES_DEV; res->uid= m.RES_UID; res->gid= m.RES_GID; break; case EENTERMOUNT: res->inode_nr = m.RES_INODE_NR; res->char_processed = m.RES_OFFSET; res->symloop = m.RES_SYMLOOP2; break; case ELEAVEMOUNT: res->char_processed = m.RES_OFFSET; res->symloop = m.RES_SYMLOOP2; break; case ESYMLINK: res->char_processed = m.RES_OFFSET; res->symloop = m.RES_SYMLOOP2; break; default: break; } return r; } /*===========================================================================* * req_mkdir * *===========================================================================*/ PUBLIC int req_mkdir(fs_e, inode_nr, lastc, uid, gid, dmode) endpoint_t fs_e; ino_t inode_nr; char *lastc; uid_t uid; gid_t gid; mode_t dmode; { int r; cp_grant_id_t grant_id; size_t len; message m; len= strlen(lastc) + 1; grant_id= cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); if (gid == -1) panic(__FILE__, "req_mkdir: cpf_grant_direct failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_MKDIR_S; m.REQ_INODE_NR = inode_nr; m.REQ_MODE = dmode; m.REQ_UID = uid; m.REQ_GID = gid; m.REQ_GRANT = grant_id; m.REQ_PATH_LEN = len; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); return r; } /* Structure for REQ_MKNOD request */ typedef struct mknod_req { int fs_e; ino_t inode_nr; uid_t uid; gid_t gid; mode_t rmode; dev_t dev; char *lastc; } mknod_req_t; /*===========================================================================* * req_newnode * *===========================================================================*/ PUBLIC int req_newnode(fs_e, uid, gid, dmode, dev, res) endpoint_t fs_e; uid_t uid; gid_t gid; mode_t dmode; dev_t dev; struct node_details *res; { int r; message m; /* Fill in request message */ m.m_type = REQ_NEWNODE; m.REQ_MODE = dmode; m.REQ_DEVx = dev; m.REQ_UID = uid; m.REQ_GID = gid; /* Send/rec request */ r = fs_sendrec(fs_e, &m); res->fs_e = m.m_source; res->inode_nr = m.RES_INODE_NR; res->fmode = m.RES_MODE; res->fsize = m.RES_FILE_SIZE; res->dev = m.RES_DEV; res->uid= m.RES_UID; res->gid= m.RES_GID; return r; } /*===========================================================================* * req_mountpoint * *===========================================================================*/ PUBLIC int req_mountpoint(fs_e, inode_nr) endpoint_t fs_e; ino_t inode_nr; { int r; message m; /* Fill in request message */ m.m_type = REQ_MOUNTPOINT_S; m.REQ_INODE_NR = inode_nr; /* Send/rec request */ return fs_sendrec(fs_e, &m); } /*===========================================================================* * req_mknod * *===========================================================================*/ PUBLIC int req_mknod(fs_e, inode_nr, lastc, uid, gid, dmode, dev) endpoint_t fs_e; ino_t inode_nr; char *lastc; uid_t uid; gid_t gid; mode_t dmode; dev_t dev; { int r; size_t len; cp_grant_id_t grant_id; message m; len= strlen(lastc) + 1; grant_id= cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); if (gid == -1) panic(__FILE__, "req_mknod: cpf_grant_direct failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_MKNOD_S; m.REQ_INODE_NR = inode_nr; m.REQ_MODE = dmode; m.REQ_DEVx = dev; m.REQ_UID = uid; m.REQ_GID = gid; m.REQ_GRANT = grant_id; m.REQ_PATH_LEN = len; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); return r; } /*===========================================================================* * req_putnode * *===========================================================================*/ PUBLIC int req_putnode(fs_e, inode_nr, count) int fs_e; ino_t inode_nr; int count; { message m; /* Fill in request message */ m.m_type = REQ_PUTNODE; m.REQ_INODE_NR = inode_nr; m.REQ_COUNT = count; /* Send/rec request */ return fs_sendrec(fs_e, &m); } /*===========================================================================* * req_rdlink * *===========================================================================*/ PUBLIC int req_rdlink(fs_e, inode_nr, who_e, buf, len) endpoint_t fs_e; ino_t inode_nr; endpoint_t who_e; vir_bytes buf; size_t len; { message m; int r; cp_grant_id_t gid; gid= cpf_grant_magic(fs_e, who_e, buf, len, CPF_WRITE); if (gid == -1) panic(__FILE__, "req_rdlink: cpf_grant_magic failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_RDLINK_S; m.REQ_INODE_NR = inode_nr; m.REQ_GRANT = gid; m.REQ_SLENGTH = len; /* Send/rec request */ r= fs_sendrec(fs_e, &m); cpf_revoke(gid); return r; } /*===========================================================================* * req_readsuper * *===========================================================================*/ PUBLIC int req_readsuper(fs_e, label, dev, readonly, isroot, res_nodep) endpoint_t fs_e; char *label; dev_t dev; int readonly; int isroot; struct node_details *res_nodep; { int r; cp_grant_id_t gid; size_t len; message m; len= strlen(label)+1; gid= cpf_grant_direct(fs_e, (vir_bytes)label, len, CPF_READ); if (gid == -1) panic(__FILE__, "req_req_readsuper: cpf_grant_direct failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_READSUPER_S; m.REQ_READONLY = readonly; m.REQ_GRANT2 = gid; m.REQ_DEV = dev; m.REQ_ISROOT = isroot; m.REQ_PATH_LEN = len; /* Send/rec request */ if ((r = fs_sendrec(fs_e, &m)) != OK) return r; /* Fill in response structure */ res_nodep->fs_e = m.m_source; res_nodep->inode_nr = m.RES_INODE_NR; res_nodep->fmode = m.RES_MODE; res_nodep->fsize = m.RES_FILE_SIZE; res_nodep->uid = m.RES_UID; res_nodep->gid = m.RES_GID; return OK; } /* Structure for REQ_READ and REQ_WRITE request */ typedef struct readwrite_req { int rw_flag; endpoint_t fs_e; endpoint_t user_e; ino_t inode_nr; unsigned short inode_index; int seg; u64_t pos; unsigned int num_of_bytes; char *user_addr; } readwrite_req_t; /*===========================================================================* * req_readwrite * *===========================================================================*/ PUBLIC int req_readwrite(fs_e, inode_nr, inode_index, pos, rw_flag, user_e, user_addr, num_of_bytes, new_posp, cum_iop) endpoint_t fs_e; ino_t inode_nr; unsigned short inode_index; u64_t pos; int rw_flag; endpoint_t user_e; char *user_addr; unsigned int num_of_bytes; u64_t *new_posp; unsigned int *cum_iop; { int r; cp_grant_id_t gid; message m; if (ex64hi(pos) != 0) panic(__FILE__, "req_readwrite: pos too large", NO_NUM); gid= cpf_grant_magic(fs_e, user_e, (vir_bytes)user_addr, num_of_bytes, (rw_flag == READING ? CPF_WRITE : CPF_READ)); if (gid == -1) panic(__FILE__, "req_readwrite: cpf_grant_magic failed", NO_NUM); /* Fill in request message */ m.m_type = rw_flag == READING ? REQ_READ_S : REQ_WRITE_S; m.REQ_FD_INODE_NR = inode_nr; m.REQ_FD_GID = gid; m.REQ_FD_POS = ex64lo(pos); m.REQ_FD_NBYTES = num_of_bytes; m.REQ_FD_INODE_INDEX = inode_index; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(gid); if (r != OK) return r; /* Fill in response structure */ *new_posp = cvul64(m.RES_FD_POS); *cum_iop = m.RES_FD_CUM_IO; return OK; } /*===========================================================================* * req_rename * *===========================================================================*/ PUBLIC int req_rename(fs_e, old_dir, old_name, new_dir, new_name) endpoint_t fs_e; ino_t old_dir; char *old_name; ino_t new_dir; char *new_name; { int r; cp_grant_id_t gid_old, gid_new; size_t len_old, len_new; message m; len_old= strlen(old_name) + 1; gid_old= cpf_grant_direct(fs_e, (vir_bytes)old_name, len_old, CPF_READ); if (gid_old == -1) panic(__FILE__, "req_rename: cpf_grant_direct failed", NO_NUM); len_new= strlen(new_name) + 1; gid_new= cpf_grant_direct(fs_e, (vir_bytes)new_name, len_new, CPF_READ); if (gid_new == -1) panic(__FILE__, "req_rename: cpf_grant_direct failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_RENAME_S; m.REQ_REN_OLD_DIR = old_dir; m.REQ_REN_NEW_DIR = new_dir; m.REQ_REN_GRANT_OLD = gid_old; m.REQ_REN_LEN_OLD = len_old; m.REQ_REN_GRANT_NEW = gid_new; m.REQ_REN_LEN_NEW = len_new; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(gid_old); cpf_revoke(gid_new); return r; } /*===========================================================================* * req_rmdir * *===========================================================================*/ PUBLIC int req_rmdir(fs_e, inode_nr, lastc) endpoint_t fs_e; ino_t inode_nr; char *lastc; { int r; cp_grant_id_t gid; size_t len; message m; len= strlen(lastc) + 1; gid= cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); if (gid == -1) panic(__FILE__, "req_rmdir: cpf_grant_direct failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_RMDIR_S; m.REQ_INODE_NR = inode_nr; m.REQ_GRANT = gid; m.REQ_PATH_LEN = len; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(gid); return r; } /*===========================================================================* * req_slink * *===========================================================================*/ PUBLIC int req_slink(fs_e, inode_nr, lastc, who_e, path_addr, path_length, uid, gid) endpoint_t fs_e; ino_t inode_nr; char *lastc; endpoint_t who_e; char *path_addr; unsigned short path_length; uid_t uid; gid_t gid; { int r; size_t len; cp_grant_id_t gid_name, gid_buf; message m; len= strlen(lastc) + 1; gid_name= cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); if (gid_name == -1) panic(__FILE__, "req_slink: cpf_grant_direct failed", NO_NUM); gid_buf= cpf_grant_magic(fs_e, who_e, (vir_bytes)path_addr, path_length, CPF_READ); if (gid_buf == -1) { cpf_revoke(gid_buf); panic(__FILE__, "req_slink: cpf_grant_magic failed", NO_NUM); } /* Fill in request message */ m.m_type = REQ_SLINK_S; m.REQ_INODE_NR = inode_nr; m.REQ_UID = uid; m.REQ_GID = gid; m.REQ_GRANT = gid_name; m.REQ_PATH_LEN = len; m.REQ_GRANT2 = gid_buf; m.REQ_SLENGTH = path_length; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(gid_name); cpf_revoke(gid_buf); return r; } /*===========================================================================* * req_stat * *===========================================================================*/ PUBLIC int req_stat(fs_e, inode_nr, who_e, buf, pos) int fs_e; ino_t inode_nr; int who_e; char *buf; int pos; { cp_grant_id_t gid; int r; message m; struct stat sb; if (pos != 0) { gid= cpf_grant_direct(fs_e, (vir_bytes)&sb, sizeof(struct stat), CPF_WRITE); } else { gid= cpf_grant_magic(fs_e, who_e, (vir_bytes)buf, sizeof(struct stat), CPF_WRITE); } if (gid < 0) return gid; /* Fill in request message */ m.m_type = REQ_STAT; m.REQ_INODE_NR = inode_nr; m.REQ_GRANT = gid; /* Send/rec request */ r= fs_sendrec(fs_e, &m); cpf_revoke(gid); if (r == OK && pos != 0) { sb.st_size -= pos; r= sys_vircopy(SELF, D, (vir_bytes)&sb, who_e, D, (vir_bytes)buf, sizeof(struct stat)); } return r; } /*===========================================================================* * req_sync * *===========================================================================*/ PUBLIC int req_sync(fs_e) endpoint_t fs_e; { message m; /* Fill in request message */ m.m_type = REQ_SYNC; /* Send/rec request */ return fs_sendrec(fs_e, &m); } /* Structure for REQ_UNLINK request */ typedef struct unlink_req { int fs_e; ino_t d_inode_nr; uid_t uid; gid_t gid; char *lastc; } unlink_req_t; /*===========================================================================* * req_unlink * *===========================================================================*/ PUBLIC int req_unlink(fs_e, inode_nr, lastc) endpoint_t fs_e; ino_t inode_nr; char *lastc; { cp_grant_id_t gid; size_t len; int r; message m; len= strlen(lastc) + 1; gid= cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ); if (gid == -1) panic(__FILE__, "req_unlink: cpf_grant_direct failed", NO_NUM); /* Fill in request message */ m.m_type = REQ_UNLINK_S; m.REQ_INODE_NR = inode_nr; m.REQ_GRANT = gid; m.REQ_PATH_LEN = len; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(gid); return r; } /*===========================================================================* * req_unmount * *===========================================================================*/ PUBLIC int req_unmount(fs_e) endpoint_t fs_e; { message m; /* Fill in request message */ m.m_type = REQ_UNMOUNT; /* Send/rec request */ return fs_sendrec(fs_e, &m); } /*===========================================================================* * req_utime * *===========================================================================*/ PUBLIC int req_utime(fs_e, inode_nr, actime, modtime) endpoint_t fs_e; ino_t inode_nr; time_t actime; time_t modtime; { message m; /* Fill in request message */ m.m_type = REQ_UTIME; m.REQ_INODE_NR = inode_nr; m.REQ_ACTIME = actime; m.REQ_MODTIME = modtime; /* Send/rec request */ return fs_sendrec(fs_e, &m); } /*===========================================================================* * req_newdriver * *===========================================================================*/ PUBLIC int req_newdriver(fs_e, dev, driver_e) endpoint_t fs_e; Dev_t dev; endpoint_t driver_e; { /* Note: this is the only request function that doesn't use the * fs_sendrec internal routine, since we want to avoid the dead * driver recovery mechanism here. This function is actually called * during the recovery. */ message m; int r; /* Fill in request message */ m.m_type = REQ_NEW_DRIVER; m.REQ_DEV = dev; m.REQ_DRIVER_E = driver_e; /* Issue request */ if ((r = sendrec(fs_e, &m)) != OK) { printf("VFSreq_newdriver: error sending message to %d: %d\n", fs_e, r); return r; } return OK; } /*===========================================================================* * fs_sendrec * *===========================================================================*/ PRIVATE int fs_sendrec_f(char *file, int line, endpoint_t fs_e, message *reqm) { /* This is the low level function that sends requests to FS processes. * It also handles driver recovery mechanism and reissuing the * request which failed due to a dead driver. */ int r, old_driver_e, new_driver_e; message origm, m; struct vmnt *vmp; if (fs_e == PM_PROC_NR) { printf("from %s, %d\n", file, line); panic(__FILE__, "talking to PM", NO_NUM); } /* Make a copy of the request so that we can load it back in * case of a dead driver */ origm = *reqm; for (;;) { /* Do the actual send, receive */ if (OK != (r=sendrec(fs_e, reqm))) { printf("VFS:fs_sendrec:%s:%d: error sending message. FS_e: %d req_nr: %d err: %d\n", file, line, fs_e, reqm->m_type, r); } if(r == OK) { /* Sendrec was okay */ break; } /* Dead driver */ if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) { old_driver_e = NONE; /* Find old driver by endpoint */ for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { if (vmp->m_fs_e == fs_e) { /* found FS */ old_driver_e = vmp->m_driver_e; dmap_unmap_by_endpt(old_driver_e); /* unmap driver */ break; } } /* No FS ?? */ if (old_driver_e == NONE) panic(__FILE__, "VFSdead_driver: couldn't find FS\n", fs_e); /* Wait for a new driver. */ for (;;) { new_driver_e = 0; printf("VFSdead_driver: waiting for new driver\n"); r = receive(RS_PROC_NR, &m); if (r != OK) { panic(__FILE__, "VFSdead_driver: unable to receive from RS", r); } if (m.m_type == DEVCTL) { /* Map new driver */ r = fs_devctl(m.ctl_req, m.dev_nr, m.driver_nr, m.dev_style, m.m_force); if (m.ctl_req == DEV_MAP && r == OK) { new_driver_e = m.driver_nr; printf("VFSdead_driver: new driver endpoint: %d\n", new_driver_e); } } else { panic(__FILE__, "VFSdead_driver: got message from RS, type", m.m_type); } m.m_type = r; if ((r = send(RS_PROC_NR, &m)) != OK) { panic(__FILE__, "VFSdead_driver: unable to send to RS", r); } /* New driver is ready */ if (new_driver_e) break; } /* Copy back original request */ *reqm = origm; continue; } printf("fs_sendrec: unhandled error %d sending to %d\n", r, fs_e); panic(__FILE__, "fs_sendrec: unhandled error", NO_NUM); } /* Return message type */ return reqm->m_type; }