Hello, I am trying to write a tee filter in C language, almost like the UNIX utility. But I have no idea where to begin can anybody give me a direction I should start in.

Dani AI

Generated

For : implement tee as a simple byte duplicator that reads from stdin and writes each chunk to stdout plus any files you open. is right about the basic idea (two streams), and correctly described the Unix utility behavior. The short plan: parse an optional -a flag, open each filename into an array of file descriptors, loop reading from stdin with read(), and write each buffer to every open fd with a small helper that retries on EINTR and handles partial writes.

The snippet below is a compact, POSIX-style starting point. It uses open/read/write so binary data is preserved, ignores SIGPIPE so a closed downstream reader doesn't kill the whole process immediately, and closes any file descriptor that returns EPIPE. It is intentionally small; extend it for better error recovery, option parsing, or buffering tweaks as needed.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <signal.h>

#define BUF_SIZE 8192

static ssize_t safe_write(int fd, const void *buf, size_t count) {
    const unsigned char *p = buf;
    size_t left = count;
    while (left > 0) {
        ssize_t w = write(fd, p, left);
        if (w < 0) {
            if (errno == EINTR) continue;
            return -1;
        }
        p += w;
        left -= w;
    }
    return count;
}

int main(int argc, char **argv) {
    int append = 0, i = 1;
    while (i < argc && argv[i][0] == '-') {
        if (strcmp(argv[i], "-a") == 0) append = 1;
        else { fprintf(stderr, "Usage: %s [-a] [file...]\n", argv[0]); return 2; }
        i++;
    }

    int nfiles = argc - i;
    int total = 1 + nfiles; /* stdout + files */
    int *fds = malloc(total * sizeof(int));
    if (!fds) { perror("malloc"); return 1; }

    fds[0] = STDOUT_FILENO;
    for (int j = 0; j < nfiles; ++j) {
        const char *name = argv[i + j];
        int flags = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC);
        int fd = open(name, flags, 0666);
        if (fd < 0) { fprintf(stderr, "open %s: %s\n", name, strerror(errno)); fds[j + 1] = -1; }
        else fds[j + 1] = fd;
    }

    signal(SIGPIPE, SIG_IGN); /* writes return EPIPE instead of killing process */

    char buf[BUF_SIZE];
    ssize_t r;
    while ((r = read(STDIN_FILENO, buf, sizeof buf)) > 0) {
        for (int j = 0; j < total; ++j) {
            int fd = fds[j];
            if (fd < 0) continue;
            if (safe_write(fd, buf, (size_t)r) < 0) {
                if (errno == EPIPE) { close(fd); fds[j] = -1; continue; }
                fprintf(stderr, "write error on fd %d: %s\n", fd, strerror(errno));
            }
        }
    }
    if (r < 0) perror("read");

    for (int j = 1; j < total; ++j) if (fds[j] >= 0) close(fds[j]);
    free(fds);
    return 0;
}

Compile with cc -std=c99 -Wall -O2 -o mytee mytee.c. Notes: using fopen/fwrite is simpler but can hide buffering differences; read/write is safer for raw streams. To see the standard behavior and options for tee, consult the tee(1) man page and the POSIX tee description.

Recommended Answers

All 3 Replies

Two FILE streams, a and b, write the same to both.

a tee filter what in the world is that............

a tee filter what in the world is that............

It's a common UNIX utility. Basically, you pipe the output of one command to tee, and it acts like a "tee" pipe in plumbing, allowing you to output to to different places, like STDOUT and a file, at the same time.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.