How to set fifo permissions so that file can be created - c

I am doing a school project in which I have to buplicate the syslog daemon. I am trying to write for the syslog daemon via a named pipe which is opened with command
char * fdfifo = "/fifo";
mkfifo(fdfifo, 0666);
However when I try to open the pipe, i get an error message from errno:
Value of errno: 13
Error printed by perror: Permission denied
Error opening file: Permission denied
when I run the application as sudo, the file is created as it should be. And the problem is only encountered when the file, in which I am trying to store the file descriptor doesn't exist and I have to create the file.
Here is my full code until the point of the error:
pthread_mutex_t lock2;
char * logName;
int fd[2];
static volatile int keepRunning = 1;
void intHandler(int dummy) {
keepRunning = 0;
}
int openLog(char* logname, pthread_mutex_t lock, pthread_t tid){
signal(SIGINT, intHandler);
lock2=lock;
logName = logname;
// FILE *f;
pid_t pid;
/* Fork off the parent process */
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
return 0;
/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);
/* Catch, ignore and handle signals */
//TODO: Implement a working signal handler */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0){
exit(EXIT_SUCCESS);
}
/* Set new file permissions */
umask(0);
char * fdfifo = "/fifo";
mkfifo(fdfifo, 0666);
int errnum;
errnum = errno;
fprintf(stderr, "Value of errno: %d\n", errno);
perror("Error printed by perror");
fprintf(stderr, "Error opening file: %s\n", strerror( errnum ));

Unless you are root (e.g. sudo 'd) you do not have permissions to create anything, including a fifo in the / directory suggest you choose a dir you do have write permission to. Changing the permissions on / is not recommended.

Related

Logging to a file in daemon process

I am following a quick guide how to create daemon process in C, that was created as an answer to one of Stack Overflow questions.
And here is a problem, to make this code easier for me I have created a file, where I am logging some debug data, but when I make a second fork(), my new child seems not to log anything. I check the list of processes that exists. I have no idea why it did not print anything to my file. Any ideas? 0.o
My adjusted code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#define LOG_FILE "/local_pv/asiwek/daemon_test/daemon_log.log"
static void skeleton_daemon(FILE* file)
{
pid_t pid;
/* Fork off the parent process */
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
fprintf(file ,"I'm a child! \n");
/* On success: The child process becomes session leader */
if (setsid() < 0)
{
fprintf(file ,"ERROR: setsid()! \n");
exit(EXIT_FAILURE);
}
/* Catch, ignore and handle signals */
//TODO: Implement a working signal handler */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
{
fprintf(file ,"ERROR: fork()! \n");
exit(EXIT_FAILURE);
}
/* Success: Let the parent terminate */
if (pid > 0)
{
fprintf(file, "I'm a parent of the child! pid : %d", pid);
exit(EXIT_SUCCESS);
}
fprintf(file ,"New Child!! \n"); // here program stops logging
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriated directory */
chdir("/local_pv/asiwek/daemon_test/");
fprintf(file ,"chdir \n");
/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
{
close (x);
}
/* Open the log file */
//openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
fprintf(file ,"skeleton_daemon() end. \n");
}
int main()
{
FILE* f = fopen(LOG_FILE, "w");
skeleton_daemon(f);
fprintf(f ,"Oh boy I am a daemon!!! \n");
while (1)
{
//TODO: Insert daemon code here.
// syslog (LOG_NOTICE, "First daemon started.");
fprintf(f, "Some log.");
sleep (200);
break;
}
//syslog (LOG_NOTICE, "First daemon terminated.");
//closelog();
fclose(f);
return EXIT_SUCCESS;
}

How to implement a concurrent server to create a worker process for each client request in C using double-fork technique?

I'm trying to implement a concurrent server in C using a daemon process and fifo (named pipes). My server and client applications successfully communicate but I want my server to handle multiple client requests concurrently. To handle multiple client requests, I have to create separate worker processes using double fork technique. I think I need to fork my worker process at the beginning of the server's infinite loop.
However, with this way server creates tons of processes and never stops to listen new client request. At some point I should block creating new processes but I can't figure out how to do it. I think exit(0) function at the end of the second child should do it and kill the second child process but it seems not working and program keeps creating new processes in an infinite loop.
Server:
createDaemon(argv[1]);
umask(0);
mkfifo(serverFifoPath, 0666)
int serverFd = open(serverFifoPath, O_RDONLY);
int dummyFd = open(serverFifoPath, O_WRONLY);
signal(SIGPIPE, SIG_IGN)
for(;;)
{
syslog(LOG_NOTICE, "DAEMON STARTED");
pid_t pid;
if ( (pid = fork()) < 0)
{
syslog(LOG_ERR, "fork error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
else if (pid == 0)
{ /* first child */
if ( (pid = fork()) < 0)
{
syslog(LOG_ERR, "fork error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
else if (pid > 0)
{
exit(0); /* parent from 2nd fork == 1st child */
}
/* second child. */
syslog(LOG_NOTICE, "second child, pid = %d\n", getpid());
//Read PID of the client
pid_t clientPID = 0;
read(serverFd, &clientPID, sizeof(clientPID))
//Server make other reads here
//and other server operations
exit(0); /* I think this exit(0) should kill the second child
after processing client request but it seems not
working and program creates many processes*/
}
/* wait for first child */
if (waitpid(pid, NULL, 0) != pid)
{
syslog(LOG_ERR, "waitpid error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
//original process
}
int clientFd = open(clientFifo, O_WRONLY);
//Server writes to fifo here
close(clientFd);
}
Client:
mkfifo(clientFifo, 0666);
int serverFd = open(serverFifoPath, O_WRONLY);
//Client writes here
int clientFd = open(clientFifo, O_RDONLY);
unlink(clientFifo);
//Client reads here
And I got my createDaemon function from here: Creating a Daemon in Linux

fcntl F_GETLK always return true

i'm trying to make a single instance daemon using a lock file but fcntl() doesn't seem to work as expected...
int creat_lock_file (char * pid_fn)
{
struct flock pid_lck = {F_WRLCK, SEEK_SET, 0, 0, 0 };
/* Open/Create pid file */
int pid_fd = open (pid_fn, O_CREAT | O_WRONLY, 0640);
if (pid_fd == -1)
{
syslog (LOG_ERR, "Unable to open PID file > [Errno: %s]", strerror(errno));
return -1;
}
/* Place write lock on pid file */
if (fcntl(pid_fd, F_SETLK, &pid_lck) == -1) {
/* Unhandled error ocured */
syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
close (pid_fd);
return -1;
}
/* Write PID to lock file */
char pid_lock_buf[11];
sprintf (pid_lock_buf, "%ld\n", (long) getpid ());
write (pid_fd, pid_lock_buf, strlen (pid_lock_buf)+1);
return 0;
}
int get_lock_file_status (char * pid_fn)
{
struct flock pid_lck = {F_WRLCK, SEEK_SET, 0, 0, 0 };
/* Open/Create pid file */
int pid_fd = open (pid_fn, O_CREAT | O_WRONLY, 0640);
if (pid_fd == -1)
{
syslog (LOG_ERR, "Unable to open PID file > [Errno: %s]", strerror(errno));
return -1;
}
/* try locking pid file*/
if(fcntl(pid_fd, F_GETLK, &pid_lck) == -1)
{
if(errno == EAGAIN || errno == EACCES) /* file already locked, close fd and return -1 */
{
close (pid_fd);
return -1;
}
else /* Unhandled error ocured */
{
syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
close (pid_fd);
return -1;
}
}
close (pid_fd);
return 0;
}
so i call get_lock_file_status and exit if it returns -1 to make sure no other instance is running than i do some stuff (fork chdir etc) and call creat_lock_file to crate and lock a pid file after successfully creating a daemon...
when complied and run the program works as expected runs creates lock file and writes pid to it but when a second instance is started the second instance simply opens the same lock file and writes it's own pid to it!
what am i doing wrong? shouldn't the second instance return -1 in get_lock_file_status?
You're checking the result of F_GETLK in the wrong way. fcntl(2) with F_GETLK only returns -1 on errors. The correct way to check if it would be possible to acquire the lock is to check if the l_type field of the struct flock is set to F_UNLCK, like in the following:
/* try locking pid file*/
if(fcntl(pid_fd, F_GETLK, &pid_lck) == -1) {
syslog (LOG_ERR, "Unhandled error ocured while locking PID file > [Errno: %s]", strerror(errno));
close(pid_fd);
return -1;
}
close(pid_fd);
return (pid_lck.l_type == F_UNLCK) ? 0 : -1;
It should be possible to roll creat_lock_file() and get_lock_file_status() into a single function that opens the file (and creates it if it doesn't exist), tries to set a lock on it, and returns whether the locking was successful (e.g., either a file descriptor or -1).
You should truncate(2) the PID file to zero bytes before writing the PID into it by the way. Say the PID of your process is 5 and the old PID in the PID file is 123. Writing "5" would then make the contents of the PID file "523". Truncating the file to zero bytes solves this problem. (O_TRUNC won't work since you'd be clearing the file when opening it to test if the lock is set.)
Removing the PID file with unlink(2) when the program exits is pretty common too. That way the non-existence of the file indicates the daemon isn't running (though it's not foolproof as the process or system could crash).

process termination doesn't affect waitpid()

I need to simulate the following bash commands using C under Linux (with fork, exec, kill, signal, wait, waitpid, dup2, open, sleep, pipe etc).
[0] echo 'tail-f $1' > /tmp/rtail
[1]/tmp/rtail ~/.bash_history >> /tmp/1.txt &
PID of process [1] should be saved.
[2] Expect termination of the command started on step [1]. After termination print on the screen: "Program 1 terminated."
So far I have this code:
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
pid_t pID = fork();
if (pID == 0) // child
{
int file = open("/tmp/rtail", O_CREAT | O_WRONLY);
//Now we redirect standard output to the file using dup2
dup2(file, 1);
puts("tail -f $1");
close(file);
system("chmod 777 /tmp/rtail");
exit(0);
} else if (pID < 0) // failed to fork
{
printf("Failed to fork");
exit(1);
// Throw exception
} else // parent
{
pid_t pID2 = fork();
if (pID2 == 0) {
char tmp1[20];
sprintf(tmp1, "echo %i > /tmp/pidprog1", getpid());
system(tmp1);
int file = open("/tmp/1.txt", O_APPEND | O_WRONLY);
//Now we redirect standard output to the file using dup2
dup2(file, 1);
FILE* proc = popen("sh /tmp/rtail ~/.bash_history", "r");
char tmp[20];
while (fgets(tmp, 40, proc) != NULL) {
printf(tmp);
}
fclose(proc);
exit(0);
}
else if (pID2 < 0) // failed to fork
{
printf("Failed to fork");
exit(1);
// Throw exception
} else {
FILE* fl = fopen("/tmp/pidprog1", "r");
char buff[10];
fgets(buff, 10, fl);
int pidc = atoi(buff);
fclose(fl);
int status;
waitpid(pidc, &status, 0);
printf("Program 1 terminated\n");
}
}
// Code executed by both parent and child.
return 0;
}
The problem is that when I manually kill the process using PID saved into /tmp/pidprog1, parent process doesn't stop waiting and doesn't print "Program 1 terminated" line.
The parent is very likely reading a garbage value into pidc. You are doing nothing to ensure that the grandchild has actually written the pid before the parent tries to read it. You need to use wait to ensure that valid pids are in the file. (Or, just keep track of the pids from the return value of fork.)
You are not doing enough error checking: what happens if any open fails? (eg, when you try
to open /tmp/1.txt for appending but it doesn't already exist?)
Why are you using fgets to read 40 characters into a buffer of size 20?
Why are you dup'ing and using fputs instead of just writing to the fd?
Why are you printing error messages to stdout instead of stderr ( use perror ).

How do I ensure that only one copy of a daemon is running?

My code to daemonize a process is:
static int daemonize( const char *lockfile )
{
pid_t pid, sid, parent;
int lfp = -1;
char buf[16];
/* already a daemon */
if ( getppid() == 1 ) return 1;
/* Each copy of the daemon will try to
* create a file and write its process ID
* in it. This will allow administrators
* to identify the process easily
*/
/* Create the lock file as the current user */
if ( lockfile && lockfile[0] ) {
lfp = open(lockfile,O_RDWR|O_CREAT,LOCKMODE);
if ( lfp < 0 ) {
syslog( LOG_ERR, "unable to create lock file %s, code=%d (%s)",
lockfile, errno, strerror(errno) );
exit(EXIT_FAILURE);
}
}
/* If the file is already locked, then to ensure that
* only one copy of record is running. The filelock function will fail
* with errno set to EACCESS or EAGAIN.
*/
if (filelock(lfp) < 0) {
if (errno == EACCES || errno == EAGAIN) {
close(lfp);
//return(1);
exit(EXIT_FAILURE);
}
syslog(LOG_ERR, "can't lock %s: %s", lockfile, strerror(errno));
exit(EXIT_FAILURE);
}
ftruncate(lfp, 0);
sprintf(buf, "%ld", (long)getpid());
write(lfp, buf, strlen(buf)+1);
/* Drop user if there is one, and we were run as RUN_AS_USER */
if ( getuid() == 0 || geteuid() == 0 ) {
struct passwd *pw = getpwnam(RUN_AS_USER);
if ( pw ) {
syslog( LOG_NOTICE, "setting user to " RUN_AS_USER );
setuid( pw->pw_uid );
}
}
/* Trap signals that we expect to recieve */
signal(SIGCHLD,child_handler);
signal(SIGUSR1,child_handler);
signal(SIGALRM,child_handler);
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
syslog( LOG_ERR, "unable to fork daemon, code=%d (%s)",
errno, strerror(errno) );
exit(EXIT_FAILURE);
}
/* If we got a good PID, then we can exit the parent process. */
if (pid > 0) {
/* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
for two seconds to elapse (SIGALRM). pause() should not return. */
alarm(2);
pause();
exit(EXIT_FAILURE);
}
/* At this point we are executing as the child process */
parent = getppid();
/* Cancel certain signals */
signal(SIGCHLD,SIG_DFL); /* A child process dies */
signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
/* Change the file mode mask */
umask(0);
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
syslog( LOG_ERR, "unable to create a new session, code %d (%s)",
errno, strerror(errno) );
exit(EXIT_FAILURE);
}
/* Change the current working directory. This prevents the current
directory from being locked; hence not being able to remove it. */
if ((chdir("/")) < 0) {
syslog( LOG_ERR, "unable to change directory to %s, code %d (%s)",
"/", errno, strerror(errno) );
exit(EXIT_FAILURE);
}
/* Redirect standard files to /dev/null */
freopen( "/dev/null", "r", stdin);
freopen( "/dev/null", "w", stdout);
freopen( "/dev/null", "w", stderr);
/* Tell the parent process that we are A-okay */
kill( parent, SIGUSR1 );
return 0;
}
I want to run only one instance of my program at a time when I start it using:
service [script] start
But whenever this command executes two or more times, it creates the same number of daemon processes in the running condition. I want to get rid of this behavior. Any suggestion will be highly appreciated.
Don't use a file lock; instead, use the O_EXCL flag to open(), which will fail with EEXIST if the file already exists. This is normally done with the pid file, since it needs to be exclusive anyway.
Another alternative to a pid file is to open a tcp/udp port from your daemon. Running another instance of the daemon will fail when trying to open that same port.

Resources