Back to index

lightdm  1.3.2
Classes | Enumerations | Functions | Variables
process.c File Reference
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <grp.h>
#include <glib/gstdio.h>
#include <config.h>
#include "process.h"

Go to the source code of this file.

Classes

struct  ProcessPrivate

Enumerations

enum  {
  RUN, GOT_DATA, GOT_SIGNAL, STOPPED,
  LAST_SIGNAL
}

Functions

 G_DEFINE_TYPE (Process, process, G_TYPE_OBJECT)
Processprocess_get_current (void)
Processprocess_new (void)
void process_set_clear_environment (Process *process, gboolean clear_environment)
gboolean process_get_clear_environment (Process *process)
void process_set_env (Process *process, const gchar *name, const gchar *value)
const gchar * process_get_env (Process *process, const gchar *name)
void process_set_command (Process *process, const gchar *command)
const gchar * process_get_command (Process *process)
static void process_watch_cb (GPid pid, gint status, gpointer data)
static void process_run (Process *process)
gboolean process_start (Process *process)
gboolean process_get_is_running (Process *process)
GPid process_get_pid (Process *process)
void process_signal (Process *process, int signum)
static gboolean quit_timeout_cb (Process *process)
void process_stop (Process *process)
void process_wait (Process *process)
int process_get_exit_status (Process *process)
static void process_init (Process *process)
static void process_stopped (Process *process)
static void process_finalize (GObject *object)
static void signal_cb (int signum, siginfo_t *info, void *data)
static gboolean handle_signal (GIOChannel *source, GIOCondition condition, gpointer data)
static void process_class_init (ProcessClass *klass)

Variables

static guint signals [LAST_SIGNAL] = { 0 }
static Processcurrent_process = NULL
static GHashTable * processes = NULL
static int signal_pipe [2]

Class Documentation

struct ProcessPrivate

Definition at line 34 of file process.c.

Class Members
gboolean clear_environment
gchar * command
GHashTable * env
int exit_status
GPid pid
guint quit_timeout

Enumeration Type Documentation

anonymous enum
Enumerator:
RUN 
GOT_DATA 
GOT_SIGNAL 
STOPPED 
LAST_SIGNAL 

Definition at line 25 of file process.c.


Function Documentation

G_DEFINE_TYPE ( Process  ,
process  ,
G_TYPE_OBJECT   
)
static gboolean handle_signal ( GIOChannel *  source,
GIOCondition  condition,
gpointer  data 
) [static]

Definition at line 312 of file process.c.

{
    int signo;
    pid_t pid;
    Process *process;

    if (read (signal_pipe[0], &signo, sizeof (int)) < 0 || 
        read (signal_pipe[0], &pid, sizeof (pid_t)) < 0)
    {
        g_warning ("Error reading from signal pipe: %s", strerror (errno));
        return TRUE;
    }

    g_debug ("Got signal %d from process %d", signo, pid);

    process = g_hash_table_lookup (processes, GINT_TO_POINTER (pid));
    if (process == NULL)
        process = process_get_current ();
    if (process)
        g_signal_emit (process, signals[GOT_SIGNAL], 0, signo);

    return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void process_class_init ( ProcessClass klass) [static]

Definition at line 337 of file process.c.

{
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
    struct sigaction action;

    klass->run = process_run;
    klass->stopped = process_stopped;
    object_class->finalize = process_finalize;  

    g_type_class_add_private (klass, sizeof (ProcessPrivate));

    signals[RUN] =
        g_signal_new ("run",
                      G_TYPE_FROM_CLASS (klass),
                      G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (ProcessClass, run),
                      NULL, NULL,
                      g_cclosure_marshal_VOID__VOID,
                      G_TYPE_NONE, 0); 
    signals[GOT_DATA] =
        g_signal_new ("got-data",
                      G_TYPE_FROM_CLASS (klass),
                      G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (ProcessClass, got_data),
                      NULL, NULL,
                      g_cclosure_marshal_VOID__VOID,
                      G_TYPE_NONE, 0); 
    signals[GOT_SIGNAL] =
        g_signal_new ("got-signal",
                      G_TYPE_FROM_CLASS (klass),
                      G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (ProcessClass, got_signal),
                      NULL, NULL,
                      g_cclosure_marshal_VOID__INT,
                      G_TYPE_NONE, 1, G_TYPE_INT);
    signals[STOPPED] =
        g_signal_new ("stopped",
                      G_TYPE_FROM_CLASS (klass),
                      G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (ProcessClass, stopped),
                      NULL, NULL,
                      g_cclosure_marshal_VOID__VOID,
                      G_TYPE_NONE, 0);

    /* Catch signals and feed them to the main loop via a pipe */
    processes = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
    if (pipe (signal_pipe) != 0)
        g_critical ("Failed to create signal pipe");
    fcntl (signal_pipe[0], F_SETFD, FD_CLOEXEC);
    fcntl (signal_pipe[1], F_SETFD, FD_CLOEXEC);
    g_io_add_watch (g_io_channel_unix_new (signal_pipe[0]), G_IO_IN, handle_signal, NULL);
    action.sa_sigaction = signal_cb;
    sigemptyset (&action.sa_mask);
    action.sa_flags = SA_SIGINFO;
    sigaction (SIGTERM, &action, NULL);
    sigaction (SIGINT, &action, NULL);
    sigaction (SIGHUP, &action, NULL);
    sigaction (SIGUSR1, &action, NULL);
    sigaction (SIGUSR2, &action, NULL);
}

Here is the call graph for this function:

static void process_finalize ( GObject *  object) [static]

Definition at line 284 of file process.c.

{
    Process *self;

    self = PROCESS (object);

    if (self->priv->pid > 0)
        g_hash_table_remove (processes, GINT_TO_POINTER (self->priv->pid));

    g_free (self->priv->command);
    g_hash_table_unref (self->priv->env);

    if (self->priv->pid)
        kill (self->priv->pid, SIGTERM);

    G_OBJECT_CLASS (process_parent_class)->finalize (object);
}

Here is the caller graph for this function:

gboolean process_get_clear_environment ( Process process)

Definition at line 87 of file process.c.

{
    g_return_val_if_fail (process != NULL, FALSE);
    return process->priv->clear_environment;
}
const gchar* process_get_command ( Process process)

Definition at line 119 of file process.c.

{
    g_return_val_if_fail (process != NULL, NULL);
    return process->priv->command;
}

Definition at line 62 of file process.c.

Here is the call graph for this function:

Here is the caller graph for this function:

const gchar* process_get_env ( Process process,
const gchar *  name 
)

Definition at line 102 of file process.c.

{
    g_return_val_if_fail (process != NULL, NULL);
    g_return_val_if_fail (name != NULL, NULL);
    return g_hash_table_lookup (process->priv->env, name);
}
int process_get_exit_status ( Process process)

Definition at line 265 of file process.c.

{
    g_return_val_if_fail (process != NULL, -1);
    return process->priv->exit_status;
}

Here is the caller graph for this function:

gboolean process_get_is_running ( Process process)

Definition at line 208 of file process.c.

{
    g_return_val_if_fail (process != NULL, FALSE);
    return process->priv->pid != 0;
}
GPid process_get_pid ( Process process)

Definition at line 215 of file process.c.

{
    g_return_val_if_fail (process != NULL, 0);
    return process->priv->pid;
}

Here is the caller graph for this function:

static void process_init ( Process process) [static]

Definition at line 272 of file process.c.

{
    process->priv = G_TYPE_INSTANCE_GET_PRIVATE (process, PROCESS_TYPE, ProcessPrivate);
    process->priv->env = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
}
Process* process_new ( void  )

Definition at line 74 of file process.c.

{
    return g_object_new (PROCESS_TYPE, NULL);
}

Here is the caller graph for this function:

static void process_run ( Process process) [static]

Definition at line 147 of file process.c.

{
    gint argc;
    gchar **argv;
    GHashTableIter iter;
    gpointer key, value;
    GError *error = NULL;

    if (!g_shell_parse_argv (process->priv->command, &argc, &argv, &error))
    {
        g_warning ("Error parsing command %s: %s", process->priv->command, error->message);
        _exit (EXIT_FAILURE);
    }

    if (process->priv->clear_environment)
#ifdef HAVE_CLEARENV
        clearenv ();
#else
        environ = NULL;
#endif

    g_hash_table_iter_init (&iter, process->priv->env);
    while (g_hash_table_iter_next (&iter, &key, &value))
        g_setenv ((gchar *)key, (gchar *)value, TRUE);
  
    execvp (argv[0], argv);

    g_warning ("Error executing child process %s: %s", argv[0], g_strerror (errno));
    _exit (EXIT_FAILURE);
}

Here is the caller graph for this function:

void process_set_clear_environment ( Process process,
gboolean  clear_environment 
)

Definition at line 80 of file process.c.

{
    g_return_if_fail (process != NULL);
    process->priv->clear_environment = clear_environment;
}

Here is the caller graph for this function:

void process_set_command ( Process process,
const gchar *  command 
)

Definition at line 110 of file process.c.

{
    g_return_if_fail (process != NULL);

    g_free (process->priv->command);
    process->priv->command = g_strdup (command);
}

Here is the caller graph for this function:

void process_set_env ( Process process,
const gchar *  name,
const gchar *  value 
)

Definition at line 94 of file process.c.

{
    g_return_if_fail (process != NULL);
    g_return_if_fail (name != NULL);
    g_hash_table_insert (process->priv->env, g_strdup (name), g_strdup (value));  
}

Here is the caller graph for this function:

void process_signal ( Process process,
int  signum 
)

Definition at line 222 of file process.c.

{
    g_return_if_fail (process != NULL);

    if (process->priv->pid == 0)
        return;

    g_debug ("Sending signal %d to process %d", signum, process->priv->pid);

    if (kill (process->priv->pid, signum) < 0)
        g_warning ("Error sending signal %d to process %d: %s", signum, process->priv->pid, strerror (errno));
}

Here is the caller graph for this function:

gboolean process_start ( Process process)

Definition at line 179 of file process.c.

{
    pid_t pid;

    g_return_val_if_fail (process != NULL, FALSE);
    g_return_val_if_fail (process->priv->command != NULL, FALSE);  
    g_return_val_if_fail (process->priv->pid == 0, FALSE);

    pid = fork ();
    if (pid < 0)
    {
        g_warning ("Failed to fork: %s", strerror (errno));
        return FALSE;
    }

    if (pid == 0)
        g_signal_emit (process, signals[RUN], 0);

    g_debug ("Launching process %d: %s", pid, process->priv->command);

    process->priv->pid = pid;

    g_hash_table_insert (processes, GINT_TO_POINTER (process->priv->pid), g_object_ref (process));
    g_child_watch_add (process->priv->pid, process_watch_cb, process);

    return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void process_stop ( Process process)

Definition at line 244 of file process.c.

{
    g_return_if_fail (process != NULL);

    /* Send SIGTERM, and then SIGKILL if no response */
    process->priv->quit_timeout = g_timeout_add (5000, (GSourceFunc) quit_timeout_cb, process);
    process_signal (process, SIGTERM);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void process_stopped ( Process process) [static]

Definition at line 279 of file process.c.

{
}

Here is the caller graph for this function:

void process_wait ( Process process)

Definition at line 254 of file process.c.

{
    int exit_status;

    g_return_if_fail (process != NULL);

    waitpid (process->priv->pid, &exit_status, 0);
    process_watch_cb (process->priv->pid, exit_status, process);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void process_watch_cb ( GPid  pid,
gint  status,
gpointer  data 
) [static]

Definition at line 126 of file process.c.

{
    Process *process = data;

    process->priv->exit_status = status;

    if (WIFEXITED (status))
        g_debug ("Process %d exited with return value %d", pid, WEXITSTATUS (status));
    else if (WIFSIGNALED (status))
        g_debug ("Process %d terminated with signal %d", pid, WTERMSIG (status));

    if (process->priv->quit_timeout)
        g_source_remove (process->priv->quit_timeout);
    process->priv->quit_timeout = 0;  
    process->priv->pid = 0;
    g_hash_table_remove (processes, GINT_TO_POINTER (pid));

    g_signal_emit (process, signals[STOPPED], 0);
}

Here is the caller graph for this function:

static gboolean quit_timeout_cb ( Process process) [static]

Definition at line 236 of file process.c.

{
    process->priv->quit_timeout = 0;
    process_signal (process, SIGKILL);
    return FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void signal_cb ( int  signum,
siginfo_t *  info,
void *  data 
) [static]

Definition at line 303 of file process.c.

{
    /* NOTE: Using g_printerr as can't call g_warning from a signal callback */
    if (write (signal_pipe[1], &info->si_signo, sizeof (int)) < 0 ||
        write (signal_pipe[1], &info->si_pid, sizeof (pid_t)) < 0)
        g_printerr ("Failed to write to signal pipe: %s", strerror (errno));
}

Here is the caller graph for this function:


Variable Documentation

Process* current_process = NULL [static]

Definition at line 57 of file process.c.

GHashTable* processes = NULL [static]

Definition at line 58 of file process.c.

int signal_pipe[2] [static]

Definition at line 59 of file process.c.

guint signals[LAST_SIGNAL] = { 0 } [static]

Definition at line 32 of file process.c.