I have following program in C, which should run as a deamon and whenever is something written into FIFO, it should write it into a file.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#define BUF_LENGTH 255
volatile int signal_flag = 1;
void signal_handler(int sig)
{
signal_flag = 1;
}
char *getTimeString()
{
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
char *timeStr = asctime (timeinfo);
timeStr[strlen(timeStr) - 1] = 0;
return timeStr;
}
void printUsage()
{
printf("Usage: syslog_daemon PATH INTERVAL\n");
}
int main(int argc, char *argv[])
{
/* print usage */
if(argc != 3)
{
printUsage();
exit(EXIT_SUCCESS);
}
/* process arguments */
char *logFilePath = argv[1];
int interval = atoi(argv[2]);
/* establish the signal handler */
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = signal_handler;
sigaction(SIGALRM, &action, NULL);
/* initialize variables */
int fd;
/*char buf[BUF_LENGTH];
int length;*/
int msgs = 0;
/* Create FIFO if not created */
if (mkfifo("/tmp/pb173_syslog", 0766) == -1 && errno != EEXIST)
{
fprintf(stderr, "Making FIFO failed with error %d\n", errno);
exit(EXIT_FAILURE);
}
/* Run */
daemon(1, 1);
while(1)
{
/* Open FIFO */
fd = open("/tmp/pb173_syslog", O_RDONLY);
close(fd);
/* Open and write into file */
FILE *f = fopen(logFilePath, "a");
fprintf(f, "Daemon write: %d\n", msgs);
fclose(f);
/* Process SIGALRM and write syslog */
if(signal_flag)
{
openlog("syslog_daemon v2", LOG_CONS, LOG_DAEMON);
syslog(LOG_INFO, "Messages written: %d\n", msgs);
closelog();
msgs++;
signal_flag = 0;
alarm(interval);
}
}
return 0;
}
But this program does not write anything into the file. It seems, that when the FIFO is open, it cannot write anywhere. But if I don't open the FIFO, the program writes into the file without any problems. Does anyone know what is the problem? Thanks for any help.
It hangs on open trying to open a FIFO which does not have the second endpoint (the writer) connected.
You may want to use O_NONBLOCK.
Here is a quote from strace output that shows where it hangs:
$ strace -p 23114
Process 23114 attached - interrupt to quit
open("/tmp/pb173_syslog", O_RDONLY
If you write something to the FIFO (e.g. echo test > /tmp/pb173_syslog) it unblocks and starts working.
Related
I'm implementing a pipe in C, where multiples producer programs (9 in my case) write data to one single consumer program.
The problem is that some producers (some times one or two) exit the program abruptly when calling the write() function.
The code is simple, here is the producer code:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#define MSG_SIZE_BYTES 4
void send(unsigned int * msg){
int fd, msg_size;
int r;
char buffer [5];
char myfifo[50] = "/tmp/myfifo";
fd = open(myfifo, O_WRONLY);
if(fd == -1){
perror("error open SEND to fifo");
}
r = write(fd, msg, MSG_SIZE_BYTES);
if(r == -1){
perror("error writing to fifo");
}
close(fd);
printf("Message send\n");
}
int main(int argc, char *argv[]){
int cluster_id = atoi(argv[1]);
unsigned int msg[1];
msg[0] = cluster_id;
while(1){
printf("Press a key to continue...\n");
getchar();
send(msg);
}
}
And here is the consumer code
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#define MSG_SIZE_BYTES 4
int receive(unsigned int * received_msg){
int fd, msg_size;
int ret_code;
char buffer [5];
char myfifo[50] = "/tmp/myfifo";
fd = open(myfifo, O_RDONLY);
if(fd == -1)
perror("error open RECV to fifo");
ret_code = read(fd, received_msg, MSG_SIZE_BYTES);
close(fd);
if (ret_code == -1){
printf("\nERROR\n");
return 0;
}
return 1;
}
void main(){
mkfifo("/tmp/myfifo", 0666);
unsigned int msg[1];
while(1){
receive(msg);
printf("receive msg from id %d\n", msg[0]);
}
}
I'm compiling the producers and consumer with the following command: gcc -o my_progam my_program.c
To reproduce the problem, you need to open 9 terminals to run each producer and 1 terminal to run the consumer.
Execute the consumer: ./consumer
Execute the producer in all terminals simultaneously, passing to each execution an associated ID passed by command line. Ex: ./producer 0, ./producer 1.
After the producer send messages some times (10 in average), one arbitrary producer will abruptly stop its execution, showing the problem.
The following image depicts the execution:
Terminals ready to execute
The following image depicts the error on producer ID 3
Error on producer 3
Thanks in advance
It looks like the consumer program closes the reading end of the pipe after reading data:
fd = open(myfifo, O_RDONLY);
if(fd == -1){
perror("error open RECV to fifo");
}
ret_code = read(fd, received_msg, MSG_SIZE_BYTES);
close(fd);
All other writers, which are currently trying to write() data (i.e. are blocked in the write()-syscall) now receive a SIGPIPE, which leads to program termination (if no other signal handling is specified).
Your consumer program may not close the filedescriptor while producers are writing. Just read the next datum without closing.
Problem SOLVED:
The problem is that I was opening and closing the FIFO at each message, generating a Broken pipe in some write attempts. Removing the close() and inserting the open() function for BOTH producer and consumer at the begging of the code instead inside the loop solved the problem.
Here is the code of producer with the bug fixed:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#define MSG_SIZE_BYTES 4
int my_fd;
void send(unsigned int * msg){
int fd, msg_size;
int r;
char buffer [5];
char myfifo[50] = "/tmp/myfifo"
if(fd == -1){
perror("error open SEND to fifo");
}
r = write(my_fd, msg, MSG_SIZE_BYTES);
if(r == -1){
perror("error writing to fifo");
}
//close(fd);
printf("Message send\n");
}
int main(int argc, char *argv[]){
int cluster_id = atoi(argv[1]);
unsigned int msg[1];
msg[0] = cluster_id;
my_fd = open("/tmp/myfifo", O_WRONLY);
while(1){
printf("Press a key to continue...\n");
getchar();
send(msg);
}
}
And here is the consumer code:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#define MSG_SIZE_BYTES 4
int my_fd;
int receive(unsigned int * received_msg){
int fd, msg_size;
int ret_code;
char buffer [5];
char myfifo[50] = "/tmp/myfifo";
if(fd == -1)
perror("error open RECV to fifo");
ret_code = read(my_fd, received_msg, MSG_SIZE_BYTES);
//close(fd);
if (ret_code == -1){
printf("\nERROR\n");
return 0;
}
return 1;
}
void main(){
mkfifo("/tmp/myfifo", 0666);
my_fd = open("/tmp/myfifo", O_RDONLY);
unsigned int msg[1];
while(1){
receive(msg);
printf("receive msg from id %d\n", msg[0]);
}
}
Thank you all!!
I have a program I'm writing with a globally defined File variable that I'm trying to access by the parent after it forks a child. However, the child is the one that is writing to the file so when I try to read it as the parent I get a Error: No such file or directory. Only it's not thrown as an error, it's stored in the tmpFP file. I'm not sure how to get around this.
I've omitted some code for legibility, the references to sockets are from a custom library, assume that works. The relevant comments should be in all caps, they point to where I believe the problem arises.
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <stdarg.h>
#include "Socket.h"
#include "ToUpper.h" /* definitions shared by client and server */
#define LINE_SIZE 50
#define MAX_WORDS 10
#define MAX_LINE 1024
#define MAX_TMP 100
#define MAX_ARGS 4 /* allows program name + 3 positional parameters */
#define MIN_ARGS 2 /* must have at least 1 positional parameter */
#define NUM_PARMS 4 /* allows program name + 2 parameters + NULL */
#define ERR_RETURN -1
/* variables to hold socket descriptors */
ServerSocket welcome_socket;
Socket connect_socket;
char new_line[MAX_LINE];
char tmp_name[MAX_TMP]; //DECLARING FILENAME
char id_str[MAX_TMP];
char arr[LINE_SIZE]={0};
int id;
FILE *fp; //FILE USED IN CHILD PROCESS
void toupper_service(void);
int main(int argc, char* argv[])
{
FILE *tmpFP; //FILE USED IN PARENT PROCESS
pid_t spid; /* pid_t is typedef for Linux process ID */
int c=0,index=0;
id = (int) getpid();
sprintf(id_str, "%d", id);
strcpy(tmp_name,"tmp");
strcat(tmp_name, id_str);
if (argc < 2)
{
printf("No port specified\n");
return (-1);
}
welcome_socket = ServerSocket_new(atoi(argv[1]));
connect_socket = ServerSocket_accept(welcome_socket);
Socket_close(welcome_socket);
while (c!=EOF)
{
while((c=Socket_getc(connect_socket))!='\n')
{
arr[index]=c;
index++;
}
arr[index]='\0';
/* accept an incoming client connection; blocks the
* process until a connection attempt by a client.
* creates a new data transfer socket.
*/
spid = fork(); /* create child == service process */
if (spid == -1)
{
perror("fork");
exit (-1);
}
if (spid == 0)
{/* code for the service process */
toupper_service();
Socket_close(connect_socket);
exit (0);
} /* end service process */
else /* daemon process closes its connect socket */
{
waitpid(spid,NULL,0);
//PASSES THIS TEST SOMEHOW
if((tmpFP = fopen (tmp_name, "r")) == NULL)
{
fprintf(stderr, "%s\n",tmp_name);
fprintf (stderr, "error opening tmp file\n");
exit (-1);
}
while((c=fgetc(tmpFP))!=EOF)
{
//PRINTS OUT ERROR HERE A LETTER AT A TIME
fprintf(stderr, "c: %d %c\n", c, (char)c);
Socket_putc(c, connect_socket);
}
remove(tmp_name);
Socket_putc('\0', connect_socket);
Socket_close(connect_socket);
/* reap a zombie every time through the loop, avoid blocking*/
}
}/* end of infinite loop for daemon process */
fprintf(stderr, "C: %d\n",c);
}
void toupper_service(void)
{
int i=0, c, pointer,num_words=0,index=0;
int too_many_words=0;
char *word[MAX_WORDS]={NULL};
//THIS IS THE OTHER PLACE TMP_NAME IS USED
fp = freopen(tmp_name, "w", stdout);
while ((c=arr[index])!='\0')
{
if(c==' '||c=='\t'||c=='\n') //word encountered
{
if(num_words>=MAX_WORDS-1)
{
printf("Too many commands passed\n");
too_many_words=1;
exit(0);
break;
}
arr[index]='\0';
word[num_words]=&arr[pointer];
pointer=i+1;
num_words++;
}
index++;
}
word[num_words]=NULL;
if(too_many_words==0)
{
c=0;
int error=execvp(word[0],word);
}
return;
}
I am looking for copying PID value from User space to Kernel space, here is my code snaps.
Kernel Module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
MODULE_LICENSE ("GPL");
struct siginfo sinfo;
pid_t pid;
struct task_struct *task;
int init_module()
{
memset(&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGIO;
sinfo.si_code = SI_USER;
pid = 5218; // Everytime a new PID
// task = find_task_by_vpid(pid); I am also working on new and old version of UBUNTU so thats why this is here
task = pid_task(find_vpid(pid), PIDTYPE_PID);
printk("%d .\n", task);
if(task == NULL) {
printk("Cannot find PID from user program\r\n");
return 0;
}
send_sig_info(SIGIO, &sinfo, task);
return 0;
}
void cleanup_module ()
{
printk(KERN_ALERT"\nGoodBye World\n\n");
}
Userspace Code:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
void signal_handler(int signum)
{
if (signum == SIGIO) printf("SIGIO\r\n"); return;
}
int main()
{
int i = 1;
signal(SIGIO, signal_handler);
printf("My PID is %d.\n", getpid());
while (i);
return 0;
}
Now, here I am always running user space program to get PID and then I always have to edit the pid variable in Kernel module.
I found one way to access information from user space into Kernel space and vice-versa (i.e., using copy_from/to_user() )
But I am unable to understand either of them for getting a PID from user space, I have to make file in /dev directory and should apply all the required functions for just getting PID?
Is there any other way? if not, then can anyone please help me to do this? I am new in c programming and playing with kernel module directly so its hard for me.
Look into code you have given, it seems that you want to handle SIGIO signal
Here is my attempt to solve your problem,
signal_kernel.c file :
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/siginfo.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
#include <linux/debugfs.h>
#include <linux/pid.h>
#define MAX 10
MODULE_LICENSE("GPL");
struct dentry *file;
static ssize_t write_conf_pid(struct file *file, const char *buf,
size_t count, loff_t *position)
{
char temp_str[MAX];
int ret;
int pid = 0;
struct siginfo sinfo;
struct task_struct *task;
/* NEVER TRUST USER INPUT */
if (count > MAX)
return -EINVAL;
if (copy_from_user(temp_str, buf, MAX) != 0)
return -EFAULT;
ret = sscanf(temp_str, "%d", &pid);
if (ret != 1) {
pr_info("Error in reading PID value from user");
return -EINVAL;
}
pr_info("User entered pid %d\n", pid);
memset(&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGIO;
sinfo.si_code = SI_USER;
task = pid_task(find_vpid(pid), PIDTYPE_PID);
if (task == NULL) {
pr_info("Cannot find PID from user program\r\n");
return -ENODEV;
}
ret = send_sig_info(SIGIO, &sinfo, task);
if (ret < 0)
pr_info("Error sending signal\n");
return count;
}
static const struct file_operations my_fops = {
.write = write_conf_pid,
};
int init_module()
{
/* Only root can write to this file */
file = debugfs_create_file("pidconf", 0200, NULL, NULL, &my_fops);
return 0;
}
void cleanup_module()
{
pr_info("\nGoodBye World\n\n");
}
signal_user.c file :
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
void signal_handler(int signum)
{
if (signum == SIGIO)
printf("SIGIO\r\n");
return;
}
int main()
{
int i = 1;
signal(SIGIO, signal_handler);
printf("My PID is %d.\n", getpid());
while (i);
return 0;
}
After compiling and running both user space and kernel space program, use debugfs interface to send PID value to Kernel space,
$ insmod signal_kernel.ko
$ ./signal_user
My PID is 17633.
... # Process will run in loop due to while(1)
From another terminal, provide PID to debugfs interface,
$ echo 17633 > /sys/kernel/debug/pidconf
There are various ways (sysfs, misc_char_device, char device etc.) to this task, but this will give you brief idea about using copy_from_user() and copy_to_user()
Please note that there is little error handling done in signal_user.c and signal_kernel.c.
I am trying to make this work but no luck, basically i need to write to the pipe and then make the pipe return back with the text i sent. I have a server.c and client.c , so i make the server.c run..., open a new terminal and then run the client.. the problem is that the client doesnt do anything when i run it.. I am sure i am missing something.. like closing the pipe. i am not sure.. I would really appreciate some guidance
server.c
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define PIPE1 "PIPE1"
#define PIPE5 "PIPE5"
#define MAX_BUF_SIZE 255
int main(int argc, char *argv[])
{
int rdfd1,rdfd2,rdfd3,rdfd4, wrfd1,wrfd2,wrfd3,wrfd4,ret_val, count, numread1,numread2,numread3,numread4;
char buf1[MAX_BUF_SIZE];
char buf2[MAX_BUF_SIZE];
char buf3[MAX_BUF_SIZE];
char buf4[MAX_BUF_SIZE];
/* Create the first named - pipe */
ret_val = mkfifo(PIPE1, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
return 1;
}
ret_val = mkfifo(PIPE5, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
return 1;
}
/* Open the first named pipe for reading */
rdfd1 = open(PIPE1, O_RDONLY);
/* Open the first named pipe for writing */
wrfd1 = open(PIPE5, O_WRONLY);
/* Read from the pipes */
numread1 = read(rdfd1, buf1, MAX_BUF_SIZE);
buf1[numread1] = '0';
printf("Server : Read From the pipe : %sn", buf1);
/*
* Write the converted content to
* pipe
*/
write(wrfd1, buf1, strlen(buf1));
}
client.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PIPE1 "PIPE1"
#define PIPE5 "PIPE5"
#define MAX_BUF_SIZE 255
int main(int argc, char *argv[ ]) {
pid_t childpid;
int error;
int i;
int nprocs;
/* check command line for a valid number of processes to generate */
int wrfd1, rdfd1, numread;
char rdbuf[MAX_BUF_SIZE];
if ( (argc != 2) || ((nprocs = atoi (argv[1])) <= 0) ) {
fprintf (stderr, "Usage: %s nprocs\n", argv[0]);
return 1;
}
for (i = 1; i < nprocs; i++) {
/* create the remaining processes */
if ((childpid = fork()) == -1) {
fprintf(stderr, "[%ld]:failed to create child %d: %s\n", (long)getpid(), i, strerror(errno));
return 1;
}
/* Open the first named pipe for writing */
wrfd1 = open(PIPE5, O_WRONLY);
/* Open the second named pipe for reading */
rdfd1 = open(PIPE1, O_RDONLY);
if (childpid)
break;
char string1[100];
if(sprintf(string1, "This is process %d with ID %ld and parent id %ld\n", i, (long)getpid(), (long)getppid())) {
write(wrfd1,string1, strlen(string1));
}
/* Read from the pipe */
numread = read(rdfd1, rdbuf, MAX_BUF_SIZE);
rdbuf[numread] = '0';
printf("Full Duplex Client : Read From the Pipe : %sn", rdbuf);
}
return 0;
}
It seems like both server and client read from PIPE1 and write to PIPE5. Shouldn't one of them write to PIPE1 so that the other can read it from the other end?
Also, if you're testing with ./client 1, your for (i = 1; i < nprocs; i++) loop will never execute.
One last thing, see this question. I'm not entirely sure it applies to your code, but it's worth keeping in mind.
Shouldn't this line be '\0' ?
buf1[numread1] = '0';
I have a program that checks the modification time of a file and executes the file if it has changed. Currently it works if I run it on my mac, but it seg faults if I run it on ubuntu. Please help me.
note: this is in c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define CONTERROR(cond, statement) \
if (cond) { \
perror(statement); \
continue; \
}
#define FATALERROR(cond, statement) \
if (cond) { \
perror(statement); \
exit(EXIT_FAILURE); \
}
/**
* Handler for the signals.
*/
static void handler(int signum) {
;
}
/**
* Main.
*/
int main(int argc, char *argv[]) {
struct sigaction sa;
struct stat buf;
struct itimerval tb;
pid_t pid;
int modTime;
if (argc != 2) {
fprintf(stderr, "usage: remote file\n");
exit(EXIT_FAILURE);
}
FATALERROR(stat(argv[1], &buf) == -1, "stat");
modTime = buf.st_mtime;
tb.it_interval.tv_sec = 0;
tb.it_interval.tv_usec = 50000;
tb.it_value.tv_sec = 0;
tb.it_value.tv_usec = 50000;
setitimer(ITIMER_REAL, &tb, 0);
sa.sa_handler = handler;
FATALERROR(sigemptyset(&sa.sa_mask) == -1, "mask");
FATALERROR(sigaction(SIGALRM, &sa, NULL) == -1, "sigaction");
while (1) {
pause();
CONTERROR(stat(argv[1], &buf) == -1, "stat");
if (modTime != buf.st_mtime) {
modTime = buf.st_mtime;
pid = fork();
FATALERROR(pid == -1, "fork");
if (!pid) {
execlp("rexec", "rexec", NULL);
fprintf(stderr, "exec\n");
}
}
}
exit(EXIT_SUCCESS);
}
Most of your sigaction structure is not initialized, so could contain random data. If sa_flags.SA_SIGINFO is accidentally set in this uninitialized data, then the signal will cause sa_sigaction instead of sa_handler to be called, which is also uninitialized, so will almost certainly crash.
You may find it easier to debug if you initialize all the fields, including making sure you have set the flags in a way the ensures the signals behaves the way you want.