예제 #1
0
asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
	int err = -EBADF;

	lock_kernel();
#ifdef FDSET_DEBUG	
	printk (KERN_ERR __FUNCTION__ " 0: oldfd = %d, newfd = %d\n", 
		oldfd, newfd);
#endif
	if (!fcheck(oldfd))
		goto out;
	if (newfd >= NR_OPEN)
		goto out;	/* following POSIX.1 6.2.1 */

	err = newfd;
	if (newfd == oldfd)
		goto out;

	/* We must be able to do the fd setting inside dupfd() without
           blocking after the sys_close(). */
	if ((err = expand_files(current->files, newfd)) < 0)
		goto out;
	
	sys_close(newfd);
	err = dupfd(oldfd, newfd);
out:
#ifdef FDSET_DEBUG	
	printk (KERN_ERR __FUNCTION__ ": return %d\n", err);
#endif
	unlock_kernel();
	return err;
}
예제 #2
0
static inline int dupfd(unsigned int fd, unsigned int start)
{
	struct files_struct * files = current->files;
	struct file * file;
	unsigned int newfd;
	int error;

	error = -EINVAL;
	if (start >= NR_OPEN)
		goto out;

	error = -EBADF;
	file = fget(fd);
	if (!file)
		goto out;

repeat:
	error = -EMFILE;
	if (start < files->next_fd)
		start = files->next_fd;
	/* At this point, start MUST be <= max_fdset */
#if 1
	if (start > files->max_fdset)
		printk (KERN_ERR "dupfd: fd %d, max %d\n", 
			start, files->max_fdset);
#endif
	newfd = find_next_zero_bit(files->open_fds->fds_bits, 
				files->max_fdset,
				start);
	if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
		goto out_putf;

	error = expand_files(files, newfd);
	if (error < 0)
		goto out_putf;
	if (error) /* If we might have blocked, try again. */
		goto repeat;

	FD_SET(newfd, files->open_fds);
	FD_CLR(newfd, files->close_on_exec);
	if (start <= files->next_fd)
		files->next_fd = newfd + 1;
	fd_install(newfd, file);
	error = newfd;
out:
#ifdef FDSET_DEBUG	
	if (error < 0)
		printk (KERN_ERR __FUNCTION__ ": return %d\n", error);
#endif
	return error;

out_putf:
	fput(file);
	goto out;
}
예제 #3
0
/* Install a given filp in a given files_struct, with CLOEXEC set.
 * Safe for files != current->files.
 * Mostly cut-and-paste from linux-2.6.0/fs/fcntl.c:locate_fd()
 */
int cr_dup_other(struct files_struct *files, struct file *filp)
{
    unsigned int newfd;
    unsigned int start;
    unsigned int max_fds;
    int error;
    cr_fdtable_t *fdt;

    spin_lock(&files->file_lock);

repeat: 
    fdt = cr_fdtable(files);
    start = CR_NEXT_FD(files, fdt);
    newfd = start;
    max_fds = CR_MAX_FDS(fdt);
    if (start < max_fds) {
	newfd = find_next_zero_bit(CR_OPEN_FDS_BITS(fdt),
				   max_fds, start);
    }

    /* XXX: Really shouldn't be using current here.
     * However, I haven't bothered to figure out the locking
     * requirements for using anything else.
     * XXX: Probably could just pass the limit in.
     * XXX: Later kernels push this into expand_files()
     */
    error = -EMFILE;
    if (newfd >= CR_RLIM(current)[RLIMIT_NOFILE].rlim_cur) {
	goto out;
    }

    error = expand_files(files, newfd);
    if (error < 0) {
	goto out;
    } else if (error) {
	/* grew - search again (also reacquires fdt) */
	goto repeat;
    }

    CR_NEXT_FD(files, fdt) = newfd + 1;

    /* Claim */
    cr_set_open_fd(newfd, fdt);
    cr_set_close_on_exec(newfd, fdt);

    /* Install */
    get_file(filp);
    rcu_assign_pointer(fdt->fd[newfd], filp);

    error = newfd;
    
out:
    spin_unlock(&files->file_lock);
    return error;
}
예제 #4
0
파일: open.c 프로젝트: 274914765/C
/*
 * Find an empty file descriptor entry, and mark it busy.
 */
int get_unused_fd_flags(int flags)
{
    struct files_struct * files = current->files;
    int fd, error;
    struct fdtable *fdt;

      error = -EMFILE;
    spin_lock(&files->file_lock);

repeat:
    fdt = files_fdtable(files);
    fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
                files->next_fd);

    /*
     * N.B. For clone tasks sharing a files structure, this test
     * will limit the total number of files that can be opened.
     */
    if (fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
        goto out;

    /* Do we need to expand the fd array or fd set?  */
    error = expand_files(files, fd);
    if (error < 0)
        goto out;

    if (error) {
        /*
          * If we needed to expand the fs array we
         * might have blocked - try again.
         */
        error = -EMFILE;
        goto repeat;
    }

    FD_SET(fd, fdt->open_fds);
    if (flags & O_CLOEXEC)
        FD_SET(fd, fdt->close_on_exec);
    else
        FD_CLR(fd, fdt->close_on_exec);
    files->next_fd = fd + 1;
#if 1
    /* Sanity check */
    if (fdt->fd[fd] != NULL) {
        printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
        fdt->fd[fd] = NULL;
    }
#endif
    error = fd;

out:
    spin_unlock(&files->file_lock);
    return error;
}
예제 #5
0
/**
 * @brief Program entry point
 * @details reads options and arguments with getopt and calls the appropriate
 * expand function.
 *
 * @param argc The argument counter
 * @param argv The argument vector
 * @return 0 on success; otherwise non-zero
 */
int main(int argc, char **argv)
{
    int c;
    while((c = getopt(argc, argv, shortopts)) != -1)
    {
        switch(c)
        {
            case 't':
                if(ISDIGIT(*optarg))
                {
                    tabstop = strtol(optarg, NULL, 0);
                    if(tabstop == 0)
                    {
                        // TODO: errorhandling
                        (void) printf("tabstop cannot be 0");
                        return 1;
                    }
                }
                else
                {
                    // TODO: errorhandling
                    (void) printf("NaN");
                    return 1;
                }
                break;

            case ':':
                // TODO: errorhandling
                (void) printf("case ':'");
                return 1;

            case '?':
                // TODO: errorhandling
                (void) printf("case '?'");
                return 1;

            default:
                assert(0);
        }
    }

    char error = 0;

    if(optind < argc)
    {
        file_list = &argv[optind];
        error = expand_files();
    }
    else
        error = expand_stdin();

    return error;
}
예제 #6
0
static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
{
	struct files_struct *oldf, *newf;
	struct file **old_fds, **new_fds;
	int open_files, size, i, error = 0, expand;

	/*
	 * A background process may not have any files ...
	 */
	oldf = current->files;
	if (!oldf)
		goto out;

	if (clone_flags & CLONE_FILES) {
		atomic_inc(&oldf->count);
		goto out;
	}

	/*
	 * Note: we may be using current for both targets (See exec.c)
	 * This works because we cache current->files (old) as oldf. Don't
	 * break this.
	 */
	tsk->files = NULL;
	error = -ENOMEM;
	newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL);
	if (!newf) 
		goto out;

	atomic_set(&newf->count, 1);

	spin_lock_init(&newf->file_lock);
	newf->next_fd	    = 0;
	newf->max_fds	    = NR_OPEN_DEFAULT;
	newf->max_fdset	    = __FD_SETSIZE;
	newf->close_on_exec = &newf->close_on_exec_init;
	newf->open_fds	    = &newf->open_fds_init;
	newf->fd	    = &newf->fd_array[0];

	spin_lock(&oldf->file_lock);

	open_files = count_open_files(oldf, oldf->max_fdset);
	expand = 0;

	/*
	 * Check whether we need to allocate a larger fd array or fd set.
	 * Note: we're not a clone task, so the open count won't  change.
	 */
	if (open_files > newf->max_fdset) {
		newf->max_fdset = 0;
		expand = 1;
	}
	if (open_files > newf->max_fds) {
		newf->max_fds = 0;
		expand = 1;
	}

	/* if the old fdset gets grown now, we'll only copy up to "size" fds */
	if (expand) {
		spin_unlock(&oldf->file_lock);
		spin_lock(&newf->file_lock);
		error = expand_files(newf, open_files-1);
		spin_unlock(&newf->file_lock);
		if (error < 0)
			goto out_release;
		spin_lock(&oldf->file_lock);
	}

	old_fds = oldf->fd;
	new_fds = newf->fd;

	memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, open_files/8);
	memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, open_files/8);

	for (i = open_files; i != 0; i--) {
		struct file *f = *old_fds++;
		if (f) {
			get_file(f);
		} else {
			/*
			 * The fd may be claimed in the fd bitmap but not yet
			 * instantiated in the files array if a sibling thread
			 * is partway through open().  So make sure that this
			 * fd is available to the new process.
			 */
			FD_CLR(open_files - i, newf->open_fds);
		}
		*new_fds++ = f;
	}
	spin_unlock(&oldf->file_lock);

	/* compute the remainder to be cleared */
	size = (newf->max_fds - open_files) * sizeof(struct file *);

	/* This is long word aligned thus could use a optimized version */ 
	memset(new_fds, 0, size); 

	if (newf->max_fdset > open_files) {
		int left = (newf->max_fdset-open_files)/8;
		int start = open_files / (8 * sizeof(unsigned long));

		memset(&newf->open_fds->fds_bits[start], 0, left);
		memset(&newf->close_on_exec->fds_bits[start], 0, left);
	}

	tsk->files = newf;
	error = 0;
out:
	return error;

out_release:
	free_fdset (newf->close_on_exec, newf->max_fdset);
	free_fdset (newf->open_fds, newf->max_fdset);
	free_fd_array(newf->fd, newf->max_fds);
	kmem_cache_free(files_cachep, newf);
	goto out;
}
예제 #7
0
/*
 * Allocate a new files structure and copy contents from the
 * passed in files structure.
 * errorp will be valid only when the returned files_struct is NULL.
 */
static struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
{
	struct files_struct *newf;
	struct file **old_fds, **new_fds;
	int open_files, size, i, expand;
	struct fdtable *old_fdt, *new_fdt;

	*errorp = -ENOMEM;
	newf = alloc_files();
	if (!newf)
		goto out;

	spin_lock(&oldf->file_lock);
	old_fdt = files_fdtable(oldf);
	new_fdt = files_fdtable(newf);
	size = old_fdt->max_fdset;
	open_files = count_open_files(old_fdt);
	expand = 0;

	/*
	 * Check whether we need to allocate a larger fd array or fd set.
	 * Note: we're not a clone task, so the open count won't  change.
	 */
	if (open_files > new_fdt->max_fdset) {
		new_fdt->max_fdset = 0;
		expand = 1;
	}
	if (open_files > new_fdt->max_fds) {
		new_fdt->max_fds = 0;
		expand = 1;
	}

	/* if the old fdset gets grown now, we'll only copy up to "size" fds */
	if (expand) {
		spin_unlock(&oldf->file_lock);
		spin_lock(&newf->file_lock);
		*errorp = expand_files(newf, open_files-1);
		spin_unlock(&newf->file_lock);
		if (*errorp < 0)
			goto out_release;
		new_fdt = files_fdtable(newf);
		/*
		 * Reacquire the oldf lock and a pointer to its fd table
		 * who knows it may have a new bigger fd table. We need
		 * the latest pointer.
		 */
		spin_lock(&oldf->file_lock);
		old_fdt = files_fdtable(oldf);
	}

	old_fds = old_fdt->fd;
	new_fds = new_fdt->fd;

	memcpy(new_fdt->open_fds->fds_bits, old_fdt->open_fds->fds_bits, open_files/8);
	memcpy(new_fdt->close_on_exec->fds_bits, old_fdt->close_on_exec->fds_bits, open_files/8);

	for (i = open_files; i != 0; i--) {
		struct file *f = *old_fds++;
		if (f) {
			get_file(f);
		} else {
			/*
			 * The fd may be claimed in the fd bitmap but not yet
			 * instantiated in the files array if a sibling thread
			 * is partway through open().  So make sure that this
			 * fd is available to the new process.
			 */
			FD_CLR(open_files - i, new_fdt->open_fds);
		}
		rcu_assign_pointer(*new_fds++, f);
	}
	spin_unlock(&oldf->file_lock);

	/* compute the remainder to be cleared */
	size = (new_fdt->max_fds - open_files) * sizeof(struct file *);

	/* This is long word aligned thus could use a optimized version */ 
	memset(new_fds, 0, size); 

	if (new_fdt->max_fdset > open_files) {
		int left = (new_fdt->max_fdset-open_files)/8;
		int start = open_files / (8 * sizeof(unsigned long));

		memset(&new_fdt->open_fds->fds_bits[start], 0, left);
		memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);
	}

out:
	return newf;

out_release:
	free_fdset (new_fdt->close_on_exec, new_fdt->max_fdset);
	free_fdset (new_fdt->open_fds, new_fdt->max_fdset);
	free_fd_array(new_fdt->fd, new_fdt->max_fds);
	kmem_cache_free(files_cachep, newf);
	return NULL;
}
예제 #8
0
static int task_get_unused_fd_flags(struct shfile_proc *proc, int flags)
{
	struct files_struct *files = proc->files;
	int fd, error;
	struct fdtable *fdt;
	unsigned long rlim_cur;
	unsigned long irqs;

	if (files == NULL)
		return -ESRCH;

	error = -EMFILE;
	spin_lock(&files->file_lock);

repeat:
	fdt = files_fdtable(files);
	fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, files->next_fd);

	/*
	 * N.B. For clone tasks sharing a files structure, this test
	 * will limit the total number of files that can be opened.
	 */
	rlim_cur = 0;
	if (lock_task_sighand(proc->tsk, &irqs)) {
		rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur;
		unlock_task_sighand(proc->tsk, &irqs);
	}
	if (fd >= rlim_cur)
		goto out;

	/* Do we need to expand the fd array or fd set?  */
	error = expand_files(files, fd);
	if (error < 0)
		goto out;

	if (error) {
		/*
		 * If we needed to expand the fs array we
		 * might have blocked - try again.
		 */
		error = -EMFILE;
		goto repeat;
	}

	__set_open_fd(fd, fdt);
	if (flags & O_CLOEXEC)
		__set_close_on_exec(fd, fdt);
	else
		__clear_close_on_exec(fd, fdt);
	files->next_fd = fd + 1;
#if 1
	/* Sanity check */
	if (fdt->fd[fd] != NULL) {
		printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
		fdt->fd[fd] = NULL;
	}
#endif
	error = fd;

out:
	spin_unlock(&files->file_lock);
	return error;
}