288 lines
7.4 KiB
C
288 lines
7.4 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
|
*
|
|
* Copyright (C) 2014 Colin Walters <walters@verbum.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation; either version 2 of the licence or (at
|
|
* your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General
|
|
* Public License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <glib-unix.h>
|
|
#include <json-glib/json-glib.h>
|
|
#include <gio/gunixoutputstream.h>
|
|
|
|
#include "rpmostree-util.h"
|
|
#include "libgsystem.h"
|
|
|
|
void
|
|
_rpmostree_set_error_from_errno (GError **error,
|
|
gint errsv)
|
|
{
|
|
g_set_error_literal (error,
|
|
G_IO_ERROR,
|
|
g_io_error_from_errno (errsv),
|
|
g_strerror (errsv));
|
|
errno = errsv;
|
|
}
|
|
|
|
void
|
|
_rpmostree_set_prefix_error_from_errno (GError **error,
|
|
gint errsv,
|
|
const char *format,
|
|
...)
|
|
{
|
|
gs_free char *formatted = NULL;
|
|
va_list args;
|
|
|
|
va_start (args, format);
|
|
formatted = g_strdup_vprintf (format, args);
|
|
va_end (args);
|
|
|
|
_rpmostree_set_error_from_errno (error, errsv);
|
|
g_prefix_error (error, "%s", formatted);
|
|
errno = errsv;
|
|
}
|
|
|
|
void
|
|
_rpmostree_perror_fatal (const char *message)
|
|
{
|
|
perror (message);
|
|
exit (1);
|
|
}
|
|
|
|
gboolean
|
|
_rpmostree_util_enumerate_directory_allow_noent (GFile *dirpath,
|
|
const char *queryargs,
|
|
GFileQueryInfoFlags queryflags,
|
|
GFileEnumerator **out_direnum,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
gboolean ret = FALSE;
|
|
GError *temp_error = NULL;
|
|
gs_unref_object GFileEnumerator *ret_direnum = NULL;
|
|
|
|
ret_direnum = g_file_enumerate_children (dirpath, queryargs, queryflags,
|
|
cancellable, &temp_error);
|
|
if (!ret_direnum)
|
|
{
|
|
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
|
{
|
|
g_clear_error (&temp_error);
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
g_propagate_error (error, temp_error);
|
|
|
|
goto out;
|
|
}
|
|
|
|
ret = TRUE;
|
|
gs_transfer_out_value (out_direnum, &ret_direnum);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
gboolean
|
|
_rpmostree_file_load_contents_utf8_allow_noent (GFile *path,
|
|
char **out_contents,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
gboolean ret = FALSE;
|
|
GError *temp_error = NULL;
|
|
gs_free char *ret_contents = NULL;
|
|
|
|
ret_contents = gs_file_load_contents_utf8 (path, cancellable, &temp_error);
|
|
if (!ret_contents)
|
|
{
|
|
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
|
{
|
|
g_clear_error (&temp_error);
|
|
}
|
|
else
|
|
{
|
|
g_propagate_error (error, temp_error);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
ret = TRUE;
|
|
gs_transfer_out_value (out_contents, &ret_contents);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
gboolean
|
|
_rpmostree_util_update_checksum_from_file (GChecksum *checksum,
|
|
GFile *src,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
gboolean ret = FALSE;
|
|
gsize bytes_read;
|
|
char buf[4096];
|
|
gs_unref_object GInputStream *filein = NULL;
|
|
|
|
filein = (GInputStream*)g_file_read (src, cancellable, error);
|
|
if (!filein)
|
|
goto out;
|
|
|
|
do
|
|
{
|
|
if (!g_input_stream_read_all (filein, buf, sizeof(buf), &bytes_read,
|
|
cancellable, error))
|
|
goto out;
|
|
|
|
g_checksum_update (checksum, (guint8*)buf, bytes_read);
|
|
}
|
|
while (bytes_read > 0);
|
|
|
|
ret = TRUE;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static char *
|
|
ost_get_prev_commit (OstreeRepo *repo, char *checksum)
|
|
{
|
|
char *ret = NULL;
|
|
gs_unref_variant GVariant *commit = NULL;
|
|
gs_unref_variant GVariant *parent_csum_v = NULL;
|
|
GError *tmp_error = NULL;
|
|
|
|
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, checksum,
|
|
&commit, &tmp_error))
|
|
goto out;
|
|
|
|
ret = ostree_commit_get_parent (commit);
|
|
|
|
out:
|
|
g_clear_error (&tmp_error);
|
|
|
|
return ret;
|
|
}
|
|
|
|
GPtrArray *
|
|
_rpmostree_util_get_commit_hashes (OstreeRepo *repo,
|
|
const char *beg,
|
|
const char *end,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
GPtrArray *ret = NULL;
|
|
gs_free char *beg_checksum = NULL;
|
|
gs_free char *end_checksum = NULL;
|
|
gs_free char *parent = NULL;
|
|
char *checksum = NULL;
|
|
gboolean worked = FALSE;
|
|
|
|
if (!ostree_repo_read_commit (repo, beg, NULL, &beg_checksum, cancellable, error))
|
|
goto out;
|
|
|
|
ret = g_ptr_array_new_with_free_func (g_free);
|
|
g_ptr_array_add (ret, g_strdup (beg)); // Add the user defined REFSPEC.
|
|
|
|
if (end &&
|
|
!ostree_repo_read_commit (repo, end, NULL, &end_checksum, cancellable, error))
|
|
goto out;
|
|
|
|
if (end && g_str_equal (end_checksum, beg_checksum))
|
|
goto worked_out;
|
|
|
|
checksum = beg_checksum;
|
|
while ((parent = ost_get_prev_commit (repo, checksum)))
|
|
{
|
|
if (end && g_str_equal (end_checksum, parent))
|
|
{ // Add the user defined REFSPEC.
|
|
g_ptr_array_add (ret, g_strdup (end));
|
|
break;
|
|
}
|
|
|
|
g_ptr_array_add (ret, parent);
|
|
checksum = parent;
|
|
}
|
|
|
|
if (end && !parent)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Invalid ref range: %s is not a parent of %s", end, beg);
|
|
goto out;
|
|
}
|
|
|
|
worked_out:
|
|
worked = TRUE;
|
|
|
|
out:
|
|
if (!worked)
|
|
{
|
|
g_ptr_array_free (ret, TRUE);
|
|
ret = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
gboolean
|
|
_rpmostree_sync_wait_on_pid (pid_t pid,
|
|
GError **error)
|
|
{
|
|
gboolean ret = FALSE;
|
|
pid_t r;
|
|
int estatus;
|
|
|
|
do
|
|
r = waitpid (pid, &estatus, 0);
|
|
while (G_UNLIKELY (r == -1 && errno == EINTR));
|
|
|
|
if (r == -1)
|
|
{
|
|
_rpmostree_set_prefix_error_from_errno (error, errno, "waitpid: ");
|
|
goto out;
|
|
}
|
|
|
|
if (!g_spawn_check_exit_status (estatus, error))
|
|
goto out;
|
|
|
|
ret = TRUE;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
char *
|
|
_rpmostree_util_next_version (const char *auto_version_prefix,
|
|
const char *last_version)
|
|
{
|
|
unsigned long long num = 0;
|
|
const char *end = NULL;
|
|
|
|
if (!last_version || !g_str_has_prefix (last_version, auto_version_prefix))
|
|
return g_strdup (auto_version_prefix);
|
|
|
|
if (g_str_equal (last_version, auto_version_prefix))
|
|
return g_strdup_printf ("%s.1", auto_version_prefix);
|
|
|
|
end = last_version + strlen(auto_version_prefix);
|
|
|
|
if (*end != '.')
|
|
return g_strdup (auto_version_prefix);
|
|
++end;
|
|
|
|
num = g_ascii_strtoull (end, NULL, 10);
|
|
return g_strdup_printf ("%s.%llu", auto_version_prefix, num + 1);
|
|
}
|