-
Simon McVittie authored
Signed-off-by:
Simon McVittie <smcv@collabora.com>
Simon McVittie authoredSigned-off-by:
Simon McVittie <smcv@collabora.com>
flatpak-utils.c 5.77 KiB
/*
* A cut-down version of common/flatpak-utils from Flatpak
*
* Copyright © 2014 Red Hat, Inc
*
* 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.1 of the License, 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, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Alexander Larsson <alexl@redhat.com>
*/
#include "config.h"
#include "subprojects/libglnx/config.h"
#include "flatpak-utils-private.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <termios.h>
#define RUNNING_ON_VALGRIND 0
/* Sometimes this is /var/run which is a symlink, causing weird issues when we pass
* it as a path into the sandbox */
char *
flatpak_get_real_xdg_runtime_dir (void)
{
return realpath (g_get_user_runtime_dir (), NULL);
}
char *
flatpak_get_timezone (void)
{
g_autofree gchar *symlink = NULL;
gchar *etc_timezone = NULL;
const gchar *tzdir;
tzdir = getenv ("TZDIR");
if (tzdir == NULL)
tzdir = "/usr/share/zoneinfo";
symlink = flatpak_resolve_link ("/etc/localtime", NULL);
if (symlink != NULL)
{
/* Resolve relative path */
g_autofree gchar *canonical = flatpak_canonicalize_filename (symlink);
char *canonical_suffix;
/* Strip the prefix and slashes if possible. */
if (g_str_has_prefix (canonical, tzdir))
{
canonical_suffix = canonical + strlen (tzdir);
while (*canonical_suffix == '/')
canonical_suffix++;
return g_strdup (canonical_suffix);
}
}
if (g_file_get_contents ("/etc/timezeone", &etc_timezone,
NULL, NULL))
{
g_strchomp (etc_timezone);
return etc_timezone;
}
/* Final fall-back is UTC */
return g_strdup ("UTC");
}
static gboolean
needs_quoting (const char *arg)
{
while (*arg != 0)
{
char c = *arg;
if (!g_ascii_isalnum (c) &&
!(c == '-' || c == '/' || c == '~' ||
c == ':' || c == '.' || c == '_' ||
c == '=' || c == '@'))
return TRUE;
arg++;
}
return FALSE;
}
char *
flatpak_quote_argv (const char *argv[],
gssize len)
{
GString *res = g_string_new ("");
int i;
if (len == -1)
len = g_strv_length ((char **) argv);
for (i = 0; i < len; i++)
{
if (i != 0)
g_string_append_c (res, ' ');
if (needs_quoting (argv[i]))
{
g_autofree char *quoted = g_shell_quote (argv[i]);
g_string_append (res, quoted);
}
else
g_string_append (res, argv[i]);
}
return g_string_free (res, FALSE);
}
char *
flatpak_readlink (const char *path,
GError **error)
{
return glnx_readlinkat_malloc (-1, path, NULL, error);
}
char *
flatpak_resolve_link (const char *path,
GError **error)
{
g_autofree char *link = flatpak_readlink (path, error);
g_autofree char *dirname = NULL;
if (link == NULL)
return NULL;
if (g_path_is_absolute (link))
return g_steal_pointer (&link);
dirname = g_path_get_dirname (path);
return g_build_filename (dirname, link, NULL);
}
char *
flatpak_canonicalize_filename (const char *path)
{
g_autoptr(GFile) file = g_file_new_for_path (path);
return g_file_get_path (file);
}
/* If memfd_create() is available, generate a sealed memfd with contents of
* @str. Otherwise use an O_TMPFILE @tmpf in anonymous mode, write @str to
* @tmpf, and lseek() back to the start. See also similar uses in e.g.
* rpm-ostree for running dracut.
*/
gboolean
flatpak_buffer_to_sealed_memfd_or_tmpfile (GLnxTmpfile *tmpf,
const char *name,
const char *str,
size_t len,
GError **error)
{
if (len == -1)
len = strlen (str);
glnx_autofd int memfd = memfd_create (name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
int fd; /* Unowned */
if (memfd != -1)
{
fd = memfd;
}
else
{
/* We use an anonymous fd (i.e. O_EXCL) since we don't want
* the target container to potentially be able to re-link it.
*/
if (!G_IN_SET (errno, ENOSYS, EOPNOTSUPP))
return glnx_throw_errno_prefix (error, "memfd_create");
if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, tmpf, error))
return FALSE;
fd = tmpf->fd;
}
if (ftruncate (fd, len) < 0)
return glnx_throw_errno_prefix (error, "ftruncate");
if (glnx_loop_write (fd, str, len) < 0)
return glnx_throw_errno_prefix (error, "write");
if (lseek (fd, 0, SEEK_SET) < 0)
return glnx_throw_errno_prefix (error, "lseek");
if (memfd != -1)
{
/* Valgrind doesn't currently handle G_ADD_SEALS, so lets not seal when debugging... */
if ((!RUNNING_ON_VALGRIND) &&
fcntl (memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL) < 0)
return glnx_throw_errno_prefix (error, "fcntl(F_ADD_SEALS)");
/* The other values can stay default */
tmpf->fd = glnx_steal_fd (&memfd);
tmpf->initialized = TRUE;
}
return TRUE;
}