예제 #1
0
/* Guestfs.set_event_callback */
CAMLprim value
ocaml_guestfs_set_event_callback (value gv, value closure, value events)
{
  CAMLparam3 (gv, closure, events);
  char key[64];
  int eh;
  uint64_t event_bitmask;

  guestfs_h *g = Guestfs_val (gv);

  event_bitmask = event_bitmask_of_event_list (events);

  value *root = guestfs_safe_malloc (g, sizeof *root);
  *root = closure;

  eh = guestfs_set_event_callback (g, event_callback_wrapper,
                                   event_bitmask, 0, root);

  if (eh == -1) {
    free (root);
    ocaml_guestfs_raise_error (g, "set_event_callback");
  }

  /* XXX This global root is generational, but we cannot rely on every
   * user having the OCaml 3.11 version which supports this.
   */
  caml_register_global_root (root);

  snprintf (key, sizeof key, "_ocaml_event_%d", eh);
  guestfs_set_private (g, key, root);

  CAMLreturn (Val_int (eh));
}
예제 #2
0
/* Guestfs.set_event_callback */
value
ocaml_guestfs_set_event_callback (value gv, value closure, value events)
{
  CAMLparam3 (gv, closure, events);
  char key[64];
  int eh;
  uint64_t event_bitmask;

  guestfs_h *g = Guestfs_val (gv);

  event_bitmask = event_bitmask_of_event_list (events);

  value *root = guestfs_int_safe_malloc (g, sizeof *root);
  *root = closure;

  eh = guestfs_set_event_callback (g, event_callback_wrapper,
                                   event_bitmask, 0, root);

  if (eh == -1) {
    free (root);
    ocaml_guestfs_raise_error (g, "set_event_callback");
  }

  caml_register_generational_global_root (root);

  snprintf (key, sizeof key, "_ocaml_event_%d", eh);
  guestfs_set_private (g, key, root);

  CAMLreturn (Val_int (eh));
}
예제 #3
0
int
main (int argc, char *argv[])
{
  guestfs_h *g;
  const char *key;
  void *data;
  size_t count;

  g = guestfs_create ();
  if (g == NULL)
    error (EXIT_FAILURE, errno, "guestfs_create");

  if (guestfs_set_event_callback (g, close_callback, GUESTFS_EVENT_CLOSE,
                                  0, NULL) == -1)
    exit (EXIT_FAILURE);

  guestfs_set_private (g, PREFIX "a", (void *) 1);
  guestfs_set_private (g, PREFIX "b", (void *) 2);
  guestfs_set_private (g, PREFIX "c", (void *) 3);
  guestfs_set_private (g, PREFIX "a", (void *) 4); /* overwrites previous */

  /* Check we can fetch keys. */
  assert (guestfs_get_private (g, PREFIX "a") == (void *) 4);
  assert (guestfs_get_private (g, PREFIX "b") == (void *) 2);
  assert (guestfs_get_private (g, PREFIX "c") == (void *) 3);
  assert (guestfs_get_private (g, PREFIX "d") == NULL);

  /* Check we can count keys by iterating. */
  count = 0;
  data = guestfs_first_private (g, &key);
  while (data != NULL) {
    if (strncmp (key, PREFIX, strlen (PREFIX)) == 0)
      count++;
    data = guestfs_next_private (g, &key);
  }
  assert (count == 3);

  /* Delete some keys. */
  guestfs_set_private (g, PREFIX "a", NULL);
  guestfs_set_private (g, PREFIX "b", NULL);

  /* Count them again. */
  count = 0;
  data = guestfs_first_private (g, &key);
  while (data != NULL) {
    if (strncmp (key, PREFIX, strlen (PREFIX)) == 0)
      count++;
    data = guestfs_next_private (g, &key);
  }
  assert (count == 1);

  /* Closing should implicitly call the close_callback function. */
  guestfs_close (g);

  assert (close_callback_called == 1);

  exit (EXIT_SUCCESS);
}
예제 #4
0
/* Common function to set up event callbacks and record data in memory
 * for a particular pass (0 <= pass < NR_TEST_PASSES).
 */
static void
set_up_event_handlers (guestfs_h *g, size_t pass)
{
  struct pass_data *data;

  assert (/* 0 <= pass && */ pass < NR_TEST_PASSES);

  data = &pass_data[pass];
  data->pass = pass;
  data->nr_events = 0;
  data->events = NULL;
  get_time (&data->start_t);
  data->incomplete_log_message = -1;
  data->seen_launch = 0;

  guestfs_set_event_callback (g, close_callback,
                              GUESTFS_EVENT_CLOSE, 0, data);
  guestfs_set_event_callback (g, subprocess_quit_callback,
                              GUESTFS_EVENT_SUBPROCESS_QUIT, 0, data);
  guestfs_set_event_callback (g, launch_done_callback,
                              GUESTFS_EVENT_LAUNCH_DONE, 0, data);
  guestfs_set_event_callback (g, appliance_callback,
                              GUESTFS_EVENT_APPLIANCE, 0, data);
  guestfs_set_event_callback (g, library_callback,
                              GUESTFS_EVENT_LIBRARY, 0, data);
  guestfs_set_event_callback (g, trace_callback,
                              GUESTFS_EVENT_TRACE, 0, data);

  guestfs_set_verbose (g, 1);
  guestfs_set_trace (g, 1);
}
예제 #5
0
int
main (int argc, char *argv[])
{
  guestfs_h *g;
  const char *filename = "test.log";
  FILE *debugfp;

  debugfp = fopen (filename, "w");
  if (debugfp == NULL) {
    perror (filename);
    exit (EXIT_FAILURE);
  }

  g = guestfs_create ();
  if (g == NULL) {
    fprintf (stderr, "failed to create handle\n");
    exit (EXIT_FAILURE);
  }

  if (guestfs_set_event_callback
      (g, debug_to_file,
       GUESTFS_EVENT_LIBRARY | GUESTFS_EVENT_APPLIANCE |
       GUESTFS_EVENT_WARNING | GUESTFS_EVENT_TRACE,
       0, debugfp) == -1)
    exit (EXIT_FAILURE);

  if (guestfs_set_verbose (g, 1) == -1)
    exit (EXIT_FAILURE);

  if (guestfs_set_trace (g, 1) == -1)
    exit (EXIT_FAILURE);

  if (guestfs_add_drive_opts (g, "/dev/null",
                              GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
                              GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
                              -1) == -1)
    exit (EXIT_FAILURE);

  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  guestfs_close (g);

  exit (EXIT_SUCCESS);
}
예제 #6
0
PyObject *
py_guestfs_set_event_callback (PyObject *self, PyObject *args)
{
  PyObject *py_g;
  guestfs_h *g;
  PyObject *py_callback;
  unsigned PY_LONG_LONG events;
  int eh;
  PyObject *py_eh;
  char key[64];

  if (!PyArg_ParseTuple (args, (char *) "OOK:guestfs_set_event_callback",
                         &py_g, &py_callback, &events))
    return NULL;

  if (!PyCallable_Check (py_callback)) {
    PyErr_SetString (PyExc_TypeError,
                     "callback parameter is not callable "
                     "(eg. lambda or function)");
    return NULL;
  }

  g = get_handle (py_g);

  eh = guestfs_set_event_callback (g, py_guestfs_event_callback_wrapper,
                                   events, 0, py_callback);
  if (eh == -1) {
    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
    return NULL;
  }

  /* Increase the refcount for this callback since we are storing it
   * in the opaque C libguestfs handle.  We need to remember that we
   * did this, so we can decrease the refcount for all undeleted
   * callbacks left around at close time (see py_guestfs_close).
   */
  Py_XINCREF (py_callback);

  snprintf (key, sizeof key, "_python_event_%d", eh);
  guestfs_set_private (g, key, py_callback);

  py_eh = PyLong_FromLong ((long) eh);
  return py_eh;
}
예제 #7
0
JNIEXPORT jint JNICALL
Java_com_redhat_et_libguestfs_GuestFS__1set_1event_1callback
  (JNIEnv *env, jobject obj, jlong jg, jobject jcallback, jlong jevents)
{
  guestfs_h *g = (guestfs_h *) (long) jg;
  int r;
  struct callback_data *data;
  jclass callback_class;
  jmethodID method;
  char key[64];

  callback_class = (*env)->GetObjectClass (env, jcallback);
  method = (*env)->GetMethodID (env, callback_class, METHOD_NAME, METHOD_SIGNATURE);
  if (method == 0) {
    throw_exception (env, "GuestFS.set_event_callback: callback class does not implement the EventCallback interface");
    return -1;
  }

  data = malloc (sizeof *data);
  if (data == NULL) {
    throw_out_of_memory (env, "malloc");
    return -1;
  }
  (*env)->GetJavaVM (env, &data->jvm);
  data->method = method;

  r = guestfs_set_event_callback (g, java_callback,
                                  (uint64_t) jevents, 0, data);
  if (r == -1) {
    free (data);
    throw_exception (env, guestfs_last_error (g));
    return -1;
  }

  /* Register jcallback as a global reference so the GC won't free it. */
  data->callback = (*env)->NewGlobalRef (env, jcallback);

  /* Store 'data' in the handle, so we can free it at some point. */
  snprintf (key, sizeof key, "_java_event_%d", r);
  guestfs_set_private (g, key, data);

  return (jint) r;
}
예제 #8
0
int
run_event (const char *cmd, size_t argc, char *argv[])
{
  int r;
  struct entry *entry = NULL, *old_entry;

  if (argc != 3) {
    fprintf (stderr,
             _("use 'event <name> <eventset> <script>' to register an event handler\n"));
    goto error;
  }

  entry = calloc (1, sizeof *entry);
  if (entry == NULL) {
    perror ("calloc");
    goto error;
  }
  entry->eh = -1;

  r = event_bitmask_of_event_set (argv[1], &entry->event_bitmask);
  if (r == -1)
    goto error;

  entry->name = strdup (argv[0]);
  if (entry->name == NULL) {
    perror ("strdup");
    goto error;
  }
  entry->command = strdup (argv[2]);
  if (entry->command == NULL) {
    perror ("strdup");
    goto error;
  }

  entry->eh =
    guestfs_set_event_callback (g, do_event_handler,
                                entry->event_bitmask, 0, entry);
  if (entry->eh == -1)
    goto error;

  r = hash_insert_if_absent (event_handlers, entry, (const void **) &old_entry);
  if (r == -1)
    goto error;
  if (r == 0) {                 /* old_entry set to existing entry */
    entry->next = old_entry->next;
    /* XXX are we allowed to update the old entry? */
    old_entry->next = entry;
  }

  return 0;

 error:
  if (entry) {
    if (entry->eh >= 0)
      guestfs_delete_event_callback (g, entry->eh);
    free (entry->name);
    free (entry->command);
    free (entry);
  }
  return -1;
}
예제 #9
0
static void
test_virtio_serial (void)
{
  int fd, r, eh;
  char tmpfile[] = "/tmp/speedtestXXXXXX";
  struct sigaction sa, old_sa;

  if (!virtio_serial_upload && !virtio_serial_download)
    return;

  /* Create a sparse file.  We could upload from /dev/zero, but we
   * won't get progress messages because libguestfs tests if the
   * source file is a regular file.
   */
  fd = mkstemp (tmpfile);
  if (fd == -1)
    error (EXIT_FAILURE, errno, "mkstemp: %s", tmpfile);
  if (ftruncate (fd, TEST_SERIAL_MAX_SIZE) == -1)
    error (EXIT_FAILURE, errno, "ftruncate");
  if (close (fd) == -1)
    error (EXIT_FAILURE, errno, "close");

  g = guestfs_create ();
  if (!g)
    error (EXIT_FAILURE, errno, "guestfs_create");

  if (guestfs_add_drive_scratch (g, INT64_C (100*1024*1024), -1) == -1)
    exit (EXIT_FAILURE);

  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  /* Make and mount a filesystem which will be used by the download test. */
  if (guestfs_mkfs (g, "ext4", "/dev/sda") == -1)
    exit (EXIT_FAILURE);
  if (guestfs_mount (g, "/dev/sda", "/") == -1)
    exit (EXIT_FAILURE);

  /* Time out the upload after TEST_SERIAL_MAX_TIME seconds have passed. */
  memset (&sa, 0, sizeof sa);
  sa.sa_handler = stop_transfer;
  sa.sa_flags = SA_RESTART;
  sigaction (SIGALRM, &sa, &old_sa);

  /* Get progress messages, which will tell us how much data has been
   * transferred.
   */
  eh = guestfs_set_event_callback (g, progress_cb, GUESTFS_EVENT_PROGRESS,
                                   0, NULL);
  if (eh == -1)
    exit (EXIT_FAILURE);

  if (virtio_serial_upload) {
    gettimeofday (&start, NULL);
    rate = -1;
    operation = "upload";
    alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME);

    /* For the upload test, upload the sparse file to /dev/null in the
     * appliance.  Hopefully this is mostly testing just virtio-serial.
     */
    guestfs_push_error_handler (g, NULL, NULL);
    r = guestfs_upload (g, tmpfile, "/dev/null");
    alarm (0);
    unlink (tmpfile);
    guestfs_pop_error_handler (g);

    /* It's possible that the upload will finish before the alarm fires,
     * or that the upload will be stopped by the alarm.
     */
    if (r == -1 && guestfs_last_errno (g) != EINTR) {
      fprintf (stderr,
               "%s: expecting upload command to return EINTR\n%s\n",
               guestfs_int_program_name, guestfs_last_error (g));
      exit (EXIT_FAILURE);
    }

    if (rate == -1) {
    rate_error:
      fprintf (stderr, "%s: internal error: progress callback was not called! (r=%d, errno=%d)\n",
               guestfs_int_program_name,
               r, guestfs_last_errno (g));
      exit (EXIT_FAILURE);
    }

    print_rate ("virtio-serial upload rate:", rate);
  }

  if (virtio_serial_download) {
    /* For the download test, download a sparse file within the
     * appliance to /dev/null on the host.
     */
    if (guestfs_touch (g, "/sparse") == -1)
      exit (EXIT_FAILURE);
    if (guestfs_truncate_size (g, "/sparse", TEST_SERIAL_MAX_SIZE) == -1)
      exit (EXIT_FAILURE);

    gettimeofday (&start, NULL);
    rate = -1;
    operation = "download";
    alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME);
    guestfs_push_error_handler (g, NULL, NULL);
    r = guestfs_download (g, "/sparse", "/dev/null");
    alarm (0);
    guestfs_pop_error_handler (g);

    if (r == -1 && guestfs_last_errno (g) != EINTR) {
      fprintf (stderr,
               "%s: expecting download command to return EINTR\n%s\n",
               guestfs_int_program_name, guestfs_last_error (g));
      exit (EXIT_FAILURE);
    }

    if (rate == -1)
      goto rate_error;

    print_rate ("virtio-serial download rate:", rate);
  }

  if (guestfs_shutdown (g) == -1)
    exit (EXIT_FAILURE);

  guestfs_close (g);

  /* Restore SIGALRM signal handler. */
  sigaction (SIGALRM, &old_sa, NULL);
}
예제 #10
0
/* Worker thread. */
static void *
start_thread (void *thread_data_vp)
{
  struct thread_data *thread_data = thread_data_vp;
  int quit = 0;
  int err;
  size_t i;
  guestfs_h *g;
  unsigned errors = 0;
  char id[64];

  for (;;) {
    CLEANUP_FREE char *log_file = NULL;
    CLEANUP_FCLOSE FILE *log_fp = NULL;

    /* Take the next process. */
    err = pthread_mutex_lock (&mutex);
    if (err != 0) {
      fprintf (stderr, "%s: pthread_mutex_lock: %s",
               guestfs_int_program_name, strerror (err));
      goto error;
    }

    i = n;
    if (i > 0) {
      printf ("%zu to go ...          \r", n);
      fflush (stdout);

      n--;
    }
    else
      quit = 1;

    err = pthread_mutex_unlock (&mutex);
    if (err != 0) {
      fprintf (stderr, "%s: pthread_mutex_unlock: %s",
               guestfs_int_program_name, strerror (err));
      goto error;
    }

    if (quit)                   /* Work finished. */
      break;

    g = guestfs_create ();
    if (g == NULL) {
      perror ("guestfs_create");
      errors++;
      if (!ignore_errors)
        goto error;
    }

    /* Only if using --log, set up a callback.  See examples/debug-logging.c */
    if (log_template != NULL) {
      size_t j, k;

      log_file = malloc (log_file_size + 1);
      if (log_file == NULL) abort ();
      for (j = 0, k = 0; j < strlen (log_template); ++j) {
        if (log_template[j] == '%') {
          snprintf (&log_file[k], log_file_size - k, "%zu", i);
          k += strlen (&log_file[k]);
        }
        else
          log_file[k++] = log_template[j];
      }
      log_file[k] = '\0';
      log_fp = fopen (log_file, "w");
      if (log_fp == NULL) {
        perror (log_file);
        abort ();
      }
      guestfs_set_event_callback (g, message_callback,
                                  event_bitmask, 0, log_fp);
    }

    snprintf (id, sizeof id, "%zu", i);
    guestfs_set_identifier (g, id);

    guestfs_set_trace (g, trace);
    guestfs_set_verbose (g, verbose);

    if (guestfs_add_drive_ro (g, "/dev/null") == -1) {
      errors++;
      if (!ignore_errors)
        goto error;
    }

    if (guestfs_launch (g) == -1) {
      errors++;
      if (!ignore_errors)
        goto error;
    }

    if (guestfs_shutdown (g) == -1) {
      errors++;
      if (!ignore_errors)
        goto error;
    }

    guestfs_close (g);
  }

  if (errors > 0) {
    fprintf (stderr, "%s: thread %d: %u errors were ignored\n",
             guestfs_int_program_name, thread_data->thread_num, errors);
    goto error;
  }

  thread_data->r = 0;
  return &thread_data->r;

 error:
  thread_data->r = -1;
  return &thread_data->r;
}
예제 #11
0
파일: reopen.c 프로젝트: imcleod/libguestfs
int
run_reopen (const char *cmd, size_t argc, char *argv[])
{
  guestfs_h *g2;
  int r;
  const char *p;
  guestfs_error_handler_cb cb;
  void *cb_data;

  if (argc > 0) {
    fprintf (stderr, _("'reopen' command takes no parameters\n"));
    return -1;
  }

  if (guestfs_shutdown (g) == -1)
    return -1;

  /* Open the new handle first, so we can copy the settings from the
   * old one to the new one, and also so if it fails we still have an
   * open handle.
   */
  g2 = guestfs_create ();
  if (g2 == NULL) {
    fprintf (stderr, _("reopen: guestfs_create: failed to create handle\n"));
    return -1;
  }

  /* Now copy some of the settings from the old handle.  The settings
   * we copy are those which are set by guestfish itself.
   */
  cb = guestfs_get_error_handler (g, &cb_data);
  guestfs_set_error_handler (g2, cb, cb_data);

  r = guestfs_get_verbose (g);
  if (r >= 0)
    guestfs_set_verbose (g2, r);

  r = guestfs_get_trace (g);
  if (r >= 0)
    guestfs_set_trace (g2, r);

  r = guestfs_get_autosync (g);
  if (r >= 0)
    guestfs_set_autosync (g2, r);

  p = guestfs_get_path (g);
  if (p)
    guestfs_set_path (g2, p);

  r = guestfs_get_pgroup (g);
  if (r >= 0)
    guestfs_set_pgroup (g2, r);

  if (progress_bars)
    guestfs_set_event_callback (g2, progress_callback,
                                GUESTFS_EVENT_PROGRESS, 0, NULL);

  /* Close the original handle. */
  guestfs_close (g);
  g = g2;

  /* We don't bother copying event handlers over to the new handle,
   * but we have to reset the list because they were registered
   * against the old handle.
   */
  free_event_handlers ();
  init_event_handlers ();

  return 0;
}