⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exec.c

📁 unix/linux 编程实践一书的所有源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/exec.c * *  Copyright (C) 1991, 1992  Linus Torvalds *//* * #!-checking implemented by tytso. *//* * Demand-loading implemented 01.12.91 - no need to read anything but * the header into memory. The inode of the executable is put into * "current->executable", and page faults do the actual loading. Clean. * * Once more I can proudly say that linux stood up to being changed: it * was less than 2 hours work to get demand-loading completely implemented. * * Demand loading changed July 1993 by Eric Youngdale.   Use mmap instead, * current->executable is only used by the procfs.  This allows a dispatch * table to check for several different types  of binary formats.  We keep * trying until we recognize the file or we run out of supported binary * formats.  */#include <linux/fs.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/a.out.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/malloc.h>#include <linux/binfmts.h>#include <linux/personality.h>#include <asm/system.h>#include <asm/segment.h>#include <asm/pgtable.h>#include <linux/config.h>#ifdef CONFIG_KERNELD#include <linux/kerneld.h>#endifasmlinkage int sys_exit(int exit_code);asmlinkage int sys_brk(unsigned long);/* * Here are the actual binaries that will be accepted: * add more with "register_binfmt()" if using modules... * * These are defined again for the 'real' modules if you are using a * module definition for these routines. */static struct linux_binfmt *formats = (struct linux_binfmt *) NULL;void binfmt_setup(void){#ifdef CONFIG_BINFMT_ELF	init_elf_binfmt();#endif#ifdef CONFIG_BINFMT_AOUT	init_aout_binfmt();#endif#ifdef CONFIG_BINFMT_JAVA	init_java_binfmt();#endif	/* This cannot be configured out of the kernel */	init_script_binfmt();}int register_binfmt(struct linux_binfmt * fmt){	struct linux_binfmt ** tmp = &formats;	if (!fmt)		return -EINVAL;	if (fmt->next)		return -EBUSY;	while (*tmp) {		if (fmt == *tmp)			return -EBUSY;		tmp = &(*tmp)->next;	}	fmt->next = formats;	formats = fmt;	return 0;	}#ifdef CONFIG_MODULESint unregister_binfmt(struct linux_binfmt * fmt){	struct linux_binfmt ** tmp = &formats;	while (*tmp) {		if (fmt == *tmp) {			*tmp = fmt->next;			return 0;		}		tmp = &(*tmp)->next;	}	return -EINVAL;}#endif	/* CONFIG_MODULES */int open_inode(struct inode * inode, int mode){	int fd;	if (!inode->i_op || !inode->i_op->default_file_ops)		return -EINVAL;	fd = get_unused_fd();	if (fd >= 0) {		struct file * f = get_empty_filp();		if (!f) {			put_unused_fd(fd);			return -ENFILE;		}		f->f_flags = mode;		f->f_mode = (mode+1) & O_ACCMODE;		f->f_inode = inode;		f->f_pos = 0;		f->f_reada = 0;		f->f_op = inode->i_op->default_file_ops;		if (f->f_op->open) {			int error = f->f_op->open(inode,f);			if (error) {				f->f_count--;				put_unused_fd(fd);				return error;			}		}		current->files->fd[fd] = f;		inode->i_count++;	}	return fd;}/* * Note that a shared library must be both readable and executable due to * security reasons. * * Also note that we take the address to load from from the file itself. */asmlinkage int sys_uselib(const char * library){	int fd, retval;	struct file * file;	struct linux_binfmt * fmt;	fd = sys_open(library, 0, 0);	if (fd < 0)		return fd;	file = current->files->fd[fd];	retval = -ENOEXEC;	if (file && file->f_inode && file->f_op && file->f_op->read) {		for (fmt = formats ; fmt ; fmt = fmt->next) {			int (*fn)(int) = fmt->load_shlib;			if (!fn)				continue;			retval = fn(fd);			if (retval != -ENOEXEC)				break;		}	}	sys_close(fd);  	return retval;}/* * count() counts the number of arguments/envelopes * * We also do some limited EFAULT checking: this isn't complete, but * it does cover most cases. I'll have to do this correctly some day.. */static int count(char ** argv){	int error, i = 0;	char ** tmp, *p;	if ((tmp = argv) != NULL) {		error = verify_area(VERIFY_READ, tmp, sizeof(char *));		if (error)			return error;		while ((p = get_user(tmp++)) != NULL) {			i++;			error = verify_area(VERIFY_READ, p, 1);			if (error)				return error;		}	}	return i;}/* * 'copy_string()' copies argument/envelope strings from user * memory to free pages in kernel mem. These are in a format ready * to be put directly into the top of new user memory. * * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies * whether the string and the string array are from user or kernel segments: *  * from_kmem     argv *        argv ** *    0          user space    user space *    1          kernel space  user space *    2          kernel space  kernel space *  * We do this by playing games with the fs segment register.  Since it * is expensive to load a segment register, we try to avoid calling * set_fs() unless we absolutely have to. */unsigned long copy_strings(int argc,char ** argv,unsigned long *page,		unsigned long p, int from_kmem){	char *tmp, *tmp1, *pag = NULL;	int len, offset = 0;	unsigned long old_fs, new_fs;	if (!p)		return 0;	/* bullet-proofing */	new_fs = get_ds();	old_fs = get_fs();	if (from_kmem==2)		set_fs(new_fs);	while (argc-- > 0) {		if (from_kmem == 1)			set_fs(new_fs);		if (!(tmp1 = tmp = get_user(argv+argc)))			panic("VFS: argc is wrong");		if (from_kmem == 1)			set_fs(old_fs);		while (get_user(tmp++));		len = tmp - tmp1;		if (p < len) {	/* this shouldn't happen - 128kB */			set_fs(old_fs);			return 0;		}		while (len) {			--p; --tmp; --len;			if (--offset < 0) {				offset = p % PAGE_SIZE;				if (from_kmem==2)					set_fs(old_fs);				if (!(pag = (char *) page[p/PAGE_SIZE]) &&				    !(pag = (char *) page[p/PAGE_SIZE] =				      (unsigned long *) get_free_page(GFP_USER))) 					return 0;				if (from_kmem==2)					set_fs(new_fs);			}			if (len == 0 || offset == 0)			  *(pag + offset) = get_user(tmp);			else {			  int bytes_to_copy = (len > offset) ? offset : len;			  tmp -= bytes_to_copy;			  p -= bytes_to_copy;			  offset -= bytes_to_copy;			  len -= bytes_to_copy;			  memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);			}		}	}	if (from_kmem==2)		set_fs(old_fs);	return p;}unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm){	unsigned long stack_base;	struct vm_area_struct *mpnt;	int i;	stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;	p += stack_base;	if (bprm->loader)		bprm->loader += stack_base;	bprm->exec += stack_base;	mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);	if (mpnt) {		mpnt->vm_mm = current->mm;		mpnt->vm_start = PAGE_MASK & (unsigned long) p;		mpnt->vm_end = STACK_TOP;		mpnt->vm_page_prot = PAGE_COPY;		mpnt->vm_flags = VM_STACK_FLAGS;		mpnt->vm_ops = NULL;		mpnt->vm_offset = 0;		mpnt->vm_inode = NULL;		mpnt->vm_pte = 0;		insert_vm_struct(current->mm, mpnt);		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;	}	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {		if (bprm->page[i]) {			current->mm->rss++;			put_dirty_page(current,bprm->page[i],stack_base);		}		stack_base += PAGE_SIZE;	}	return p;}/* * Read in the complete executable. This is used for "-N" files * that aren't on a block boundary, and for files on filesystems * without bmap support. */int read_exec(struct inode *inode, unsigned long offset,	char * addr, unsigned long count, int to_kmem){	struct file file;	int result = -ENOEXEC;	if (!inode->i_op || !inode->i_op->default_file_ops)		goto end_readexec;	file.f_mode = 1;	file.f_flags = 0;	file.f_count = 1;	file.f_inode = inode;	file.f_pos = 0;	file.f_reada = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -