[BACK]Return to kern_exec.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/kern_exec.c between version 1.103.2.3 and 1.103.2.4

version 1.103.2.3, 2000/12/08 09:13:53 version 1.103.2.4, 2000/12/13 15:50:20
Line 62 
Line 62 
 #include <machine/cpu.h>  #include <machine/cpu.h>
 #include <machine/reg.h>  #include <machine/reg.h>
   
   /*
    * Exec function switch:
    *
    * Note that each makecmds function is responsible for loading the
    * exec package with the necessary functions for any exec-type-specific
    * handling.
    *
    * Functions for specific exec types should be defined in their own
    * header file.
    */
   extern const struct execsw execsw_builtin[];
   extern int nexecs_builtin;
   static const struct execsw **execsw = NULL;
   static int nexecs;
   int exec_maxhdrsz;              /* must not be static - netbsd32 needs it */
   
   #ifdef LKM
   /* list of supported emulations */
   static
   LIST_HEAD(emlist_head, emul_entry) el_head = LIST_HEAD_INITIALIZER(el_head);
   struct emul_entry {
           LIST_ENTRY(emul_entry) el_list;
           const struct emul *el_emul;
           int ro_entry;
   };
   
   /* list of dynamically loaded execsw entries */
   static
   LIST_HEAD(execlist_head, exec_entry) ex_head = LIST_HEAD_INITIALIZER(ex_head);
   struct exec_entry {
           LIST_ENTRY(exec_entry) ex_list;
           const struct execsw *es;
   };
   
   /* structure used for building execw[] */
   struct execsw_entry {
           struct execsw_entry *next;
           const struct execsw *es;
   };
   #endif /* LKM */
   
   /* NetBSD emul struct */
 extern char sigcode[], esigcode[];  extern char sigcode[], esigcode[];
 #ifdef SYSCALL_DEBUG  #ifdef SYSCALL_DEBUG
 extern const char * const syscallnames[];  extern const char * const syscallnames[];
 #endif  #endif
   #ifdef __HAVE_SYSCALL_INTERN
   void syscall_intern __P((struct proc *));
   #else
   void syscall __P((void));
   #endif
   
 const struct emul emul_netbsd = {  const struct emul emul_netbsd = {
         "netbsd",          "netbsd",
         NULL,           /* emulation path */          NULL,           /* emulation path */
   #ifndef __HAVE_MINIMAL_EMUL
           EMUL_HAS_SYS___syscall,
         NULL,          NULL,
         sendsig,  
         SYS_syscall,          SYS_syscall,
         SYS_MAXSYSCALL,          SYS_MAXSYSCALL,
   #endif
         sysent,          sysent,
 #ifdef SYSCALL_DEBUG  #ifdef SYSCALL_DEBUG
         syscallnames,          syscallnames,
 #else  #else
         NULL,          NULL,
 #endif  #endif
           sendsig,
         sigcode,          sigcode,
         esigcode,          esigcode,
         NULL,          NULL,
         NULL,          NULL,
         NULL,          NULL,
         EMUL_HAS_SYS___syscall,  #ifdef __HAVE_SYSCALL_INTERN
           syscall_intern,
   #else
           syscall,
   #endif
 };  };
   
 /*  /*
    * Exec lock. Used to control access to execsw[] structures.
    * This must not be static so that netbsd32 can access it, too.
    */
   struct lock exec_lock;
   
   #ifdef LKM
   static const struct emul *      emul_search __P((const char *));
   static void link_es __P((struct execsw_entry **, const struct execsw *));
   #endif /* LKM */
   
   /*
  * check exec:   * check exec:
  * given an "executable" described in the exec package's namei info,   * given an "executable" described in the exec package's namei info,
  * see what we can do with it.   * see what we can do with it.
Line 172  check_exec(struct proc *p, struct exec_p
Line 237  check_exec(struct proc *p, struct exec_p
         for (i = 0; i < nexecs && error != 0; i++) {          for (i = 0; i < nexecs && error != 0; i++) {
                 int newerror;                  int newerror;
   
                 if (execsw[i].es_check == NULL)                  epp->ep_esch = execsw[i];
                         continue;                  newerror = (*execsw[i]->es_check)(p, epp);
   
                 epp->ep_esch = &execsw[i];  
                 newerror = (*execsw[i].es_check)(p, epp);  
                 /* make sure the first "interesting" error code is saved. */                  /* make sure the first "interesting" error code is saved. */
                 if (!newerror || error == ENOEXEC)                  if (!newerror || error == ENOEXEC)
                         error = newerror;                          error = newerror;
   
                 /* if es_check call was successful, update epp->ep_es */                  /* if es_check call was successful, update epp->ep_es */
                 if (!newerror && (epp->ep_flags & EXEC_HASES) == 0)                  if (!newerror && (epp->ep_flags & EXEC_HASES) == 0)
                         epp->ep_es = &execsw[i];                          epp->ep_es = execsw[i];
   
                 if (epp->ep_flags & EXEC_DESTR && error != 0)                  if (epp->ep_flags & EXEC_DESTR && error != 0)
                         return error;                          return error;
Line 259  sys_execve(struct proc *p, void *v, regi
Line 321  sys_execve(struct proc *p, void *v, regi
         struct exec_vmcmd *base_vcp = NULL;          struct exec_vmcmd *base_vcp = NULL;
   
         /*          /*
          * figure out the maximum size of an exec header, if necessary.  
          * XXX should be able to keep LKM code from modifying exec switch  
          * when we're still using it, but...  
          */  
         if (exec_maxhdrsz == 0) {  
                 for (i = 0; i < nexecs; i++)  
                         if (execsw[i].es_check != NULL  
                             && execsw[i].es_hdrsz > exec_maxhdrsz)  
                                 exec_maxhdrsz = execsw[i].es_hdrsz;  
         }  
   
         /*  
          * Init the namei data to point the file user's program name.           * Init the namei data to point the file user's program name.
          * This is done here rather than in check_exec(), so that it's           * This is done here rather than in check_exec(), so that it's
          * possible to override this settings if any of makecmd/probe           * possible to override this settings if any of makecmd/probe
Line 293  sys_execve(struct proc *p, void *v, regi
Line 343  sys_execve(struct proc *p, void *v, regi
         pack.ep_vap = &attr;          pack.ep_vap = &attr;
         pack.ep_flags = 0;          pack.ep_flags = 0;
   
           lockmgr(&exec_lock, LK_SHARED, NULL);
   
         /* see if we can run it. */          /* see if we can run it. */
         if ((error = check_exec(p, &pack)) != 0)          if ((error = check_exec(p, &pack)) != 0)
                 goto freehdr;                  goto freehdr;
Line 590  sys_execve(struct proc *p, void *v, regi
Line 642  sys_execve(struct proc *p, void *v, regi
   
         /* update p_emul, the old value is no longer needed */          /* update p_emul, the old value is no longer needed */
         p->p_emul = pack.ep_es->es_emul;          p->p_emul = pack.ep_es->es_emul;
   #ifdef __HAVE_SYSCALL_INTERN
           (*p->p_emul->e_syscall_intern)(p);
   #endif
 #ifdef KTRACE  #ifdef KTRACE
         if (KTRPOINT(p, KTR_EMUL))          if (KTRPOINT(p, KTR_EMUL))
                 ktremul(p);                  ktremul(p);
 #endif  #endif
   
           lockmgr(&exec_lock, LK_RELEASE, NULL);
   
         return (EJUSTRETURN);          return (EJUSTRETURN);
   
 bad:  bad:
Line 614  bad:
Line 670  bad:
         uvm_km_free_wakeup(exec_map, (vaddr_t) argp, NCARGS);          uvm_km_free_wakeup(exec_map, (vaddr_t) argp, NCARGS);
   
 freehdr:  freehdr:
           lockmgr(&exec_lock, LK_RELEASE, NULL);
   
         free(pack.ep_hdr, M_EXEC);          free(pack.ep_hdr, M_EXEC);
         return error;          return error;
   
 exec_abort:  exec_abort:
           lockmgr(&exec_lock, LK_RELEASE, NULL);
   
         /*          /*
          * the old process doesn't exist anymore.  exit gracefully.           * the old process doesn't exist anymore.  exit gracefully.
          * get rid of the (new) address space we have created, if any, get rid           * get rid of the (new) address space we have created, if any, get rid
Line 689  copyargs(struct exec_package *pack, stru
Line 749  copyargs(struct exec_package *pack, stru
   
         return cpp;          return cpp;
 }  }
   
   #ifdef LKM
   /*
    * Find an emulation of given name in list of emulations.
    */
   static const struct emul *
   emul_search(name)
           const char *name;
   {
           struct emul_entry *it;
   
           LIST_FOREACH(it, &el_head, el_list) {
                   if (strcmp(name, it->el_emul->e_name) == 0)
                           return it->el_emul;
           }
   
           return NULL;
   }
   
   /*
    * Add an emulation to list, if it's not there already.
    */
   int
   emul_register(emul, ro_entry)
           const struct emul *emul;
           int ro_entry;
   {
           struct emul_entry *ee;
           int error = 0;
   
           lockmgr(&exec_lock, LK_SHARED, NULL);
   
           if (emul_search(emul->e_name)) {
                   error = EEXIST;
                   goto out;
           }
   
           MALLOC(ee, struct emul_entry *, sizeof(struct emul_entry),
                   M_EXEC, M_WAITOK);
           ee->el_emul = emul;
           ee->ro_entry = ro_entry;
           LIST_INSERT_HEAD(&el_head, ee, el_list);
   
       out:
           lockmgr(&exec_lock, LK_RELEASE, NULL);
           return error;
   }
   
   /*
    * Remove emulation with name 'name' from list of supported emulations.
    */
   int
   emul_unregister(name)
           const char *name;
   {
           struct emul_entry *it;
           int i, error = 0;
           const struct proclist_desc *pd;
           struct proc *ptmp;
   
           lockmgr(&exec_lock, LK_SHARED, NULL);
   
           LIST_FOREACH(it, &el_head, el_list) {
                   if (strcmp(it->el_emul->e_name, name) == 0)
                           break;
           }
   
           if (!it) {
                   error = ENOENT;
                   goto out;
           }
   
           if (it->ro_entry) {
                   error = EBUSY;
                   goto out;
           }
   
           /* test if any execw[] entry is still using this */
           for(i=0; i < nexecs; i++) {
                   if (execsw[i]->es_emul == it->el_emul) {
                           error = EBUSY;
                           goto out;
                   }
           }
   
           /*
            * Test if any process is running under this emulation - since
            * emul_unregister() is running quite sendomly, it's better
            * to do expensive check here than to use any locking.
            */
           proclist_lock_read();
           for (pd = proclists; pd->pd_list != NULL && !error; pd++) {
                   LIST_FOREACH(ptmp, pd->pd_list, p_list) {
                           if (ptmp->p_emul == it->el_emul) {
                                   error = EBUSY;
                                   break;
                           }
                   }
           }
           proclist_unlock_read();
   
           if (error)
                   goto out;
   
   
           /* entry is not used, remove it */
           LIST_REMOVE(it, el_list);
           FREE(it, M_EXEC);
   
       out:
           lockmgr(&exec_lock, LK_RELEASE, NULL);
           return error;
   }
   
   /*
    * Add execsw[] entry.
    */
   int
   exec_add(esp, e_name)
           struct execsw *esp;
           const char *e_name;
   {
           struct exec_entry *it;
           int error = 0;
   
           lockmgr(&exec_lock, LK_EXCLUSIVE, NULL);
   
           if (!esp->es_emul) {
                   esp->es_emul = emul_search(e_name);
                   if (!esp->es_emul) {
                           error = ENOENT;
                           goto out;
                   }
           }
   
           LIST_FOREACH(it, &ex_head, ex_list) {
                   /* assume tuple (makecmds, probe_func, emulation) is unique */
                   if (it->es->es_check == esp->es_check
                       && it->es->u.elf_probe_func == esp->u.elf_probe_func
                       && it->es->es_emul == esp->es_emul) {
                           error = EEXIST;
                           goto out;
                   }
           }
   
           /* if we got here, the entry doesn't exist yet */
           MALLOC(it, struct exec_entry *, sizeof(struct exec_entry),
                   M_EXEC, M_WAITOK);
           it->es = esp;
           LIST_INSERT_HEAD(&ex_head, it, ex_list);
   
           /* update execsw[] */
           exec_init(0);
   
       out:
           lockmgr(&exec_lock, LK_RELEASE, NULL);
           return error;
   }
   
   /*
    * Remove execsw[] entry.
    */
   int
   exec_remove(esp)
           const struct execsw *esp;
   {
           struct exec_entry *it;
           int error = 0;
   
           lockmgr(&exec_lock, LK_EXCLUSIVE, NULL);
   
           LIST_FOREACH(it, &ex_head, ex_list) {
                   /* assume tuple (makecmds, probe_func, emulation) is unique */
                   if (it->es->es_check == esp->es_check
                       && it->es->u.elf_probe_func == esp->u.elf_probe_func
                       && it->es->es_emul == esp->es_emul)
                           break;
           }
           if (!it) {
                   error = ENOENT;
                   goto out;
           }
   
           /* remove item from list and free resources */
           LIST_REMOVE(it, ex_list);
           FREE(it, M_EXEC);
   
           /* update execsw[] */
           exec_init(0);
   
       out:
           lockmgr(&exec_lock, LK_RELEASE, NULL);
           return error;
   }
   
   static void
   link_es(listp, esp)
           struct execsw_entry **listp;
           const struct execsw *esp;
   {
           struct execsw_entry *et, *e1;
   
           MALLOC(et, struct execsw_entry *, sizeof(struct execsw_entry),
                           M_TEMP, M_WAITOK);
           et->next = NULL;
           et->es = esp;
           if (*listp == NULL) {
                   *listp = et;
                   return;
           }
   
           switch(et->es->es_prio) {
           case EXECSW_PRIO_FIRST:
                   /* put new entry as the first */
                   et->next = *listp;
                   *listp = et;
                   break;
           case EXECSW_PRIO_ANY:
                   /* put new entry after all *_FIRST and *_ANY entries */
                   for(e1 = *listp; e1->next
                           && e1->next->es->es_prio != EXECSW_PRIO_LAST;
                           e1 = e1->next);
                   et->next = e1->next;
                   e1->next = et;
                   break;
           case EXECSW_PRIO_LAST:
                   /* put new entry as the last one */
                   for(e1 = *listp; e1->next; e1 = e1->next);
                   e1->next = et;
                   break;
           default:
   #ifdef DIAGNOSTIC
                   panic("execw[] entry with unknown priority %d found\n",
                           et->es->es_prio);
   #endif
                   break;
           }
   }
   
   /*
    * Initialize exec structures. If init_boot is true, also does necessary
    * one-time initialization (it's called from main() that way).
    * Once system is multiuser, this should be called with exec_lock hold,
    * i.e. via exec_{add|remove}().
    */
   int
   exec_init(init_boot)
           int init_boot;
   {
           const struct execsw **new_es, * const *old_es;
           struct execsw_entry *list, *e1;
           struct exec_entry *e2;
           int i, es_sz;
   
           if (init_boot) {
                   /* do one-time initializations */
                   lockinit(&exec_lock, PWAIT, "execlck", 0, 0);
   
                   /* register compiled-in emulations */
                   for(i=0; i < nexecs_builtin; i++) {
                           if (execsw_builtin[i].es_emul)
                                   emul_register(execsw_builtin[i].es_emul, 1);
                   }
   #ifdef DIAGNOSTIC
                   if (i == 0)
                           panic("no emulations found in execsw_builtin[]\n");
   #endif
           }
   
           /*
            * Build execsw[] array from builtin entries and entries added
            * at runtime.
            */
           list = NULL;
           for(i=0; i < nexecs_builtin; i++)
                   link_es(&list, &execsw_builtin[i]);
   
           /* Add dynamically loaded entries */
           es_sz = nexecs_builtin;
           LIST_FOREACH(e2, &ex_head, ex_list) {
                   link_es(&list, e2->es);
                   es_sz++;
           }
   
           /*
            * Now that we have sorted all execw entries, create new execsw[]
            * and free no longer needed memory in the process.
            */
           new_es = malloc(es_sz * sizeof(struct execsw *), M_EXEC, M_WAITOK);
           for(i=0; list; i++) {
                   new_es[i] = list->es;
                   e1 = list->next;
                   FREE(list, M_TEMP);
                   list = e1;
           }
   
           /*
            * New execsw[] array built, now replace old execsw[] and free
            * used memory.
            */
           old_es = execsw;
           execsw = new_es;
           nexecs = es_sz;
           if (old_es)
                   free((void *)old_es, M_EXEC);
   
           /*
            * Figure out the maximum size of an exec header.
            */
           exec_maxhdrsz = 0;
           for (i = 0; i < nexecs; i++) {
                   if (execsw[i]->es_hdrsz > exec_maxhdrsz)
                           exec_maxhdrsz = execsw[i]->es_hdrsz;
           }
   
           return 0;
   }
   #endif
   
   #ifndef LKM
   /*
    * Simplified exec_init() for kernels without LKMs. Only initialize
    * exec_maxhdrsz and execsw[].
    */
   int
   exec_init(init_boot)
           int init_boot;
   {
           int i;
   
   #ifdef DIAGNOSTIC
           if (!init_boot)
                   panic("exec_init(): called with init_boot == 0");
   #endif
   
           /* do one-time initializations */
           lockinit(&exec_lock, PWAIT, "execlck", 0, 0);
   
           nexecs = nexecs_builtin;
           execsw = malloc(nexecs*sizeof(struct execsw *), M_EXEC, M_WAITOK);
   
           /*
            * Fill in execsw[] and figure out the maximum size of an exec header.
            */
           exec_maxhdrsz = 0;
           for(i=0; i < nexecs; i++) {
                   execsw[i] = &execsw_builtin[i];
                   if (execsw_builtin[i].es_hdrsz > exec_maxhdrsz)
                           exec_maxhdrsz = execsw_builtin[i].es_hdrsz;
           }
   
           return 0;
   
   }
   #endif /* !LKM */

Legend:
Removed from v.1.103.2.3  
changed lines
  Added in v.1.103.2.4

CVSweb <webmaster@jp.NetBSD.org>