dupシステムコール(リダイレクト)
Rev.6を表示中。最新版はこちら。
[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; }