Back to index

avfs  1.0.1
redir.c
Go to the documentation of this file.
00001 #include <linux/version.h>
00002 #include <linux/config.h>
00003 #ifdef CONFIG_MODVERSIONS
00004 #include <linux/modversions.h>
00005 #endif
00006 #include <linux/module.h>
00007 #include <linux/kernel.h>
00008 #include <linux/unistd.h>
00009 #include <linux/slab.h>
00010 #include <linux/fs.h>
00011 #include <linux/smp_lock.h>
00012 #include <asm/uaccess.h>
00013 #include <linux/coda_psdev.h>
00014 
00015 #ifdef MODULE_LICENSE
00016 MODULE_LICENSE("GPL");
00017 #endif
00018 
00019 #if 0
00020 #define DEB(X) printk X
00021 #else
00022 #define DEB(X)
00023 #endif
00024 
00025 #define REDIR_VERSION "0.93"
00026 
00027 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
00028 #define NEWVFS 1
00029 #else
00030 #define NEWVFS 0
00031 #endif
00032 
00033 extern void *sys_call_table[];
00034 
00035 typedef asmlinkage int (*chdir_func)    (const char *);
00036 typedef asmlinkage int (*stat_func)     (const char *, struct stat *);
00037 typedef asmlinkage int (*access_func)   (const char *, int);
00038 typedef asmlinkage int (*open_func)     (const char *, int, int);
00039 typedef asmlinkage int (*readlink_func) (const char *, char *, int);
00040 typedef asmlinkage int (*getcwd_func)   (char *, unsigned long);
00041 
00042 static chdir_func    orig_chdir;
00043 static stat_func     orig_stat;
00044 static stat_func     orig_lstat;
00045 static access_func   orig_access;
00046 static open_func     orig_open;
00047 static readlink_func orig_readlink;
00048 static getcwd_func   orig_getcwd;
00049 
00050 #if NEWVFS
00051 typedef asmlinkage long (*stat64_func)   (const char *, struct stat64 *, long);
00052 
00053 static stat64_func   orig_stat64;
00054 static stat64_func   orig_lstat64;
00055 #endif 
00056 
00057 #ifdef __i386__
00058 typedef asmlinkage int (*execve_func) (struct pt_regs);
00059 
00060 static execve_func orig_execve;
00061 #endif
00062 
00063 #define AVFS_MAGIC_CHAR '#'
00064 #define OVERLAY_DIR "/overlay"
00065 #define OVERLAY_DIR_LEN 8
00066 
00067 #define PF_AVFS 0x00008000
00068 
00069 #define path_ok(pwd) (pwd->d_parent == pwd || !list_empty(&pwd->d_hash))
00070 
00071 #if NEWVFS
00072 static char *path_pwd(char *page)
00073 {
00074        return d_path(current->fs->pwd, current->fs->pwdmnt, page, PAGE_SIZE);
00075 }
00076 
00077 static int a_path_walk(const char *pathname, int flags, struct nameidata *nd)
00078 {
00079        int error;
00080 
00081        error = 0;
00082        if (path_init(pathname, flags, nd))
00083               error = path_walk(pathname, nd);
00084 
00085        return error;
00086 }
00087 
00088 static void a_path_release(struct nameidata *nd)
00089 {
00090        dput(nd->dentry);
00091        mntput(nd->mnt);
00092 }
00093 
00094 static char *resolv_virt(const char *pathname, int must_exist, int flags)
00095 {
00096        struct nameidata root;
00097        struct nameidata nd;
00098        struct dentry *origroot;
00099        struct vfsmount *origrootmnt;
00100        char *newpathname = NULL;
00101        char *page = NULL;
00102        char *path = NULL;
00103        int pathlen = 0;
00104        int error;
00105        int newflags;
00106 
00107        lock_kernel();
00108 
00109        DEB((KERN_INFO "resolve_virt pathname: '%s'\n", 
00110             pathname ? pathname : "(null)"));
00111 
00112        error = a_path_walk(OVERLAY_DIR, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &root);
00113        if(error)
00114               goto out;
00115 
00116        origroot = current->fs->root;
00117        origrootmnt = current->fs->rootmnt;
00118 
00119        current->fs->root = root.dentry;
00120        current->fs->rootmnt = root.mnt;
00121        
00122        newflags = flags;
00123        if(must_exist)
00124               newflags |= LOOKUP_POSITIVE;
00125 
00126        error  = a_path_walk(pathname, newflags, &nd);
00127        if(!error) {
00128               if(path_ok(nd.dentry)) {
00129                      page = (char *) __get_free_page(GFP_USER);
00130                      if(page) {
00131                             path = d_path(nd.dentry, nd.mnt, page,
00132                                          PAGE_SIZE);
00133                             DEB((KERN_INFO "resolve_virt path = '%s'\n",
00134                                  path));
00135                             pathlen = (unsigned int) page + PAGE_SIZE - 
00136                                    (unsigned int) path;
00137                      }
00138               }
00139               a_path_release(&nd);
00140        }
00141 
00142        current->fs->root = origroot;
00143        current->fs->rootmnt = origrootmnt;
00144 
00145        a_path_release(&root);
00146 
00147        if(path) {
00148               int isvirtual;
00149 
00150               error  = a_path_walk(path, flags, &nd);
00151               if(!error) {
00152                      if(nd.dentry->d_inode)
00153                             isvirtual = 0;
00154                      else if(must_exist)
00155                             isvirtual = 1;
00156                      else if(strchr(path, AVFS_MAGIC_CHAR))
00157                             isvirtual = 1;
00158                      else 
00159                             isvirtual = 0;
00160 
00161                      a_path_release(&nd);
00162               }
00163               else {
00164                      isvirtual = 1;
00165               }
00166 
00167               if(!isvirtual) {
00168                      newpathname = kmalloc(pathlen + 1, GFP_USER);
00169                      if(newpathname)
00170                             strncpy(newpathname, path, pathlen);
00171               }
00172               else {
00173                      newpathname = kmalloc(OVERLAY_DIR_LEN + pathlen + 1,
00174                                          GFP_USER);
00175 
00176                      if(newpathname) {
00177                             strcpy(newpathname, OVERLAY_DIR);
00178                             strncat(newpathname, path, pathlen);
00179                      }
00180               }
00181        }
00182 
00183        if(page)
00184               free_page((unsigned long) page);
00185 
00186 
00187        DEB((KERN_INFO "resolve_virt newpathname: '%s'\n", 
00188             newpathname ? newpathname : "(null)"));
00189 
00190  out:
00191        unlock_kernel();
00192        return newpathname;
00193 }
00194 
00195 #else /* NEWVFS */
00196 
00197 static char *path_pwd(char *page)
00198 {
00199        return d_path(current->fs->pwd, page, PAGE_SIZE);
00200 }
00201 
00202 
00203 static char *resolv_virt(const char *pathname, int must_exist, int flags)
00204 {
00205        struct dentry *root, *origroot;
00206        struct dentry *dentry;
00207        char *newpathname = NULL;
00208        char *page = NULL;
00209        char *path = NULL;
00210        int pathlen = 0;
00211 
00212        lock_kernel();
00213 
00214        DEB((KERN_INFO "resolve_virt pathname: '%s'\n", 
00215             pathname ? pathname : "(null)"));
00216 
00217        root = lookup_dentry(OVERLAY_DIR, NULL, 1);
00218        if(IS_ERR(root))
00219               goto out;
00220        
00221        if(!root->d_inode) {
00222               dput(root);
00223               goto out;
00224        }
00225 
00226        origroot = current->fs->root;
00227        current->fs->root = root;
00228        
00229        dentry = lookup_dentry(pathname, NULL, flags);
00230        if(!IS_ERR(dentry)) {
00231               if((!must_exist || dentry->d_inode) && path_ok(dentry)) {
00232                      page = (char *) __get_free_page(GFP_USER);
00233                      if(page) {
00234                             path = d_path(dentry, page, PAGE_SIZE);
00235                             DEB((KERN_INFO "resolve_virt path = '%s'\n",
00236                                  path));
00237                             pathlen = (unsigned int) page + PAGE_SIZE - 
00238                                    (unsigned int) path;
00239                      }
00240               }
00241               dput(dentry);
00242        }
00243 
00244        current->fs->root = origroot;
00245        dput(root);
00246 
00247        if(path) {
00248               int isvirtual;
00249 
00250               dentry = lookup_dentry(path, NULL, flags);
00251 
00252               if(!IS_ERR(dentry)) {
00253                      if(dentry->d_inode)
00254                             isvirtual = 0;
00255                      else if(must_exist)
00256                             isvirtual = 1;
00257                      else if(strchr(path, AVFS_MAGIC_CHAR))
00258                             isvirtual = 1;
00259                      else 
00260                             isvirtual = 0;
00261 
00262                      dput(dentry);
00263               }
00264               else {
00265                      isvirtual = 1;
00266               }
00267 
00268               if(!isvirtual) {
00269                      newpathname = kmalloc(pathlen + 1, 
00270                                          GFP_USER);
00271                      if(newpathname)
00272                             strncpy(newpathname, path, pathlen);
00273               }
00274               else {
00275                      newpathname = kmalloc(OVERLAY_DIR_LEN + pathlen + 1,
00276                                          GFP_USER);
00277 
00278                      if(newpathname) {
00279                             strcpy(newpathname, OVERLAY_DIR);
00280                             strncat(newpathname, path, pathlen);
00281                      }
00282               }
00283        }
00284 
00285        if(page)
00286               free_page((unsigned long) page);
00287 
00288 
00289        DEB((KERN_INFO "resolve_virt newpathname: '%s'\n", 
00290             newpathname ? newpathname : "(null)"));
00291 
00292  out:
00293        unlock_kernel();
00294        return newpathname;
00295 }
00296 
00297 #endif /* NEWVFS */
00298 
00299 #define cwd_virtual() \
00300        (current->fs->pwd->d_sb->s_magic == CODA_SUPER_MAGIC)
00301 
00302 static char *get_abs_path(const char *filename)
00303 {
00304        char *cwd;
00305        int cwdlen, fnamelen;
00306        char *abspath, *s;
00307        char *page;
00308 
00309        if(!path_ok(current->fs->pwd))
00310               return NULL;
00311 
00312        page = (char *) __get_free_page(GFP_USER);
00313        if(!page)
00314               return NULL;
00315 
00316        cwd = path_pwd(page);
00317        cwdlen = (unsigned int) page + PAGE_SIZE - (unsigned int) cwd - 1;
00318        if(cwd_virtual() && cwdlen > OVERLAY_DIR_LEN) {
00319               cwd += OVERLAY_DIR_LEN;
00320               cwdlen -= OVERLAY_DIR_LEN;
00321        }
00322               
00323 
00324        fnamelen = strlen(filename);
00325 
00326        abspath = kmalloc(cwdlen + 1 + fnamelen + 1, GFP_USER);
00327        if(abspath) {
00328               s = abspath;
00329               strncpy(s, cwd, cwdlen);
00330               s += cwdlen;
00331               *s++ = '/';
00332               strncpy(s, filename, fnamelen + 1);
00333        }
00334        free_page((unsigned long) page);
00335        
00336        return abspath;
00337 }
00338 
00339 static char *resolve_name(const char *kfilename, int must_exist, int flags)
00340 {
00341        char *tmp;
00342        char *newfilename;          
00343 
00344        tmp = getname(kfilename);
00345        if(IS_ERR(tmp))
00346               return tmp;
00347 
00348 
00349        if((tmp[0] != '/' && cwd_virtual()) || strchr(tmp, AVFS_MAGIC_CHAR)) {
00350               DEB((KERN_INFO "resolve_name: %s (%i/%s)\n", tmp, 
00351                    current->pid,
00352                    (current->flags & PF_AVFS) ? "on" : "off"));
00353 
00354               if(strcmp(tmp, "/#avfs-on") == 0) {
00355                      printk(KERN_INFO "AVFS ON  (pid: %i)\n",
00356                             current->pid);
00357                      current->flags |= PF_AVFS;
00358                      newfilename = ERR_PTR(-EEXIST);
00359               }
00360               else if(!(current->flags & PF_AVFS))
00361                      newfilename = NULL;
00362               else if(strcmp(tmp, "/#avfs-off") == 0) {
00363                      printk(KERN_INFO "AVFS OFF (pid: %i)\n",
00364                             current->pid);
00365                      current->flags &= ~PF_AVFS;
00366                      newfilename = ERR_PTR(-EEXIST);
00367               }
00368               else {
00369                      if(tmp[0] == '/') {
00370                             newfilename = resolv_virt(tmp, must_exist, flags);
00371                      }
00372                      else {
00373                             char *abspath;
00374 
00375                             abspath = get_abs_path(tmp);
00376                             if(abspath) {
00377                                    newfilename = resolv_virt(abspath, must_exist, flags);
00378                                    kfree(abspath);
00379                             }
00380                             else
00381                                    newfilename = NULL;
00382                      }
00383               }
00384        }
00385        else 
00386               newfilename = NULL;
00387        
00388        putname(tmp);
00389        
00390        return newfilename;
00391 }
00392 
00393 asmlinkage int virt_chdir(const char *filename)
00394 {
00395        int ret;
00396        mm_segment_t old_fs;
00397        char *newfilename;
00398        
00399        if(!cwd_virtual()) {
00400               ret = (*orig_chdir)(filename);
00401               if(ret != -ENOENT) 
00402                      return ret;
00403        }
00404        else 
00405               ret = 0;
00406 
00407        newfilename = resolve_name(filename, 1, 1);
00408        if(!newfilename) {
00409               if(ret)
00410                      return ret;
00411               else
00412                      return (*orig_chdir)(filename);
00413        }
00414        if(IS_ERR(newfilename))
00415               return PTR_ERR(newfilename);
00416 
00417 
00418        DEB((KERN_INFO "CHDIR: trying '%s'\n", newfilename));
00419               
00420        old_fs = get_fs();
00421        set_fs(get_ds());
00422        ret =  (*orig_chdir)(newfilename);
00423        set_fs(old_fs);
00424        kfree(newfilename);
00425 
00426        DEB((KERN_INFO "CHDIR: result %i\n", ret));
00427        
00428        return ret;
00429 }
00430 
00431 static int do_orig_stat(stat_func sfunc, const char *filename,
00432                      struct stat *statbuf)
00433 {
00434        int ret;
00435        mm_segment_t old_fs;
00436        struct stat locbuf;
00437 
00438        old_fs = get_fs();
00439        set_fs(get_ds());
00440        ret =  (*sfunc)(filename, &locbuf);
00441        set_fs(old_fs);
00442 
00443        if(ret == 0)
00444               ret = (copy_to_user(statbuf, &locbuf, sizeof(locbuf)) ? 
00445                      -EFAULT : 0);
00446 
00447        return ret;
00448 }
00449 
00450 asmlinkage int virt_stat(const char *filename, struct stat *statbuf)
00451 {
00452        int ret;
00453        char *newfilename;
00454 
00455        if(!cwd_virtual()) {
00456               ret = (*orig_stat)(filename, statbuf);
00457               if(ret != -ENOENT) 
00458                      return ret;
00459        }
00460        else 
00461               ret = 0;
00462 
00463        newfilename = resolve_name(filename, 1, 1);
00464        if(!newfilename) {
00465               if(ret)
00466                      return ret;
00467               else
00468                      return (*orig_stat)(filename, statbuf);
00469        }
00470        if(IS_ERR(newfilename))
00471               return PTR_ERR(newfilename);
00472 
00473        DEB((KERN_INFO "STAT: trying '%s'\n", newfilename));
00474 
00475        ret = do_orig_stat(orig_stat, newfilename, statbuf);
00476        kfree(newfilename);
00477 
00478        DEB((KERN_INFO "STAT: result %i\n", ret));
00479 
00480        return ret;
00481 }
00482 
00483 asmlinkage int virt_lstat(const char *filename, struct stat *statbuf)
00484 {
00485        int ret;
00486        char *newfilename;
00487 
00488        if(!cwd_virtual()) {
00489               ret = (*orig_lstat)(filename, statbuf);
00490               if(ret != -ENOENT) 
00491                      return ret;
00492        }
00493        else 
00494               ret = 0;
00495 
00496        newfilename = resolve_name(filename, 1, 0);
00497        if(!newfilename) {
00498               if(ret)
00499                      return ret;
00500               else
00501                      return (*orig_lstat)(filename, statbuf);
00502        }
00503        if(IS_ERR(newfilename))
00504               return PTR_ERR(newfilename);
00505 
00506        DEB((KERN_INFO "LSTAT: trying '%s'\n", newfilename));
00507 
00508        ret = do_orig_stat(orig_lstat, newfilename, statbuf);
00509        kfree(newfilename);
00510 
00511        DEB((KERN_INFO "LSTAT: result %i\n", ret));
00512 
00513        return ret;
00514 }
00515 
00516 
00517 asmlinkage int virt_access(const char *filename, int mode)
00518 {
00519        int ret;
00520        mm_segment_t old_fs;
00521        char *newfilename;
00522        
00523        if(!cwd_virtual()) {
00524               ret = (*orig_access)(filename, mode);
00525               if(ret != -ENOENT) 
00526                      return ret;
00527        }
00528        else 
00529               ret = 0;
00530 
00531        newfilename = resolve_name(filename, 1, 1);
00532        if(!newfilename) {
00533               if(ret)
00534                      return ret;
00535               else
00536                      return (*orig_access)(filename, mode);
00537        }
00538        if(IS_ERR(newfilename))
00539               return PTR_ERR(newfilename);
00540 
00541        DEB((KERN_INFO "ACCESS: trying '%s'\n", newfilename));
00542               
00543        old_fs = get_fs();
00544        set_fs(get_ds());
00545        ret = (*orig_access)(newfilename, mode);
00546        set_fs(old_fs);
00547        kfree(newfilename);
00548 
00549        DEB((KERN_INFO "ACCESS: result %i\n", ret));
00550        
00551        return ret;
00552 }
00553 
00554 asmlinkage int virt_open(const char *filename, int flags, int mode)
00555 {
00556        int ret;
00557        mm_segment_t old_fs;
00558        char *newfilename;
00559        
00560        if(!cwd_virtual()) {
00561               ret = (*orig_open)(filename, flags, mode);
00562               if(ret != -ENOENT) 
00563                      return ret;
00564        }
00565        else 
00566               ret = 0;
00567 
00568        newfilename = resolve_name(filename, 1, 1);
00569        if(!newfilename) {
00570               if(ret)
00571                      return ret;
00572               else
00573                      return (*orig_open)(filename, flags, mode);
00574        }
00575        if(IS_ERR(newfilename))
00576               return PTR_ERR(newfilename);
00577 
00578        DEB((KERN_INFO "OPEN: trying '%s'\n", newfilename));
00579               
00580        old_fs = get_fs();
00581        set_fs(get_ds());
00582        ret = (*orig_open)(newfilename, flags, mode);
00583        set_fs(old_fs);
00584        kfree(newfilename);
00585 
00586        DEB((KERN_INFO "OPEN: result %i\n", ret));
00587        
00588        return ret;
00589 }
00590 
00591 asmlinkage int virt_readlink(const char *filename, char *buf, int bufsiz)
00592 {
00593        int ret;
00594        mm_segment_t old_fs;
00595        char *newfilename;
00596        char *locbuf;
00597        int len;
00598        
00599        if(!cwd_virtual()) {
00600               ret = (*orig_readlink)(filename, buf, bufsiz);
00601               if(ret != -ENOENT) 
00602                      return ret;
00603        }
00604        else 
00605               ret = 0;
00606 
00607        newfilename = resolve_name(filename, 1, 0);
00608        if(!newfilename) {
00609               if(ret)
00610                      return ret;
00611               else
00612                      return (*orig_readlink)(filename, buf, bufsiz);
00613        }
00614        if(IS_ERR(newfilename))
00615               return PTR_ERR(newfilename);
00616 
00617        DEB((KERN_INFO "READLINK: trying '%s'\n", newfilename));
00618 
00619        /* bufsiz is legal (already checked by sys_readlink) */
00620        len = bufsiz;
00621        if(bufsiz > PAGE_SIZE)
00622               len = PAGE_SIZE;
00623                      
00624        locbuf = (char *) __get_free_page(GFP_USER);
00625                      
00626        ret = -ENOMEM;
00627        if(locbuf) {
00628               old_fs = get_fs();
00629               set_fs(get_ds());
00630               ret =  (*orig_readlink)(newfilename, locbuf, len);
00631               set_fs(old_fs);
00632 
00633               if(ret >= 0)
00634                      if(copy_to_user(buf, locbuf, len))
00635                             ret = -EFAULT;
00636               free_page((unsigned long) locbuf);
00637        }
00638        kfree(newfilename);
00639 
00640        DEB((KERN_INFO "READLINK: result %i\n", ret));
00641        
00642        return ret;
00643 }
00644 
00645 asmlinkage int virt_getcwd(char *buf, unsigned long size)
00646 {
00647        int ret;
00648        char *cwd;
00649        unsigned long cwdlen;
00650        char *page;
00651        char *newcwd;
00652        unsigned long newlen;
00653        
00654        ret = (*orig_getcwd)(buf, size);
00655 
00656        if(!cwd_virtual() || ret < 0)
00657               return ret;
00658               
00659        if(!path_ok(current->fs->pwd))
00660               return -ENOENT;
00661        
00662        page = (char *) __get_free_page(GFP_USER);
00663        if(!page)
00664               return -ENOMEM;
00665        
00666        cwd = path_pwd(page);
00667        cwdlen = PAGE_SIZE + (page - cwd) - 1;
00668        
00669        if(cwdlen >= OVERLAY_DIR_LEN && 
00670           strncmp(cwd, OVERLAY_DIR, OVERLAY_DIR_LEN) == 0) {
00671               if(cwdlen == OVERLAY_DIR_LEN) {
00672                      newcwd = "/";
00673                      newlen = 1;
00674               }
00675               else {
00676                      newcwd = cwd + OVERLAY_DIR_LEN;
00677                      newlen = cwdlen - OVERLAY_DIR_LEN;
00678               }
00679 
00680               ret = -ERANGE;
00681               if(newlen + 1 <= size) {
00682                      ret = newlen + 1;
00683                      if(copy_to_user(buf, newcwd, newlen + 1))
00684                             ret = -EFAULT;
00685               }
00686        }
00687        free_page((unsigned long) page);
00688 
00689        return ret;
00690 }
00691 
00692 
00693 #if NEWVFS
00694 static long do_orig_stat64(stat64_func sfunc, const char *filename,
00695                            struct stat64 * statbuf, long flags)
00696 {
00697        long ret;
00698        mm_segment_t old_fs;
00699        struct stat64 locbuf;
00700 
00701        old_fs = get_fs();
00702        set_fs(get_ds());
00703        ret =  (*sfunc)(filename, &locbuf, flags);
00704        set_fs(old_fs);
00705 
00706        if(ret == 0)
00707               ret = (copy_to_user(statbuf, &locbuf, sizeof(locbuf)) ? 
00708                      -EFAULT : 0);
00709 
00710        return ret;
00711 }
00712 
00713 asmlinkage long virt_stat64(char * filename, struct stat64 * statbuf, long flags)
00714 {
00715        long ret;
00716        char *newfilename;
00717 
00718        if(!cwd_virtual()) {
00719               ret = (*orig_stat64)(filename, statbuf, flags);
00720               if(ret != -ENOENT) 
00721                      return ret;
00722        }
00723        else 
00724               ret = 0;
00725 
00726        newfilename = resolve_name(filename, 1, 1);
00727        if(!newfilename) {
00728               if(ret)
00729                      return ret;
00730               else
00731                      return (*orig_stat64)(filename, statbuf, flags);
00732        }
00733        if(IS_ERR(newfilename))
00734               return PTR_ERR(newfilename);
00735 
00736        DEB((KERN_INFO "STAT64: trying '%s'\n", newfilename));
00737 
00738        ret = do_orig_stat64(orig_stat64, newfilename, statbuf, flags);
00739        kfree(newfilename);
00740 
00741        DEB((KERN_INFO "STAT64: result %li\n", ret));
00742 
00743        return ret;
00744 }
00745 
00746 asmlinkage long virt_lstat64(char * filename, struct stat64 * statbuf, long flags)
00747 {
00748        long ret;
00749        char *newfilename;
00750 
00751        if(!cwd_virtual()) {
00752               ret = (*orig_lstat64)(filename, statbuf, flags);
00753               if(ret != -ENOENT) 
00754                      return ret;
00755        }
00756        else 
00757               ret = 0;
00758 
00759        newfilename = resolve_name(filename, 1, 0);
00760        if(!newfilename) {
00761               if(ret)
00762                      return ret;
00763               else
00764                      return (*orig_lstat64)(filename, statbuf, flags);
00765        }
00766        if(IS_ERR(newfilename))
00767               return PTR_ERR(newfilename);
00768 
00769        DEB((KERN_INFO "LSTAT64: trying '%s'\n", newfilename));
00770 
00771        ret = do_orig_stat64(orig_lstat64, newfilename, statbuf, flags);
00772        kfree(newfilename);
00773 
00774        DEB((KERN_INFO "LSTAT64: result %li\n", ret));
00775 
00776        return ret;
00777 }
00778 
00779 #endif /* NEWVFS */
00780 
00781 #ifdef __i386__
00782 
00783 asmlinkage int real_execve(struct pt_regs *regs)
00784 {
00785        int error;
00786        char * filename;
00787 
00788 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
00789        lock_kernel();
00790 #endif
00791        filename = getname((char *) regs->ebx);
00792        error = PTR_ERR(filename);
00793        if (IS_ERR(filename))
00794               goto out;
00795        error = do_execve(filename, (char **) regs->ecx, (char **) regs->edx, regs);
00796        if (error == 0) {
00797 #ifdef PT_DTRACE
00798               current->ptrace &= ~PT_DTRACE;
00799 #else
00800               current->flags &= ~PF_DTRACE;
00801 #endif
00802        }
00803        putname(filename);
00804 
00805  out:
00806 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
00807         unlock_kernel();
00808 #endif
00809        return error;
00810 }
00811 
00812 asmlinkage int virt_execve(struct pt_regs regs)
00813 {
00814        int ret;
00815        char *newfilename;
00816        char *filename = (char *) regs.ebx;
00817 
00818        if(!cwd_virtual()) {
00819               ret = real_execve(&regs);
00820               if(ret != -ENOENT) 
00821                      return ret;
00822        }
00823        else 
00824               ret = 0;
00825 
00826        newfilename = resolve_name(filename, 1, 1);
00827        if(!newfilename) {
00828               if(ret)
00829                      return ret;
00830               else
00831                      return real_execve(&regs);
00832        }
00833        if(IS_ERR(newfilename))
00834                 return PTR_ERR(newfilename);
00835 
00836        DEB((KERN_INFO "EXECVE: trying '%s'\n", newfilename));
00837 
00838        ret = do_execve(newfilename, (char **) regs.ecx, (char **) regs.edx,
00839                      &regs);
00840        if (ret == 0) {
00841 #ifdef PT_DTRACE
00842                 current->ptrace &= ~PT_DTRACE;
00843 #else
00844                 current->flags &= ~PF_DTRACE;
00845 #endif
00846        }
00847        kfree(newfilename);
00848 
00849        DEB((KERN_INFO "EXECVE: result %i\n", ret));
00850 
00851        return ret;
00852 }
00853 #endif /* __i386__ */
00854 
00855 void *replace_syscall(int index, void *new_syscall)
00856 {
00857        void *orig_syscall = sys_call_table[index];
00858 
00859        printk(KERN_INFO "replacing syscall nr. %3i [%p] with [%p]\n", 
00860               index, orig_syscall, new_syscall);
00861        sys_call_table[index] = new_syscall;
00862        
00863        return orig_syscall;
00864 }
00865 
00866 int init_module(void)
00867 {
00868        printk(KERN_INFO "redir init (version %s)\n", REDIR_VERSION);
00869 
00870        orig_chdir    = replace_syscall(__NR_chdir,    virt_chdir);
00871        orig_stat     = replace_syscall(__NR_stat,     virt_stat);
00872        orig_lstat    = replace_syscall(__NR_lstat,    virt_lstat);
00873        orig_access   = replace_syscall(__NR_access,   virt_access);
00874        orig_open     = replace_syscall(__NR_open,     virt_open);
00875        orig_readlink = replace_syscall(__NR_readlink, virt_readlink);
00876        orig_getcwd   = replace_syscall(__NR_getcwd,   virt_getcwd);
00877 
00878 #if NEWVFS
00879        orig_stat64   = replace_syscall(__NR_stat64,   virt_stat64);
00880        orig_lstat64  = replace_syscall(__NR_lstat64,  virt_lstat64);
00881 #endif
00882 
00883 #ifdef __i386__
00884        orig_execve   = replace_syscall(__NR_execve,   virt_execve);
00885 #endif
00886 
00887        return 0;
00888 }
00889 
00890 
00891 void cleanup_module(void)
00892 {
00893        printk(KERN_INFO "redir cleanup\n");
00894    
00895        replace_syscall(__NR_chdir,    orig_chdir);
00896        replace_syscall(__NR_stat,     orig_stat);
00897        replace_syscall(__NR_lstat,    orig_lstat);
00898        replace_syscall(__NR_access,   orig_access);
00899        replace_syscall(__NR_open,     orig_open);
00900        replace_syscall(__NR_readlink, orig_readlink);
00901        replace_syscall(__NR_getcwd,   orig_getcwd);
00902 
00903 #if NEWVFS
00904        replace_syscall(__NR_stat64,   orig_stat64);
00905        replace_syscall(__NR_lstat64,  orig_lstat64);
00906 #endif
00907 
00908 #ifdef __i386__
00909        replace_syscall(__NR_execve,   orig_execve);
00910 #endif
00911 
00912 }
00913 
00914 
00915 /* 
00916  * Local Variables:
00917  * indent-tabs-mode: t
00918  * c-basic-offset: 8
00919  * End:
00920  */