[root@localhost north]# cat dup.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
void file_dup1();
void file_dup2();
void file_dup3();
void main(int argc, char *argv[])
{
int fd = open("dup.txt", O_CREAT|O_RDWR|O_TRUNC);
close(fd);
switch (atoi(argv[1])) {
case 1: file_dup1(); break;
case 2: file_dup2(); break;
case 3: file_dup3(); break;
}
system("cat dup.txt");
}
void file_dup1()
{
int fd1 = open("dup.txt", O_RDWR);// current->files[fd1] = &file1
int fd2 = open("dup.txt", O_RDWR);// current->files[fd2] = &file2
write(fd1, "1", 1); // current->files[fd1]->f_op.write("1",1,current->files[fd1]->f_pos); current->files[fd1]->f_pos += 1;
write(fd2, "a", 1); // current->files[fd2]->f_op.write("a",1,current->files[fd2]->f_pos); current->files[fd2]->f_pos += 1;
write(fd1, "2", 1); // current->files[fd1]->f_op.write("2",1,current->files[fd1]->f_pos); current->files[fd1]->f_pos += 1;
write(fd2, "b", 1); // current->files[fd2]->f_op.write("b",1,current->files[fd2]->f_pos); current->files[fd2]->f_pos += 1;
write(fd1, "3", 1); // current->files[fd1]->f_op.write("3",1,current->files[fd1]->f_pos); current->files[fd1]->f_pos += 1;
write(fd2, "c", 1); // current->files[fd2]->f_op.write("c",1,current->files[fd2]->f_pos); current->files[fd2]->f_pos += 1;
write(fd1, "4\n", 2);// current->files[fd1]->f_op.write("4\n",2,current->files[fd1]->f_pos); current->files[fd1]->f_pos += 2;
}
void file_dup2()
{
int fd = open("dup.txt", O_RDWR);// current->files[fd] = &file
dup2(fd, 10); // current->files[10] = current->files[fd]
dup2(fd, 11); // current->files[11] = current->files[fd]
write(fd, "1", 1); // current->files[fd]->f_op.write("1",1,current->files[fd]->f_pos); current->files[fd]->f_pos += 1;
write(10, "a", 1); // current->files[10]->f_op.write("a",1,current->files[10]->f_pos); current->files[10]->f_pos += 1;
write(11, "A", 1); // current->files[11]->f_op.write("A",1,current->files[11]->f_pos); current->files[11]->f_pos += 1;
write(fd, "2", 1); // current->files[fd]->f_op.write("2",1,current->files[fd]->f_pos); current->files[fd]->f_pos += 1;
write(10, "b", 1); // current->files[10]->f_op.write("b",1,current->files[10]->f_pos); current->files[10]->f_pos += 1;
write(11, "B", 1); // current->files[11]->f_op.write("B",1,current->files[11]->f_pos); current->files[11]->f_pos += 1;
write(fd, "3\n", 2); // current->files[fd]->f_op.write("3\n",2,current->files[fd]->f_pos); current->files[fd]->f_pos += 2;
}
void file_dup3()
{
int fd = open("dup.txt", O_RDWR);// current->files[fd] = &file
dup2(fd, 10); // current->files[10] = current->files[fd]
dup2(10, 11); // current->files[11] = current->files[10]
write(fd, "1", 1); //current->files[fd]->f_op.write("1",1,current->files[fd]->f_pos); current->files[fd]->f_pos += 1;
write(10, "a", 1); //current->files[10]->f_op.write("a",1,current->files[10]->f_pos); current->files[10]->f_pos += 1;
write(11, "A", 1); //current->files[11]->f_op.write("A",1,current->files[11]->f_pos); current->files[11]->f_pos += 1;
write(fd, "2", 1); //current->files[fd]->f_op.write("2",1,current->files[fd]->f_pos); current->files[fd]->f_pos += 1;
write(10, "b", 1); //current->files[10]->f_op.write("b",1,current->files[10]->f_pos); current->files[10]->f_pos += 1;
write(11, "B", 1); //current->files[11]->f_op.write("B",1,current->files[11]->f_pos); current->files[11]->f_pos += 1;
write(fd, "3\n", 2); //current->files[fd]->f_op.write("3\n",2,current->files[fd]->f_pos); current->files[fd]->f_pos += 2;
}
[root@localhost north]# ./dup.out 1
abc4
[root@localhost north]# ./dup.out 2
1aA2bB3
[root@localhost north]# ./dup.out 3
1aA2bB3
コマンドで表示/エラーをファイルに出力するケースは、シェルマターでfile_dup3()での実装に相当。
[root@localhost north]# cat errout.c
#include <stdio.h>
#include <unistd.h>
void main()
{
write(1, "stdout\n", 7);
write(2, "errout\n", 7);
}
[root@localhost north]# ./errout.out 1>errout.txt 2>errout.txt // dup2(1. errout.txt);dup2(2, errout.txt)
[root@localhost north]# cat errout.txt
errout
[root@localhost north]# ./errout.out 2>&1 1>errout.txt // dup2(2, 1);dup2(1, errout.txt)
errout
[root@localhost north]# cat errout.txt
stdout
[root@localhost north]# ./errout.out 1>errout.txt 2>&1 // dup2(1, errout.txt);dup2(2, 1)
[root@localhost north]# cat errout.txt
stdout
errout
カーネル
struct file {
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
spinlock_t f_lock;
#ifdef CONFIG_SMP
int f_sb_list_cpu;
#endif
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_state f_ra;
u64 f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
void *private_data;
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
struct list_head f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
};
const struct file_operations ext3_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.unlocked_ioctl = ext3_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext3_compat_ioctl,
#endif
.mmap = generic_file_mmap,
.open = dquot_file_open,
.release = ext3_release_file,
.fsync = ext3_sync_file,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
};
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
long ret;
if (force_o_largefile())
flags |= O_LARGEFILE;
ret = do_sys_open(AT_FDCWD, filename, flags, mode);
asmlinkage_protect(3, ret, filename, flags, mode);
return ret;
}
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
struct filename *tmp = getname(filename);
int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op, lookup);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fsnotify_open(f);
fd_install(fd, f);
}
}
putname(tmp);
}
return fd;
}
struct file *do_filp_open(int dfd, struct filename *pathname,
const struct open_flags *op, int flags)
{
struct nameidata nd;
struct file *filp;
filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
if (unlikely(filp == ERR_PTR(-ECHILD)))
filp = path_openat(dfd, pathname, &nd, op, flags);
if (unlikely(filp == ERR_PTR(-ESTALE)))
filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL);
return filp;
}
void fd_install(unsigned int fd, struct file *file)
{
__fd_install(current->files, fd, file);
}
struct fd {
struct file *file;
int need_put;
};
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
size_t, count)
{
struct fd f = fdget(fd);
ssize_t ret = -EBADF;
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_write(f.file, buf, count, &pos);
file_pos_write(f.file, pos);
fdput(f);
}
return ret;
}
static inline struct fd fdget(unsigned int fd)
{
int b;
struct file *f = fget_light(fd, &b);
return (struct fd){f,b};
}
static inline loff_t file_pos_read(struct file *file)
{
return file->f_pos;
}
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
if (!(file->f_mode & FMODE_WRITE))
return -EBADF;
if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
return -EINVAL;
if (unlikely(!access_ok(VERIFY_READ, buf, count)))
return -EFAULT;
ret = rw_verify_area(WRITE, file, pos, count);
if (ret >= 0) {
count = ret;
if (file->f_op->write)
ret = file->f_op->write(file, buf, count, pos);
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0) {
fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
}
return ret;
}
static inline void file_pos_write(struct file *file, loff_t pos)
{
file->f_pos = pos;
}
asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
{
int err = -EBADF;
struct file * file, *tofree;
struct files_struct * files = current->files;
spin_lock(&files->file_lock);
if (!(file = fcheck(oldfd)))
goto out_unlock;
err = newfd;
if (newfd == oldfd)
goto out_unlock;
err = -EBADF;
if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
goto out_unlock;
get_file(file); /* We are now finished with oldfd */
err = expand_files(files, newfd);
if (err < 0)
goto out_fput;
err = -EBUSY;
tofree = files->fd[newfd];
if (!tofree && FD_ISSET(newfd, files->open_fds))
goto out_fput;
files->fd[newfd] = file;
FD_SET(newfd, files->open_fds);
FD_CLR(newfd, files->close_on_exec);
spin_unlock(&files->file_lock);
if (tofree)
filp_close(tofree, files);
err = newfd;
out:
return err;
out_unlock:
spin_unlock(&files->file_lock);
goto out;
out_fput:
spin_unlock(&files->file_lock);
fput(file);
goto out;
}
備考
リダイレクトは運用上の名称で、実装上の名称は重複(duplicate)です。