I have the following problem.
I have two processes that are being synchronized with semaphores and the idea is this:
process 1 writes something to the txt file
process 2 writes something to the txt file
process 1 writes something to the test file
I have included this sample code that demonstrates the problem:
// semaphore names
#define NAME1 "/s1"
#define NAME2 "/s2"
int main()
{
/* semaphores for process synchronization */
sem_t *sm1;
sm1 = sem_open( NAME1, O_CREAT, 0666, 0);
sem_t *sm2;
sm2 = sem_open(NAME2, O_CREAT, 0666, 0);
/* processes*/
int proc1;
int proc2;
/* file lock struct */
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
/* create a text file */
FILE *fp;
int fd;
fp = fopen("output.txt", "w"); // create and close the file
fclose(fp);
if((fd = open("output.txt", O_RDWR)) == -1) { // open the file again to get file descriptor
perror("open");
exit(1);
}
fp = fdopen(fd, "w");
/* first process */
if ((proc1 = fork()) < 0) {
perror("fork");
exit(2);
}
else if(proc1 == 0) {
fl.l_type = F_WRLCK; // set the lock type and pid of the forked process
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) { // lock the file before writing to it
perror("fcntl");
exit(1);
}
fprintf(fp, "proc1 - action1\n"); // write to the file
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) { // unlock the file so other processes can write to it
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc1 - action1\n");
sem_post(sm1); // let the second process run
sem_wait(sm2); // wait till the second process is done
// write one more thing the same way to the text file after the second process is done
fl.l_type = F_WRLCK;
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(fp, "proc1 - action2\n");
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc1 - action2\n");
exit(0);
}
/* second process */
if ((proc2 = fork()) < 0) {
perror("fork");
exit(2);
}
else if(proc2 == 0) {
sem_wait(sm1); // waits for proc1 to perform it's first action
// write something to the text file and let proc1 write it's second action
fl.l_type = F_WRLCK;
fl.l_pid = getpid();
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(fp, "proc2 - action1\n");
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
fprintf(stdout, "proc2 - action1\n");
sem_post(sm2);
exit(0);
}
// wait for both processes to finish
waitpid(proc1, NULL, 0);
waitpid(proc2, NULL, 0);
sem_close(sm1);
sem_unlink(NAME1);
sem_close(sm2);
sem_unlink(NAME2);
return 0;
}
I have included the fprintf with stdout lines so that you can see that the output in the terminal is correct:
-proc1 - action1
-proc2 - action1
-proc1 - action2
Just like they are being synchronized. However, the output in the output.txt file is this:
-proc2 - action1
-proc1 - action1
-proc1 - action2
Why is this happening?
Also, before the process writes to the file, I always lock it so that no other process can access it and then unlock it again.
I'm not sure if I'm doing this right so I'd appreciate any advice I can get!
Thanks a lot!
You have buffered IO by default - so the buffer isn't actually flushed to the file until you close it if it is smaller output than the buffer size (otherwise you get a buffer's worth at a time when it is full... often 8kb or so). Note also that each process gets its own, separate buffer.
To fix, flush your output after printing, and before writing, fseek() to SEEK_END to ensure you are at the end of the file.
fprintf(fp, "proc1 - action1\n"); // write to the file
fflush(fp);
BTW, i didn't check for the validity of your semaphore code, just noticed you were missing this crucial piece of information. In general, however, if you are using file locking, the semaphore is redundant...
fp = fopen("output.txt", "w"); will truncate the file and is not synchronized, so process #2 may truncate the file even if process #1 has already written something to it. Same for fp = fdopen(fd, "w");
Also, you are heading for trouble if you keep the file open while the other process writes to it. At least you should SEEK to the (new) end of the file after the second process finished its writing or you may overwrite what process #2 did. Better close the file before the other process runs and reopen afterwards. This will also make sure any buffered data is flushed.
Related
I'm new with fcntl locking and following this example to create a sample lock in linux using c code: http://www.informit.com/articles/article.aspx?p=23618&seqNum=4
I wonder how can we can print out which process hold the lock file and which process is waiting for lock. I consider using l_pid to figure out the process id which is holding the lock but i'm not sure the right way to do it.
What is the best way to print out which process is holding the lock?
As the man 2 fcntl page describes, you can use the F_GETLK to obtain the process ID that has the conflicting lock (if the conflicting lock is a process-associated one). So, for example,
/* Return 0 if descriptor locked exclusively, positive PID if
a known process holds a conflicting lock, or -1 if the
descriptor cannot be locked (and errno has the reason).
*/
static pid_t lock_exclusively(const int fd)
{
struct flock lock;
int err = 0;
if (fd == -1) {
errno = EINVAL;
return -1;
}
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (!fcntl(fd, F_SETLK, &lock))
return 0;
/* Remember the cause of the failure */
err = errno;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_pid = 0;
if (fcntl(fd, F_GETLK, &lock) == 0 && lock.l_pid > 0)
return lock.l_pid;
errno = err;
return -1;
}
Do note that fd must be open for reading and writing. I recommend using open(path, O_RDWR | O_NOCTTY) or open(path, O_WRONLY | O_NOCTTY). Closing any file descriptor to the same file will release the lock.
Some may say that re-setting the lock memebers before the second fcntl() call is unnecessary, but I'd rather err on the side of caution here.
As to how to report it, I would simply use
int fd;
pid_t p;
fd = open(path, O_RDWR | O_NOCTTY);
if (fd == -1) {
fprintf(stderr, "%s: Cannot open file: %s.\n",
path, strerror(errno));
exit(EXIT_FAILURE);
}
p = lock_exclusively(fd);
if (p < 0) {
fprintf(stderr, "%s: Cannot lock file: %s.\n",
path, strerror(errno));
exit(EXIT_FAILURE);
} else
if (p > 0) {
fprintf(stderr, "%s: File is already locked by process %ld.\n",
path, (long)p);
exit(EXIT_FAILURE);
}
/* fd is now open and exclusive-locked. */
The user can always run e.g. ps -o cmd= -p PID to see what command that is (or you can try reading /proc/PID/cmdline in Linux).
From the example code:
printf ("locking\n");
/* Initialize the flock structure. */
memset (&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
/* Place a write lock on the file. */
fcntl (fd, F_SETLKW, &lock);
printf ("locked; hit Enter to unlock... ");
You need to change the fcntl (fd, F_SETLKW, &lock); to:
if (fcntl (fd, F_SETLK, &lock) == -1) {
printf ("File is locked by pid %i\n", lock.l_pid);
return 0;
}
The F_SETLKW command blocks if it cannot get the lock. F_SETLK will return if it cannot get the lock. Really the code should also check errno == EACCESS or errno == EAGAIN after getting the -1 return value.
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).
Round 2
After reading some of the answers, my revised code is:
int pid = fork();
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
if (in) { //if '<' char was found in string inputted by user
int fd0 = open(input, O_RDONLY, 0);
dup2(fd0, STDIN_FILENO);
close(fd0);
in = 0;
}
if (out) { //if '>' was found in string inputted by user
int fd1 = creat(output, 0644);
dup2(fd1, STDOUT_FILENO);
close(fd1);
out = 0;
}
execvp(res[0], res);
perror("execvp");
_exit(1);
} else {
waitpid(pid, 0, 0);
free(res);
}
It works, but seems the standard output isn't being reconnected or something to that effect. Here is execution:
SHELL$ cat > file
hello, world
this is a test
SHELL$ cat < file //no output
SHELL$ ls //no output
'<' and '>' both work, but after they are executed there is no output.
Round 1
I have been working on a relatively simple shell in C for a while now, but I am having trouble implementing input (<) and output (>) redirection. Help me find the issues in the following code:
int fd;
int pid = fork();
int current_out;
if (in) { //if '<' char was found in string inputted by user
fd = open(input, O_RDONLY, 0);
dup2(fd, STDIN_FILENO);
in = 0;
current_out = dup(0);
}
if (out) { //if '>' was found in string inputted by user
fd = creat(output, 0644);
dup2(fd, STDOUT_FILENO);
out = 0;
current_out = dup(1);
}
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
execvp(res[0], res);
perror("execvp");
_exit(1);
} else {
waitpid(pid, 0, 0);
dup2(current_out, 1);
free(res);
}
I may have some unnecessary material in there because I have been trying different things to get it to work. I am not sure what is going wrong.
You have way too many file descriptors open after your redirection. Let's dissect the two paragraphs:
if (in) { //if '<' char was found in string inputted by user
fd = open(input, O_RDONLY, 0);
dup2(fd, STDIN_FILENO);
in = 0;
current_in = dup(0); // Fix for symmetry with second paragraph
}
if (out) { //if '>' was found in string inputted by user
fd = creat(output, 0644);
dup2(fd, STDOUT_FILENO);
out = 0;
current_out = dup(1);
}
I'm going to be charitable and ignore the fact that you are ignoring errors. However, you will need to error check your system calls.
In the first paragraph, you open a file and capture the file descriptor (it might well be 3) in the variable fd. You then duplicate the file descriptor over standard input (STDIN_FILENO). Note, though, that file descriptor 3 is still open. Then you do a dup(0) (which, for consistency, should be STDIN_FILENO), getting another file descriptor, perhaps 4. So you have file descriptors 0, 3 and 4 pointing at the same file (and, indeed, the same open file description — noting that an open file description is different from an open file descriptor). If your intention with current_in was to preserve the (parent) shell's standard input, you have to do that dup() before you do the dup2() that overwrites the output. However, you would be better off not altering the parent shell's file descriptors; it is less overhead than re-duplicating the file descriptors.
Then you more or less repeat the process in the second paragraph, first overwriting the only record of file descriptor 3 being open with the fd = creat(...) call but obtaining a new descriptor, perhaps 5, then duplicating that over standard output. You then do a dup(1), yielding another file descriptor, perhaps 6.
So, you have stdin and stdout of the main shell redirected to the files (and no way of reinstating those to the original values). Your first problem, therefore, is that you are doing the redirection before you fork(); you should be doing it after the fork() — though when you get to piping between processes, you will need to create pipes before forking.
Your second problem is that you need to close a plethora of file descriptors, one of which you no longer have a reference for.
So, you might need:
if ((pid = fork()) < 0)
...error...
else if (pid == 0)
{
/* Be childish */
if (in)
{
int fd0 = open(input, O_RDONLY);
dup2(fd0, STDIN_FILENO);
close(fd0);
}
if (out)
{
int fd1 = creat(output , 0644) ;
dup2(fd1, STDOUT_FILENO);
close(fd1);
}
...now the child has stdin coming from the input file,
...stdout going to the output file, and no extra files open.
...it is safe to execute the command to be executed.
execve(cmd[0], cmd, env); // Or your preferred alternative
fprintf(stderr, "Failed to exec %s\n", cmd[0]);
exit(1);
}
else
{
/* Be parental */
...wait for child to die, etc...
}
Before you do any of this, you should ensure that you've already flushed the shell's standard I/O channels, probably by using fflush(0), so that if the forked child writes to standard error because of a problem, there is no extraneous duplicated output.
Also note that the various open() calls should be error-checked.
You have way too many file descriptors open after your redirection. The code which you need is this.
if (pid == 0)
{ /* for the child process: */
// function for redirection ( '<' , '>' )
int fd0,fd1,i,in=0,out=0;
char input[64],output[64];
// finds where '<' or '>' occurs and make that argv[i] = NULL , to ensure that command wont't read that
for(i=0;argv[i]!='\0';i++)
{
if(strcmp(argv[i],"<")==0)
{
argv[i]=NULL;
strcpy(input,argv[i+1]);
in=2;
}
if(strcmp(argv[i],">")==0)
{
argv[i]=NULL;
strcpy(output,argv[i+1]);
out=2;
}
}
//if '<' char was found in string inputted by user
if(in)
{
// fdo is file-descriptor
int fd0;
if ((fd0 = open(input, O_RDONLY, 0)) < 0) {
perror("Couldn't open input file");
exit(0);
}
// dup2() copies content of fdo in input of preceeding file
dup2(fd0, 0); // STDIN_FILENO here can be replaced by 0
close(fd0); // necessary
}
//if '>' char was found in string inputted by user
if (out)
{
int fd1 ;
if ((fd1 = creat(output , 0644)) < 0) {
perror("Couldn't open the output file");
exit(0);
}
dup2(fd1, STDOUT_FILENO); // 1 here can be replaced by STDOUT_FILENO
close(fd1);
}
execvp(*argv, argv);
perror("execvp");
_exit(1);
// another syntax
/* if (!(execvp(*argv, argv) >= 0)) { // execute the command
printf("*** ERROR: exec failed\n");
exit(1);
*/
}
else if((pid) < 0)
{
printf("fork() failed!\n");
exit(1);
}
else { /* for the parent: */
while (!(wait(&status) == pid)) ; // good coding to avoid race_conditions(errors)
}
}
Here's what's happening. After you call fork() there are two processes executing that are duplicates of the original process. The difference is in the return value of fork() which is stored in pid.
Then both processes (the shell and the child) redirect their stdin and stdout to the same files. I think you were trying to save the previous fd in current_out, but as Seth Robertson points out, this doesn't currently work, since the wrong file descriptor is being saved. The parent also restores its stdout, but not stdin.
You could fix this bug, but you can do better. You don't actually have to redirect parent's output, just the child's. So simply check pid first. Then there is also no need to restore any file descriptors.
i executed the following c code on my ubuntu machine...i have read about fcntl()'s use to lock a file and even reading will not be allowed if F_WRLCK opton is set...so i started this program and before relinquishing the lock by pressing enter i tried to open the file in two ways- by directly double clicking on file1.cpp and by running a different c program in a new terminal...both the time the file was opened...so how did fcntl() allow opening of these files when F_WRLCK is set...
int main(int argc, char *argv[])
{
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
int fd;
fl.l_pid = getpid();
if ((fd = open("/home/file1.cpp", O_WRONLY)) == -1)
{
perror("open");
exit(1);
}
if (fcntl(fd, F_SETLKW, &fl) == -1)
{
perror("fcntl");
exit(1);
}
printf("Press <RETURN> to release lock: ");
getchar();
fl.l_type = F_UNLCK; /* set to unlock same region */
if (fcntl(fd, F_SETLK, &fl) == -1)
{
perror("fcntl");
exit(1);
}
printf("Unlocked.\n");
close(fd);
return 0;
}
fcntl locks are purely advisory locks. Their only effect is to cause fcntl F_SETLK calls to block when the lock cannot be obtained. They have absolutely no effect on IO operations. It's up to your program to obtain the locks it needs before performing IO when synchronization is necessary.
This is completely analogous to using mutexes to protect objects in memory. The mutex will not prevent you from reading or writing memory addresses; it's just a protocol you use to make sure your program only reads and writes and proper times.
The goal of this project is to use pipes and forks to execute a line-count utility already written in a multi-process manner (one process per argument). I'm currently working on getting a single process working before expanding to handle multiple args.
Given two executables, lc1 and lc2, I want lc2 to establish a pipe to the stdout file descriptor of lc1, so that when execlp("lc1", argv[1], NULL) is called, the output will be read in by
while ((c= read(pipefd[0], readin, SIZE)) > 0)
According to my Unix book, I should use the open, dup2, close method for redirecting stdout to stdin, and here's my code:
int pid, c, i;
char *readin= (char *)malloc(sizeof(SIZE));
if (pipe(pipefd)== -1)
perror("Can't open a pipe\n");
for (i=1; i< argc; i++){
if ((pid= fork())==-1)
perror("Can't fork\n");
run(argv[i]);
}
//close pipe
close(1);
if (dup2(pipefd[0], 0)==-1)
perror("Can't redirect stdin");
close(pipefd[1]);
for (i=1; i< argc; i++){
if ((wait(NULL))== -1)
perror("Wait error");
while ((c= read(pipefd[0], readin, SIZE)) > 0){;
//print buf count
total += atoi(readin);
}
}
The run function is
void run(char *f){
int fp;
if ((fp= open(f, O_RDONLY)) == -1)
perror("Can't open the file");
close(pipefd[0]);
dup2(pipefd[1], 1);
close(pipefd[1]);
execlp("ls1", f, NULL);
}
When I try to execute this code, I get a stdin redirect error saying bad file descriptor. Why is this happening, and would appreciate any hints to for fixing.
run(argv[i]) is executed by both parent and child because are not assigning the functionality based on the returned PID, so one close after the other may have closed.
See below code, can he handy, I will use the code sample for situations like this. :
int main()
{
int pipe_fd[2] = {0};
int pid = -1;
int status = -1;
int ret_value = INVALID_CMD;
int cmd_output_len = -1;
status = pipe(pipe_fd);
if(status<0)
{
perror("pipe create err");
}
else
{
pid = fork();
if(pid<0)
{
}
else if (pid == 0)
{
/*Child functionality*/
child_func(pipe_fd, cmd);
}
else
{
/*Parent functionality*/
cmd_output_len = parent_fun(pid, pipe_fd);
}
}
return ret_value;
}
int child_func(int pipe_fd[], const char * cmd)
{
int status = 5;
int read_fd = pipe_fd[0]; /*read file descriptor*/
int write_fd = pipe_fd[1]; /*write file descriptor*/
int exit_status = 0;
/*close read fd*/
close(read_fd);
/*dup2 stdout to write fd*/
//status = dup2(1, write_fd);
status = dup2(write_fd, 1);
if(status<0)
{
exit(-1);
}
else
{
system(cmd);
exit(0);
}
}
int parent_fun(int child_id, int pipe_fd[])
{
int status = -1;
int len = 0;
bool_e break_loop = FALSE;
int read_fd = pipe_fd[0]; /*read file descriptor*/
int write_fd = pipe_fd[1]; /*write file descriptor*/
/*close write fd*/
close(write_fd);
while(1)
{
sleep(1);
status = waitpid(child_id, &status, WNOHANG);
switch(status)
{
case 0:
/*Child is still active*/
printf("No process waiting to exit..\n");
len = do_ur_fun(read_fd);
write(1, output, len);
break;
/*case EINTR:
case ECHILD:
case EINVAL:
perror("waitpid error");
break_loop = TRUE;
break;*/
default:
if(status<0)
{
perror("waitpid error");
break_loop = TRUE;
len = -1;
}
else if(child_id == status)
{
/*Valid staus from child*/
len = read_output(read_fd, output);
//write(1, output, len);
break_loop = TRUE;
}
else
{
}
break;
}
if(TRUE == break_loop)
{
break;
}
}
return len;
}
int do_ur_fun (int read_fd)
{
/*Do your exec*/
}
MaheshGupta024 identified a very important problem in your code; I'm assuming you will fix that.
One of the other problem areas is:
close(1);
if (dup2(pipefd[0], 0)==-1)
perror("Can't redirect stdin");
close(pipefd[1]);
for (i=1; i< argc; i++){
if ((wait(NULL))== -1)
perror("Wait error");
while ((c= read(pipefd[0], readin, SIZE)) > 0){;
//print buf count
total += atoi(readin);
}
}
The first close closes the process's standard output; this is seldom a good idea. The next line duplicates the read end of the pipe to standard input - which is fine. As noted in a comment above, perror() does not exit. You then close the write end of the pipe - that's correct; but you should presumably close the read end of the pipe too since you have set it to come from the pipe.
Your loop starts OK; you have redundant parentheses in the wait() line. You read from pipefd[0] instead of standard input - so maybe you didn't want to close pipefd[0] but neither did you need to duplicate it to standard input. You then have a nested loop that reads on the pipe while there's more data to be read from a child - you don't absolutely need the wait() code with its loop since the inner while won't terminate until all the children are dead. On the other hand, there's no great harm in it - after the first child dies, you'll read the data from all the other children, then go into the outer loop and wait for each other child, with the inner loop terminating immediately since there is no data left to read.
So:
Don't close stdout.
Don't dup the pipe read to stdin.
Decide whether you want to clean up the loop - it will work, but could be cleaner.
The run() function is:
void run(char *f){
int fp;
if ((fp= open(f, O_RDONLY)) == -1)
perror("Can't open the file");
close(pipefd[0]);
dup2(pipefd[1], 1);
close(pipefd[1]);
execlp("ls1", f, NULL);
}
The argument should be const char *f (or use name or file instead of f). I would also pass the pipefd array to the function rather than use a global variable
.
Do not call a file descriptor fp; that name conventionally indicates a variable of type FILE *, not int.
However, you don't need to open the file in the first place - unless you want the calling program to do the error reporting instead of the invoked program. However, if you do want the calling program to do the error reporting, you should close the file descriptor before proceeding. (I've already commented on perror() returning).
It would be a good idea to print an error message after execlp(); the only time the function returns is when it fails, so there is no need to test its return value. You might want to exit too - rather than have the failed function go through the rest of the main program after the call to run().
Good points: you did close both the pipe file descriptors.
Hence:
void run(const char *file, int *pipefd)
{
close(pipefd[0]);
dup2(pipefd[1], 1);
close(pipefd[1]);
execlp("ls1", f, NULL);
perror("Failed to exec ls1");
exit(EXIT_FAILURE);
}