You Are Here Home > C Programming

C Programming

Popen+ a Bidirectional Popen Implementation With Ability to Access PID and Kill/Terminate Processes

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!

:)

Popen+ a Bidirectional Popen Implementation With Ability to Access PID and Kill/Terminate Processes

SQLite And The Problem Of Storing Long Long Integers

Recently, I was trying to store a very large integer value in a SQLite column, it didn’t matter wether I used INTEGER or UNSIGNED BIG INT, SQLite rounded it for me and I was left with an integer value that wasn’t even close to what I needed.

So one solution was to just use a VARCHAR or TEXT or event a BLOB and insert the number with quotes around it but guess what? SQLite did it again!!!

It turns out that SQLite tries to convert your values to ints to give you some benefits with sorting and comparing etc. – in case you didn’t know you really wanted an int rather than a BLOB – and that happens here in one of it’s functions:

/*
** Try to convert a value into a numeric representation if we can
** do so without loss of information.  In other words, if the string
** looks like a number, convert it into a number.  If it does not
** look like a number, leave it alone.
*/
static void applyNumericAffinity(Mem *pRec){
  if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
    double rValue;
    i64 iValue;
    u8 enc = pRec->enc;
    if( (pRec->flags&MEM_Str)==0 ) return;
    if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
    if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
      pRec->u.i = iValue;
      pRec->flags |= MEM_Int;
    }else{
      pRec->r = rValue;
      pRec->flags |= MEM_Real;
    }
  }
}

The solution to this issue is to prepend a 0 to your number and use a BLOB or TEXT type column and insert it like this: ’0THEVERYLARGENUMBER’

Don’t get me wrong, SQLite is a great library that I’ve been using, it’s very well tested and works great, it’s fast and thread safe, I specially like it’s licensee:

/*
** 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.
**
*************************************************************************

I hope this helps…

SQLite And The Problem Of Storing Long Long Integers
« Newer PostsOlder Posts »