On Github:
https://github.com/Codingrecipes/Popen+
This is a little popen implementation which will make it easier to kill processes and will give you access to the PID of the process, I don’t know why they didn’t do this in popen but I’m sure they had good reasons because those guys are way too smart…
popen_plus.h:
/* ** Author: Hamid Alipour http://codingrecipes.com http://twitter.com/code_head ** SQLite style license: ** ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. **/ #ifndef POPEN_PLUS_H #define POPEN_PLUS_H #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <paths.h> #include <sys/stat.h> #include <dirent.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #define READ 0 #define WRITE 1 struct popen_plus_process { pthread_mutex_t mutex; pid_t pid; FILE *read_fp; FILE *write_fp; }; struct popen_plus_process *popen_plus(const char *command); int popen_plus_close(struct popen_plus_process *process); int popen_plus_kill(struct popen_plus_process *process); int popen_plus_kill_by_id(int process_id); int popen_plus_terminate(struct popen_plus_process *process); int popen_plus_terminate_with_id(int process_id); #endif
popen_plus.c:
/* ** Author: Hamid Alipour http://codingrecipes.com http://twitter.com/code_head ** SQLite style license: ** ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. **/ #include <errno.h> #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <paths.h> #include <sys/stat.h> #include <dirent.h> #include <stdlib.h> #include <string.h> #include "popen_plus.h" struct popen_plus_process *popen_plus(const char *command) { int inpipe[2]; int outpipe[2]; char *argv[4]; struct popen_plus_process *process = malloc(sizeof(struct popen_plus_process)); if (!process) goto error_out; if (pipe(inpipe) != 0) goto clean_process_out; if (pipe(outpipe) != 0) goto clean_inpipe_out; process->read_fp = fdopen(outpipe[READ], "r"); if (!process->read_fp) goto clean_outpipe_out; process->write_fp = fdopen(inpipe[WRITE], "w"); if (!process->write_fp) goto clean_read_fp_out; if (pthread_mutex_init(&process->mutex, NULL) != 0) goto clean_write_fp_out; process->pid = fork(); if (process->pid == -1) goto clean_mutex_out; if (process->pid == 0) { close(outpipe[READ]); close(inpipe[WRITE]); if (inpipe[READ] != STDIN_FILENO) { dup2(inpipe[READ], STDIN_FILENO); close(inpipe[READ]); } if (outpipe[WRITE] != STDOUT_FILENO) { dup2(outpipe[WRITE], STDOUT_FILENO); close(outpipe[WRITE]); } argv[0] = "sh"; argv[1] = "-c"; argv[2] = (char *) command; argv[3] = NULL; execv(_PATH_BSHELL, argv); exit(127); } close(outpipe[WRITE]); close(inpipe[READ]); return process; clean_mutex_out: pthread_mutex_destroy(&process->mutex); clean_write_fp_out: fclose(process->write_fp); clean_read_fp_out: fclose(process->read_fp); clean_outpipe_out: close(outpipe[READ]); close(outpipe[WRITE]); clean_inpipe_out: close(inpipe[READ]); close(inpipe[WRITE]); clean_process_out: free(process); error_out: return NULL; } int popen_plus_close(struct popen_plus_process *process) { int pstat; pid_t pid; /** * If someone else destrys this mutex, then this call will fail and we know * that another thread already cleaned up the process so we can safely return * and since we are destroying this mutex bellow then we don't need to unlock * it... */ if (pthread_mutex_lock(&process->mutex) != 0) return 0; if (process->pid != -1) { do { pid = waitpid(process->pid, &pstat, 0); } while (pid == -1 && errno == EINTR); } if (process->read_fp) fclose(process->read_fp); if (process->write_fp) fclose(process->write_fp); pthread_mutex_destroy(&process->mutex); free(process); return (pid == -1 ? -1 : pstat); } int popen_plus_kill(struct popen_plus_process *process) { char command[64]; sprintf(command, "kill -9 %d", process->pid); system(command); return 0; } int popen_plus_kill_by_id(int process_id) { char command[64]; sprintf(command, "kill -9 %d", process_id); system(command); return 0; } int popen_plus_terminate(struct popen_plus_process *process) { char command[64]; sprintf(command, "kill -TERM %d", process->pid); system(command); return 0; } int popen_plus_terminate_with_id(int process_id) { char command[64]; sprintf(command, "kill -TERM %d", process_id); system(command); return 0; }
This code was inspired by many sources and I think I perfected it, although you might find bugs or issues and if you do, please let me know if the comments section.
You can use it like so:
struct popen_plus_process *process = popen_plus("ls -l"); if (!process) { /* Failed do something and return or exit */ return -1; } int MAX_BUFFER = 256; char buffer[256]; while (!feof(process->read_fp)) if (fgets(buffer, MAX_BUFFER, process->read_fp) != NULL) printf("%s\n", buffer); popen_plus_close(process);
To kill a process:
popen_plus_kill(process); popen_plus_close(process);
Terminate is similar to kill…
I hope this helps someone!
I'm a programmer at 