The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/binfmt_misc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  binfmt_misc.c
    3  *
    4  *  Copyright (C) 1997 Richard GŁnther
    5  *
    6  *  binfmt_misc detects binaries via a magic or filename extension and invokes
    7  *  a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
    8  *  binfmt_mz.
    9  *
   10  *  1997-04-25 first version
   11  *  [...]
   12  *  1997-05-19 cleanup
   13  *  1997-06-26 hpa: pass the real filename rather than argv[0]
   14  *  1997-06-30 minor cleanup
   15  *  1997-08-09 removed extension stripping, locking cleanup
   16  *  2001-02-28 AV: rewritten into something that resembles C. Original didn't.
   17  */
   18 
   19 #include <linux/module.h>
   20 #include <linux/init.h>
   21 
   22 #include <linux/binfmts.h>
   23 #include <linux/slab.h>
   24 #include <linux/ctype.h>
   25 #include <linux/file.h>
   26 #include <linux/pagemap.h>
   27 
   28 #include <asm/uaccess.h>
   29 
   30 enum {
   31         VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
   32 };
   33 
   34 static LIST_HEAD(entries);
   35 static int enabled = 1;
   36 
   37 enum {Enabled, Magic};
   38 
   39 typedef struct {
   40         struct list_head list;
   41         unsigned long flags;            /* type, status, etc. */
   42         int offset;                     /* offset of magic */
   43         int size;                       /* size of magic/mask */
   44         char *magic;                    /* magic or filename extension */
   45         char *mask;                     /* mask, NULL for exact match */
   46         char *interpreter;              /* filename of interpreter */
   47         char *name;
   48         struct dentry *dentry;
   49 } Node;
   50 
   51 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
   52 
   53 /* 
   54  * Check if we support the binfmt
   55  * if we do, return the node, else NULL
   56  * locking is done in load_misc_binary
   57  */
   58 static Node *check_file(struct linux_binprm *bprm)
   59 {
   60         char *p = strrchr(bprm->filename, '.');
   61         struct list_head *l;
   62 
   63         for (l = entries.next; l != &entries; l = l->next) {
   64                 Node *e = list_entry(l, Node, list);
   65                 char *s;
   66                 int j;
   67 
   68                 if (!test_bit(Enabled, &e->flags))
   69                         continue;
   70 
   71                 if (!test_bit(Magic, &e->flags)) {
   72                         if (p && !strcmp(e->magic, p + 1))
   73                                 return e;
   74                         continue;
   75                 }
   76 
   77                 s = bprm->buf + e->offset;
   78                 if (e->mask) {
   79                         for (j = 0; j < e->size; j++)
   80                                 if ((*s++ ^ e->magic[j]) & e->mask[j])
   81                                         break;
   82                 } else {
   83                         for (j = 0; j < e->size; j++)
   84                                 if ((*s++ ^ e->magic[j]))
   85                                         break;
   86                 }
   87                 if (j == e->size)
   88                         return e;
   89         }
   90         return NULL;
   91 }
   92 
   93 /*
   94  * the loader itself
   95  */
   96 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
   97 {
   98         Node *fmt;
   99         struct file * file;
  100         char iname[BINPRM_BUF_SIZE];
  101         char *iname_addr = iname;
  102         int retval;
  103 
  104         retval = -ENOEXEC;
  105         if (!enabled)
  106                 goto _ret;
  107 
  108         /* to keep locking time low, we copy the interpreter string */
  109         read_lock(&entries_lock);
  110         fmt = check_file(bprm);
  111         if (fmt) {
  112                 strncpy(iname, fmt->interpreter, BINPRM_BUF_SIZE - 1);
  113                 iname[BINPRM_BUF_SIZE - 1] = '\0';
  114         }
  115         read_unlock(&entries_lock);
  116         if (!fmt)
  117                 goto _ret;
  118 
  119         allow_write_access(bprm->file);
  120         fput(bprm->file);
  121         bprm->file = NULL;
  122 
  123         /* Build args for interpreter */
  124         remove_arg_zero(bprm);
  125         retval = copy_strings_kernel(1, &bprm->filename, bprm);
  126         if (retval < 0) goto _ret; 
  127         bprm->argc++;
  128         retval = copy_strings_kernel(1, &iname_addr, bprm);
  129         if (retval < 0) goto _ret; 
  130         bprm->argc++;
  131         bprm->filename = iname; /* for binfmt_script */
  132 
  133         file = open_exec(iname);
  134         retval = PTR_ERR(file);
  135         if (IS_ERR(file))
  136                 goto _ret;
  137         bprm->file = file;
  138 
  139         retval = prepare_binprm(bprm);
  140         if (retval >= 0)
  141                 retval = search_binary_handler(bprm, regs);
  142 _ret:
  143         return retval;
  144 }
  145 
  146 /* Command parsers */
  147 
  148 /*
  149  * parses and copies one argument enclosed in del from *sp to *dp,
  150  * recognising the \x special.
  151  * returns pointer to the copied argument or NULL in case of an
  152  * error (and sets err) or null argument length.
  153  */
  154 static char *scanarg(char *s, char del)
  155 {
  156         char c;
  157 
  158         while ((c = *s++) != del) {
  159                 if (c == '\\' && *s == 'x') {
  160                         s++;
  161                         if (!isxdigit(*s++))
  162                                 return NULL;
  163                         if (!isxdigit(*s++))
  164                                 return NULL;
  165                 }
  166         }
  167         return s;
  168 }
  169 
  170 static int unquote(char *from)
  171 {
  172         char c = 0, *s = from, *p = from;
  173 
  174         while ((c = *s++) != '\0') {
  175                 if (c == '\\' && *s == 'x') {
  176                         s++;
  177                         c = toupper(*s++);
  178                         *p = (c - (isdigit(c) ? '' : 'A' - 10)) << 4;
  179                         c = toupper(*s++);
  180                         *p++ |= c - (isdigit(c) ? '' : 'A' - 10);
  181                         continue;
  182                 }
  183                 *p++ = c;
  184         }
  185         return p - from;
  186 }
  187 
  188 /*
  189  * This registers a new binary format, it recognises the syntax
  190  * ':name:type:offset:magic:mask:interpreter:'
  191  * where the ':' is the IFS, that can be chosen with the first char
  192  */
  193 static Node *create_entry(const char *buffer, size_t count)
  194 {
  195         Node *e;
  196         int memsize, err;
  197         char *buf, *p;
  198         char del;
  199 
  200         /* some sanity checks */
  201         err = -EINVAL;
  202         if ((count < 11) || (count > 256))
  203                 goto out;
  204 
  205         err = -ENOMEM;
  206         memsize = sizeof(Node) + count + 8;
  207         e = (Node *) kmalloc(memsize, GFP_USER);
  208         if (!e)
  209                 goto out;
  210 
  211         p = buf = (char *)e + sizeof(Node);
  212 
  213         memset(e, 0, sizeof(Node));
  214         if (copy_from_user(buf, buffer, count))
  215                 goto Efault;
  216 
  217         del = *p++;     /* delimeter */
  218 
  219         memset(buf+count, del, 8);
  220 
  221         e->name = p;
  222         p = strchr(p, del);
  223         if (!p)
  224                 goto Einval;
  225         *p++ = '\0';
  226         if (!e->name[0] ||
  227             !strcmp(e->name, ".") ||
  228             !strcmp(e->name, "..") ||
  229             strchr(e->name, '/'))
  230                 goto Einval;
  231         switch (*p++) {
  232                 case 'E': e->flags = 1<<Enabled; break;
  233                 case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
  234                 default: goto Einval;
  235         }
  236         if (*p++ != del)
  237                 goto Einval;
  238         if (test_bit(Magic, &e->flags)) {
  239                 char *s = strchr(p, del);
  240                 if (!s)
  241                         goto Einval;
  242                 *s++ = '\0';
  243                 e->offset = simple_strtoul(p, &p, 10);
  244                 if (*p++)
  245                         goto Einval;
  246                 e->magic = p;
  247                 p = scanarg(p, del);
  248                 if (!p)
  249                         goto Einval;
  250                 p[-1] = '\0';
  251                 if (!e->magic[0])
  252                         goto Einval;
  253                 e->mask = p;
  254                 p = scanarg(p, del);
  255                 if (!p)
  256                         goto Einval;
  257                 p[-1] = '\0';
  258                 if (!e->mask[0])
  259                         e->mask = NULL;
  260                 e->size = unquote(e->magic);
  261                 if (e->mask && unquote(e->mask) != e->size)
  262                         goto Einval;
  263                 if (e->size + e->offset > BINPRM_BUF_SIZE)
  264                         goto Einval;
  265         } else {
  266                 p = strchr(p, del);
  267                 if (!p)
  268                         goto Einval;
  269                 *p++ = '\0';
  270                 e->magic = p;
  271                 p = strchr(p, del);
  272                 if (!p)
  273                         goto Einval;
  274                 *p++ = '\0';
  275                 if (!e->magic[0] || strchr(e->magic, '/'))
  276                         goto Einval;
  277                 p = strchr(p, del);
  278                 if (!p)
  279                         goto Einval;
  280                 *p++ = '\0';
  281         }
  282         e->interpreter = p;
  283         p = strchr(p, del);
  284         if (!p)
  285                 goto Einval;
  286         *p++ = '\0';
  287         if (!e->interpreter[0])
  288                 goto Einval;
  289 
  290         if (*p == '\n')
  291                 p++;
  292         if (p != buf + count)
  293                 goto Einval;
  294         return e;
  295 
  296 out:
  297         return ERR_PTR(err);
  298 
  299 Efault:
  300         kfree(e);
  301         return ERR_PTR(-EFAULT);
  302 Einval:
  303         kfree(e);
  304         return ERR_PTR(-EINVAL);
  305 }
  306 
  307 /*
  308  * Set status of entry/binfmt_misc:
  309  * '1' enables, '' disables and '-1' clears entry/binfmt_misc
  310  */
  311 static int parse_command(const char *buffer, size_t count)
  312 {
  313         char s[4];
  314 
  315         if (!count)
  316                 return 0;
  317         if (count > 3)
  318                 return -EINVAL;
  319         if (copy_from_user(s, buffer, count))
  320                 return -EFAULT;
  321         if (s[count-1] == '\n')
  322                 count--;
  323         if (count == 1 && s[0] == '')
  324                 return 1;
  325         if (count == 1 && s[0] == '1')
  326                 return 2;
  327         if (count == 2 && s[0] == '-' && s[1] == '1')
  328                 return 3;
  329         return -EINVAL;
  330 }
  331 
  332 /* generic stuff */
  333 
  334 static void entry_status(Node *e, char *page)
  335 {
  336         char *dp;
  337         char *status = "disabled";
  338 
  339         if (test_bit(Enabled, &e->flags))
  340                 status = "enabled";
  341 
  342         if (!VERBOSE_STATUS) {
  343                 sprintf(page, "%s\n", status);
  344                 return;
  345         }
  346 
  347         sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
  348         dp = page + strlen(page);
  349         if (!test_bit(Magic, &e->flags)) {
  350                 sprintf(dp, "extension .%s\n", e->magic);
  351         } else {
  352                 int i;
  353 
  354                 sprintf(dp, "offset %i\nmagic ", e->offset);
  355                 dp = page + strlen(page);
  356                 for (i = 0; i < e->size; i++) {
  357                         sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
  358                         dp += 2;
  359                 }
  360                 if (e->mask) {
  361                         sprintf(dp, "\nmask ");
  362                         dp += 6;
  363                         for (i = 0; i < e->size; i++) {
  364                                 sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
  365                                 dp += 2;
  366                         }
  367                 }
  368                 *dp++ = '\n';
  369                 *dp = '\0';
  370         }
  371 }
  372 
  373 static struct inode *bm_get_inode(struct super_block *sb, int mode)
  374 {
  375         struct inode * inode = new_inode(sb);
  376 
  377         if (inode) {
  378                 inode->i_mode = mode;
  379                 inode->i_uid = 0;
  380                 inode->i_gid = 0;
  381                 inode->i_blksize = PAGE_CACHE_SIZE;
  382                 inode->i_blocks = 0;
  383                 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  384         }
  385         return inode;
  386 }
  387 
  388 static void bm_clear_inode(struct inode *inode)
  389 {
  390         Node *e = inode->u.generic_ip;
  391 
  392         if (e) {
  393                 write_lock(&entries_lock);
  394                 list_del(&e->list);
  395                 write_unlock(&entries_lock);
  396                 kfree(e);
  397         }
  398 }
  399 
  400 static void kill_node(Node *e)
  401 {
  402         struct dentry *dentry;
  403 
  404         write_lock(&entries_lock);
  405         dentry = e->dentry;
  406         if (dentry) {
  407                 list_del(&e->list);
  408                 INIT_LIST_HEAD(&e->list);
  409                 e->dentry = NULL;
  410         }
  411         write_unlock(&entries_lock);
  412 
  413         if (dentry) {
  414                 dentry->d_inode->i_nlink--;
  415                 d_drop(dentry);
  416                 dput(dentry);
  417         }
  418 }
  419 
  420 /* /<entry> */
  421 
  422 static ssize_t
  423 bm_entry_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
  424 {
  425         Node *e = file->f_dentry->d_inode->u.generic_ip;
  426         loff_t pos = *ppos;
  427         ssize_t res;
  428         char *page;
  429         int len;
  430 
  431         if (!(page = (char*) __get_free_page(GFP_KERNEL)))
  432                 return -ENOMEM;
  433 
  434         entry_status(e, page);
  435         len = strlen(page);
  436 
  437         res = -EINVAL;
  438         if (pos < 0)
  439                 goto out;
  440         res = 0;
  441         if (pos >= len)
  442                 goto out;
  443         if (len < pos + nbytes)
  444                 nbytes = len - pos;
  445         res = -EFAULT;
  446         if (copy_to_user(buf, page + pos, nbytes))
  447                 goto out;
  448         *ppos = pos + nbytes;
  449         res = nbytes;
  450 out:
  451         free_page((unsigned long) page);
  452         return res;
  453 }
  454 
  455 static ssize_t bm_entry_write(struct file *file, const char *buffer,
  456                                 size_t count, loff_t *ppos)
  457 {
  458         struct dentry *root;
  459         Node *e = file->f_dentry->d_inode->u.generic_ip;
  460         int res = parse_command(buffer, count);
  461 
  462         switch (res) {
  463                 case 1: clear_bit(Enabled, &e->flags);
  464                         break;
  465                 case 2: set_bit(Enabled, &e->flags);
  466                         break;
  467                 case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
  468                         down(&root->d_inode->i_sem);
  469                         down(&root->d_inode->i_zombie);
  470 
  471                         kill_node(e);
  472 
  473                         up(&root->d_inode->i_zombie);
  474                         up(&root->d_inode->i_sem);
  475                         dput(root);
  476                         break;
  477                 default: return res;
  478         }
  479         return count;
  480 }
  481 
  482 static struct file_operations bm_entry_operations = {
  483         read:           bm_entry_read,
  484         write:          bm_entry_write,
  485 };
  486 
  487 /* /register */
  488 
  489 static ssize_t bm_register_write(struct file *file, const char *buffer,
  490                                size_t count, loff_t *ppos)
  491 {
  492         Node *e;
  493         struct dentry *root, *dentry;
  494         struct super_block *sb = file->f_vfsmnt->mnt_sb;
  495         int err = 0;
  496 
  497         e = create_entry(buffer, count);
  498 
  499         if (IS_ERR(e))
  500                 return PTR_ERR(e);
  501 
  502         root = dget(sb->s_root);
  503         down(&root->d_inode->i_sem);
  504         dentry = lookup_one_len(e->name, root, strlen(e->name));
  505         err = PTR_ERR(dentry);
  506         if (!IS_ERR(dentry)) {
  507                 down(&root->d_inode->i_zombie);
  508                 if (dentry->d_inode) {
  509                         err = -EEXIST;
  510                 } else {
  511                         struct inode * inode = bm_get_inode(sb, S_IFREG | 0644);
  512                         err = -ENOMEM;
  513 
  514                         if (inode) {
  515                                 write_lock(&entries_lock);
  516 
  517                                 e->dentry = dget(dentry);
  518                                 inode->u.generic_ip = e;
  519                                 inode->i_fop = &bm_entry_operations;
  520                                 d_instantiate(dentry, inode);
  521 
  522                                 list_add(&e->list, &entries);
  523                                 write_unlock(&entries_lock);
  524 
  525                                 err = 0;
  526                         }
  527                 }
  528                 up(&root->d_inode->i_zombie);
  529                 dput(dentry);
  530         }
  531         up(&root->d_inode->i_sem);
  532         dput(root);
  533 
  534         if (err) {
  535                 kfree(e);
  536                 return -EINVAL;
  537         }
  538         return count;
  539 }
  540 
  541 static struct file_operations bm_register_operations = {
  542         write:          bm_register_write,
  543 };
  544 
  545 /* /status */
  546 
  547 static ssize_t
  548 bm_status_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
  549 {
  550         char *s = enabled ? "enabled" : "disabled";
  551         int len = strlen(s);
  552         loff_t pos = *ppos;
  553 
  554         if (pos < 0)
  555                 return -EINVAL;
  556         if (pos >= len)
  557                 return 0;
  558         if (len < pos + nbytes)
  559                 nbytes = len - pos;
  560         if (copy_to_user(buf, s + pos, nbytes))
  561                 return -EFAULT;
  562         *ppos = pos + nbytes;
  563         return nbytes;
  564 }
  565 
  566 static ssize_t bm_status_write(struct file * file, const char * buffer,
  567                 size_t count, loff_t *ppos)
  568 {
  569         int res = parse_command(buffer, count);
  570         struct dentry *root;
  571 
  572         switch (res) {
  573                 case 1: enabled = 0; break;
  574                 case 2: enabled = 1; break;
  575                 case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
  576                         down(&root->d_inode->i_sem);
  577                         down(&root->d_inode->i_zombie);
  578 
  579                         while (!list_empty(&entries))
  580                                 kill_node(list_entry(entries.next, Node, list));
  581 
  582                         up(&root->d_inode->i_zombie);
  583                         up(&root->d_inode->i_sem);
  584                         dput(root);
  585                 default: return res;
  586         }
  587         return count;
  588 }
  589 
  590 static struct file_operations bm_status_operations = {
  591         read:           bm_status_read,
  592         write:          bm_status_write,
  593 };
  594 
  595 /* / */
  596 
  597 static struct dentry * bm_lookup(struct inode *dir, struct dentry *dentry)
  598 {
  599         d_add(dentry, NULL);
  600         return NULL;
  601 }
  602 
  603 static struct inode_operations bm_dir_inode_operations = {
  604         lookup:         bm_lookup,
  605 };
  606 
  607 /* Superblock handling */
  608 
  609 static int bm_statfs(struct super_block *sb, struct statfs *buf)
  610 {
  611         buf->f_type = sb->s_magic;
  612         buf->f_bsize = PAGE_CACHE_SIZE;
  613         buf->f_namelen = 255;
  614         return 0;
  615 }
  616 
  617 static struct super_operations s_ops = {
  618         statfs:         bm_statfs,
  619         put_inode:      force_delete,
  620         clear_inode:    bm_clear_inode,
  621 };
  622 
  623 static struct super_block *bm_read_super(struct super_block * sb, void * data, int silent)
  624 {
  625         struct qstr names[2] = {{name:"status"}, {name:"register"}};
  626         struct inode * inode;
  627         struct dentry * dentry[3];
  628         int i;
  629 
  630         for (i=0; i<sizeof(names)/sizeof(names[0]); i++) {
  631                 names[i].len = strlen(names[i].name);
  632                 names[i].hash = full_name_hash(names[i].name, names[i].len);
  633         }
  634 
  635         sb->s_blocksize = PAGE_CACHE_SIZE;
  636         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
  637         sb->s_magic = 0x42494e4d;
  638         sb->s_op = &s_ops;
  639 
  640         inode = bm_get_inode(sb, S_IFDIR | 0755);
  641         if (!inode)
  642                 return NULL;
  643         inode->i_op = &bm_dir_inode_operations;
  644         inode->i_fop = &dcache_dir_ops;
  645         dentry[0] = d_alloc_root(inode);
  646         if (!dentry[0]) {
  647                 iput(inode);
  648                 return NULL;
  649         }
  650         dentry[1] = d_alloc(dentry[0], &names[0]);
  651         if (!dentry[1])
  652                 goto out1;
  653         dentry[2] = d_alloc(dentry[0], &names[1]);
  654         if (!dentry[2])
  655                 goto out2;
  656         inode = bm_get_inode(sb, S_IFREG | 0644);
  657         if (!inode)
  658                 goto out3;
  659         inode->i_fop = &bm_status_operations;
  660         d_add(dentry[1], inode);
  661         inode = bm_get_inode(sb, S_IFREG | 0400);
  662         if (!inode)
  663                 goto out3;
  664         inode->i_fop = &bm_register_operations;
  665         d_add(dentry[2], inode);
  666 
  667         sb->s_root = dentry[0];
  668         return sb;
  669 
  670 out3:
  671         dput(dentry[2]);
  672 out2:
  673         dput(dentry[1]);
  674 out1:
  675         dput(dentry[0]);
  676         return NULL;
  677 }
  678 
  679 static struct linux_binfmt misc_format = {
  680         NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0
  681 };
  682 
  683 static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER);
  684 
  685 static struct vfsmount *bm_mnt;
  686 
  687 static int __init init_misc_binfmt(void)
  688 {
  689         int err = register_filesystem(&bm_fs_type);
  690         if (!err) {
  691                 bm_mnt = kern_mount(&bm_fs_type);
  692                 err = PTR_ERR(bm_mnt);
  693                 if (IS_ERR(bm_mnt))
  694                         unregister_filesystem(&bm_fs_type);
  695                 else {
  696                         err = register_binfmt(&misc_format);
  697                         if (err) {
  698                                 unregister_filesystem(&bm_fs_type);
  699                                 kern_umount(bm_mnt);
  700                         }
  701                 }
  702         }
  703         return err;
  704 }
  705 
  706 static void __exit exit_misc_binfmt(void)
  707 {
  708         unregister_binfmt(&misc_format);
  709         unregister_filesystem(&bm_fs_type);
  710         kern_umount(bm_mnt);
  711 }
  712 
  713 EXPORT_NO_SYMBOLS;
  714 
  715 module_init(init_misc_binfmt);
  716 module_exit(exit_misc_binfmt);
  717 MODULE_LICENSE("GPL");

Cache object: 1ac2a5aaec73fd228d6d42b1b9493a3c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.