dup 系统调用的奇怪行为
Strange behavior of dup system call
所以,我在 Linux 中阅读了有关文件 I/O 的内容,并考虑使用它。但是,我在代码中遇到了两个 st运行ge 行为,我正在努力寻找它们的原因。
/*
* This program shows the usage of dup and dup2 functions
*/
#include "creep.h"
#include <fcntl.h>
#define BUFSIZE 2048
int main(int argc, char *argv[]) {
int fd, dup_fd, n;
char buf[BUFSIZE], buff[BUFSIZE];
if (argc != 2)
err_quit("Usage: dup <filename>\n");
fd = open(argv[1], O_RDWR);
while ((n = read(fd, buf, BUFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
dup_fd = dup(fd);
while ((n = read(dup_fd, buff, BUFSIZE)) > 0)
if (write(STDOUT_FILENO, buff, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
printf("\nValues are : %d and %d\n", fd, dup_fd);
close(fd);
exit(0);
}
现在,当我 运行 这个程序时 :-
# ./dup dup.c
它实际上只打印文件一次,而不是针对第二个重复的描述符。
我 运行 上面的 strace 希望找出发生了什么但我只能看到这个 ->
open("dup.c", O_RDWR) = 3
read(3, "/*\n * This program shows the usa"..., 2048) = 708
write(1, "/*\n * This program shows the usa"..., 708/
------------omitting the file from trace-------------
read(3, "", 2048) = 0
dup(3) = 4
read(4, "", 2048) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f170112d000
write(1, "\n", 1
) = 1
write(1, "Values are : 3 and 4\n", 21Values are : 3 and 4
) = 21
close(3)
第一次在 fd
上调用 read/write 时,缓冲区中有文件内容,这有点奇怪。但是对于 dup_fd
,缓冲区是空的。我不知道为什么会这样。以前,我两次都使用相同的缓冲区,我认为我应该使用单独的缓冲区但无济于事。
我读到 dup
函数给出了最小编号的可用文件描述符,它是原始文件描述符的副本。在进程 Table 条目中的文件指针指向文件描述符的同一文件 table 的意义上是重复的。
为什么我无法读取具有重复文件描述符的文件。我做错了什么吗?
creep.h
头文件:-
/*
* My own header, to be included before all standard system headers written by me.
*/
#ifndef _CREEP_H
#define _CREEP_H
#define _POSIX_C_SOURCE 200809L
#if defined(SOLARIS)
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 700
#endif
#include <sys/types.h> /* some systems will require this */
#include <sys/stat.h>
#include <sys/termios.h> /* for winsize */
#if defined(MACOS) || !defined(TIOCGWINSZ)
#include <sys/ioctl.h>
#endif
#include <stdio.h> /* for convenience */
#include <stdlib.h> /* for convenience */
#include <stddef.h> /* for offsetof */
#include <string.h> /* for convenience */
#include <unistd.h> /* for convenience */
#include <signal.h> /* for SIG_ERR */
#include <errno.h> /* for definition of errno */
#include <stdarg.h> /* ISO C variable arguments */
#include <syslog.h> /* for convenience */
#define MAXLINE 4096 /* max line length */
/*
* Default file access permissions for new files.
*/
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/*
* Default permissions for new directories.
*/
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | SIXOTH)
typedef void Sigfunc(int); /* for signal handlers */
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
/*
* Prototypes for my own functions.
*/
char *path_alloc(size_t *);
long open_max(void);
int set_cloexec(int);
void clr_fl(int, int);
void set_fl(int, int);
void pr_exit(int);
void pr_mask(const char *);
Sigfunc *signal_intr(int, Sigfunc *);
void daemonize(const char *);
void sleep_us(unsigned int);
ssize_t readn(int, void *, size_t);
ssize_t writen(int, const void *, size_t);
int fd_pipe(int *);
int recv_fd(int, ssize_t (*func) (int, const void *, size_t));
int send_fd(int, int);
int send_err(int, int, const char *);
int serv_listen(const char *);
int serv_accept(int, uid_t *);
int cli_conn(const char *);
int buf_args(char *, int (*func)(int, char **));
int tty_cbreak(int);
int tty_raw(int);
int tty_reset(int);
void tty_atexit(void);
struct termios *tty_termios(void);
int ptym_open(char *, int);
int ptys_open(char *);
#ifdef TIOCGWINSZ
pid_t pty_fork(int *, char *, int, const struct termios *, const struct winsize *);
#endif
int lock_reg(int, int, int, off_t, int, off_t);
#define read_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lcok(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
pid_t lock_test(int, int, off_t, int, off_t);
#define is_read_lockable(fd, offset, whence, len) \
(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define is_write_lockable(fd, offset, whence, len) \
(lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)
void err_msg(const char *, ...);
void err_dump(const char *, ...) __attribute__((noreturn));
void err_quit(const char *, ...) __attribute__((noreturn));
void err_cont(int, const char *, ...);
void err_exit(int, const char *, ...) __attribute__((noreturn));
void err_ret(const char *, ...);
void err_sys(const char *, ...) __attribute__((noreturn));
void log_msg(const char *, ...);
void log_open(const char *, int, int);
void log_quit(const char *, ...) __attribute__((noreturn));
void log_ret(const char *, ...);
void log_sys(const char *, ...) __attribute__((noreturn));
void log_exit(int, const char *, ...) __attribute__((noreturn));
void TELL_WAIT(void);
void TELL_PARENT(pid_t);
void TELL_CHILD(pid_t);
void WAIT_PARENT(void);
void WAIT_CHILD(void);
/*
* ERROR Function Definitions
*/
static void err_doit(int, int, const char *, va_list);
/*
* Nonfatal error rleated to a system call.
* Print a message and return.
*/
void err_ret(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
}
/*
* Fata error related to a system call.
* Print a message and terminate.
*/
void err_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Nonfatal error unrealted to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void err_cont(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
}
/*
* Fatal error unrelated to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void err_exit(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Fatal error related to a system call.
* Print a message, dump core and terminate.
*/
void err_dump(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
abort(); /* dump core and terminate */
exit(1); /* shouldn't get here */
}
/*
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void err_msg(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
}
/*
* Fatale error unrelated to a system call.
* Print a message and terminate.
*/
void err_quit(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap) {
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
if (errnoflag)
snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s", strerror(error));
strcat(buf, "\n");
fflush(stdout);
fputs(buf, stderr);
fflush(NULL);
}
#if 0
/*
* ERROR Routines for programs that can run as a Daemon.
* Commented out because of undefined reference of log_to_stderr.
*/
static void log_doit(int, int, int, const char *, va_list ap);
/*
* Caller must define and set this: nonzero if
* interactive, zero if daemon
*/
extern int log_to_stderr;
/*
* Initialize syslog(), if running as daemon.
*/
void log_open(const char *ident, int option, int facility) {
if (log_to_stderr == 0)
openlog(ident, option, facility);
}
/*
* Nonfatal error rleated to a system call.
* Print a message with the systems' errno value and return.
*/
void log_ret(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, errno, LOG_ERR, fmt, ap);
va_end(ap);
}
/*
* Fata error related to a system call.
* Print a message and terminate.
*/
void log_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, errno, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Fatal error unrelated to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void log_exit(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, error, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void log_msg(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(0, 0, LOG_ERR, fmt, ap);
va_end(ap);
}
/*
* Fatale error unrelated to a system call.
* Print a message and terminate.
*/
void log_quit(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(0, 0, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void log_doit(int errnoflag, int error, int priority, const char *fmt, va_list ap) {
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
if (errnoflag)
snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s", strerror(error));
strcat(buf, "\n");
if (log_to_stderr) {
fflush(stdout);
fputs(buf, stderr);
fflush(stderr);
} else {
syslog(priority, "%s", buf);
}
}
#endif
#endif /* _CREEP_H */
当您到达 dup
时,您的第一个循环已经结束。
为什么结束了?因为你阅读了一切。 fd
在文件末尾。
然后你复制它。现在您有 2 个 fd
引用同一个文件对象("open file description" 在 POSIX 术语中)。它们在文件末尾 。
您需要倒回 (lseek(dup_fd, 0, SEEK_SET)
) 才能再次阅读该文件。请注意,查找是对文件对象的操作,因此它会影响两个 fd
。您可以搜索 fd
到位置 0,然后从 dup_fd
读取并再次读取内容。
您甚至可以在调用 read(fd,...)
和 read(dup_fd,...)
之间交替调用,如果您只是在阅读时打印每个块,您仍然会按顺序获取文件内容。
这是预期的行为。 The POSIX documentation for dup()
状态:
The dup()
function provides an alternative interface to the service
provided by fcntl()
using the F_DUPFD
command. The call
dup(fildes)
shall be equivalent to:
fcntl(fildes, F_DUPFD, 0);
F_DUPFD
Return a new file descriptor which shall be allocated as described in
File Descriptor Allocation, except that it shall be the lowest
numbered available file descriptor greater than or equal to the third
argument, arg
, taken as an integer of type int
. The new file
descriptor shall refer to the same open file description as the
original file descriptor, and shall share any locks. The FD_CLOEXEC
flag associated with the new file descriptor shall be cleared to keep
the file open across calls to one of the exec functions.
注意粗体部分:"same open file description"。
这意味着 dup()
的文件描述符与其 dup()
的来源共享相同的当前文件偏移量。
并且您已经通过读取文件中的所有数据将该偏移量设置为文件末尾。
所以,我在 Linux 中阅读了有关文件 I/O 的内容,并考虑使用它。但是,我在代码中遇到了两个 st运行ge 行为,我正在努力寻找它们的原因。
/*
* This program shows the usage of dup and dup2 functions
*/
#include "creep.h"
#include <fcntl.h>
#define BUFSIZE 2048
int main(int argc, char *argv[]) {
int fd, dup_fd, n;
char buf[BUFSIZE], buff[BUFSIZE];
if (argc != 2)
err_quit("Usage: dup <filename>\n");
fd = open(argv[1], O_RDWR);
while ((n = read(fd, buf, BUFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
dup_fd = dup(fd);
while ((n = read(dup_fd, buff, BUFSIZE)) > 0)
if (write(STDOUT_FILENO, buff, n) != n)
err_sys("write error");
if (n < 0)
err_sys("read error");
printf("\nValues are : %d and %d\n", fd, dup_fd);
close(fd);
exit(0);
}
现在,当我 运行 这个程序时 :-
# ./dup dup.c
它实际上只打印文件一次,而不是针对第二个重复的描述符。
我 运行 上面的 strace 希望找出发生了什么但我只能看到这个 ->
open("dup.c", O_RDWR) = 3
read(3, "/*\n * This program shows the usa"..., 2048) = 708
write(1, "/*\n * This program shows the usa"..., 708/
------------omitting the file from trace-------------
read(3, "", 2048) = 0
dup(3) = 4
read(4, "", 2048) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f170112d000
write(1, "\n", 1
) = 1
write(1, "Values are : 3 and 4\n", 21Values are : 3 and 4
) = 21
close(3)
第一次在 fd
上调用 read/write 时,缓冲区中有文件内容,这有点奇怪。但是对于 dup_fd
,缓冲区是空的。我不知道为什么会这样。以前,我两次都使用相同的缓冲区,我认为我应该使用单独的缓冲区但无济于事。
我读到 dup
函数给出了最小编号的可用文件描述符,它是原始文件描述符的副本。在进程 Table 条目中的文件指针指向文件描述符的同一文件 table 的意义上是重复的。
为什么我无法读取具有重复文件描述符的文件。我做错了什么吗?
creep.h
头文件:-
/*
* My own header, to be included before all standard system headers written by me.
*/
#ifndef _CREEP_H
#define _CREEP_H
#define _POSIX_C_SOURCE 200809L
#if defined(SOLARIS)
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 700
#endif
#include <sys/types.h> /* some systems will require this */
#include <sys/stat.h>
#include <sys/termios.h> /* for winsize */
#if defined(MACOS) || !defined(TIOCGWINSZ)
#include <sys/ioctl.h>
#endif
#include <stdio.h> /* for convenience */
#include <stdlib.h> /* for convenience */
#include <stddef.h> /* for offsetof */
#include <string.h> /* for convenience */
#include <unistd.h> /* for convenience */
#include <signal.h> /* for SIG_ERR */
#include <errno.h> /* for definition of errno */
#include <stdarg.h> /* ISO C variable arguments */
#include <syslog.h> /* for convenience */
#define MAXLINE 4096 /* max line length */
/*
* Default file access permissions for new files.
*/
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/*
* Default permissions for new directories.
*/
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | SIXOTH)
typedef void Sigfunc(int); /* for signal handlers */
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
/*
* Prototypes for my own functions.
*/
char *path_alloc(size_t *);
long open_max(void);
int set_cloexec(int);
void clr_fl(int, int);
void set_fl(int, int);
void pr_exit(int);
void pr_mask(const char *);
Sigfunc *signal_intr(int, Sigfunc *);
void daemonize(const char *);
void sleep_us(unsigned int);
ssize_t readn(int, void *, size_t);
ssize_t writen(int, const void *, size_t);
int fd_pipe(int *);
int recv_fd(int, ssize_t (*func) (int, const void *, size_t));
int send_fd(int, int);
int send_err(int, int, const char *);
int serv_listen(const char *);
int serv_accept(int, uid_t *);
int cli_conn(const char *);
int buf_args(char *, int (*func)(int, char **));
int tty_cbreak(int);
int tty_raw(int);
int tty_reset(int);
void tty_atexit(void);
struct termios *tty_termios(void);
int ptym_open(char *, int);
int ptys_open(char *);
#ifdef TIOCGWINSZ
pid_t pty_fork(int *, char *, int, const struct termios *, const struct winsize *);
#endif
int lock_reg(int, int, int, off_t, int, off_t);
#define read_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lcok(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
pid_t lock_test(int, int, off_t, int, off_t);
#define is_read_lockable(fd, offset, whence, len) \
(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define is_write_lockable(fd, offset, whence, len) \
(lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)
void err_msg(const char *, ...);
void err_dump(const char *, ...) __attribute__((noreturn));
void err_quit(const char *, ...) __attribute__((noreturn));
void err_cont(int, const char *, ...);
void err_exit(int, const char *, ...) __attribute__((noreturn));
void err_ret(const char *, ...);
void err_sys(const char *, ...) __attribute__((noreturn));
void log_msg(const char *, ...);
void log_open(const char *, int, int);
void log_quit(const char *, ...) __attribute__((noreturn));
void log_ret(const char *, ...);
void log_sys(const char *, ...) __attribute__((noreturn));
void log_exit(int, const char *, ...) __attribute__((noreturn));
void TELL_WAIT(void);
void TELL_PARENT(pid_t);
void TELL_CHILD(pid_t);
void WAIT_PARENT(void);
void WAIT_CHILD(void);
/*
* ERROR Function Definitions
*/
static void err_doit(int, int, const char *, va_list);
/*
* Nonfatal error rleated to a system call.
* Print a message and return.
*/
void err_ret(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
}
/*
* Fata error related to a system call.
* Print a message and terminate.
*/
void err_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Nonfatal error unrealted to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void err_cont(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
}
/*
* Fatal error unrelated to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void err_exit(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, error, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Fatal error related to a system call.
* Print a message, dump core and terminate.
*/
void err_dump(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
abort(); /* dump core and terminate */
exit(1); /* shouldn't get here */
}
/*
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void err_msg(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
}
/*
* Fatale error unrelated to a system call.
* Print a message and terminate.
*/
void err_quit(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(0, 0, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap) {
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
if (errnoflag)
snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s", strerror(error));
strcat(buf, "\n");
fflush(stdout);
fputs(buf, stderr);
fflush(NULL);
}
#if 0
/*
* ERROR Routines for programs that can run as a Daemon.
* Commented out because of undefined reference of log_to_stderr.
*/
static void log_doit(int, int, int, const char *, va_list ap);
/*
* Caller must define and set this: nonzero if
* interactive, zero if daemon
*/
extern int log_to_stderr;
/*
* Initialize syslog(), if running as daemon.
*/
void log_open(const char *ident, int option, int facility) {
if (log_to_stderr == 0)
openlog(ident, option, facility);
}
/*
* Nonfatal error rleated to a system call.
* Print a message with the systems' errno value and return.
*/
void log_ret(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, errno, LOG_ERR, fmt, ap);
va_end(ap);
}
/*
* Fata error related to a system call.
* Print a message and terminate.
*/
void log_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, errno, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Fatal error unrelated to a system call.
* Error code passed as explicit parameter.
* Print a message and return.
*/
void log_exit(int error, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(1, error, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void log_msg(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(0, 0, LOG_ERR, fmt, ap);
va_end(ap);
}
/*
* Fatale error unrelated to a system call.
* Print a message and terminate.
*/
void log_quit(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
log_doit(0, 0, LOG_ERR, fmt, ap);
va_end(ap);
exit(2);
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void log_doit(int errnoflag, int error, int priority, const char *fmt, va_list ap) {
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
if (errnoflag)
snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s", strerror(error));
strcat(buf, "\n");
if (log_to_stderr) {
fflush(stdout);
fputs(buf, stderr);
fflush(stderr);
} else {
syslog(priority, "%s", buf);
}
}
#endif
#endif /* _CREEP_H */
当您到达 dup
时,您的第一个循环已经结束。
为什么结束了?因为你阅读了一切。 fd
在文件末尾。
然后你复制它。现在您有 2 个 fd
引用同一个文件对象("open file description" 在 POSIX 术语中)。它们在文件末尾 。
您需要倒回 (lseek(dup_fd, 0, SEEK_SET)
) 才能再次阅读该文件。请注意,查找是对文件对象的操作,因此它会影响两个 fd
。您可以搜索 fd
到位置 0,然后从 dup_fd
读取并再次读取内容。
您甚至可以在调用 read(fd,...)
和 read(dup_fd,...)
之间交替调用,如果您只是在阅读时打印每个块,您仍然会按顺序获取文件内容。
这是预期的行为。 The POSIX documentation for dup()
状态:
The
dup()
function provides an alternative interface to the service provided byfcntl()
using theF_DUPFD
command. The calldup(fildes)
shall be equivalent to:fcntl(fildes, F_DUPFD, 0);
F_DUPFD
Return a new file descriptor which shall be allocated as described in File Descriptor Allocation, except that it shall be the lowest numbered available file descriptor greater than or equal to the third argument,
arg
, taken as an integer of typeint
. The new file descriptor shall refer to the same open file description as the original file descriptor, and shall share any locks. TheFD_CLOEXEC
flag associated with the new file descriptor shall be cleared to keep the file open across calls to one of the exec functions.
注意粗体部分:"same open file description"。
这意味着 dup()
的文件描述符与其 dup()
的来源共享相同的当前文件偏移量。
并且您已经通过读取文件中的所有数据将该偏移量设置为文件末尾。