hal/hald-runner Makefile.am, NONE, 1.1 main.c, NONE, 1.1 runner.c, NONE, 1.1 runner.h, NONE, 1.1 utils.c, NONE, 1.1 utils.h, NONE, 1.1

David Zeuthen david at freedesktop.org
Fri Jan 20 18:45:29 PST 2006


Update of /cvs/hal/hal/hald-runner
In directory gabe:/tmp/cvs-serv12741/hald-runner

Added Files:
	Makefile.am main.c runner.c runner.h utils.c utils.h 
Log Message:
2006-01-20  David Zeuthen  <davidz at redhat.com>

	Great patch from Sjoerd Simons <sjoerd at luon.net>: As most people
	probably know by now, various people don't really like that hal
	running as root. We'd much rather see only a small process running
	as root and the main hal process running unpriviledged. Which is
	exactly what this patch does :)

	How does it work? Just before drops it's root privs. a small
	program is startup which will remain running as root and does the
	real execution of the addons/probes/callouts on hals
	behalf. Communication between hald and hald-runner is done via a
	p2p dbus connection. Resulting in a process tree like this:

	  hal       /usr/sbin/hald
	  root      \_ /usr/lib/hal/hald-runner
	  root          \_ /usr/lib/hal/hald-addon-acpi
	  root          \_ /usr/lib/hal/hald-addon-storage
	  root          \_ /usr/lib/hal/hald-addon-storage

	The patch consists out of two parts. First the implementation of
	hald-runner, which is about 700 lines of code. And then a part
	transforming the hald code from the current spawning code in utils
	to an interface that can talk to the runner.

	* AUTHORS: Add Sjoerd Simons <sjoerd at luon.net>. Revise my own
	email address.

	* configure.in (AC_OUTPUT): Add hald-runner

	* Makefile.am (SUBDIRS): Add hald-runner

	* hald/Makefile.am (hald_SOURCES): add hald_runner.[ch]

	* hald-runner/utils.c, hald-runner/utils.h, hald-runner/runner.c,
	hald-runner/runner.h, hald-runner/main.c, hald-runner/Makefile.am,
	hald/linux2/osspec.c, hald/linux2/classdev.c,
	hald/linux2/blockdev.c, hald/util.[ch], hald/hald_dbus.c,
	hald/hald.c, hald/hald_runner.[ch]: New and changed files with
	slight changes. See the descriptive text above and discussion at
	http://lists.freedesktop.org/archives/hal/2006-January/004327.html
	for details. 
	Changed function hald_runner_start_runner() in hald/hald_runner.c
	to print out runner path and improve error handling when runner
	is not found. Also removed dbus_server_unref (server) in 
	handle_connection() in same file.

	* hald/haldaemon.in: Remove --retain-privileges as this is no longer
	needed

	* hald/run-hald.sh, hald/debug-hald.sh, hald/valgrind-hald.sh:
	Remove --retain-privileges and use --with-runner pointing to
	../hald-runner/hald-runner



--- NEW FILE: Makefile.am ---
## Process this file with automake to produce Makefile.in
INCLUDES = \
	-DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \
	-DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
	-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
	-DPACKAGE_BIN_DIR=\""$(bindir)"\" \
	-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
	-DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
	-DPACKAGE_SCRIPT_DIR=\""$(datadir)/hal/scripts"\" \
	-I$(top_srcdir) \
	@PACKAGE_CFLAGS@

libexec_PROGRAMS = hald-runner

hald_runner_SOURCES = main.c runner.c runner.h utils.h utils.c
hald_runner_LDADD = @PACKAGE_LIBS@ @DBUS_LIBS@

--- NEW FILE: main.c ---
/***************************************************************************
 * CVSID: $Id: main.c,v 1.1 2006/01/21 02:45:27 david Exp $
 *
 * main.c - Main dbus interface of the hald runner
 *
 * Copyright (C) 2006 Sjoerd Simons, <sjoerd at luon.net>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#define DBUS_API_SUBJECT_TO_CHANGE 
#include <dbus/dbus-glib-lowlevel.h>

#include <glib.h>
#include "utils.h"
#include "runner.h"

static gboolean
parse_first_part(run_request *r, DBusMessage *msg, DBusMessageIter *iter) {
  DBusMessageIter sub_iter;
  char *tmpstr;

  /* First should be the device UDI */
  if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) 
    goto malformed;
  dbus_message_iter_get_basic(iter, &tmpstr);
  r->udi = g_strdup(tmpstr);

  /* Then the environment array */
  if (!dbus_message_iter_next(iter) ||
      dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) 
    goto malformed;
  dbus_message_iter_recurse(iter, &sub_iter);
  r->environment = get_string_array(&sub_iter);

  /* Then argv */
  if (!dbus_message_iter_next(iter) ||
      dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) 
    goto malformed;
  dbus_message_iter_recurse(iter, &sub_iter);
  r->argv = get_string_array(&sub_iter);

  return TRUE;

malformed:
  return FALSE;
}

static void
handle_run(DBusConnection *con, DBusMessage *msg) {
  DBusMessage *reply;
  DBusMessageIter iter;
  run_request *r;
  char *tmpstr;

  r = new_run_request();
  g_assert(dbus_message_iter_init(msg, &iter));

  if (!parse_first_part(r, msg, &iter)) 
    goto malformed;

  /* Next a string of what should be written to stdin */
  if (!dbus_message_iter_next(&iter) ||
      dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) 
    goto malformed;
  dbus_message_iter_get_basic(&iter, &tmpstr);
  r->input = g_strdup(tmpstr);

  /* Then an bool to indicate if we should grab stderr */
  if (!dbus_message_iter_next(&iter) ||
      dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) 
    goto malformed;
  dbus_message_iter_get_basic(&iter, &(r->error_on_stderr));

  /* Then an uint32 timeout for it */
  if (!dbus_message_iter_next(&iter) ||
      dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) 
    goto malformed;
  dbus_message_iter_get_basic(&iter, &(r->timeout));

  /* let run_request_run handle the reply */
  run_request_run(r, con, msg);
  return ;
malformed:
  del_run_request(r);
  reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Malformed",
                                 "Malformed run request");
  dbus_connection_send(con, reply, NULL);
  dbus_message_unref(reply);
}

static void
handle_start(DBusConnection *con, DBusMessage *msg) {
  DBusMessage *reply;
  DBusMessageIter iter;
  run_request *r;

  r = new_run_request();
  g_assert(dbus_message_iter_init(msg, &iter));

  if (!dbus_message_iter_init(msg, &iter) || !parse_first_part(r, msg, &iter)) 
    goto malformed;

  if (run_request_run(r, NULL, NULL)) {
    reply = dbus_message_new_method_return(msg);
  } else {
    reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Failed",
                                    "Start request failed");
  }
  dbus_connection_send(con, reply, NULL);
  dbus_message_unref(reply);
  return ;
malformed:
  del_run_request(r);
  reply = dbus_message_new_error(msg, "org.freedesktop.HalRunner.Malformed",
                                 "Malformed start request");
  dbus_connection_send(con, reply, NULL);
  dbus_message_unref(reply);
}

static void
handle_kill(DBusConnection *con, DBusMessage *msg) {
  DBusError error;
  DBusMessage *reply = NULL;
  char *udi;

  dbus_error_init (&error);
  if (!dbus_message_get_args(msg, &error,
                             DBUS_TYPE_STRING, &udi,
                             DBUS_TYPE_INVALID)) {
    reply = dbus_message_new_error (msg, 
                                     "org.freedesktop.HalRunner.Malformed", 
                                     "Malformed kill message");
    g_assert(reply);
    dbus_connection_send (con, reply, NULL);
    dbus_message_unref(reply);
    return;
  }
  run_kill_udi(udi);
  /* always successfull */
  reply = dbus_message_new_method_return(msg);
  dbus_connection_send(con, reply, NULL);
  dbus_message_unref(reply);
}

static DBusHandlerResult
filter(DBusConnection *con, DBusMessage *msg, void *user_data) {
  DBusMessage *reply;

  if (dbus_message_is_method_call(msg,
        "org.freedesktop.HalRunner", "Run")) {
    handle_run(con, msg);
    return DBUS_HANDLER_RESULT_HANDLED;
  } else if (dbus_message_is_method_call(msg,
              "org.freedesktop.HalRunner", "Start")) {
    handle_start(con, msg);
    return DBUS_HANDLER_RESULT_HANDLED;
  } else if (dbus_message_is_method_call(msg,
              "org.freedesktop.HalRunner", "Kill")) {
    handle_kill(con, msg);
    return DBUS_HANDLER_RESULT_HANDLED;
  } else if (dbus_message_is_method_call(msg,
              "org.freedesktop.HalRunner", "KillAll")) {
    run_kill_all();
    /* alwasy successfull */
    reply = dbus_message_new_method_return(msg);
    dbus_connection_send(con, reply, NULL);
    dbus_message_unref(reply);
    return DBUS_HANDLER_RESULT_HANDLED;
  }
  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

int
main(int argc, char **argv) {
  DBusConnection *c;
  DBusError error;
  GMainLoop *loop;
  char *dbus_address;

  run_init();
  dbus_error_init(&error);
  dbus_address = getenv("HALD_RUNNER_DBUS_ADDRESS");
  g_assert(dbus_address != NULL);

  c = dbus_connection_open(dbus_address, &error);
  if (c == NULL) 
    goto error;

  loop = g_main_loop_new(NULL, FALSE);

  dbus_connection_setup_with_g_main(c, NULL);
  dbus_connection_set_exit_on_disconnect(c, TRUE);
  dbus_connection_add_filter(c, filter, NULL, NULL);

  g_main_loop_run(loop);

  fprintf(stderr, "Should not be reached\n");
  
error:
 fprintf(stderr,"An error has occured: %s\n", error.message);
 return -1;
}

--- NEW FILE: runner.c ---
/***************************************************************************
 * CVSID: $Id: runner.c,v 1.1 2006/01/21 02:45:27 david Exp $
 *
 * runner.c - Process running code
 *
 * Copyright (C) 2006 Sjoerd Simons, <sjoerd at luon.net>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>

#define DBUS_API_SUBJECT_TO_CHANGE 
#include <dbus/dbus-glib-lowlevel.h>

#include <glib.h>
#include "utils.h"
#include "runner.h"

/* Successful run of the program */
#define HALD_RUN_SUCCESS 0x0 
/* Process was killed because of running too long */
#define  HALD_RUN_TIMEOUT 0x1 
/* Failed to start for some reason */
#define HALD_RUN_FAILED 0x2
/* Killed on purpose, e.g. hal_util_kill_device_helpers */   
#define HALD_RUN_KILLED 0x4

GHashTable *udi_hash = NULL;

typedef struct {
  run_request *r;
  DBusMessage *msg;
  DBusConnection *con;
  GPid pid;
  gint stderr_v;
  guint watch;
  guint timeout;
  gboolean sent_kill;
} run_data;

static void
del_run_data(run_data *rd) {
  if (rd == NULL) 
    return;

  del_run_request(rd->r);
  if (rd->msg) {
    dbus_message_unref(rd->msg);
  }
  g_spawn_close_pid(rd->pid);

  if (rd->stderr_v >= 0) {
    close(rd->stderr_v);
  }

  if (rd->timeout != 0) {
    g_source_remove(rd->timeout);
  }
  g_free(rd);
}

run_request *
new_run_request(void) {
  run_request *result;
  result = g_new0(run_request, 1);
  g_assert(result != NULL);
  return result;
}

void
del_run_request(run_request *r) {
  if (r == NULL) 
    return;
  g_free(r->udi);
  free_string_array(r->environment);
  free_string_array(r->argv);
  g_free(r->input);
  g_free(r);
}

static void
send_reply(DBusConnection *con, DBusMessage *msg, 
           guint32 exit_type, gint32 return_code, gchar **error) {
  DBusMessage *reply;
  DBusMessageIter iter;
  int i;

  if (con == NULL || msg == NULL) 
    return;

  reply = dbus_message_new_method_return(msg);
  g_assert(reply != NULL);

  dbus_message_iter_init_append(reply, &iter);
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &exit_type);
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &return_code);
  if (error != NULL) for (i = 0; error[i] != NULL; i++) {
    dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &error[i]);
  }

  dbus_connection_send(con, reply, NULL);
  dbus_message_unref(reply);
}

static void
remove_from_hash_table(run_data *rd) {
  GList *list;
  /* Remove to the hashtable */
  list = (GList *)g_hash_table_lookup(udi_hash, rd->r->udi);
  list = g_list_remove(list, rd);
  /* The hash table will take care to not leak the dupped string */
  g_hash_table_insert(udi_hash, g_strdup(rd->r->udi), list);
}

static void
run_exited(GPid pid, gint status, gpointer data) {
  run_data *rd = (run_data *)data;
  char **error = NULL;

  printf("%s exited\n", rd->r->argv[0]);
  rd->watch = 0;
  if (rd->sent_kill == TRUE) {
    /* We send it a kill, so ignore */
    del_run_data(rd);
    return;
  }
  /* Check if it was a normal exit */
  if (!WIFEXITED(status)) {
    /* No not normal termination ? crash ? */
    send_reply(rd->con, rd->msg, HALD_RUN_FAILED, 0, NULL);
    remove_from_hash_table(rd);
    del_run_data(rd);
    return;
  }
  /* normal exit */
  if (rd->stderr_v >= 0) {
    /* Need to read stderr */
    error = get_string_array_from_fd(rd->stderr_v);
    rd->stderr_v = -1;
  }
  if (rd->msg != NULL) {
    send_reply(rd->con, rd->msg, HALD_RUN_SUCCESS, WEXITSTATUS(status), error);
  }
  free_string_array(error);

  remove_from_hash_table(rd);
  del_run_data(rd);
}

static gboolean
run_timedout(gpointer data) {
  run_data *rd = (run_data *)data;
  /* Time is up, kill the process, send reply that it was killed! 
   * Don't wait for exit, because it could hang in state D
   */ 
  kill(rd->pid, SIGTERM);
  /* Ensure the timeout is not removed in the delete */
  rd->timeout = 0;
  /* So the exit watch will know it's killed  in case it runs*/
  rd->sent_kill = TRUE;

  send_reply(rd->con, rd->msg, HALD_RUN_TIMEOUT, 0, NULL);
  remove_from_hash_table(rd);
  return FALSE;
}

static
gboolean find_program(char **argv) {
  /* Search for the program in the dirs where it's allowed to be */
  char *dirs[] = { PACKAGE_LIBEXEC_DIR, PACKAGE_SCRIPT_DIR, NULL };
  char *program;
  char *path = NULL;
  struct stat buf;
  int i;

  if (argv[0] == NULL) 
    return FALSE;
  program = g_path_get_basename(argv[0]);
  for (i = 0; dirs[i] != NULL; i++) {
    path = g_build_filename(dirs[i], program, NULL);
    if (stat(path, &buf) == 0) {
        break;
    }
    g_free(path);
    path = NULL;
  }
  g_free(program);
  if (path == NULL) 
    return FALSE;
  else {
    /* Replace program in argv[0] with the full path */
    g_free(argv[0]);
    argv[0] = path;
  }
  return TRUE;
}


/* Run the given request and reply it's result on msg */
gboolean 
run_request_run(run_request *r, DBusConnection *con, DBusMessage *msg) {
  GPid pid;
  GError *error = NULL;
  gint *stdin_p = NULL;
  gint *stderr_p = NULL;
  gint stdin_v;
  gint stderr_v = -1;
  run_data *rd = NULL;
  GList *list;

  printf("Run started %s (%d) (%d) \n!", r->argv[0], r->timeout, 
      r->error_on_stderr);
  if (r->input != NULL) {
    stdin_p = &stdin_v; 
  }
  if (r->error_on_stderr) {
    stderr_p = &stderr_v;
  }

  if (!find_program(r->argv) ||
      !g_spawn_async_with_pipes("/", r->argv, r->environment, 
                                G_SPAWN_DO_NOT_REAP_CHILD,
                                NULL, NULL, &pid, 
                                stdin_p, NULL, stderr_p, &error)) {
    del_run_request(r);
    if (con && msg) {
      send_reply(con, msg, HALD_RUN_FAILED, 0, NULL);
    }
    return FALSE;
  }

  if (r->input) {
    write(stdin_v, r->input, strlen(r->input));
    close(stdin_v);
  }

  rd = g_new0(run_data,1);
  g_assert(rd != NULL);
  rd->r = r;
  rd->msg = msg;
  if (msg != NULL) {
    dbus_message_ref(msg);
  }
  rd->con = con;
  rd->pid = pid;
  rd->stderr_v = stderr_v;
  rd->sent_kill = FALSE;

  /* Add watch for exit of the program */
  rd->watch = g_child_watch_add(pid, run_exited, rd);
  /* Add timeout if needed */
  if (r->timeout > 0) {
    rd->timeout = g_timeout_add(r->timeout, run_timedout, rd);
  } else {
    rd->timeout = 0;
  }
  /* Add to the hashtable */
  list = (GList *)g_hash_table_lookup(udi_hash, r->udi);
  list = g_list_prepend(list, rd);
  /* The hash table will take care to not leak the dupped string */
  g_hash_table_insert(udi_hash, g_strdup(r->udi), list);
  return TRUE;
}

static void
kill_rd(gpointer data, gpointer user_data) {
  run_data *rd = (run_data *)data;

  kill(rd->pid, SIGTERM);
  printf("Sent kill to %d\n", rd->pid);
  if (rd->timeout != 0) {
    /* Remove the timeout watch */
    g_source_remove(rd->timeout);
    rd->timeout = 0;
  }
  /* So the exit watch will know it's killed  in case it runs*/
  rd->sent_kill = TRUE;

  if (rd->msg != NULL) {
    send_reply(rd->con, rd->msg, HALD_RUN_KILLED, 0, NULL);
  }
}

static void
do_kill_udi(gchar *udi) {
  GList *list;
  list = (GList *)g_hash_table_lookup(udi_hash, udi);
  g_list_foreach(list, kill_rd, NULL);
  g_list_free(list);
}

/* Kill all running request for a udi */
void 
run_kill_udi(gchar *udi) {
  do_kill_udi(udi);
  g_hash_table_remove(udi_hash, udi);
}

static void
hash_kill_udi(gpointer key, gpointer value, gpointer user_data) {
  do_kill_udi(key);
}

/* Kill all running request*/
void 
run_kill_all() {
  g_hash_table_foreach_remove(udi_hash, hash_kill_udi, NULL);
}

void
run_init() {
  udi_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
}

--- NEW FILE: runner.h ---
/***************************************************************************
 * CVSID: $Id: runner.h,v 1.1 2006/01/21 02:45:27 david Exp $
 *
 * runner.h - Process running interface
 *
 * Copyright (C) 2006 Sjoerd Simons, <sjoerd at luon.net>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/
#ifndef RUNNER_H
#define RUNNER_H

#define DBUS_API_SUBJECT_TO_CHANGE 
#include <dbus/dbus-glib-lowlevel.h>

#include <glib.h>

typedef struct {
  gchar *udi;
  gchar **environment;
  gchar **argv;
  gchar *input;
  gboolean error_on_stderr;
  guint32 timeout;
} run_request;

run_request *new_run_request(void);
void del_run_request(run_request *r);

/* Run the given request and reply it's result on msg */
gboolean run_request_run(run_request *r, DBusConnection *con, DBusMessage *msg);

/* Kill all running request for a udi */
void run_kill_udi(gchar *udi);

/* Kill all running request*/
void run_kill_all();

/* initialise the actual runner data */
void run_init();
#endif /*  RUNNER_H */

--- NEW FILE: utils.c ---
/***************************************************************************
 * CVSID: $Id: utils.c,v 1.1 2006/01/21 02:45:27 david Exp $
 *
 * utils.c - Some utils for the hald runner
 *
 * Copyright (C) 2006 Sjoerd Simons, <sjoerd at luon.net>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#define DBUS_API_SUBJECT_TO_CHANGE 
#include <dbus/dbus-glib-lowlevel.h>
#include <glib.h>

#include "utils.h"

char **
get_string_array(DBusMessageIter *iter) {
  GArray *array;
  char **result;
  array = g_array_new(TRUE, FALSE, sizeof(char *));

  while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
    const char *value;
    char *t;
    dbus_message_iter_get_basic(iter, &value);
    t = g_strdup(value);
    g_array_append_vals(array, &t, 1);
    dbus_message_iter_next(iter);
  }
  result = (char **) array->data;
  g_array_free(array, FALSE);
  return result;
}

char **
get_string_array_from_fd(int fd) {
  GArray *array;
  char **result;
  GString *str;
  gsize pos;
  GIOChannel *io;
  int i = 0;

  array = g_array_new(TRUE, FALSE, sizeof(char *));
  str = g_string_new("");
  io = g_io_channel_unix_new(fd);
  while (g_io_channel_read_line_string(io, str, &pos, NULL) 
          == G_IO_STATUS_NORMAL && (i++ < 128)) {
    char *t;
    /* Remove the terminting char aka \n*/
    g_string_erase(str, pos, 1);
    t = g_strdup(str->str);
    g_array_append_vals(array, &t, 1);
  }
  g_string_free(str, TRUE);
  g_io_channel_unref(io);
  result = (char **) array->data;
  g_array_free(array, FALSE);
  return result;
}

void 
free_string_array(char **array) {
  char **p;
  for (p = array; p != NULL && *p != NULL; p++) {
    g_free(*p);
  }
  g_free(array);
}

--- NEW FILE: utils.h ---
/***************************************************************************
 * CVSID: $Id: utils.h,v 1.1 2006/01/21 02:45:27 david Exp $
 *
 * utils.h - Some utils for the hald runner
 *
 * Copyright (C) 2006 Sjoerd Simons, <sjoerd at luon.net>
 *
 * Licensed under the Academic Free License version 2.1
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/
#ifndef UTILS_H
#define UTILS_H

#define DBUS_API_SUBJECT_TO_CHANGE 
#include <dbus/dbus-glib-lowlevel.h>

char **get_string_array(DBusMessageIter *iter);
char **get_string_array_from_fd(int fd);
void free_string_array(char **array);

#endif /*  UTILS_H */




More information about the hal-commit mailing list