Weird Malloc Error (and other problems involving this shell) - c

I am working on a Shell for a C Project I am working on, and I keep encountering this strange Malloc Error whenever I interact directly with the list that stores all of the jobs and processes, I always get a weird Malloc Error that looks someething like this:
What's going on here?
Can you please help me figure out what's going on with this thing? And if possible, perhaps you could maybe give me other suggestions for how to improve it as well? Cuz I would really appreciate it.
Here's the code below:
*
* $ gcc shell.c csapp.c -lpthread -o shell
*
*
* $ ./shell
*/
#include "csapp.h"
#define TRUE 1
#define FALSE 0
#define MAXARGS 128
#define MAXCHARS 64
pid_t fg_pid = 0;
int next_jid = 1;
typedef struct list_t
{
pid_t pid;
int jid;
char *runstat;
char *cmdline;
struct list_t *next;
} list_t;
list_t *jobs_list = NULL;
void add_element(list_t **list, pid_t pid, int jid, char *runstat, char *cmdline)
{
list_t *e;
if (*list == NULL) // New empty list.
{
*list = (list_t *) malloc(sizeof(list_t));
(*list)->pid = pid;
(*list)->jid = jid;
(*list)->runstat = strndup(runstat, MAXCHARS);
(*list)->cmdline = strndup(cmdline, MAXCHARS);
(*list)->next = NULL;
}
else // List with at least one element.
{
// Loop through elements, so that e is left
// pointing to the last one in the list.
for (e = *list; e->next != NULL; e = e->next)
; // (Do nothing.)
e->next = (list_t *) malloc(sizeof(list_t));
e = e->next;
e->pid = pid;
e->jid = jid;
e->runstat = strndup(runstat, MAXCHARS);
e->cmdline = strndup(cmdline, MAXCHARS);
e->next = NULL;
}
}
void fg_list_handler(list_t ** list, pid_t pid, int jid) {
}
void change_running_status(list_t **list, pid_t pid, char *runstat) {
//THe code I wrote with changing statuses in the list for programs.
list_t *e;
e = *list;
if (e->next == NULL) {
strncpy(e->runstat, runstat, MAXCHARS);
} else {
for (e; e != NULL; e->next) {
if (pid == e->pid) {
strncpy(e->runstat, runstat, MAXCHARS);
break;
}
}
}
}
void sigint_handler(int signal) {
// Restore default behavior for next SIGINT (which will likely
// come from call to raise at the end of this function).
Signal(SIGINT, SIG_DFL);
if (fg_pid != 0) {
Kill(-fg_pid, SIGINT); //Exits out of the child process (- = Send to group).
printf("Job %d has been terminated by: User Interrupt (SIGINT) \n", fg_pid);
Signal(SIGINT, sigint_handler);
} else {
// Send SIGINT to self. (This time won't be caught be handler,
// will instead cause process to terminate.)
raise(SIGINT);
}
}
void sigtstp_handler(int signal) {
//Restores SIGSTOP to normal behavior.
Signal(SIGTSTP, SIG_DFL);
//Stops the process.
if (fg_pid != 0) {
kill(-fg_pid, SIGTSTP);
printf("Job %d has been stopped by: User Stop (SIGTSTP)\n", fg_pid);
Signal(SIGTSTP, sigtstp_handler);
} else {
raise(SIGTSTP);
}
}
/*
* Populate argv with pointers to places in line where arguments
* begin (and put \0 in buf where arguments end), so that argv[0] is
* pointer to first argument, argv[1] pointer to second, etc.
*
* (You should't need to make any changes to this function.)
*/
int parseline(char *line, char **argv) {
char *cp;
int in_arg = FALSE;
int argc = 0;
int bg = FALSE;
// Go through line, one character at a time, until reaching the
// newline character at the end.
for (cp = line; *cp != '\n'; cp++) {
if (in_arg) {
// If at the end of an argument...
if (*cp == ' ') {
*cp = '\0'; // Mark end of argument.
in_arg = FALSE;
}
} else if (*cp != ' ') { // If at beginning of new argument...
argv[argc++] = cp; // Set argv array element to point to
// new argument.
in_arg = TRUE;
}
}
*cp = '\0'; // Mark end of last argument (which was probably
// followed by \n, not space).
// If at least one argument, and last argument is &, process is
// to be run in background.
if (argc > 0 && *argv[argc - 1] == '&') {
bg = TRUE;
argv[argc - 1] = NULL; // Overwrite address of "&" to mark
// end of argv.
} else { // (Process should run in foreground.)
argv[argc] = NULL; // Mark end of argv.
}
return bg;
}
/*
* If argv[0] is a builtin command, run it and return TRUE. If it's
* not, return FALSE.
*/
int builtin_command(char **argv) {
if (strcmp(argv[0], "quit") == 0) {
// (Don't bother to return, just end the program.)
exit(0);
} else if (strcmp(argv[0], "&") == 0) {
// (Ignore & if it isn't preceded by a command.)
return TRUE;
} else if (strcmp(argv[0], "jobs") == 0) {
// Prints list of background and stopped jobs.
list_t *e;
char *runstat[MAXLINE];
for (e = jobs_list; e != NULL; e = e->next) {
strncpy(runstat, e->runstat, MAXCHARS);
//Eventually going to add an additional argument to allow it to print different lists depending on the argument.
//Prints the process only if it's currently running in the system.
if (strncmp(e->runstat, "running", MAXCHARS) == 0) {
printf("[%d], %d, %s, %s", e->jid, e->pid, e->runstat, e->cmdline);
}
}
return TRUE;
} else if (strcmp(argv[0], "bg")) {
}
return FALSE;
}
/*
* Evaluate command (a line of arguments).
*/
void eval(char *cmdline, char **envp) {
char *argv[MAXARGS];
char buf[MAXLINE];
int bg;
pid_t pid;
int jid;
char *runstat[MAXLINE];
//Used for my current implementation of status checking.
int status;
// Copy cmdline to buf, use parseline to populate argv based
// on what's in buf (and set bg based on value returned from
// parseline).
strcpy(buf, cmdline);
bg = parseline(buf, argv);
// If at least one argument, and it's not a builtin command...
// (If it is a builtin command the builtin_command function will
// run it too, not just check whether it's builtin.)
if (argv[0] != NULL && !builtin_command(argv)) {
pid = Fork();
if (pid == 0) { // In child.
//Added to work with child processes and groups of processes.
pid = getpid();
setpgid(pid, pid);
if (execve(argv[0], argv, envp) < 0) {
printf("%s is an invalid command.\n", argv[0]);
exit(0);
}
} else if (!bg) { // In parent, child running in foreground.
fg_pid = pid;
strncpy(runstat, "running", MAXCHARS);
jid = next_jid++;
//Testing Print.
printf("[%d] %d %s %s", jid, pid, runstat, cmdline);
add_element(&jobs_list, pid, jid, runstat, cmdline);
if (waitpid(pid, &status, WUNTRACED) != 0)
{
if (fg_pid != 0) {
//added check due to the first if executing down here for no reason.
if (WIFEXITED(status) >= 1) {
strncpy(runstat, "exited", MAXCHARS);
//change_running_status(&jobs_list, pid, runstat);
printf("[%d] %d %s %s", jid, pid, runstat, cmdline);
} else if (WIFSIGNALED(status) >= 1) {
strncpy(runstat, "interrupted", MAXCHARS);
//change_running_status(&jobs_list, pid, runstat);
printf("[%d] %d %s %s", jid, pid, runstat, cmdline);
} else if (WIFSTOPPED(status) >= 1) {
strncpy(runstat, "stopped", MAXCHARS);
change_running_status(&jobs_list, pid, runstat);
printf("[%d] %d %s %s", jid, pid, runstat, cmdline);
}
}
}
fg_pid = 0;
} else { // In parent, child running in background.
//Implemented the whole running thing in my usual crude methods of doing so.
strncpy(runstat, "running", MAXCHARS);
jid = next_jid++;
//runstat = 'Running';
//printf("[%d] %d %s %s", jid, pid, runstat, cmdline);
add_element(&jobs_list, pid, jid, runstat, cmdline);
}
}
}
int main(int argc, char **argv, char **envp) {
char cmdline[MAXLINE];
Signal(SIGINT, sigint_handler);
Signal(SIGTSTP, sigtstp_handler);
while (TRUE) { // exit(0) will be called from builtin_command
// if user enters "quit" command.
printf("> ");
Fgets(cmdline, MAXLINE, stdin);
eval(cmdline, envp);
}
}

dont use strndup() or strncpy() before you have read their man pages
[after using the man pages you would not use them anyway]
dont use printf() and friends in signal handlers; they are not signal-safe.

Sleeper.c:
/*
* sleeper.c
*/
/*
* Get csapp.h and csapp.c from http://csapp.cs.cmu.edu/3e/code.html
*
* $ gcc sleeper.c csapp.c -o sleeper
*
* (Ignore any compliation warnings related to code in csapp.c.)
*
* $ ./sleeper
*
* ... CTRL-C to terminate and see message indicating sleeper
* caught SIGINT. CTRL-Z to stop and see message indicating
* sleeper caught SIGTSTP. "jobs" to see list of stopped jobs
* with numerical IDs (including ./sleeper). "fg %1" to restart
* job with ID 1 (i.e., sleeper) and see message indicating
* sleeper caught SIGCONT.
*/
#include "csapp.h"
int pid;
pid_t fg_pid;
void sigint_handler(int signal) {
// Restore default behavior for next SIGINT (which will likely
// come from call to raise at the end of this function).
Signal(SIGINT, SIG_DFL);
printf("\nsleeper (%d) caught SIGINT\n", pid);
// Send SIGINT to self. (This time won't be caught be handler,
// will instead cause process to terminate.)
raise(SIGINT);
}
void sigtstp_handler(int signal) {
// Restore default behavior for next SIGTSTP ...
Signal(SIGTSTP, SIG_DFL);
printf("\nsleeper (%d) caught SIGTSTP\n", pid);
// Send SIGTSTP to self ...
raise(SIGTSTP);
}
void sigcont_handler(int signal) {
// Don't need to restore default behavior of SIGCONT, because
// default (for already running process) is to ignore it.
// Prepare for next SIGTSTP signal.
Signal(SIGTSTP, sigtstp_handler);
printf("\nsleeper (%d) caught SIGCONT\n", pid);
// Don't need to raise SIGCONT, because process is already
// running (and would ignore it).
}
// First command line argument is number of times to sleep. (0
// or no argument means to continue indefinitely.) Second argument
// -q for quiet sleeper.
int main(int argc, char **argv) {
int i, n, q;
n = argc > 1 ? atoi(argv[1]) : 0;
q = argc > 2 && strcmp("-q", argv[2]) == 0;
pid = getpid();
// Override default behavior for SIGINT, SIGTSTP and SIGCONT.
Signal(SIGINT, sigint_handler);
Signal(SIGTSTP, sigtstp_handler);
Signal(SIGCONT, sigcont_handler);
// Sleep 1 second, wake up, go back to sleep...
for (i = 0; n == 0 || i < n; i++) {
Sleep(1);
if (!q) {
printf("sleeper (%d) slept %d second(s)\n", pid, i + 1);
}
}
return 0;
}

Oh, and that's not all the code. There are several other files (ignore the errors with CSAPP.c. They resolve themselves when you use lpthread in compiling).
* csapp.h
*/
/* $begin csapp.h */
#ifndef __CSAPP_H__
#define __CSAPP_H__
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <setjmp.h>
#include <signal.h>
#include <dirent.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* Default file permissions are DEF_MODE & ~DEF_UMASK */
/* $begin createmasks */
#define DEF_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define DEF_UMASK S_IWGRP|S_IWOTH
/* $end createmasks */
/* Simplifies calls to bind(), connect(), and accept() */
/* $begin sockaddrdef */
typedef struct sockaddr SA;
/* $end sockaddrdef */
/* Persistent state for the robust I/O (Rio) package */
/* $begin rio_t */
#define RIO_BUFSIZE 8192
typedef struct {
int rio_fd; /* Descriptor for this internal buf */
int rio_cnt; /* Unread bytes in internal buf */
char *rio_bufptr; /* Next unread byte in internal buf */
char rio_buf[RIO_BUFSIZE]; /* Internal buffer */
} rio_t;
/* $end rio_t */
/* External variables */
extern int h_errno; /* Defined by BIND for DNS errors */
extern char **environ; /* Defined by libc */
/* Misc constants */
#define MAXLINE 8192 /* Max text line length */
#define MAXBUF 8192 /* Max I/O buffer size */
#define LISTENQ 1024 /* Second argument to listen() */
/* Our own error-handling functions */
void unix_error(char *msg);
void posix_error(int code, char *msg);
void dns_error(char *msg);
void gai_error(int code, char *msg);
void app_error(char *msg);
/* Process control wrappers */
pid_t Fork(void);
void Execve(const char *filename, char *const argv[], char *const envp[]);
pid_t Wait(int *status);
pid_t Waitpid(pid_t pid, int *iptr, int options);
void Kill(pid_t pid, int signum);
unsigned int Sleep(unsigned int secs);
void Pause(void);
unsigned int Alarm(unsigned int seconds);
void Setpgid(pid_t pid, pid_t pgid);
pid_t Getpgrp();
/* Signal wrappers */
typedef void handler_t(int);
handler_t *Signal(int signum, handler_t *handler);
void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
void Sigemptyset(sigset_t *set);
void Sigfillset(sigset_t *set);
void Sigaddset(sigset_t *set, int signum);
void Sigdelset(sigset_t *set, int signum);
int Sigismember(const sigset_t *set, int signum);
int Sigsuspend(const sigset_t *set);
/* Sio (Signal-safe I/O) routines */
ssize_t sio_puts(char s[]);
ssize_t sio_putl(long v);
void sio_error(char s[]);
/* Sio wrappers */
ssize_t Sio_puts(char s[]);
ssize_t Sio_putl(long v);
void Sio_error(char s[]);
/* Unix I/O wrappers */
int Open(const char *pathname, int flags, mode_t mode);
ssize_t Read(int fd, void *buf, size_t count);
ssize_t Write(int fd, const void *buf, size_t count);
off_t Lseek(int fildes, off_t offset, int whence);
void Close(int fd);
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
int Dup2(int fd1, int fd2);
void Stat(const char *filename, struct stat *buf);
void Fstat(int fd, struct stat *buf) ;
/* Directory wrappers */
DIR *Opendir(const char *name);
struct dirent *Readdir(DIR *dirp);
int Closedir(DIR *dirp);
/* Memory mapping wrappers */
void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
void Munmap(void *start, size_t length);
/* Standard I/O wrappers */
void Fclose(FILE *fp);
FILE *Fdopen(int fd, const char *type);
char *Fgets(char *ptr, int n, FILE *stream);
FILE *Fopen(const char *filename, const char *mode);
void Fputs(const char *ptr, FILE *stream);
size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
/* Dynamic storage allocation wrappers */
void *Malloc(size_t size);
void *Realloc(void *ptr, size_t size);
void *Calloc(size_t nmemb, size_t size);
void Free(void *ptr);
/* Sockets interface wrappers */
int Socket(int domain, int type, int protocol);
void Setsockopt(int s, int level, int optname, const void *optval, int optlen);
void Bind(int sockfd, struct sockaddr *my_addr, int addrlen);
void Listen(int s, int backlog);
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
/* Protocol independent wrappers */
void Getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res);
void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags);
void Freeaddrinfo(struct addrinfo *res);
void Inet_ntop(int af, const void *src, char *dst, socklen_t size);
void Inet_pton(int af, const char *src, void *dst);
/* DNS wrappers */
struct hostent *Gethostbyname(const char *name);
struct hostent *Gethostbyaddr(const char *addr, int len, int type);
/* Pthreads thread control wrappers */
void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
void * (*routine)(void *), void *argp);
void Pthread_join(pthread_t tid, void **thread_return);
void Pthread_cancel(pthread_t tid);
void Pthread_detach(pthread_t tid);
void Pthread_exit(void *retval);
pthread_t Pthread_self(void);
void Pthread_once(pthread_once_t *once_control, void (*init_function)());
/* POSIX semaphore wrappers */
void Sem_init(sem_t *sem, int pshared, unsigned int value);
void P(sem_t *sem);
void V(sem_t *sem);
/* Rio (Robust I/O) package */
ssize_t rio_readn(int fd, void *usrbuf, size_t n);
ssize_t rio_writen(int fd, void *usrbuf, size_t n);
void rio_readinitb(rio_t *rp, int fd);
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
/* Wrappers for Rio package */
ssize_t Rio_readn(int fd, void *usrbuf, size_t n);
void Rio_writen(int fd, void *usrbuf, size_t n);
void Rio_readinitb(rio_t *rp, int fd);
ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n);
ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
/* Reentrant protocol-independent client/server helpers */
int open_clientfd(char *hostname, char *port);
int open_listenfd(char *port);
/* Wrappers for reentrant protocol-independent client/server helpers */
int Open_clientfd(char *hostname, char *port);
int Open_listenfd(char *port);
#endif /* __CSAPP_H__ */
/* $end csapp.h */```

csapp.c:
* csapp.c
*/
/* $begin csapp.c */
#include "csapp.h"
/**************************
* Error-handling functions
**************************/
/* $begin errorfuns */
/* $begin unixerror */
void unix_error(char *msg) /* Unix-style error */
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0);
}
/* $end unixerror */
void posix_error(int code, char *msg) /* Posix-style error */
{
fprintf(stderr, "%s: %s\n", msg, strerror(code));
exit(0);
}
void gai_error(int code, char *msg) /* Getaddrinfo-style error */
{
fprintf(stderr, "%s: %s\n", msg, gai_strerror(code));
exit(0);
}
void app_error(char *msg) /* Application error */
{
fprintf(stderr, "%s\n", msg);
exit(0);
}
/* $end errorfuns */
void dns_error(char *msg) /* Obsolete gethostbyname error */
{
fprintf(stderr, "%s\n", msg);
exit(0);
}
/*********************************************
* Wrappers for Unix process control functions
********************************************/
/* $begin forkwrapper */
pid_t Fork(void)
{
pid_t pid;
if ((pid = fork()) < 0)
unix_error("Fork error");
return pid;
}
/* $end forkwrapper */
void Execve(const char *filename, char *const argv[], char *const envp[])
{
if (execve(filename, argv, envp) < 0)
unix_error("Execve error");
}
/* $begin wait */
pid_t Wait(int *status)
{
pid_t pid;
if ((pid = wait(status)) < 0)
unix_error("Wait error");
return pid;
}
/* $end wait */
pid_t Waitpid(pid_t pid, int *iptr, int options)
{
pid_t retpid;
if ((retpid = waitpid(pid, iptr, options)) < 0)
unix_error("Waitpid error");
return(retpid);
}
/* $begin kill */
void Kill(pid_t pid, int signum)
{
int rc;
if ((rc = kill(pid, signum)) < 0)
unix_error("Kill error");
}
/* $end kill */
void Pause()
{
(void)pause();
return;
}
unsigned int Sleep(unsigned int secs)
{
unsigned int rc;
if ((rc = sleep(secs)) < 0)
unix_error("Sleep error");
return rc;
}
unsigned int Alarm(unsigned int seconds) {
return alarm(seconds);
}
void Setpgid(pid_t pid, pid_t pgid) {
int rc;
if ((rc = setpgid(pid, pgid)) < 0)
unix_error("Setpgid error");
return;
}
pid_t Getpgrp(void) {
return getpgrp();
}
/************************************
* Wrappers for Unix signal functions
***********************************/
/* $begin sigaction */
handler_t *Signal(int signum, handler_t *handler)
{
struct sigaction action, old_action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
action.sa_flags = SA_RESTART; /* Restart syscalls if possible */
if (sigaction(signum, &action, &old_action) < 0)
unix_error("Signal error");
return (old_action.sa_handler);
}
/* $end sigaction */
void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
{
if (sigprocmask(how, set, oldset) < 0)
unix_error("Sigprocmask error");
return;
}
void Sigemptyset(sigset_t *set)
{
if (sigemptyset(set) < 0)
unix_error("Sigemptyset error");
return;
}
void Sigfillset(sigset_t *set)
{
if (sigfillset(set) < 0)
unix_error("Sigfillset error");
return;
}
void Sigaddset(sigset_t *set, int signum)
{
if (sigaddset(set, signum) < 0)
unix_error("Sigaddset error");
return;
}
void Sigdelset(sigset_t *set, int signum)
{
if (sigdelset(set, signum) < 0)
unix_error("Sigdelset error");
return;
}
int Sigismember(const sigset_t *set, int signum)
{
int rc;
if ((rc = sigismember(set, signum)) < 0)
unix_error("Sigismember error");
return rc;
}
int Sigsuspend(const sigset_t *set)
{
int rc = sigsuspend(set); /* always returns -1 */
if (errno != EINTR)
unix_error("Sigsuspend error");
return rc;
}
/*************************************************************
* The Sio (Signal-safe I/O) package - simple reentrant output
* functions that are safe for signal handlers.
*************************************************************/
/* Private sio functions */
/* $begin sioprivate */
/* sio_reverse - Reverse a string (from K&R) */
static void sio_reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
/* sio_ltoa - Convert long to base b string (from K&R) */
static void sio_ltoa(long v, char s[], int b)
{
int c, i = 0;
int neg = v < 0;
if (neg)
v = -v;
do {
s[i++] = ((c = (v % b)) < 10) ? c + '0' : c - 10 + 'a';
} while ((v /= b) > 0);
if (neg)
s[i++] = '-';
s[i] = '\0';
sio_reverse(s);
}
/* sio_strlen - Return length of string (from K&R) */
static size_t sio_strlen(char s[])
{
int i = 0;
while (s[i] != '\0')
++i;
return i;
}
/* $end sioprivate */
/* Public Sio functions */
/* $begin siopublic */
ssize_t sio_puts(char s[]) /* Put string */
{
return write(STDOUT_FILENO, s, sio_strlen(s)); //line:csapp:siostrlen
}
ssize_t sio_putl(long v) /* Put long */
{
char s[128];
sio_ltoa(v, s, 10); /* Based on K&R itoa() */ //line:csapp:sioltoa
return sio_puts(s);
}
void sio_error(char s[]) /* Put error message and exit */
{
sio_puts(s);
_exit(1); //line:csapp:sioexit
}
/* $end siopublic */
/*******************************
* Wrappers for the SIO routines
******************************/
ssize_t Sio_putl(long v)
{
ssize_t n;
if ((n = sio_putl(v)) < 0)
sio_error("Sio_putl error");
return n;
}
ssize_t Sio_puts(char s[])
{
ssize_t n;
if ((n = sio_puts(s)) < 0)
sio_error("Sio_puts error");
return n;
}
void Sio_error(char s[])
{
sio_error(s);
}
/********************************
* Wrappers for Unix I/O routines
********************************/
int Open(const char *pathname, int flags, mode_t mode)
{
int rc;
if ((rc = open(pathname, flags, mode)) < 0)
unix_error("Open error");
return rc;
}
ssize_t Read(int fd, void *buf, size_t count)
{
ssize_t rc;
if ((rc = read(fd, buf, count)) < 0)
unix_error("Read error");
return rc;
}
ssize_t Write(int fd, const void *buf, size_t count)
{
ssize_t rc;
if ((rc = write(fd, buf, count)) < 0)
unix_error("Write error");
return rc;
}
off_t Lseek(int fildes, off_t offset, int whence)
{
off_t rc;
if ((rc = lseek(fildes, offset, whence)) < 0)
unix_error("Lseek error");
return rc;
}
void Close(int fd)
{
int rc;
if ((rc = close(fd)) < 0)
unix_error("Close error");
}
int Select(int n, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout)
{
int rc;
if ((rc = select(n, readfds, writefds, exceptfds, timeout)) < 0)
unix_error("Select error");
return rc;
}
int Dup2(int fd1, int fd2)
{
int rc;
if ((rc = dup2(fd1, fd2)) < 0)
unix_error("Dup2 error");
return rc;
}
void Stat(const char *filename, struct stat *buf)
{
if (stat(filename, buf) < 0)
unix_error("Stat error");
}
void Fstat(int fd, struct stat *buf)
{
if (fstat(fd, buf) < 0)
unix_error("Fstat error");
}
/*********************************
* Wrappers for directory function
*********************************/
DIR *Opendir(const char *name)
{
DIR *dirp = opendir(name);
if (!dirp)
unix_error("opendir error");
return dirp;
}
struct dirent *Readdir(DIR *dirp)
{
struct dirent *dep;
errno = 0;
dep = readdir(dirp);
if ((dep == NULL) && (errno != 0))
unix_error("readdir error");
return dep;
}
int Closedir(DIR *dirp)
{
int rc;
if ((rc = closedir(dirp)) < 0)
unix_error("closedir error");
return rc;
}
/***************************************
* Wrappers for memory mapping functions
***************************************/
void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
void *ptr;
if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1))
unix_error("mmap error");
return(ptr);
}
void Munmap(void *start, size_t length)
{
if (munmap(start, length) < 0)
unix_error("munmap error");
}
/***************************************************
* Wrappers for dynamic storage allocation functions
***************************************************/
void *Malloc(size_t size)
{
void *p;
if ((p = malloc(size)) == NULL)
unix_error("Malloc error");
return p;
}
void *Realloc(void *ptr, size_t size)
{
void *p;
if ((p = realloc(ptr, size)) == NULL)
unix_error("Realloc error");
return p;
}
void *Calloc(size_t nmemb, size_t size)
{
void *p;
if ((p = calloc(nmemb, size)) == NULL)
unix_error("Calloc error");
return p;
}
void Free(void *ptr)
{
free(ptr);
}
/******************************************
* Wrappers for the Standard I/O functions.
******************************************/
void Fclose(FILE *fp)
{
if (fclose(fp) != 0)
unix_error("Fclose error");
}
FILE *Fdopen(int fd, const char *type)
{
FILE *fp;
if ((fp = fdopen(fd, type)) == NULL)
unix_error("Fdopen error");
return fp;
}
char *Fgets(char *ptr, int n, FILE *stream)
{
char *rptr;
if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream))
app_error("Fgets error");
return rptr;
}
FILE *Fopen(const char *filename, const char *mode)
{
FILE *fp;
if ((fp = fopen(filename, mode)) == NULL)
unix_error("Fopen error");
return fp;
}
void Fputs(const char *ptr, FILE *stream)
{
if (fputs(ptr, stream) == EOF)
unix_error("Fputs error");
}
size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
size_t n;
if (((n = fread(ptr, size, nmemb, stream)) < nmemb) && ferror(stream))
unix_error("Fread error");
return n;
}
void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
if (fwrite(ptr, size, nmemb, stream) < nmemb)
unix_error("Fwrite error");
}
/****************************
* Sockets interface wrappers
****************************/
int Socket(int domain, int type, int protocol)
{
int rc;
if ((rc = socket(domain, type, protocol)) < 0)
unix_error("Socket error");
return rc;
}
void Setsockopt(int s, int level, int optname, const void *optval, int optlen)
{
int rc;
if ((rc = setsockopt(s, level, optname, optval, optlen)) < 0)
unix_error("Setsockopt error");
}
void Bind(int sockfd, struct sockaddr *my_addr, int addrlen)
{
int rc;
if ((rc = bind(sockfd, my_addr, addrlen)) < 0)
unix_error("Bind error");
}
void Listen(int s, int backlog)
{
int rc;
if ((rc = listen(s, backlog)) < 0)
unix_error("Listen error");
}
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
int rc;
if ((rc = accept(s, addr, addrlen)) < 0)
unix_error("Accept error");
return rc;
}
void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
{
int rc;
if ((rc = connect(sockfd, serv_addr, addrlen)) < 0)
unix_error("Connect error");
}
/*******************************
* Protocol-independent wrappers
*******************************/
/* $begin getaddrinfo */
void Getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res)
{
int rc;
if ((rc = getaddrinfo(node, service, hints, res)) != 0)
gai_error(rc, "Getaddrinfo error");
}
/* $end getaddrinfo */
void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags)
{
int rc;
if ((rc = getnameinfo(sa, salen, host, hostlen, serv,
servlen, flags)) != 0)
gai_error(rc, "Getnameinfo error");
}
void Freeaddrinfo(struct addrinfo *res)
{
freeaddrinfo(res);
}
void Inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
if (!inet_ntop(af, src, dst, size))
unix_error("Inet_ntop error");
}
void Inet_pton(int af, const char *src, void *dst)
{
int rc;
rc = inet_pton(af, src, dst);
if (rc == 0)
app_error("inet_pton error: invalid dotted-decimal address");
else if (rc < 0)
unix_error("Inet_pton error");
}
/*******************************************
* DNS interface wrappers.
*
* NOTE: These are obsolete because they are not thread safe. Use
* getaddrinfo and getnameinfo instead
***********************************/
/* $begin gethostbyname */
struct hostent *Gethostbyname(const char *name)
{
struct hostent *p;
if ((p = gethostbyname(name)) == NULL)
dns_error("Gethostbyname error");
return p;
}
/* $end gethostbyname */
struct hostent *Gethostbyaddr(const char *addr, int len, int type)
{
struct hostent *p;
if ((p = gethostbyaddr(addr, len, type)) == NULL)
dns_error("Gethostbyaddr error");
return p;
}
/************************************************
* Wrappers for Pthreads thread control functions
************************************************/
void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
void * (*routine)(void *), void *argp)
{
int rc;
if ((rc = pthread_create(tidp, attrp, routine, argp)) != 0)
posix_error(rc, "Pthread_create error");
}
void Pthread_cancel(pthread_t tid) {
int rc;
if ((rc = pthread_cancel(tid)) != 0)
posix_error(rc, "Pthread_cancel error");
}
void Pthread_join(pthread_t tid, void **thread_return) {
int rc;
if ((rc = pthread_join(tid, thread_return)) != 0)
posix_error(rc, "Pthread_join error");
}
/* $begin detach */
void Pthread_detach(pthread_t tid) {
int rc;
if ((rc = pthread_detach(tid)) != 0)
posix_error(rc, "Pthread_detach error");
}
/* $end detach */
void Pthread_exit(void *retval) {
pthread_exit(retval);
}
pthread_t Pthread_self(void) {
return pthread_self();
}
void Pthread_once(pthread_once_t *once_control, void (*init_function)()) {
pthread_once(once_control, init_function);
}
/*******************************
* Wrappers for Posix semaphores
*******************************/
void Sem_init(sem_t *sem, int pshared, unsigned int value)
{
if (sem_init(sem, pshared, value) < 0)
unix_error("Sem_init error");
}
void P(sem_t *sem)
{
if (sem_wait(sem) < 0)
unix_error("P error");
}
void V(sem_t *sem)
{
if (sem_post(sem) < 0)
unix_error("V error");
}
/****************************************
* The Rio package - Robust I/O functions
****************************************/
/*
* rio_readn - Robustly read n bytes (unbuffered)
*/
/* $begin rio_readn */
ssize_t rio_readn(int fd, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nread = read(fd, bufp, nleft)) < 0) {
if (errno == EINTR) /* Interrupted by sig handler return */
nread = 0; /* and call read() again */
else
return -1; /* errno set by read() */
}
else if (nread == 0)
break; /* EOF */
nleft -= nread;
bufp += nread;
}
return (n - nleft); /* Return >= 0 */
}
/* $end rio_readn */
/*
* rio_writen - Robustly write n bytes (unbuffered)
*/
/* $begin rio_writen */
ssize_t rio_writen(int fd, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
if (errno == EINTR) /* Interrupted by sig handler return */
nwritten = 0; /* and call write() again */
else
return -1; /* errno set by write() */
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
/* $end rio_writen */
/*
* rio_read - This is a wrapper for the Unix read() function that
* transfers min(n, rio_cnt) bytes from an internal buffer to a user
* buffer, where n is the number of bytes requested by the user and
* rio_cnt is the number of unread bytes in the internal buffer. On
* entry, rio_read() refills the internal buffer via a call to
* read() if the internal buffer is empty.
*/
/* $begin rio_read */
static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
{
int cnt;
while (rp->rio_cnt <= 0) { /* Refill if buf is empty */
rp->rio_cnt = read(rp->rio_fd, rp->rio_buf,
sizeof(rp->rio_buf));
if (rp->rio_cnt < 0) {
if (errno != EINTR) /* Interrupted by sig handler return */
return -1;
}
else if (rp->rio_cnt == 0) /* EOF */
return 0;
else
rp->rio_bufptr = rp->rio_buf; /* Reset buffer ptr */
}
/* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */
cnt = n;
if (rp->rio_cnt < n)
cnt = rp->rio_cnt;
memcpy(usrbuf, rp->rio_bufptr, cnt);
rp->rio_bufptr += cnt;
rp->rio_cnt -= cnt;
return cnt;
}
/* $end rio_read */
/*
* rio_readinitb - Associate a descriptor with a read buffer and reset buffer
*/
/* $begin rio_readinitb */
void rio_readinitb(rio_t *rp, int fd)
{
rp->rio_fd = fd;
rp->rio_cnt = 0;
rp->rio_bufptr = rp->rio_buf;
}
/* $end rio_readinitb */
/*
* rio_readnb - Robustly read n bytes (buffered)
*/
/* $begin rio_readnb */
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nread = rio_read(rp, bufp, nleft)) < 0)
return -1; /* errno set by read() */
else if (nread == 0)
break; /* EOF */
nleft -= nread;
bufp += nread;
}
return (n - nleft); /* return >= 0 */
}
/* $end rio_readnb */
/*
* rio_readlineb - Robustly read a text line (buffered)
*/
/* $begin rio_readlineb */
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
{
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++) {
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n') {
n++;
break;
}
} else if (rc == 0) {
if (n == 1)
return 0; /* EOF, no data read */
else
break; /* EOF, some data was read */
} else
return -1; /* Error */
}
*bufp = 0;
return n-1;
}
/* $end rio_readlineb */
/**********************************
* Wrappers for robust I/O routines
**********************************/
ssize_t Rio_readn(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
if ((n = rio_readn(fd, ptr, nbytes)) < 0)
unix_error("Rio_readn error");
return n;
}
void Rio_writen(int fd, void *usrbuf, size_t n)
{
if (rio_writen(fd, usrbuf, n) != n)
unix_error("Rio_writen error");
}
void Rio_readinitb(rio_t *rp, int fd)
{
rio_readinitb(rp, fd);
}
ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n)
{
ssize_t rc;
if ((rc = rio_readnb(rp, usrbuf, n)) < 0)
unix_error("Rio_readnb error");
return rc;
}
ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
{
ssize_t rc;
if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0)
unix_error("Rio_readlineb error");
return rc;
}
/********************************
* Client/server helper functions
********************************/
/*
* open_clientfd - Open connection to server at <hostname, port> and
* return a socket descriptor ready for reading and writing. This
* function is reentrant and protocol-independent.
*
* On error, returns:
* -2 for getaddrinfo error
* -1 with errno set for other errors.
*/
/* $begin open_clientfd */
int open_clientfd(char *hostname, char *port) {
int clientfd, rc;
struct addrinfo hints, *listp, *p;
/* Get a list of potential server addresses */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; /* Open a connection */
hints.ai_flags = AI_NUMERICSERV; /* ... using a numeric port arg. */
hints.ai_flags |= AI_ADDRCONFIG; /* Recommended for connections */
if ((rc = getaddrinfo(hostname, port, &hints, &listp)) != 0) {
fprintf(stderr, "getaddrinfo failed (%s:%s): %s\n", hostname, port, gai_strerror(rc));
return -2;
}
/* Walk the list for one that we can successfully connect to */
for (p = listp; p; p = p->ai_next) {
/* Create a socket descriptor */
if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue; /* Socket failed, try the next */
/* Connect to the server */
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1)
break; /* Success */
if (close(clientfd) < 0) { /* Connect failed, try another */ //line:netp:openclientfd:closefd
fprintf(stderr, "open_clientfd: close failed: %s\n", strerror(errno));
return -1;
}
}
/* Clean up */
freeaddrinfo(listp);
if (!p) /* All connects failed */
return -1;
else /* The last connect succeeded */
return clientfd;
}
/* $end open_clientfd */
/*
* open_listenfd - Open and return a listening socket on port. This
* function is reentrant and protocol-independent.
*
* On error, returns:
* -2 for getaddrinfo error
* -1 with errno set for other errors.
*/
/* $begin open_listenfd */
int open_listenfd(char *port)
{
struct addrinfo hints, *listp, *p;
int listenfd, rc, optval=1;
/* Get a list of potential server addresses */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; /* Accept connections */
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* ... on any IP address */
hints.ai_flags |= AI_NUMERICSERV; /* ... using port number */
if ((rc = getaddrinfo(NULL, port, &hints, &listp)) != 0) {
fprintf(stderr, "getaddrinfo failed (port %s): %s\n", port, gai_strerror(rc));
return -2;
}
/* Walk the list for one that we can bind to */
for (p = listp; p; p = p->ai_next) {
/* Create a socket descriptor */
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue; /* Socket failed, try the next */
/* Eliminates "Address already in use" error from bind */
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt
(const void *)&optval , sizeof(int));
/* Bind the descriptor to the address */
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)
break; /* Success */
if (close(listenfd) < 0) { /* Bind failed, try the next */
fprintf(stderr, "open_listenfd close failed: %s\n", strerror(errno));
return -1;
}
}
/* Clean up */
freeaddrinfo(listp);
if (!p) /* No address worked */
return -1;
/* Make it a listening socket ready to accept connection requests */
if (listen(listenfd, LISTENQ) < 0) {
close(listenfd);
return -1;
}
return listenfd;
}
/* $end open_listenfd */
/****************************************************
* Wrappers for reentrant protocol-independent helpers
****************************************************/
int Open_clientfd(char *hostname, char *port)
{
int rc;
if ((rc = open_clientfd(hostname, port)) < 0)
unix_error("Open_clientfd error");
return rc;
}
int Open_listenfd(char *port)
{
int rc;
if ((rc = open_listenfd(port)) < 0)
unix_error("Open_listenfd error");
return rc;
}
/* $end csapp.c */

Related

One ioctl not being executed in kernel module

I wrote a kernel module demonstrating on how ioctl works.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
int base_minor = 0;
char *device_name = "msg";
int count = 1;
dev_t devicenumber;
static struct class *class = NULL;
static struct device *device = NULL;
static struct cdev mycdev;
#define MAX_SIZE 1024
char kernel_buffer[MAX_SIZE];
int buffer_index;
MODULE_LICENSE("GPL");
static int device_open(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
file->f_pos = 0;
buffer_index = 0;
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
return 0;
}
static ssize_t device_read(struct file *file, char __user *user_buffer,
size_t read_count, loff_t *offset)
{
int bytes_read;
int available_space;
int bytes_to_read;
pr_info("%s read offset:%lld\n", __func__, *offset);
available_space = MAX_SIZE - *(offset);
if (read_count < available_space)
bytes_to_read = read_count;
else
bytes_to_read = available_space;
pr_info("bytes_to_read:%d\n", bytes_to_read);
if (bytes_to_read == 0) {
pr_err("%s: No available space in the buffer for reading\n",
__func__);
return -ENOSPC;
}
if (buffer_index > *offset)
bytes_to_read = buffer_index - *offset;
else
return 0;
bytes_read = bytes_to_read - copy_to_user(user_buffer, kernel_buffer+*offset, bytes_to_read);
pr_info("%s: Copy to user returned:%d\n", __func__, bytes_to_read);
//update file offset
*offset += bytes_read;
return bytes_read;
}
static ssize_t device_write(struct file *file, const char __user *user_buffer,
size_t write_count, loff_t *offset)
{
int bytes_written;
int available_space;
int bytes_to_write;
pr_info("%s write offset:%lld\n", __func__, *offset);
available_space = MAX_SIZE - *(offset);
if (write_count < available_space)
bytes_to_write = write_count;
else
bytes_to_write = available_space;
if (bytes_to_write == 0) {
pr_err("%s: No available space in the buffer for writing\n",
__func__);
return -ENOSPC;
}
bytes_written = bytes_to_write - copy_from_user(kernel_buffer+*offset, user_buffer, bytes_to_write);
pr_info("%s: Bytes written:%d\n", __func__, bytes_written);
pr_info("%s: kernel_buffer:%s\n", __func__, kernel_buffer);
//update file offset
*offset += bytes_written;
buffer_index += bytes_written;
return bytes_written;
}
static loff_t device_lseek(struct file *file, loff_t offset, int orig)
{
loff_t new_pos = 0;
switch(orig) {
case 0 : /*seek set*/
new_pos = offset;
break;
case 1 : /*seek cur*/
new_pos = file->f_pos + offset;
break;
case 2 : /*seek end*/
new_pos = MAX_SIZE - offset;
break;
}
if(new_pos > MAX_SIZE)
new_pos = MAX_SIZE;
if(new_pos < 0)
new_pos = 0;
file->f_pos = new_pos;
return new_pos;
}
long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned char ch;
pr_info("%s: Cmd:%u\t Arg:%lu\n", __func__, cmd, arg);
switch(cmd)
{
//Get Length of buffer
case 0x01:
pr_info("Get Buffer Length\n");
put_user(MAX_SIZE, (unsigned int *)arg);
break;
//clear buffer
case 0x02:
pr_info("Clear buffer\n");
memset(kernel_buffer, 0, sizeof(kernel_buffer));
break;
//fill character
case 0x03:
get_user(ch, (unsigned char *)arg);
pr_info("Fill Character:%c\n", ch);
memset(kernel_buffer, ch, sizeof(kernel_buffer));
buffer_index = sizeof(kernel_buffer);
break;
default:
pr_info("Unknown Command:%u\n", cmd);
return -EINVAL;
}
return 0;
}
struct file_operations device_fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release,
.llseek = device_lseek,
.unlocked_ioctl = device_ioctl
};
static int test_hello_init(void)
{
class = class_create(THIS_MODULE, "myclass");
if (!alloc_chrdev_region(&devicenumber, base_minor, count, device_name)) {
printk("Device number registered\n");
printk("Major number received:%d\n", MAJOR(devicenumber));
device = device_create(class, NULL, devicenumber, NULL, device_name);
cdev_init(&mycdev, &device_fops);
mycdev.owner = THIS_MODULE;
cdev_add(&mycdev, devicenumber, count);
}
else
printk("Device number registration Failed\n");
return 0;
}
static void test_hello_exit(void)
{
device_destroy(class, devicenumber);
class_destroy(class);
cdev_del(&mycdev);
unregister_chrdev_region(devicenumber, count);
}
module_init(test_hello_init);
module_exit(test_hello_exit);
Then i wrote a user space code
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
int main(int argc, char *argv[])
{
char buffer[1024];
int fd;
unsigned int length;
unsigned char ch = 'A';
int i = 0;
fd = open("/dev/msg", O_RDWR);
if (fd < 0) {
perror("fd failed");
exit(2);
}
//Get Length - 0x01
ioctl(fd, 0x01, &length);
printf("Length:%u\n", length);
ioctl(fd, 0x02);
//Set Character - 0x03
ioctl(fd, 0x03, &ch);
perror("ioctl");
lseek(fd, 0, SEEK_SET);
perror("lseek");
length = read(fd, buffer, 1024);
perror("Read");
printf("length:%d\n", length);
buffer[1023] = '\0';
printf("Buffer:%s\n", buffer);
close(fd);
}
ioctl commands 1, 3 work but not 2. Can you please provide what's the mistake in the code
You should review the requirements for ioctl on the man page:
DESCRIPTION
The ioctl() system call manipulates the underlying device parameters of
special files. In particular, many operating characteristics of char‐
acter special files (e.g., terminals) may be controlled with ioctl()
requests. The argument fd must be an open file descriptor.
The second argument is a device-dependent request code. The third
argument is an untyped pointer to memory. It's traditionally char
*argp (from the days before void * was valid C), and will be so named
for this discussion.
An ioctl() request has encoded in it whether the argument is an in
parameter or out parameter, and the size of the argument argp in bytes.
Macros and defines used in specifying an ioctl() request are located in
the file <sys/ioctl.h>.

C - little code, file descriptor, segmentation fault

I have write this code but i have a problem
first i have a function that create a file descriptor (fd)
int fd;//global
static int init_fd(int fd) {
remove("file descriptor.txt");//if yet present
fd = open("file descriptor.txt", O_WRONLY | O_CREAT, 0666);
if (fd == -1) {
printf("Error in opening the file descriptor!\n");
exit(0);
}
return fd;
}
the second function is a handler function
static int handler(struct connection *conn, enum event ev) {
...
int i;
for (i = 0; i < array_size; i++) {
if (!strncmp(conn->uri, uri_array[i], strlen(uri_array[i]))) {
func_array[i](conn->request_method, conn->uri, NULL, init_fd(fd));
close(fd);
fd = open("file descriptor.txt", O_RDONLY);
ret = read(fd, &buf, BUFSIZ);
if (ret == -1) {
printf("Error in reading!\n");
exit(0);
}
...
}
with fun_array is a pointer to function
httpCallback_t func_array[MAXARRAY];
and the function is
void http_serve1(const char *method, const char *path, const httpOptions_t *options, int fd) {
const char *string = "All is ok1!";
int ret_value;
// send header: 200 OK
ret_value = sendHeaders(fd, TIMEOUT_SEC, NETHTTP_HTTP_HEADER_200, NETHTTP_Content_Type_text_html_utf8, NETHTTP_CRLF, NULL);
// close the file descriptor
close(fd);
}
and the function sendHeaders is
size_t sendHeaders(int fd, int seconds, const char* header1, ...) {
va_list args;
va_start(args, header1);
size_t totalSize = 0;
const char* hdr = header1;
while (hdr != NULL) {
size_t result = sendHeaders(fd, seconds, hdr, NULL); // segmentation fault
if (result < 0) {
return result;
}
totalSize += result;
hdr = va_arg(args, const char*);
va_end(args);
return totalSize;
}
if (size == SIZE) {
setErrorCode(ERROR);
return ERROR;
}
size_t sizewrite = 1024;
tmp[size] = strdup(hdr);
write(fd, tmp, sizewrite);
setErrorCode(SUCCESS);
return SUCCESS;
}
my problem is that my code create a file descriptor, but it doesn't write inside, and during the run i have problem with segmentation fault. anyone have a suggest?

copy_to_user not working - where I am on mistake?

I am trying to get some message from kernel space to userspace, when a condition fails!
Here's my kernel code:
#define MESSAGTOUSER 1
int ret_val;
struct siginfo sinfo;
pid_t id;
struct task_struct *task;
unsigned char msgBuffer[20];
unsigned char buf1[20]= "HI";
static int major_no;
static struct class *safe_class;
static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static int device_open(struct inode *inode, struct file *file);
static int device_write(struct file *file, const char *gdata, size_t len, loff_t *off);
static int device_read(struct file *file, char *buf, size_t len, loff_t *off);
static int device_release(struct inode *inode, struct file *file);
int failureDetection (char* faultMsg) {
strcpy (msgBuffer, faultMsg);
printk(KERN_ALERT"\nMessage from HBM %s\n", msgBuffer);
printk(KERN_ALERT".......... RETURN VALUE ...... : %d", ret_val);
int Reg_Dev(void);
memset (&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGUSR1;
sinfo.si_code = SI_USER;
if (id == 0) {
printk("\ncan't find User PID: %d\n", id);
}else {
//task = pid_task(find_vpid(pid), PIDTYPE_PID);
task = find_task_by_vpid(id);
send_sig_info(SIGUSR1, &sinfo, task);
}
return 0;
}
static int device_open(struct inode *inode, struct file *file){
/*sucess*/
return 0;
}
void strPrint(void) {
printk("value of msgBuffer: %s", msgBuffer);
}
static int device_write(struct file *file, const char *gdata, size_t len, loff_t *off){
get_user (id,(int *)gdata);
if(id <0)
printk(KERN_ALERT"Cann't find PID from userspace its : %i", id);
else
printk(KERN_ALERT"Successfully received the PID of userspace %i", id);
return len;
}
static int
device_read(struct file *file, char *buf, size_t len, loff_t *off){
/*success*/
return 0;
}
static int device_release(struct inode *inode, struct file *file){
/*success*/
return 0;
}
static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
switch (cmd) {
case MESSAGTOUSER:
ret_val = copy_to_user((char *)arg, msgBuffer, sizeof(arg));
printk("Msg of Kernel %s", msgBuffer);
break;
default:
break;
}
return 0;
}
static struct file_operations fops = {
.open = device_open,
.write = device_write,
.read = device_read,
.release = device_release,
.unlocked_ioctl = device_ioctl
};
int Reg_Dev(void) {
major_no = register_chrdev(0, "safe_dev", &fops);
safe_class = class_create(THIS_MODULE, "safe_dev");
device_create(safe_class,NULL, MKDEV(major_no, 0), "safe_dev");
printk("\n Device Registered and Created \n");
return 0;
}
void UnReg_dev (void) {
printk("\nUser PID : %d\n", id);
unregister_chrdev(major_no, "safe_dev");
device_destroy(safe_class, MKDEV(major_no,0));
class_unregister(safe_class);
class_destroy(safe_class);
printk("\n Device Un-Registered and Destroyed \n");
}
extern int Reg_Dev(void);
for he userspace i have this code:
#define PORT 9930
#define G_IP "192.168.10.71"
#define BUFLEN 512
#define MESSAGTOUSER 0
unsigned char *str[20];
char b1[BUFLEN], b2[BUFLEN];
struct sockaddr_in me,client;
int s, i, n=sizeof(me);
int fd;
void error_handler(char *s) {
perror(s);
exit(1);
}
void signal_handler (int signum) {
if(signum == SIGUSR1)
{
printf("\n%s\n",str);
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
error_handler("\nERROR: in Socket\n");
memset((char *) &me, 0, sizeof(me));
me.sin_family = AF_INET;
me.sin_port = PORT;
if (inet_aton(G_IP, &me.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Message from Kernel : %s", &str);
//strcpy (str, newStr);
int cntr =0; sprintf(b2, "\nFailure Message: %s\n",str);
printf("\nsending Fault to PMN Group : Tick - %d\n", cntr++);
if(sendto(s, str, sizeof(str),0,(struct sockaddr *) &me,n)==-1)
error_handler("\nERROR: in sendto()\n");
close (s);
// counter ++;
// sendAndReceiveOverUDP();
return;
}
}
int main() {
pid_t u_id;
u_id = getpid();
int i = 1;
fd = open("/dev/safe_dev",O_RDWR);
write(fd, &u_id, 4);
ioctl (fd, MESSAGTOUSER, &str);
printf("\n PID sent to device successfully: %d \n", u_id);
close(fd);
signal(SIGUSR1, signal_handler);
printf("\nMy PID is: %d\n",u_id);
//printf("Subnet 1 working fine.. Tick - %d", tv.tv_sec);
while (1)
sleep(1);
return 0;
}
Now what I am expecting to receive on Userspace:
Message from Kernel: A<->B
Sending Fault o PMN Group : tick - 0
Message from Kernel: B<->B
Sending Fault o PMN Group : tick - 1
....
...
but what is the output:
Message from Kernel:
Sending Fault o PMN Group : tick - 0
Message from Kernel:
Sending Fault o PMN Group : tick - 1
....
...
It seems that copy_to_user is not working, while in simple program just copying a string from kernel to user is working fine, but while i am using in this scenario then its not working, its compiling without any warning,
Some other Details:
failureDetection() is getting a string like A<->B mentioned in output from rest of the programs..
the same message from failureDetection is printing on kernel level but not transferring at the user level.
I have also tried to create an own string in this and tried to transfer that, but it is also not working! suppose msgBuffer = HI, then I should receive HI on to the userspace. but its not happening! can anyone please please make me correct whats wrong with this code? how can i get updates onto the userspace!!??
Sindhu..
The copy_to_user() only happens in response to the ioctl(), which only happens once, very early on in your code. Presumably at that point the kernel buffer msgBuffer is empty, because the failureDetection() function has not yet run at that point. It doesn't matter if failureDetection() runs later and sets msgBuffer then, because your userspace program never calls the ioctl() again so it doesn't see the new contents of msgBuffer.
You also have a bug in your copy_to_user() call - instead of sizeof(args) (which is a constant 4) you should probably use sizeof msgBuffer.
#caf: Thank you so much..
void signal_handler (int signum) {
if(signum == SIGUSR1)
{
fd = open ("/dev/safe_dev",O_RDWR);
ioctl (fd, MESSAGTOUSER, &str);
close (fd);
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
error_handler("\nERROR: in Socket\n");
memset((char *) &me, 0, sizeof(me));
me.sin_family = AF_INET;
me.sin_port = PORT;
if (inet_aton(G_IP, &me.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Failure Detected on Eth Cards as : %s are non reachable.", str);
printf("\nsending Fault to PMN Group : Tick - %d\n", cntr++);
sprintf(b2, "\nFailure Message: %s\n",str);
if(sendto(s, str, sizeof(str),0,(struct sockaddr *) &me,n)==-1)
error_handler("\nERROR: in sendto()\n");
close (s);
return;
}
}
I was just making a stupid mistake.. hehehe.. i was not adding it in between file open and close block.. your suggestion resolved my issue...
Thank you so much for your response..
Rahee..

How to List Active Ports and Processes using them in Linux, C Code

I am trying to write a C Code to do the same Job as:
netstat -vatp
List all Remote/Local Addresses and Processes using them. But I dunno which files should I be reading?
I tried looking into /proc/net/tcp and /proc/net/udp, but they don't have the process name or process identifier like netstat displays it!
Thanks.
You could check the source code http://freecode.com/projects/net-tools. Just download, unpack the bz2 file and you'll find the netstat.c source code
Quick analyse:
/proc/net/tcp for example has an inode tab, in /proc there is a subfolder for each of these inodes, which contains the information you need.
Some more analysing:
I think it's even worse. netstat just loops through the /proc directory and checks the contents of the numeric sub-directories to find the actual process matching the inode. Not sure as I'm just analysing
http://linux.die.net/man/5/proc is very nice reading :)
For your answer, see How can i match each /proc/net/tcp entry to each opened socket?
You could call the netstat application from within your code. Have a look at execve to capture stdout and stderr.
EDIT:
Since code says more than words:
IEFTask.h
#ifndef IEFTASK_H
#define IEFTASK_H
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <signal.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* MARK: Structure */
struct IEFTask {
const char **arguments; /* last argument should be NULL */
int standardInput;
void *callbackArgument;
void (*callback)(int term, char *out, size_t outLen,
char *err, size_t errLen, void *arg);
};
typedef struct IEFTask IEFTask;
/* MARK: Running */
int
IEFTaskRun(IEFTask *theTask);
#endif /* IEFTASK_H */
IEFTask.c
#include "IEFTask.h"
/* MARK: DECLARATION: Data Conversion */
char *
IEFTaskCreateBufferFromPipe(int fd, size_t *bufLen);
/* MARK: Running */
int
IEFTaskRun(IEFTask *myTask) {
pid_t pid;
int exitStatus, status;
int outPipe[2], errPipe[2];
assert(myTask != NULL);
/* Create stdout and stderr pipes */
{
status = pipe(outPipe);
if(status != 0) {
return -1;
}
status = pipe(errPipe);
if(status != 0) {
close(errPipe[0]);
close(errPipe[1]);
return -1;
}
}
/* Fork the process and wait pid */
{
pid = fork();
if(pid < 0) { /* error */
return -1;
} else if(pid > 0) { /* parent */
waitpid(pid, &exitStatus, 0);
exitStatus = WEXITSTATUS(exitStatus);
} else { /* child */
/* close unneeded pipes */
close(outPipe[0]);
close(errPipe[0]);
/* redirect stdout, stdin, stderr */
if(myTask->standardInput >= 0) {
close(STDIN_FILENO);
dup2(myTask->standardInput, STDIN_FILENO);
close(myTask->standardInput);
}
close(STDOUT_FILENO);
dup2(outPipe[1], STDOUT_FILENO);
close(outPipe[1]);
close(STDERR_FILENO);
dup2(errPipe[1], STDERR_FILENO);
close(errPipe[1]);
execve(myTask->arguments[0],
(char *const *)myTask->arguments, NULL);
exit(127);
}
}
/* Parent continues */
{
char *output, *error;
size_t outLen, errLen;
/* 127 = execve failed */
if(exitStatus == 127) {
close(errPipe[0]);
close(errPipe[1]);
close(outPipe[0]);
close(outPipe[1]);
return -1;
}
/* Read in data */
close(errPipe[1]);
close(outPipe[1]);
output = IEFTaskCreateBufferFromPipe(outPipe[0], &outLen);
error = IEFTaskCreateBufferFromPipe(errPipe[0], &errLen);
close(errPipe[0]);
close(outPipe[0]);
/* Call callback */
(*myTask->callback)(exitStatus,
output, outLen,
error, errLen, myTask->callbackArgument);
if(output) free(output);
if(error) free(error);
}
return 0;
}
/* MARK: Data Conversion */
#define READ_BUF_SIZE (128)
char *
IEFTaskCreateBufferFromPipe(int fd, size_t *bufLen) {
ssize_t totalRead = 0, nowRead;
char readBuffer[READ_BUF_SIZE], *myBuffer = NULL;
char *ptr;
while(1) {
nowRead = read(fd, readBuffer, READ_BUF_SIZE);
if(nowRead == -1) {
free(myBuffer);
return NULL;
} else if(nowRead == 0) {
break;
} else {
ptr = realloc(myBuffer, totalRead + nowRead);
if(ptr == NULL) {
free(myBuffer);
return NULL;
}
myBuffer = ptr;
memcpy(&(myBuffer[totalRead]), readBuffer, nowRead);
totalRead += nowRead;
}
}
if(bufLen) *bufLen = (size_t)totalRead;
return myBuffer;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "IEFTask.h"
void taskCallback(int term,
char *out, size_t outlen,
char *err, size_t errlen)
{
char *ptr;
printf("Task terminated: %d\n", term);
ptr = malloc(outlen + 1);
memcpy(ptr, out, outlen);
ptr[outlen] = '\0';
printf("***STDOUT:\n%s\n***END\n", ptr);
free(ptr);
ptr = malloc(errlen + 1);
memcpy(ptr, err, errlen);
ptr[errlen] = '\0';
printf("***STDERR:\n%s\n***END\n", ptr);
free(ptr);
}
int main() {
const char *arguments[] = {
"/bin/echo",
"Hello",
"World",
NULL
};
IEFTask myTask;
myTask.arguments = arguments;
myTask.standardInput = -1;
myTask.callback = &taskCallback;
int status;
status = IEFTaskRun(&myTask);
if(status != 0) {
printf("Failed: %s\n", strerror(errno));
}
return 0;
}

multiple processes via socketpair hang sometimes

I am trying to implement something that will give me a solution for:
| --> cmd3 --> cmd4 -->
cmd2-->|
| --> cmd5 --> cmd6 -->
and so on...
This is multiple executions of processes and pipe the results via chains of other's processes with threads, each commands chain should run in different thread.
I choose socketpair for the implementation of IPC, because pipe has a a bottleneck with the buffer size limit 64K.
When I test the program with single chain - it's work as expected, but when I am running master command and the output of it I send via socketpair to read end of multiple processes in each thread - the program stuck (look like a deadlock)
Whats I am doing wrong:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/socket.h>
typedef struct command {
char** argv;
int num_children;
struct command* master_cmd;
struct command** chains;
struct command* next;
int fd;
} command;
void be_child(command* cmd);
int execute_master_command_and_pipe_to_childs(command* cmd, int input);
int run_pipeline_sockets(command *cmd, int input);
void waitfor(int fd);
int main(int argc, char* argv[]) {
handle_segfault();
command* cmd1 = (command*) malloc(sizeof(command));
command* cmd2 = (command*) malloc(sizeof(command));
command* cmd3 = (command*) malloc(sizeof(command));
command* cmd4 = (command*) malloc(sizeof(command));
command* cmd5 = (command*) malloc(sizeof(command));
command* cmd6 = (command*) malloc(sizeof(command));
command* chains1[2];
chains1[0] = cmd3;
chains1[1] = cmd5;
char* args1[] = { "cat", "/tmp/test.log", NULL };
char* args3[] = { "sort", NULL, NULL };
char* args4[] = { "wc", "-l", NULL };
char* args5[] = { "wc", "-l", NULL };
char* args6[] = { "wc", "-l", NULL };
cmd1->argv = args1;
cmd2->argv = NULL;
cmd3->argv = args3;
cmd4->argv = args4;
cmd5->argv = args5;
cmd6->argv = args6;
cmd1->master_cmd = NULL;
cmd1->next = NULL;
cmd1->chains = NULL;
cmd1->num_children = -1;
cmd2->master_cmd = cmd1;
cmd2->chains = chains1;
cmd2->next = NULL;
cmd2->num_children = 2;
cmd3->master_cmd = NULL;
cmd3->next = cmd4;
cmd3->chains = NULL;
cmd3->num_children = -1;
cmd4->master_cmd = NULL;
cmd4->next = NULL;
cmd4->chains = NULL;
cmd4->num_children = -1;
cmd5->master_cmd = NULL;
cmd5->next = cmd6;
cmd5->chains = NULL;
cmd5->num_children = -1;
cmd6->master_cmd = NULL;
cmd6->next = NULL;
cmd6->chains = NULL;
cmd6->num_children = -1;
int rc = execute_master_command_and_pipe_to_childs(cmd2, -1);
return 0;
}
int execute_master_command_and_pipe_to_childs(command* cmd, int input) {
int num_children = cmd->num_children;
int write_pipes[num_children];
pthread_t threads[num_children];
command* master_cmd = cmd->master_cmd;
pid_t pid;
int i;
for (i = 0; i < num_children; i++) {
int new_pipe[2];
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, new_pipe) < 0) {
int errnum = errno;
fprintf(STDERR_FILENO, "ERROR (%d: %s)\n", errnum,
strerror(errnum));
return EXIT_FAILURE;
}
if (cmd->chains[i] != NULL) {
cmd->chains[i]->fd = new_pipe[0];
if (pthread_create(&threads[i], NULL, (void *) be_child,
cmd->chains[i]) != 0) {
perror("pthread_create"), exit(1);
}
write_pipes[i] = new_pipe[1];
} else {
perror("ERROR\n");
}
}
if (input != -1) {
waitfor(input);
}
int pipefd = run_pipeline_sockets(master_cmd, input);
int buffer[1024];
int len = 0;
while ((len = read(pipefd, buffer, sizeof(buffer))) != 0) {
int j;
for (j = 0; j < num_children; j++) {
if (write(write_pipes[j], &buffer, len) != len) {
fprintf(STDERR_FILENO, "Write failed (child %d)\n", j);
exit(1);
}
}
}
close(pipefd);
for (i = 0; i < num_children; i++) {
close(write_pipes[i]);
}
for (i = 0; i < num_children; i++) {
if (pthread_join(threads[i], NULL) != 0) {
perror("pthread_join"), exit(1);
}
}
}
void waitfor(int fd) {
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 500000;
retval = select(fd + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
perror("select()");
else if (retval) {
printf("Data is available now on: %d\n", fd);
} else {
printf("No data on: %d\n", fd);
///waitfor(fd);
}
}
void be_child(command* cmd) {
printf(
"fd = %d , argv = %s , args = %s , next = %d , master_cmd = %d , next_chain = %d\n",
cmd->fd, cmd->argv[0], cmd->argv[1], cmd->next, cmd->master_cmd,
cmd->chains);
waitfor(cmd->fd);
int fd = run_pipeline_sockets(cmd, cmd->fd);
waitfor(fd);
int buffer[1024];
int len = 0;
while ((len = read(fd, buffer, sizeof(buffer))) != 0) {
write(STDERR_FILENO, &buffer, len);
}
close(cmd->fd);
close(fd);
}
int run_pipeline_sockets(command *cmd, int input) {
int pfds[2] = { -1, -1 };
int pid = -1;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pfds) < 0) {
int errnum = errno;
fprintf(STDERR_FILENO, "socketpair failed (%d: %s)\n", errnum,
strerror(errnum));
return EXIT_FAILURE;
}
if ((pid = fork()) == 0) { /* child */
if (input != -1) {
dup2(input, STDIN_FILENO);
close(input);
}
if (pfds[1] != -1) {
dup2(pfds[1], STDOUT_FILENO);
close(pfds[1]);
}
if (pfds[0] != -1) {
close(pfds[0]);
}
execvp(cmd->argv[0], cmd->argv);
exit(1);
} else { /* parent */
if (input != -1) {
close(input);
}
if (pfds[1] != -1) {
close(pfds[1]);
}
if (cmd->next != NULL) {
run_pipeline_sockets(cmd->next, pfds[0]);
} else {
return pfds[0];
}
}
}
void segfault_sigaction(int signal, siginfo_t *si, void *arg) {
printf("Caught segfault at address %p\n", si->si_addr);
printf("Caught segfault errno %p\n", si->si_errno);
exit(0);
}
void handle_segfault(void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sigaction));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = segfault_sigaction;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
}
I would come at this problem from a very different angle: rather than coming up with a large data structure to manage the pipe tree, and using threads (where an io blockage in a process may block in its threads) I would use only processes.
I also fail to see how a 64K buffer is your bottleneck when you're only using a 1K buffer.
2 simple functions should guide this: (error handling omitted for brevity, and using a pseudocodey parsecmd() function which turns a space separated string into an argument vector)
int mkproc(char *cmd, int outfd)
{
Command c = parsecmd(cmd);
int pipeleft[2];
pipe(pipeleft);
if(!fork()){
close(pipeleft[1]);
dup2(pipeleft[0], 0);
dup2(outfd, 1);
execvp(c.name, c.argv);
}
close(pipeleft[0]);
return pipeleft[1];
}
Mkproc takes the fd it will write to, and returns what it will read from. This way chains are really easy to initalize:
int chain_in = mkproc("cat foo.txt", mkproc("sort", mkproc("wc -l", 1)));
the next is:
int mktree(char *cmd, int ofd0, ...)
{
int piperight[2];
pipe(piperight);
int cmdin = mkproc(cmd, piperight[1]);
close(piperight[1]);
if(!fork()){
uchar buf[4096];
int n;
while((n=read(piperight[0], buf, sizeof buf))>0){
va_list ap;
int fd;
va_start(ap, ofd0);
for(fd=ofd0; fd!=-1; fd=va_arg(ap, int)){
write(fd, buf, n);
}
va_end(ap);
}
}
return cmdin;
}
Between the two of these, it is very easy to construct trees of arbitrary complexity, as so:
int tree_in = mktree("cat foo.txt",
mktree("rot13",
mkproc("uniq", mkproc("wc -l", 1)),
mkproc("wc -l", open("out.txt", O_WRONLY)), -1),
mkproc("sort", 2), -1);
This would output a sorted foo.txt to stderr, the number of lines in rot13'd foo.txt to out.txt, and the number of non-duplicate lines of rot13'd foo.txt to stdout.

Resources