Ejemplo n.º 1
0
static gboolean
do_checkout (OtAdminDeploy     *self,
             const char        *deploy_target,
             const char        *revision,
             GCancellable      *cancellable,
             GError           **error)
{
  gboolean ret = FALSE;
  ot_lobj GFile *deploy_path = NULL;
  ot_lobj GFile *deploy_parent = NULL;
  ot_lfree char *tree_ref = NULL;
  ot_lptrarray GPtrArray *checkout_args = NULL;

  deploy_path = ot_gfile_from_build_path ("/ostree", deploy_target, NULL);
  deploy_parent = g_file_get_parent (deploy_path);
  if (!ot_gfile_ensure_directory (deploy_parent, TRUE, error))
    goto out;

  checkout_args = g_ptr_array_new ();
  ot_ptrarray_add_many (checkout_args, "ostree", "--repo=/ostree/repo",
                        "checkout", "--atomic-retarget", revision ? revision : deploy_target,
                        ot_gfile_get_path_cached (deploy_path), NULL);
  g_ptr_array_add (checkout_args, NULL);

  if (!ot_spawn_sync_checked ("/ostree", (char**)checkout_args->pdata, NULL, G_SPAWN_SEARCH_PATH,
                              NULL, NULL, NULL, NULL, error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 2
0
/**
 * ot_gfile_rename:
 * @from: Current path
 * @to: New path
 * @cancellable: a #GCancellable
 * @error: a #GError
 *
 * This function wraps the raw Unix function rename().
 *
 * Returns: %TRUE on success, %FALSE on error
 */
gboolean
ot_gfile_rename (GFile          *from,
                 GFile          *to,
                 GCancellable   *cancellable,
                 GError        **error)
{
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  if (rename (ot_gfile_get_path_cached (from),
              ot_gfile_get_path_cached (to)) < 0)
    {
      ot_util_set_error_from_errno (error, errno);
      return FALSE;
    }
  return TRUE;

}
static gboolean
update_grub (const char         *release,
             GCancellable       *cancellable,
             GError            **error)
{
  gboolean ret = FALSE;
  ot_lobj GFile *grub_path = g_file_new_for_path ("/boot/grub/grub.conf");

  if (g_file_query_exists (grub_path, cancellable))
    {
      gboolean have_grub_entry;
      if (!grep_literal (grub_path, "OSTree", &have_grub_entry,
                         cancellable, error))
        goto out;

      if (!have_grub_entry)
        {
          ot_lptrarray GPtrArray *grubby_args = NULL;
          ot_lfree char *add_kernel_arg = NULL;
          ot_lfree char *initramfs_arg = NULL;
          ot_lobj GFile *kernel_path = NULL;

          if (!get_kernel_path_from_release (release, &kernel_path, cancellable, error))
            goto out;

          if (kernel_path == NULL)
            {
              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "Couldn't find kernel for release %s", release);
              goto out;
            }

          grubby_args = g_ptr_array_new ();
          add_kernel_arg = g_strconcat ("--add-kernel=", ot_gfile_get_path_cached (kernel_path), NULL);
          initramfs_arg = g_strconcat ("--initrd=", "/boot/initramfs-ostree-", release, ".img", NULL);
          ot_ptrarray_add_many (grubby_args, "grubby", "--grub", add_kernel_arg, initramfs_arg,
                                "--copy-default", "--title=OSTree", NULL);
          g_ptr_array_add (grubby_args, NULL);

          g_print ("Adding OSTree grub entry...\n");
          if (!ot_spawn_sync_checked (NULL, (char**)grubby_args->pdata, NULL, G_SPAWN_SEARCH_PATH,
                                      NULL, NULL, NULL, NULL, error))
            goto out;
        } 
      else
        g_print ("Already have OSTree entry in grub config\n");
    }
  else
    {
      g_print ("/boot/grub/grub.conf not found, assuming you have GRUB 2\n");
    }
  
  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 4
0
gboolean
ostree_get_xattrs_for_file (GFile         *f,
                            GVariant     **out_xattrs,
                            GCancellable  *cancellable,
                            GError       **error)
{
  gboolean ret = FALSE;
  const char *path;
  ssize_t bytes_read;
  ot_lvariant GVariant *ret_xattrs = NULL;
  ot_lfree char *xattr_names = NULL;
  ot_lfree char *xattr_names_canonical = NULL;
  GVariantBuilder builder;
  gboolean builder_initialized = FALSE;

  path = ot_gfile_get_path_cached (f);

  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)"));
  builder_initialized = TRUE;

  bytes_read = llistxattr (path, NULL, 0);

  if (bytes_read < 0)
    {
      if (errno != ENOTSUP)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else if (bytes_read > 0)
    {
      xattr_names = g_malloc (bytes_read);
      if (llistxattr (path, xattr_names, bytes_read) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
      xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read);
      
      if (!read_xattr_name_array (path, xattr_names_canonical, bytes_read, &builder, error))
        goto out;
    }

  ret_xattrs = g_variant_builder_end (&builder);
  g_variant_ref_sink (ret_xattrs);
  
  ret = TRUE;
  ot_transfer_out_value (out_xattrs, &ret_xattrs);
 out:
  if (!builder_initialized)
    g_variant_builder_clear (&builder);
  return ret;
}
Ejemplo n.º 5
0
/**
 * @root: (allow-none): Change to this root; if %NULL, don't chroot
 *
 * Triggers are a set of programs to run on a root to regenerate cache
 * files.  This API call will simply run them against the given root.
 */
gboolean
ostree_run_triggers_in_root (GFile                  *root,
                             GCancellable           *cancellable,
                             GError                **error)
{
  gboolean ret = FALSE;
  int estatus;
  ot_lfree char *rel_triggerdir = NULL;
  ot_lobj GFile *triggerdir = NULL;
  ot_lptrarray GPtrArray *argv = NULL;

  rel_triggerdir = g_build_filename ("usr", "libexec", "ostree", "triggers.d", NULL);

  if (root)
    triggerdir = g_file_resolve_relative_path (root, rel_triggerdir);
  else
    triggerdir = g_file_new_for_path (rel_triggerdir);

  if (g_file_query_exists (triggerdir, cancellable))
    {
      argv = g_ptr_array_new ();
      if (root)
        {
          g_ptr_array_add (argv, "linux-user-chroot");
          g_ptr_array_add (argv, "--unshare-pid");
          g_ptr_array_add (argv, "--unshare-ipc");
          /* FIXME - unshare net too */
          g_ptr_array_add (argv, "--mount-proc");
          g_ptr_array_add (argv, "/proc");
          g_ptr_array_add (argv, "--mount-bind");
          g_ptr_array_add (argv, "/dev");
          g_ptr_array_add (argv, "/dev");
          g_ptr_array_add (argv, (char*)ot_gfile_get_path_cached (root));
        }
      g_ptr_array_add (argv, "ostree-run-triggers");
      g_ptr_array_add (argv, NULL);

      if (!g_spawn_sync (NULL, (char**)argv->pdata,
                         (char**) ostree_get_sysroot_environ (),
                         G_SPAWN_SEARCH_PATH,
                         NULL, NULL, NULL, NULL, &estatus, error))
        goto out;

      if (!g_spawn_check_exit_status (estatus, error))
        goto out;
    }

  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 6
0
/**
 * ot_gfile_unlink:
 * @path: Path to file
 * @cancellable: a #GCancellable
 * @error: a #GError
 *
 * Like g_file_delete(), except this function does not follow Unix
 * symbolic links, and will delete a symbolic link even if it's
 * pointing to a nonexistent file.  In other words, this function
 * merely wraps the raw Unix function unlink().
 *
 * Returns: %TRUE on success, %FALSE on error
 */
gboolean
ot_gfile_unlink (GFile          *path,
                 GCancellable   *cancellable,
                 GError        **error)
{
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  if (unlink (ot_gfile_get_path_cached (path)) < 0)
    {
      ot_util_set_error_from_errno (error, errno);
      return FALSE;
    }
  return TRUE;
}
Ejemplo n.º 7
0
gboolean
ostree_set_xattrs (GFile  *f, 
                   GVariant *xattrs, 
                   GCancellable *cancellable, 
                   GError **error)
{
  const char *path;
  gboolean ret = FALSE;
  int i, n;

  path = ot_gfile_get_path_cached (f);

  n = g_variant_n_children (xattrs);
  for (i = 0; i < n; i++)
    {
      const guint8* name;
      GVariant *value;
      const guint8* value_data;
      gsize value_len;
      gboolean loop_err;

      g_variant_get_child (xattrs, i, "(^&ay@ay)",
                           &name, &value);
      value_data = g_variant_get_fixed_array (value, &value_len, 1);
      
      loop_err = lsetxattr (path, (char*)name, (char*)value_data, value_len, XATTR_REPLACE) < 0;
      g_clear_pointer (&value, (GDestroyNotify) g_variant_unref);
      if (loop_err)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }

  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 8
0
/**
 * Return in @out_variant the result of memory-mapping the entire
 * contents of file @src.
 *
 * Note the returned @out_variant is not floating.
 */
gboolean
ot_util_variant_map (GFile              *src,
                     const GVariantType *type,
                     gboolean            trusted,
                     GVariant          **out_variant,
                     GError            **error)
{
  gboolean ret = FALSE;
  const char *path = NULL;
  ot_lvariant GVariant *ret_variant = NULL;
  GMappedFile *mfile = NULL;
  int fd;

  path = ot_gfile_get_path_cached (src);
  if (!ot_unix_open_noatime (path, &fd, error))
    goto out;
  mfile = g_mapped_file_new_from_fd (fd, FALSE, error);
  if (!mfile)
    goto out;
  if (!ot_unix_close (fd, error))
    goto out;

  ret_variant = g_variant_new_from_data (type,
                                         g_mapped_file_get_contents (mfile),
                                         g_mapped_file_get_length (mfile),
                                         trusted,
                                         (GDestroyNotify) g_mapped_file_unref,
                                         mfile);
  mfile = NULL;
  g_variant_ref_sink (ret_variant);
  
  ret = TRUE;
  ot_transfer_out_value(out_variant, &ret_variant);
 out:
  if (mfile)
    g_mapped_file_unref (mfile);
  return ret;
}
static gboolean
update_initramfs (const char       *release,
                  const char       *deploy_target,
                  GCancellable     *cancellable,
                  GError          **error)
{
  gboolean ret = FALSE;
  ot_lfree char *initramfs_name = NULL;
  ot_lobj GFile *initramfs_file = NULL;
  ot_lfree char *last_deploy_path = NULL;

  initramfs_name = g_strconcat ("initramfs-ostree-", release, ".img", NULL);
  initramfs_file = ot_gfile_from_build_path ("/boot", initramfs_name, NULL);
  if (!g_file_query_exists (initramfs_file, NULL))
    {
      ot_lptrarray GPtrArray *mkinitramfs_args = NULL;
      ot_lobj GFile *tmpdir = NULL;
      ot_lfree char *initramfs_tmp_path = NULL;
      ot_lfree char *ostree_vardir = NULL;
      ot_lfree char *ostree_moduledir = NULL;
      ot_lobj GFile *initramfs_tmp_file = NULL;
      ot_lobj GFileInfo *initramfs_tmp_info = NULL;
          
      if (!ostree_create_temp_dir (NULL, "ostree-initramfs", NULL, &tmpdir,
                                   cancellable, error))
        goto out;

      ostree_vardir = g_build_filename (opt_ostree_dir, "var", NULL);
      ostree_moduledir = g_build_filename (opt_ostree_dir, "modules", NULL);

      last_deploy_path = g_build_filename (opt_ostree_dir, deploy_target, NULL);

      mkinitramfs_args = g_ptr_array_new ();
      /* Note: the hardcoded /tmp path below is not actually a
       * security flaw, because we've bind-mounted dracut's view
       * of /tmp to the securely-created tmpdir above.
       */
      ot_ptrarray_add_many (mkinitramfs_args,
                            "linux-user-chroot",
                            "--mount-readonly", "/",
                            "--mount-proc", "/proc",
                            "--mount-bind", "/dev", "/dev",
                            "--mount-bind", ostree_vardir, "/var",
                            "--mount-bind", ot_gfile_get_path_cached (tmpdir), "/tmp",
                            "--mount-bind", ostree_moduledir, "/lib/modules",
                            last_deploy_path,
                            "dracut", "-f", "/tmp/initramfs-ostree.img", release,
                            NULL);
      g_ptr_array_add (mkinitramfs_args, NULL);
          
      g_print ("Generating initramfs using %s...\n", last_deploy_path);
      if (!ot_spawn_sync_checked (NULL, (char**)mkinitramfs_args->pdata, NULL,
                                  G_SPAWN_SEARCH_PATH,
                                  NULL, NULL, NULL, NULL, error))
        goto out;
          
      initramfs_tmp_file = g_file_get_child (tmpdir, "initramfs-ostree.img");
      initramfs_tmp_info = g_file_query_info (initramfs_tmp_file, OSTREE_GIO_FAST_QUERYINFO,
                                              G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                              cancellable, error);
      if (!initramfs_tmp_info)
        goto out;

      if (g_file_info_get_size (initramfs_tmp_info) == 0)
        {
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                       "Initramfs generation failed, check dracut.log");
          goto out;
        }

      if (!g_file_copy (initramfs_tmp_file, initramfs_file, 0, cancellable, NULL, NULL, error))
        goto out;
          
      g_print ("Created: %s\n", ot_gfile_get_path_cached (initramfs_file));

      (void) ot_gfile_unlink (initramfs_tmp_file, NULL, NULL);
      (void) rmdir (ot_gfile_get_path_cached (tmpdir));
    }

  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 10
0
static gboolean
cp_internal (GFile         *src,
             GFile         *dest,
             gboolean       use_hardlinks,
             GCancellable  *cancellable,
             GError       **error)
{
  gboolean ret = FALSE;
  ot_lobj GFileEnumerator *enumerator = NULL;
  ot_lobj GFileInfo *file_info = NULL;
  GError *temp_error = NULL;

  enumerator = g_file_enumerate_children (src, OSTREE_GIO_FAST_QUERYINFO,
                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                          cancellable, error);
  if (!enumerator)
    goto out;

  if (!ot_gfile_ensure_directory (dest, FALSE, error))
    goto out;

  while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, &temp_error)) != NULL)
    {
      const char *name = g_file_info_get_name (file_info);
      ot_lobj GFile *src_child = g_file_get_child (src, name);
      ot_lobj GFile *dest_child = g_file_get_child (dest, name);

      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
        {
          if (!ot_gfile_ensure_directory (dest_child, FALSE, error))
            goto out;

          /* Can't do this even though we'd like to; it fails with an error about
           * setting standard::type not being supported =/
           *
           if (!g_file_set_attributes_from_info (dest_child, file_info, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
           cancellable, error))
           goto out;
          */
          if (chmod (ot_gfile_get_path_cached (dest_child),
                     g_file_info_get_attribute_uint32 (file_info, "unix::mode")) == -1)
            {
              ot_util_set_error_from_errno (error, errno);
              goto out;
            }

          if (!cp_internal (src_child, dest_child, use_hardlinks, cancellable, error))
            goto out;
        }
      else
        {
          gboolean did_link = FALSE;
          (void) unlink (ot_gfile_get_path_cached (dest_child));
          if (use_hardlinks)
            {
              if (link (ot_gfile_get_path_cached (src_child), ot_gfile_get_path_cached (dest_child)) == -1)
                {
                  if (!(errno == EMLINK || errno == EXDEV))
                    {
                      ot_util_set_error_from_errno (error, errno);
                      goto out;
                    }
                  use_hardlinks = FALSE;
                }
              else
                did_link = TRUE;
            }
          if (!did_link)
            {
              if (!g_file_copy (src_child, dest_child,
                                G_FILE_COPY_OVERWRITE | G_FILE_COPY_ALL_METADATA | G_FILE_COPY_NOFOLLOW_SYMLINKS,
                                cancellable, NULL, NULL, error))
                goto out;
            }
        }
      g_clear_object (&file_info);
    }
  if (temp_error)
    {
      g_propagate_error (error, temp_error);
      goto out;
    }

  ret = TRUE;
 out:
  return ret;
}
Ejemplo n.º 11
0
gboolean
ostree_create_temp_file_from_input (GFile            *dir,
                                    const char       *prefix,
                                    const char       *suffix,
                                    GFileInfo        *finfo,
                                    GVariant         *xattrs,
                                    GInputStream     *input,
                                    GFile           **out_file,
                                    GCancellable     *cancellable,
                                    GError          **error)
{
  gboolean ret = FALSE;
  GError *temp_error = NULL;
  int i = 0;
  ot_lfree char *possible_name = NULL;
  ot_lobj GFile *possible_file = NULL;
  ot_lfree guchar *ret_csum = NULL;
  GString *tmp_name = NULL;

  tmp_name = create_tmp_string (ot_gfile_get_path_cached (dir),
                                prefix, suffix);
  
  /* 128 attempts seems reasonable... */
  for (i = 0; i < 128; i++)
    {
      if (g_cancellable_set_error_if_cancelled (cancellable, error))
        goto out;

      g_free (possible_name);
      possible_name = subst_xxxxxx (tmp_name->str);
      g_clear_object (&possible_file);
      possible_file = g_file_get_child (dir, possible_name);
      
      if (!ostree_create_file_from_input (possible_file, finfo, xattrs, input,
                                          cancellable, &temp_error))
        {
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
            {
              g_clear_error (&temp_error);
              continue;
            }
          else
            {
              g_propagate_error (error, temp_error);
              goto out;
            }
        }
      else
        {
          break;
        }
    }
  if (i >= 128)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Exhausted 128 attempts to create a temporary file");
      goto out;
    }

  ret = TRUE;
  ot_transfer_out_value(out_file, &possible_file);
 out:
  if (tmp_name)
    g_string_free (tmp_name, TRUE);
  return ret;
}
Ejemplo n.º 12
0
gboolean
ostree_create_file_from_input (GFile            *dest_file,
                               GFileInfo        *finfo,
                               GVariant         *xattrs,
                               GInputStream     *input,
                               GCancellable     *cancellable,
                               GError          **error)
{
  gboolean ret = FALSE;
  const char *dest_path;
  guint32 uid, gid, mode;
  ot_lobj GFileOutputStream *out = NULL;

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  if (finfo != NULL)
    {
      mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
    }
  else
    {
      mode = S_IFREG | 0664;
    }
  dest_path = ot_gfile_get_path_cached (dest_file);

  if (S_ISDIR (mode))
    {
      if (mkdir (ot_gfile_get_path_cached (dest_file), mode) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else if (S_ISREG (mode))
    {
      out = g_file_create (dest_file, 0, cancellable, error);
      if (!out)
        goto out;

      if (input)
        {
          if (g_output_stream_splice ((GOutputStream*)out, input, 0,
                                      cancellable, error) < 0)
            goto out;
        }

      if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
        goto out;
    }
  else if (S_ISLNK (mode))
    {
      const char *target = g_file_info_get_attribute_byte_string (finfo, "standard::symlink-target");
      if (symlink (target, dest_path) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else if (S_ISCHR (mode) || S_ISBLK (mode))
    {
      guint32 dev = g_file_info_get_attribute_uint32 (finfo, "unix::rdev");
      if (mknod (dest_path, mode, dev) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else if (S_ISFIFO (mode))
    {
      if (mkfifo (dest_path, mode) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Invalid mode %u", mode);
      goto out;
    }

  if (finfo != NULL)
    {
      uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
      gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
      
      if (lchown (dest_path, uid, gid) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          g_prefix_error (error, "lchown(%u, %u) failed: ", uid, gid);
          goto out;
        }
    }

  if (!S_ISLNK (mode))
    {
      if (chmod (dest_path, mode) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          g_prefix_error (error, "chmod(%u) failed: ", mode);
          goto out;
        }
    }

  if (xattrs != NULL)
    {
      if (!ostree_set_xattrs (dest_file, xattrs, cancellable, error))
        goto out;
    }

  ret = TRUE;
 out:
  if (!ret && !S_ISDIR(mode))
    {
      (void) unlink (dest_path);
    }
  return ret;
}