Esempio n. 1
0
static int PCS_Stream_close(php_stream *stream, int close_handle TSRMLS_DC)
{
	PCS_STREAM_DATA *dp = stream->abstract;

	free_dp(&dp);

	return 0;
}
Esempio n. 2
0
/* Remove the user with matching user and group name and
 * remove all her transactions from the transaction list.
 * Return 0 on success, and -1 if no matching user exists.
 * Remember to free memory no longer needed.
 * (Wait on implementing the removal of the user's transactions until you
 * get to Part III below, when you will implement transactions.)
 */
int remove_user(Group *group, const char *user_name) {
    /* Gets the previous user before the user to be deleted if the to be deleted
     * user is not a head. If the to be deleted user is a head, the to be deleted
     * is returned. If the user doesn't exist in the group, NULL is returned.
     */
    User *prev_user = find_prev_user(group, user_name);

    /* If the user returned is not NULL, this means that user exists in the group,
     * therefore we check if the returned user is a head or the previous user.
     *      1) If it is a previous user, we set the previous user next pointer to
     *         the next next user and free space for the deleted user.
     */
    if (prev_user != NULL) {
        if (strcmp(prev_user->name, user_name) == 0) {
            group->users = prev_user->next;
            remove_xct(group, user_name);
            free_dp(prev_user->name);
            free_dp(prev_user);
            return 0;

        /*      2) If it is a head node, we reset the head to the next user and free
         *         up space for the deleted node. Free space for the user name 
         *         and the user, also points the user to NULL to avoid dangling 
         *         pointers.
         */
        } else if (strcmp(prev_user->next->name, user_name) == 0) {
            User *temp = prev_user->next;
            prev_user->next = prev_user->next->next;
            remove_xct(group, user_name);
            free_dp(temp->name);
            free_dp(temp);
        }

        // Return 0 if we the deletion is successful.
        return 0;

    /* If the user returned is NULL, that means the user name doesn't exist, no
     * users are deleted, and -1 is returned.
     */
    } else {
        return -1;
    }
}
Esempio n. 3
0
int do_exec(char *path, char **argv, char **env, int shebanged /* oh my */)
{
	unsigned int i=0;
	addr_t end, eip;
	unsigned int argc=0, envc=0;
	char **backup_argv=0, **backup_env=0;
	/* Sanity */
	if(!path || !*path)
		return -EINVAL;
	/* Load the file, and make sure that it is valid and accessible */
	if(EXEC_LOG == 2) 
		printk(0, "[%d]: Checking executable file (%s)\n", current_process->pid, path);
	struct file *efil;
	int err_open;
	efil = fs_file_open(path, _FREAD, 0, &err_open);
	if(!efil)
		return err_open;
	/* are we allowed to execute it? */
	if(!vfs_inode_check_permissions(efil->inode, MAY_EXEC, 0))
	{
		file_put(efil);
		return -EACCES;
	}
	/* is it a valid elf? */
	int header_size = 0;
#if CONFIG_ARCH == TYPE_ARCH_X86_64
	header_size = sizeof(elf64_header_t);
#elif CONFIG_ARCH == TYPE_ARCH_X86
	header_size = sizeof(elf32_header_t);
#endif
	/* read in the ELF header, and check if it's a shebang */
	if(header_size < 2) header_size = 2;
	unsigned char mem[header_size];
	fs_file_pread(efil, 0, mem, header_size);
	
	if(__is_shebang(mem))
		return loader_do_shebang(efil, argv, env);
	
	int other_bitsize=0;
	if(!is_valid_elf(mem, 2) && !other_bitsize) {
		file_put(efil);
		return -ENOEXEC;
	}
	
	if(EXEC_LOG == 2) 
		printk(0, "[%d]: Copy data\n", current_process->pid);
	/* okay, lets back up argv and env so that we can
	 * clear out the address space and not lose data...
	 * If this call if coming from a shebang, then we don't check the pointers,
	 * since they won't be from userspace */
	size_t total_args_len = 0;
	if((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, argv, 0)) && argv) {
		while((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, argv[argc], 0)) && argv[argc] && *argv[argc])
			argc++;
		backup_argv = (char **)kmalloc(sizeof(addr_t) * argc);
		for(i=0;i<argc;i++) {
			backup_argv[i] = (char *)kmalloc(strlen(argv[i]) + 1);
			_strcpy(backup_argv[i], argv[i]);
			total_args_len += strlen(argv[i])+1 + sizeof(char *);
		}
	}
	if((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, env, 0)) && env) {
		while((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, env[envc], 0)) && env[envc] && *env[envc]) envc++;
		backup_env = (char **)kmalloc(sizeof(addr_t) * envc);
		for(i=0;i<envc;i++) {
			backup_env[i] = (char *)kmalloc(strlen(env[i]) + 1);
			_strcpy(backup_env[i], env[i]);
			total_args_len += strlen(env[i])+1 + sizeof(char *);
		}
	}
	total_args_len += 2 * sizeof(char *);
	/* and the path too! */
	char *path_backup = (char *)kmalloc(strlen(path) + 1);
	_strcpy((char *)path_backup, path);
	path = path_backup;
	
	/* Preexec - This is the point of no return. Here we close out unneeded 
	 * file descs, free up the page directory and clear up the resources 
	 * of the task */
	if(EXEC_LOG)
		printk(0, "Executing (p%dt%d, cpu %d, tty %d): %s\n", current_process->pid, current_thread->tid, current_thread->cpu->knum, current_process->pty ? current_process->pty->num : 0, path);
	preexec();
	
	/* load in the new image */
	strncpy((char *)current_process->command, path, 128);
	if(!loader_parse_elf_executable(mem, efil, &eip, &end))
		eip=0;
	/* do setuid and setgid */
	if(efil->inode->mode & S_ISUID) {
		current_process->effective_uid = efil->inode->uid;
	}
	if(efil->inode->mode & S_ISGID) {
		current_process->effective_gid = efil->inode->gid;
	}
	/* we don't need the file anymore, close it out */
	file_put(efil);
	file_close_cloexec();
	if(!eip) {
		printk(5, "[exec]: Tried to execute an invalid ELF file!\n");
		free_dp(backup_argv, argc);
		free_dp(backup_env, envc);
		kfree(path);
		tm_thread_exit(0);
	}
	
	if(EXEC_LOG == 2) 
		printk(0, "[%d]: Updating task values\n", current_process->pid);
	/* Setup the task with the proper values (libc malloc stack) */
	addr_t end_l = end;
	end = ((end-1)&PAGE_MASK) + PAGE_SIZE;
	total_args_len += PAGE_SIZE;
	/* now we need to copy back the args and env into userspace
	 * writeable memory...yippie. */
	addr_t args_start = end + PAGE_SIZE;
	addr_t env_start = args_start;
	addr_t alen = 0;
	mm_mmap(end, total_args_len,
			PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0, 0);
	if(backup_argv) {
		memcpy((void *)args_start, backup_argv, sizeof(addr_t) * argc);
		alen += sizeof(addr_t) * argc;
		*(addr_t *)(args_start + alen) = 0; /* set last argument value to zero */
		alen += sizeof(addr_t);
		argv = (char **)args_start;
		for(i=0;i<argc;i++)
		{
			char *old = argv[i];
			char *new = (char *)(args_start+alen);
			unsigned len = strlen(old) + 4;
			argv[i] = new;
			_strcpy(new, old);
			kfree(old);
			alen += len;
		}
		kfree(backup_argv);
	}
	env_start = args_start + alen;
	alen = 0;
	if(backup_env) {
		memcpy((void *)env_start, backup_env, sizeof(addr_t) * envc);
		alen += sizeof(addr_t) * envc;
		*(addr_t *)(env_start + alen) = 0; /* set last argument value to zero */
		alen += sizeof(addr_t);
		env = (char **)env_start;
		for(i=0;i<envc;i++)
		{
			char *old = env[i];
			char *new = (char *)(env_start+alen);
			unsigned len = strlen(old) + 1;
			env[i] = new;
			_strcpy(new, old);
			kfree(old);
			alen += len;
		}
		kfree(backup_env);
	}
	end = (env_start + alen) & PAGE_MASK;
	current_process->env = env;
	current_process->argv = argv;
	kfree(path);
	
	/* set the heap locations, and map in the start */
	current_process->heap_start = current_process->heap_end = end + PAGE_SIZE*2;
	addr_t ret = mm_mmap(end + PAGE_SIZE, PAGE_SIZE,
			PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0, 0);
	/* now, we just need to deal with the syscall return stuff. When the syscall
	 * returns, it'll just jump into the entry point of the new process */
	tm_thread_lower_flag(current_thread, THREAD_SCHEDULE);
	/* the kernel cares if it has executed something or not */
	if(!(kernel_state_flags & KSF_HAVEEXECED))
		set_ksf(KSF_HAVEEXECED);
	arch_loader_exec_initializer(argc, eip);
	if(EXEC_LOG == 2) 
		printk(0, "[%d]: Performing call\n", current_process->pid);
	return 0;
}
Esempio n. 4
0
/* Remove all transactions that belong to the user_name from the group's
 * transaction list. This helper function should be called by remove_user.
 * If there are no transactions for this user, the function should do nothing.
 * Remember to free memory no longer needed.
 */
void remove_xct(Group *group, const char *user_name) {
    /* Initializes a pointer to the first node of the xct list in order to traverse
     * through the list to find the list to find the correct xct to be deleted.
     */
    Xct *curr = group->xcts;

    /* Checks if the head of the xct list matches the user name that should be
     * deleted from xcts. After deletion, it frees memory that is no longer needed
     * by the pointer and points to NULL to avoid dangling pointers.
     */
    while (strcmp(curr->name, user_name) == 0) {
        Xct *tmp = curr;
        if (curr->next == NULL) {
            group->xcts = NULL;
            curr = group->xcts;
            free_dp(tmp->name);
            free_dp(tmp);
            return;
        } else {
            group->xcts = curr->next;
            curr = group->xcts;
            free_dp(tmp->name);
            free_dp(tmp);
        }
    }

    /* Traverses through the rest of the xct list to find other xct nodes to 
     * delete if any. The xct node is deleted and then the memory is freed and
     * the pointer is pointed to NULL to avoid dangling pointer. 
     */
    if (curr != NULL) {
        while (curr != NULL && curr->next != NULL) {
            if (strcmp(curr->next->name, user_name) == 0) {
                Xct *tmp = curr->next;

                /* Checks if next is NULL, if it is NULL, it means that the end of
                 * of the list have been reached and the last xct should be deleted.
                 */
                if (tmp->next == NULL) {
                    curr->next = NULL;

                    /* If the next is not NULL, current next pointer is set to the xct
                     * after tmp.
                     */
                } else {
                    curr->next = curr->next->next;
                }
                free_dp(tmp->name);
                free_dp(tmp);
            }

            /* Checks if next xct after current is NULL, if the current is NULL we
             * can check for the name of the xct.
             */
            if (curr->next != NULL) {
                if (strcmp(curr->next->name, user_name) != 0) {
                    curr = curr->next;
                }
            }
        }
    }
}
Esempio n. 5
0
/* Add the transaction represented by user_name and amount to the appropriate
 * transaction list, and update the balances of the corresponding user and group.
 * Note that updating a user's balance might require the user to be moved to a
 * different position in the list to keep the list in sorted order. Returns 0 on
 * success, and -1 if the specified user does not exist.
 */
int add_xct(Group *group, const char *user_name, double amount) {
    /* Allocate space for the new xct that is to be added to the list of
     * xcts.
     */
    Xct *new_xct = (Xct*) malloc (sizeof(Xct));

    /* Checks if malloc failed, if malloc failed, a error message is printed to
     * standard output and exit code of 256.
     */
    if (new_xct == NULL) {
        print_exit("ERROR: Malloc failed", 256);

    /* If malloc didn't fail, the user name and the amount is assigned to the new
     * xct and the next pointer is set to NULL temporarily.
     */
    } else {
        int size_to_malloc = (strlen(user_name)+1)*sizeof(char);
        new_xct->name = (char*) malloc (size_to_malloc);

        /* Checks if the current malloc failed, if it failed a message is printed
         * to standard output and exit code of 256 is set.
         */
        if (new_xct->name == NULL) {
            print_exit("ERROR: Malloc failed", 256);
        }
        strncpy(new_xct->name, user_name, size_to_malloc);
        new_xct->name[size_to_malloc] = '\0';
        new_xct->amount = amount;
        new_xct->next = NULL;
    }

    /* Finds the previous user to the user that added a xct in order to change
     * the user's balance and re-organize the list.
     */
    User *prev_user = find_prev_user(group, user_name);

    /* If no user was found with the same user name in the list of users, -1 is
     * returned.
     */
    if (prev_user == NULL) {
        free_dp(new_xct->name);
        free_dp(new_xct);
        return -1;

    /* Checks if the user returned is the head of the list of users, if it is, 
     * the head is changed so that the user can be moved to its correct location.
     */
    } else if (strcmp(prev_user->name, user_name) == 0) {
        push_xct(group, new_xct);
        prev_user->balance += amount;
        sort_user(group, prev_user, user_name);
        return 0;

    /* Checks if the user returned is in the middle of the list of users, the 
     * user is remvoed from its current position and placed in the correct
     * position in the users of list.
     */
    } else {
        push_xct(group, new_xct);
        prev_user->next->balance += amount;
        sort_user(group, prev_user, user_name);
        return 0;
    }
}
Esempio n. 6
0
/* Add a group with name group_name to the group_list referred to by
 * group_list_ptr. The groups are ordered by the time that the group was
 * added to the list with new groups added to the end of the list.
 *
 * Returns 0 on success and -1 if a group with this name already exists.
 *
 * (I.e, allocate and initialize a Group struct, and insert it
 * into the group_list. Note that the head of the group list might change
 * which is why the first argument is a double pointer.)
 */
int add_group(Group **group_list_ptr, const char *group_name) {
    /* Allocates space in memory for new_group in order to add the group the
     * group_list
     */
    Group *new_group = (Group*) malloc (sizeof(Group));

    /* Checks if malloc have allocated space.
     *     1) If it didn't, print out error message and exit with code 256
     */
    if (new_group == NULL) {
        print_exit("ERROR: Malloc failed", 256);

    /*     2) If it did, set the new group_name, set users, xcts and next pointers
     *        to NULL
     */
    } else {
        int size_to_malloc = (strlen(group_name) + 1) * sizeof(char);
        new_group->name = (char*) malloc (size_to_malloc);

        /* Checks if malloc completed successfully, if it didn't complete 
         * successfully it will print out an error message to standard output.
         */
        if (new_group->name == NULL) {
            print_exit("ERROR: Malloc failed", 256);
        }
        strncpy(new_group->name, group_name, size_to_malloc);
        new_group->name[size_to_malloc] = '\0';

        /* All other pointers are set NULL until the embedded linked list are 
         * declared and initialized. 
         */
        new_group->users = NULL;
        new_group->xcts = NULL;
        new_group->next = NULL;
    }

    /* Checks if the list is empty.
     * If it is, it sets the new_group to the head of the list and 0 is returned
     */
    if (*group_list_ptr == NULL) {
        *group_list_ptr = new_group;
        return 0;

    /* If it is not an empty list, it will traverse the list to detect if a group
     * with the same name already exists.
     */
    } else {
        Group *curr = *group_list_ptr;
        while (curr != NULL) {

            /* Compares the current group name with the group_name (user wants
             * to add). 
             *     1) If a group with the same name exists, -1 is returned
             */
            if (strcmp(curr->name, group_name) == 0) {
                free_dp(new_group->name);
                free_dp(new_group);
                return -1;
            } else if (curr->next == NULL) {
                curr->next = new_group;
                return 0;
            } else {
                curr = curr->next;
            }
        }
        return 0;
    }
}
Esempio n. 7
0
void free_user_xct(void *in_ptr, void *main_ptr) {
    free_dp(in_ptr);
    free_dp(main_ptr);
}
Esempio n. 8
0
/* Add a new user with the specified user name to the specified group. Return zero
 * on success and -1 if the group already has a user with that name.
 * (allocate and initialize a User data structure and insert it into the
 * appropriate group list)
 */
int add_user(Group *group, const char *user_name) {
    /* Allocates space in memory for the user, and checks if malloc has been
     * completed successfully.
     */
    User *new_user = (User*) malloc (sizeof(User));

    /* If malloc is not completed succesfully, an error message will be printed
     * out to standard output and program will exit with 256 exit code
     */
    if (new_user == NULL) {
        print_exit("ERROR: Malloc failed", 256);

    /* If malloc has been completed successfully, the user name is set to user_name
     * and set initial balance to 0
     */
    } else {
        int size_to_malloc = (strlen(user_name)+1)*sizeof(char);
        new_user->name = (char*) malloc (size_to_malloc);

        /* Checks if malloc is completed succesfully, if it is not completed
         * successfully, and error message will be printed out the screen and exit
         * code of 256.
         */
        if (new_user->name == NULL) {
            print_exit("ERROR: Malloc failed", 256);
        }

        /* Copies the user_name given to the user name got the newly created
         * user.
         */
        strncpy(new_user->name, user_name, size_to_malloc);
        new_user->name[size_to_malloc] = '\0';

        /* Sets all other values to either 0.0 if it is double, or NULL if it is
         * a pointer to another linked list.
         */
        new_user->balance = 0.0;
        new_user->next = NULL;
    }

    // Returns the user if the user already exists in the group.
    User *prev_user = find_prev_user(group, user_name);

    /* If prev_user is NULL, meaning no user in the group exists with the same
     * name. We can add the new user in this case to the specified group.
     */
    if (prev_user == NULL) {
        prev_user = new_user;
        User *tmp = group->users;
        group->users = prev_user;
        group->users->next = tmp;
        return 0;

    /* If prev_user is not NULL, this means that a user with the same name already
     * exists, so we don't add the new user and just return -1. Free space for 
     * the user name and the user, also points the user to NULL to avoid dangling 
     * pointers
     */
    } else {
        free_dp(new_user->name);
        free_dp(new_user);
        return -1;
    }
}
Esempio n. 9
0
int do_exec(task_t *t, char *path, char **argv, char **env)
{
	unsigned int i=0;
	addr_t end, eip;
	unsigned int argc=0, envc=0;
	int desc;
	char **backup_argv=0, **backup_env=0;
	/* Sanity */
	if(!t) panic(PANIC_NOSYNC, "Tried to execute with empty task");
	if(t == kernel_task) panic(0, "Kernel is being executed at the gallows!");
	if(t != current_task)
		panic(0, "I don't know, was really drunk at the time");
	if(t->magic != TASK_MAGIC)
		panic(0, "Invalid task in exec (%d)", t->pid);
	if(!path || !*path)
		return -EINVAL;
	/* Load the file, and make sure that it is valid and accessable */
	if(EXEC_LOG == 2) 
		printk(0, "[%d]: Checking executable file (%s)\n", t->pid, path);
	struct file *efil;
	int err_open, num;
	efil=d_sys_open(path, O_RDONLY, 0, &err_open, &num);
	if(efil)
		desc = num;
	else
		desc = err_open;
	if(desc < 0 || !efil)
		return -ENOENT;
	if(!permissions(efil->inode, MAY_EXEC))
	{
		sys_close(desc);
		return -EACCES;
	}
	/* Detirmine if the file is a valid ELF */
	int header_size = 0;
#if CONFIG_ARCH == TYPE_ARCH_X86_64
	header_size = sizeof(elf64_header_t);
#elif CONFIG_ARCH == TYPE_ARCH_X86
	header_size = sizeof(elf32_header_t);
#endif
	char mem[header_size];
	read_data(desc, mem, 0, header_size);
	int other_bitsize=0;
#if CONFIG_ARCH == TYPE_ARCH_X86_64
	if(is_valid_elf32_otherarch(mem, 2))
		other_bitsize = 1;
#endif
	if(!is_valid_elf(mem, 2) && !other_bitsize) {
		sys_close(desc);
		return -ENOEXEC;
	}
	
	if(EXEC_LOG == 2) 
		printk(0, "[%d]: Copy data\n", t->pid);
	/* okay, lets back up argv and env so that we can
	 * clear out the address space and not lose data..*/
	if(__is_valid_user_ptr(SYS_EXECVE, argv, 0)) {
		while(__is_valid_user_ptr(SYS_EXECVE, argv[argc], 0) && *argv[argc]) argc++;
		backup_argv = (char **)kmalloc(sizeof(addr_t) * argc);
		for(i=0;i<argc;i++) {
			backup_argv[i] = (char *)kmalloc(strlen(argv[i]) + 1);
			_strcpy(backup_argv[i], argv[i]);
		}
	}
	if(__is_valid_user_ptr(SYS_EXECVE, env, 0)) {
		while(__is_valid_user_ptr(SYS_EXECVE, env[envc], 0) && *env[envc]) envc++;
		backup_env = (char **)kmalloc(sizeof(addr_t) * envc);
		for(i=0;i<envc;i++) {
			backup_env[i] = (char *)kmalloc(strlen(env[i]) + 1);
			_strcpy(backup_env[i], env[i]);
		}
	}
	/* and the path too! */
	char *path_backup = (char *)kmalloc(strlen(path) + 1);
	_strcpy((char *)path_backup, path);
	path = path_backup;
	
	if(pd_cur_data->count > 1)
		printk(0, "[exec]: Not sure what to do here...\n");
	/* Preexec - This is the point of no return. Here we close out unneeded 
	 * file descs, free up the page directory and clear up the resources 
	 * of the task */
	if(EXEC_LOG)
		printk(0, "Executing (task %d, cpu %d, tty %d, cwd=%s): %s\n", t->pid, ((cpu_t *)t->cpu)->apicid, t->tty, current_task->thread->pwd->name, path);
	preexec(t, desc);
	strncpy((char *)t->command, path, 128);
	if(other_bitsize)
	{
#if CONFIG_ARCH == TYPE_ARCH_X86_64
		if(!process_elf_other(mem, desc, &eip, &end))
			eip=0;
#endif
	} else if(!process_elf(mem, desc, &eip, &end))
		eip=0;
	sys_close(desc);
	if(!eip) {
		printk(5, "[exec]: Tried to execute an invalid ELF file!\n");
		free_dp(backup_argv, argc);
		free_dp(backup_env, envc);
#if DEBUG
		panic(0, "");
#endif
		exit(0);
	}
	
	if(EXEC_LOG == 2) 
		printk(0, "[%d]: Updating task values\n", t->pid);
	/* Setup the task with the proper values (libc malloc stack) */
	addr_t end_l = end;
	end = (end&PAGE_MASK);
	user_map_if_not_mapped_noclear(end);
	/* now we need to copy back the args and env into userspace
	 * writeable memory...yippie. */
	addr_t args_start = end + PAGE_SIZE;
	addr_t env_start = args_start;
	addr_t alen = 0;
	if(backup_argv) {
		for(i=0;i<(sizeof(addr_t) * (argc+1))/PAGE_SIZE + 2;i++)
			user_map_if_not_mapped_noclear(args_start + i * PAGE_SIZE);
		memcpy((void *)args_start, backup_argv, sizeof(addr_t) * argc);
		alen += sizeof(addr_t) * argc;
		*(addr_t *)(args_start + alen) = 0; /* set last argument value to zero */
		alen += sizeof(addr_t);
		argv = (char **)args_start;
		for(i=0;i<argc;i++)
		{
			char *old = argv[i];
			char *new = (char *)(args_start+alen);
			user_map_if_not_mapped_noclear((addr_t)new);
			unsigned len = strlen(old) + 4;
			user_map_if_not_mapped_noclear((addr_t)new + len + 1);
			argv[i] = new;
			_strcpy(new, old);
			kfree(old);
			alen += len;
		}
		kfree(backup_argv);
	}
	env_start = args_start + alen;
	alen = 0;
	if(backup_env) {
		for(i=0;i<(((sizeof(addr_t) * (envc+1))/PAGE_SIZE) + 2);i++)
			user_map_if_not_mapped_noclear(env_start + i * PAGE_SIZE);
		memcpy((void *)env_start, backup_env, sizeof(addr_t) * envc);
		alen += sizeof(addr_t) * envc;
		*(addr_t *)(env_start + alen) = 0; /* set last argument value to zero */
		alen += sizeof(addr_t);
		env = (char **)env_start;
		for(i=0;i<envc;i++)
		{
			char *old = env[i];
			char *new = (char *)(env_start+alen);
			user_map_if_not_mapped_noclear((addr_t)new);
			unsigned len = strlen(old) + 1;
			user_map_if_not_mapped_noclear((addr_t)new + len + 1);
			env[i] = new;
			_strcpy(new, old);
			kfree(old);
			alen += len;
		}
		kfree(backup_env);
	}
	end = (env_start + alen) & PAGE_MASK;
	t->env = env;
	t->argv = argv;
	kfree(path);
	
	t->heap_start = t->heap_end = end + PAGE_SIZE;
	if(other_bitsize)
		raise_task_flag(t, TF_OTHERBS);
	user_map_if_not_mapped_noclear(t->heap_start);
	/* Zero the heap and stack */
	memset((void *)end_l, 0, PAGE_SIZE-(end_l%PAGE_SIZE));
	memset((void *)(end+PAGE_SIZE), 0, PAGE_SIZE);
	memset((void *)(STACK_LOCATION - STACK_SIZE), 0, STACK_SIZE);
	/* Release everything */
	if(EXEC_LOG == 2) 
		printk(0, "[%d]: Performing call\n", t->pid);
	
	set_int(0);
	lower_task_flag(t, TF_SCHED);
	if(!(kernel_state_flags & KSF_HAVEEXECED))
		set_ksf(KSF_HAVEEXECED);
	arch_specific_exec_initializer(t, argc, eip);
	return 0;
}