symbian-qemu-0.9.1-12/qemu-symbian-svp/linux-user/linuxload.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /* Code for loading Linux executables.  Mostly linux kernel code.  */
       
     2 
       
     3 #include <sys/types.h>
       
     4 #include <sys/stat.h>
       
     5 #include <fcntl.h>
       
     6 #include <errno.h>
       
     7 #include <unistd.h>
       
     8 #include <stdio.h>
       
     9 #include <stdlib.h>
       
    10 
       
    11 #include "qemu.h"
       
    12 
       
    13 #define NGROUPS 32
       
    14 
       
    15 /* ??? This should really be somewhere else.  */
       
    16 abi_long memcpy_to_target(abi_ulong dest, const void *src,
       
    17                           unsigned long len)
       
    18 {
       
    19     void *host_ptr;
       
    20 
       
    21     host_ptr = lock_user(VERIFY_WRITE, dest, len, 0);
       
    22     if (!host_ptr)
       
    23         return -TARGET_EFAULT;
       
    24     memcpy(host_ptr, src, len);
       
    25     unlock_user(host_ptr, dest, 1);
       
    26     return 0;
       
    27 }
       
    28 
       
    29 static int in_group_p(gid_t g)
       
    30 {
       
    31     /* return TRUE if we're in the specified group, FALSE otherwise */
       
    32     int		ngroup;
       
    33     int		i;
       
    34     gid_t	grouplist[NGROUPS];
       
    35 
       
    36     ngroup = getgroups(NGROUPS, grouplist);
       
    37     for(i = 0; i < ngroup; i++) {
       
    38 	if(grouplist[i] == g) {
       
    39 	    return 1;
       
    40 	}
       
    41     }
       
    42     return 0;
       
    43 }
       
    44 
       
    45 static int count(char ** vec)
       
    46 {
       
    47     int		i;
       
    48 
       
    49     for(i = 0; *vec; i++) {
       
    50         vec++;
       
    51     }
       
    52 
       
    53     return(i);
       
    54 }
       
    55 
       
    56 static int prepare_binprm(struct linux_binprm *bprm)
       
    57 {
       
    58     struct stat		st;
       
    59     int mode;
       
    60     int retval, id_change;
       
    61 
       
    62     if(fstat(bprm->fd, &st) < 0) {
       
    63 	return(-errno);
       
    64     }
       
    65 
       
    66     mode = st.st_mode;
       
    67     if(!S_ISREG(mode)) {	/* Must be regular file */
       
    68 	return(-EACCES);
       
    69     }
       
    70     if(!(mode & 0111)) {	/* Must have at least one execute bit set */
       
    71 	return(-EACCES);
       
    72     }
       
    73 
       
    74     bprm->e_uid = geteuid();
       
    75     bprm->e_gid = getegid();
       
    76     id_change = 0;
       
    77 
       
    78     /* Set-uid? */
       
    79     if(mode & S_ISUID) {
       
    80     	bprm->e_uid = st.st_uid;
       
    81 	if(bprm->e_uid != geteuid()) {
       
    82 	    id_change = 1;
       
    83 	}
       
    84     }
       
    85 
       
    86     /* Set-gid? */
       
    87     /*
       
    88      * If setgid is set but no group execute bit then this
       
    89      * is a candidate for mandatory locking, not a setgid
       
    90      * executable.
       
    91      */
       
    92     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
       
    93 	bprm->e_gid = st.st_gid;
       
    94 	if (!in_group_p(bprm->e_gid)) {
       
    95 		id_change = 1;
       
    96 	}
       
    97     }
       
    98 
       
    99     memset(bprm->buf, 0, sizeof(bprm->buf));
       
   100     retval = lseek(bprm->fd, 0L, SEEK_SET);
       
   101     if(retval >= 0) {
       
   102         retval = read(bprm->fd, bprm->buf, 128);
       
   103     }
       
   104     if(retval < 0) {
       
   105 	perror("prepare_binprm");
       
   106 	exit(-1);
       
   107 	/* return(-errno); */
       
   108     }
       
   109     else {
       
   110 	return(retval);
       
   111     }
       
   112 }
       
   113 
       
   114 /* Construct the envp and argv tables on the target stack.  */
       
   115 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
       
   116                               abi_ulong stringp, int push_ptr)
       
   117 {
       
   118     int n = sizeof(abi_ulong);
       
   119     abi_ulong envp;
       
   120     abi_ulong argv;
       
   121 
       
   122     sp -= (envc + 1) * n;
       
   123     envp = sp;
       
   124     sp -= (argc + 1) * n;
       
   125     argv = sp;
       
   126     if (push_ptr) {
       
   127         /* FIXME - handle put_user() failures */
       
   128         sp -= n;
       
   129         put_user_ual(envp, sp);
       
   130         sp -= n;
       
   131         put_user_ual(argv, sp);
       
   132     }
       
   133     sp -= n;
       
   134     /* FIXME - handle put_user() failures */
       
   135     put_user_ual(argc, sp);
       
   136 
       
   137     while (argc-- > 0) {
       
   138         /* FIXME - handle put_user() failures */
       
   139         put_user_ual(stringp, argv);
       
   140         argv += n;
       
   141         stringp += target_strlen(stringp) + 1;
       
   142     }
       
   143     /* FIXME - handle put_user() failures */
       
   144     put_user_ual(0, argv);
       
   145     while (envc-- > 0) {
       
   146         /* FIXME - handle put_user() failures */
       
   147         put_user_ual(stringp, envp);
       
   148         envp += n;
       
   149         stringp += target_strlen(stringp) + 1;
       
   150     }
       
   151     /* FIXME - handle put_user() failures */
       
   152     put_user_ual(0, envp);
       
   153 
       
   154     return sp;
       
   155 }
       
   156 
       
   157 int loader_exec(const char * filename, char ** argv, char ** envp,
       
   158              struct target_pt_regs * regs, struct image_info *infop)
       
   159 {
       
   160     struct linux_binprm bprm;
       
   161     int retval;
       
   162     int i;
       
   163 
       
   164     bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
       
   165     for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
       
   166             bprm.page[i] = 0;
       
   167     retval = open(filename, O_RDONLY);
       
   168     if (retval < 0)
       
   169         return retval;
       
   170     bprm.fd = retval;
       
   171     bprm.filename = (char *)filename;
       
   172     bprm.argc = count(argv);
       
   173     bprm.argv = argv;
       
   174     bprm.envc = count(envp);
       
   175     bprm.envp = envp;
       
   176 
       
   177     retval = prepare_binprm(&bprm);
       
   178 
       
   179     infop->host_argv = argv;
       
   180 
       
   181     if(retval>=0) {
       
   182         if (bprm.buf[0] == 0x7f
       
   183                 && bprm.buf[1] == 'E'
       
   184                 && bprm.buf[2] == 'L'
       
   185                 && bprm.buf[3] == 'F') {
       
   186 #ifndef TARGET_HAS_ELFLOAD32
       
   187             retval = load_elf_binary(&bprm,regs,infop);
       
   188 #else
       
   189             retval = load_elf_binary_multi(&bprm, regs, infop);
       
   190 #endif
       
   191 #if defined(TARGET_HAS_BFLT)
       
   192         } else if (bprm.buf[0] == 'b'
       
   193                 && bprm.buf[1] == 'F'
       
   194                 && bprm.buf[2] == 'L'
       
   195                 && bprm.buf[3] == 'T') {
       
   196             retval = load_flt_binary(&bprm,regs,infop);
       
   197 #endif
       
   198         } else {
       
   199             fprintf(stderr, "Unknown binary format\n");
       
   200             return -1;
       
   201         }
       
   202     }
       
   203 
       
   204     if(retval>=0) {
       
   205         /* success.  Initialize important registers */
       
   206         do_init_thread(regs, infop);
       
   207         return retval;
       
   208     }
       
   209 
       
   210     /* Something went wrong, return the inode and free the argument pages*/
       
   211     for (i=0 ; i<MAX_ARG_PAGES ; i++) {
       
   212         free(bprm.page[i]);
       
   213     }
       
   214     return(retval);
       
   215 }