Using cat and execvp - cat

Trying to understand why this section of code using the cat command isn't working with execvp in C.
char *in[5] ={"cat", "file1.txt", ">>", "file2.txt", 0};
execvp(in[0], in);
When I run it displays the contents of file1.txt but then says:
cat: >> No such file or directory.
Then displays the contents of file2.txt
Why wouldn't it recognize the >> operator in this instance?

You can read the "man tee" command which it read from standard input and write to standard output and files. You could achieve this with below example.
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
/*
Implementation of below command:
cat file1.txt > file2.txt
*/
char *cmd1[] = { "/bin/cat", "file1.txt", 0 };
char *cmd2[] = { "tee", "file2.txt", 0 };
static void sigchld_hdl (int sig)
{
int status;
while (waitpid(-1, &status, 0) > 0) {
if(WIFEXITED(status))
printf("Child exited with code %d\n", WEXITSTATUS(status)); }
}
int runcmd(int pfd[])
{
int i=0;
switch (fork()) {
case -1:
perror ("fork");
return 1;
case 0:
dup2(pfd[0], 0);
close(pfd[1]); /* the child does not need this end of the pipe */
execvp(cmd2[0], cmd2);
perror(cmd2[0]);
exit(10);
default: /* parent */
dup2(pfd[1], 1);
close(pfd[0]); /* the parent does not need this end of the pipe */
execvp(cmd1[0], cmd1);
perror(cmd1[0]);
}
sleep(1);
}
int main (int argc, char *argv[])
{
struct sigaction act;
int fd[2];
pipe(fd);
memset (&act, 0, sizeof(act));
act.sa_handler = sigchld_hdl;
if (sigaction(SIGCHLD, &act, 0)) {
perror ("sigaction");
return 1;
}
runcmd(fd);
return 0;
}

Related

How does named pipe in Linux works?

I'm trying to use named pipe in Linux, using mkfifo.
Below are codes for sender / reader of named pipe :
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define MSG_SIZE 100
//SENDER
int main() {
char msg[MSG_SIZE] = "FIFO is for first-in, first-out.";
int fd;
int cnt;
if(fd = open("./hello", O_RDWR) < 0) { //fifo acts as a typical file
perror("Failed to make fifo : ");
printf("Error : %d\n", errno);
exit(1);
}
int len = strlen(msg) + 1;
while(1) {
if(write(fd, msg, len) == -1) {
perror("Failed to write into fifo : ");
exit(1);
}
else{
printf("Succeed to write msg!");
break;
}
}
sleep(1);
return 0;
}
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#define MSG_SIZE 100
//READER
int main() {
char msg_rc[MSG_SIZE];
int fd;
if(access("./hello",F_OK) == 0) {
fd = open("./hello", O_RDWR);
if(fd < 0) {
perror("Failed to open fifo : ");
exit(1);
}
}
else {
if(fd = mkfifo("./hello", O_RDWR) < 0) {
perror("Failed to open fifo : ");
exit(1);
}
}
printf("Waiting for fifo update");
while(1) {
if(read(fd, msg_rc, MSG_SIZE) == -1) {
perror("Failed to read from fifo : ");
exit(1);
}
printf("Read msg : %s\n", msg_rc);
break;
}
return 0;
}
When I used these codes,
% ./fifoSender
FIFO is for first-in, first-out.Succeed to write msg!%
% ./fifoReader
fifoSender shows msg, and fifoReader shows no msg, which are not desirable behavior.
Any advice will be helpful. Thanks in advance
The main problem is these two lines
if(fd = open("./hello", O_RDWR) < 0) {
if(fd = mkfifo("./hello", O_RDWR) < 0) {
They don't do what you think they do.
Firstly, O_RDWR is a wrong argument for mkfifo. It expects Unix file permissions mask, such as S_IRWU"S_IRWG|S_IRWO, or just 0666.
Secondly and most importantly, since the priority of = is lower than that of <, they are parsed like this:
if(fd = (open("./hello", O_RDWR) < 0)) {
Now, when open("./hello", O_RDWR) is less than 0 (which is highly likely, given that it is either never created or created with an incorrect mode), fd becomes 1, which is the standard output file descriptor.
The correct incantation is
if((fd = open("./hello", O_RDWR)) < 0) { // note () around assignment
if((fd = mkfifo("./hello", 0666)) < 0) {
There are several more subtle shortcomings.
Here is the working code,
// sender
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define PIPE_NAME "./hello"
int main(int argc, char *argv[])
{
const char *message = "FIFO is for first-in, first-out\n";
// Open the pipe for writing
int pipe_fd = open(PIPE_NAME, O_WRONLY);
if (pipe_fd < 0) {
perror("open");
exit(1);
}
// Write data to the pipe
while(1){
int n = write(pipe_fd, message, strlen(message));
if (n < 0) {
perror("write");
exit(1);
}
sleep(1);
}
// Close the pipe
close(pipe_fd);
return 0;
}
//receiver
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define PIPE_NAME "./hello"
int main(int argc, char *argv[])
{
// Create the named pipe
mknod(PIPE_NAME, S_IFIFO | 0666, 0);
// Open the pipe for reading
int pipe_fd = open(PIPE_NAME, O_RDONLY);
if (pipe_fd < 0) {
perror("open");
exit(1);
}
// Read data from the pipe
char buffer[1024];
while(1){
int n = read(pipe_fd, buffer, sizeof(buffer));
if (n < 0) {
perror("read");
exit(1);
}
// Print the data that was read
printf("Received: %.*s\n", n, buffer);
}
// Close the pipe
close(pipe_fd);
return 0;
}

Why this kernel module does not handle open and read syscall?

I'm learning about Linux kernel module with Ubuntu 20.04 (Linux kernel 5.4.0-37 generic). The following is the code that actual code.
I have expected to following module to that pass single byte random number between 0-255 (get_random_bytes(&c, 1)) to user space buffer when it handle ->read() syscall then print a message to dmesg.
But Unfortunately, for now, it does not work. It seems like does not add handle of ->read() and ->open() syscalls.
Why it does not handle ->read() and ->open() syscall?
User space applicattion code (open and read device file) app.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main() {
char c[8];
memset(c, '\0', 8);
int fd = open("/dev/devsaikoro0", O_RDONLY);
read(fd, &c, 1);
//printf("Hello\n");
printf("%s\n", c);
}
Kernel module code:
#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/random.h>
MODULE_LICENSE("Dual BSD/GPL");
static int devsaikoro_num = 3;
static int devsaikoro_major = 0;
static int devsaikoro_minor = 0;
static struct cdev devsaikoro_cdev;
static struct class *devsaikoro_class = NULL;
static dev_t saikoro_dev;
ssize_t read_num(struct file * filp, char __user *buf, size_t count, loff_t *f_pos)
{
int retval;
char c;
get_random_bytes(&c, 1);
if (copy_to_user(buf, &c, 1)) {
printk("devsaikoro read failed\n");
retval = -EFAULT;
return retval;
} else {
printk("devsaikoro read succeeded\n");
return 1;
}
}
struct file_operations fops = {
.read = read_num,
};
int saikoro_open(struct inode *inode, struct file *file) {
printk("devsaikoro open\n");
file->f_op = &fops;
return 0;
}
struct file_operations fops2 = {
.open = saikoro_open,
};
static int devsaikoro_init(void)
{
dev_t dev = MKDEV(devsaikoro_major, 0);
int alloc_ret = 0;
int major;
int cdev_err = 0;
struct device *class_dev = NULL;
alloc_ret = alloc_chrdev_region(&dev, 0, devsaikoro_num, "devsaikoro");
if (alloc_ret) {
goto error;
}
devsaikoro_major = major = MAJOR(dev);
cdev_init(&devsaikoro_cdev, &fops2);
devsaikoro_cdev.owner = THIS_MODULE;
cdev_err = cdev_add(&devsaikoro_cdev, MKDEV(devsaikoro_major, 0), devsaikoro_num);
if (cdev_err)
goto error;
devsaikoro_class = class_create(THIS_MODULE, "devsaikoro");
if (IS_ERR(devsaikoro_class))
goto error;
saikoro_dev = MKDEV(devsaikoro_major, devsaikoro_minor);
class_dev = device_create(devsaikoro_class, NULL, saikoro_dev, NULL, "devsaikoro%d", devsaikoro_minor);
printk(KERN_ALERT "devsaikoro_driver (major %d) installed\n", major);
return 0;
error:
if (cdev_err == 0) {
cdev_del(&devsaikoro_cdev);
}
if (alloc_ret == 0) {
unregister_chrdev_region(dev, devsaikoro_num);
}
return -1;
}
static void devsaikoro_exit(void)
{
dev_t dev = MKDEV(devsaikoro_major, 0);
device_destroy(devsaikoro_class, saikoro_dev);
class_destroy(devsaikoro_class);
cdev_del(&devsaikoro_cdev);
unregister_chrdev_region(dev, devsaikoro_num);
printk(KERN_ALERT "devsaikoro driver removed\n");
}
module_init(devsaikoro_init);
module_exit(devsaikoro_exit);

Alternate Without Semaphores

The program below creates two processes.
The parent process prints the numbers from 0 to 9, while the
child process prints the characters from A to J.
How can I make it alternate the printing using only signals? so no using semaphores or any IPCs.
#include <stdio.h>
int main()
{
int i = 0;
if (fork() == 0) /* Child process */
{
for (i = 0; i < 10; i++) {
printf("%c\n", i + 65);
}
} else /* Parent process */
{
for (i = 0; i < 10; i++) {
printf("%d\n", i);
}
}
}
I figured it out.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>
int main()
{
int i=0;
int status;
int childPID = fork();
if (childPID == 0) /* Child process */
{
for(i=0;i<10;i++){
printf("%c\n",i+65);
kill(getpid(), SIGSTOP);
}
} else /* Parent process */
{
for(i=0;i<10;i++) {
waitpid(childPID,&status,WUNTRACED);
printf("%d\n",i);
kill(childPID, SIGCONT);
}
}
}

trying to use pipe(2) with the sort unix tool but not working

I have been struggling to find what I'm doing wrong and I can't seem to find the issue. When I compile the code below, I get an I/O error.
e.g: /usr/bin/sort: read failed: -: Input/output error
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv, char **envp)
{
int fd[2];
pid_t pid;
pipe(fd);
pid = fork();
if (pid == -1) {
exit(EXIT_FAILURE);
}
if (pid == 0) { /* child */
char *exe[]= { "/usr/bin/sort", NULL };
close(fd[0]);
execve("/usr/bin/sort", exe, envp);
}
else {
char *a[] = { "zilda", "andrew", "bartholomeu", NULL };
int i;
close(fd[1]);
for (i = 0; a[i]; i++)
printf("%s\n", a[i]);
}
return 0;
}
dup2(fd[0], 0) in the child.
dup2(fd[1], 1) in the parent.
close the other fd.

I can't understand sigaction() result

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
void handler(int sig)
{
pid_t pid;
int status;
while( (pid = waitpid(-1, &status, WNOHANG)) > 0 )
printf("%d\n", pid);
}
int main(void)
{
struct sigaction act;
pid_t pid;
int ch;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD, &act, 0);
pid = fork();
if( pid == 0 ) {
exit(0);
}
else {
if( (ch = fgetc(stdin)) == EOF )
printf("EOF\n");
}
}
Hello, I want to know about sigaction function. If I execute this program, the result is like below.
[process id]
EOF
Why EOF is in stdin buffer after processing SIGCHLD signal ? I don't know why this happen. or Maybe I don't know how to use sigaction function ?
fgetc() returns EOF if the file is at end-of-file or an error occurs while trying to read the character. In this case, read() being interrupted by a signal is an error, and the SA_RESTART option to sigaction() prevents this error.
To distinguish between EOF and error, use feof() or ferror(), or test the variable errno. errno will be 0 for the EOF case, non-zero for an error (EINTR in this case).

Resources