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;
}

備考

リダイレクトは運用上の名称で、実装上の名称は重複(duplicate)です。

最終更新 2017/06/08 21:02:37 - north
(2014/08/04 18:34:01 作成)


検索

アクセス数
3690614
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。