mirror of
https://github.com/flatpak/flatpak.git
synced 2026-01-26 14:13:26 +00:00
When the .flatpak directory doesn't exist, there are no running instances. Closes: #2027 Approved by: alexlarsson
388 lines
11 KiB
C
388 lines
11 KiB
C
/*
|
|
* Copyright © 2018 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:
|
|
* Matthias Clasen <mclasen@redhat.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <locale.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
#include "libglnx/libglnx.h"
|
|
|
|
#include "flatpak-builtins.h"
|
|
#include "flatpak-table-printer.h"
|
|
#include "flatpak-run-private.h"
|
|
|
|
static gboolean opt_show_cols;
|
|
static const char **opt_cols;
|
|
|
|
static GOptionEntry options[] = {
|
|
{ "show-columns", 0, 0, G_OPTION_ARG_NONE, &opt_show_cols, N_("Show available columns"), NULL },
|
|
{ "columns", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_cols, N_("What information to show"), N_("FIELD,…") },
|
|
{ NULL }
|
|
};
|
|
|
|
static struct {
|
|
const char *name;
|
|
const char *title;
|
|
const char *desc;
|
|
int len;
|
|
} all_columns[] = {
|
|
{ "application", N_("Application"), N_("Show the application ID"), 0 },
|
|
{ "arch", N_("Architecture"), N_("Show the architecture"), 0 },
|
|
{ "branch", N_("Branch"), N_("Show the application branch"), 0 },
|
|
{ "commit", N_("Commit"), N_("Show the application commit"), 12 },
|
|
{ "runtime", N_("Runtime"), N_("Show the runtime ID"), 0 },
|
|
{ "runtime-branch", N_("Runtime Branch"), N_("Show the runtime branch"), 0 },
|
|
{ "runtime-commit", N_("Runtime Commit"), N_("Show the runtime commit"), 12 },
|
|
{ "pid", N_("PID"), N_("Show the PID of the main process"), 0 },
|
|
};
|
|
|
|
#define ALL_COLUMNS "pid,application,arch,branch,runtime,runtime-branch"
|
|
#define DEFAULT_COLUMNS "pid,application,runtime"
|
|
|
|
static int
|
|
find_column (const char *name,
|
|
GError **error)
|
|
{
|
|
int i;
|
|
int candidate;
|
|
|
|
candidate = -1;
|
|
for (i = 0; i < G_N_ELEMENTS(all_columns); i++)
|
|
{
|
|
if (g_str_equal (all_columns[i].name, name))
|
|
{
|
|
return i;
|
|
}
|
|
else if (g_str_has_prefix (all_columns[i].name, name))
|
|
{
|
|
if (candidate == -1)
|
|
{
|
|
candidate = i;
|
|
}
|
|
else
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Ambiguous column: %s"), name);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (candidate >= 0)
|
|
return candidate;
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unknown colum: %s"), name);
|
|
return -1;
|
|
}
|
|
|
|
static char *
|
|
column_help (void)
|
|
{
|
|
GString *s = g_string_new ("");
|
|
int len;
|
|
int i;
|
|
|
|
g_string_append (s, _("Available columns:\n"));
|
|
|
|
len = 0;
|
|
for (i = 0; i < G_N_ELEMENTS(all_columns); i++)
|
|
len = MAX (len, strlen (all_columns[i].name));
|
|
|
|
len += 4;
|
|
for (i = 0; i < G_N_ELEMENTS(all_columns); i++)
|
|
g_string_append_printf (s, " %-*s %s\n", len, all_columns[i].name, all_columns[i].desc);
|
|
|
|
g_string_append_printf (s, " %-*s %s\n", len, "all", _("Show all columns"));
|
|
g_string_append_printf (s, " %-*s %s\n", len, "help", _("Show available columns"));
|
|
|
|
return g_string_free (s, FALSE);
|
|
}
|
|
|
|
static void
|
|
show_columns (void)
|
|
{
|
|
g_autofree char *col_help = column_help ();
|
|
g_print ("%s", col_help);
|
|
}
|
|
|
|
static char *
|
|
get_instance_pid (const char *instance)
|
|
{
|
|
g_autofree char *path = NULL;
|
|
char *pid;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
path = g_build_filename (g_get_user_runtime_dir (), ".flatpak", instance, "pid", NULL);
|
|
|
|
if (!g_file_get_contents (path, &pid, NULL, &error))
|
|
{
|
|
g_debug ("Failed to load pid file for instance '%s': %s", instance, error->message);
|
|
return NULL;
|
|
}
|
|
|
|
return pid;
|
|
}
|
|
|
|
static GKeyFile *
|
|
get_instance_info (const char *instance)
|
|
{
|
|
g_autofree char *path = NULL;
|
|
GKeyFile *key_file = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
path = g_build_filename (g_get_user_runtime_dir (), ".flatpak", instance, "info", NULL);
|
|
|
|
key_file = g_key_file_new ();
|
|
if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error))
|
|
{
|
|
g_debug ("Failed to load info file for instance '%s': %s", instance, error->message);
|
|
return NULL;
|
|
}
|
|
|
|
return key_file;
|
|
}
|
|
|
|
static char *
|
|
get_instance_column (GKeyFile *info,
|
|
const char *name)
|
|
{
|
|
if (info == NULL)
|
|
return NULL;
|
|
|
|
if (strcmp (name, "application") == 0)
|
|
return g_key_file_get_string (info, "Application", "name", NULL);
|
|
if (strcmp (name, "arch") == 0)
|
|
return g_key_file_get_string (info, "Instance", "arch", NULL);
|
|
if (strcmp (name, "branch") == 0)
|
|
return g_key_file_get_string (info, "Instance", "branch", NULL);
|
|
else if (strcmp (name, "commit") == 0)
|
|
return g_key_file_get_string (info, "Instance", "app-commit", NULL);
|
|
else if (strcmp (name, "runtime") == 0)
|
|
{
|
|
g_autofree char *full_ref = g_key_file_get_string (info, "Application", "runtime", NULL);
|
|
g_auto(GStrv) ref = flatpak_decompose_ref (full_ref, NULL);
|
|
return g_strdup (ref[1]);
|
|
}
|
|
else if (strcmp (name, "runtime-branch") == 0)
|
|
{
|
|
g_autofree char *full_ref = g_key_file_get_string (info, "Application", "runtime", NULL);
|
|
g_auto(GStrv) ref = flatpak_decompose_ref (full_ref, NULL);
|
|
return g_strdup (ref[3]);
|
|
}
|
|
else if (strcmp (name, "runtime-commit") == 0)
|
|
return g_key_file_get_string (info, "Instance", "runtime-commit", NULL);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static gboolean
|
|
enumerate_instances (const char *columns,
|
|
GError **error)
|
|
{
|
|
g_autofree char *base_dir = NULL;
|
|
g_autoptr(GFile) file = NULL;
|
|
g_autoptr(GFileEnumerator) enumerator = NULL;
|
|
GFileInfo *dir_info;
|
|
FlatpakTablePrinter *printer;
|
|
g_auto(GStrv) cols = NULL;
|
|
g_autofree int *col_idx = NULL;
|
|
int n_cols;
|
|
int i;
|
|
|
|
cols = g_strsplit (columns, ",", 0);
|
|
n_cols = g_strv_length (cols);
|
|
col_idx = g_new (int, n_cols);
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
col_idx[i] = find_column (cols[i], error);
|
|
if (col_idx[i] == -1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
printer = flatpak_table_printer_new ();
|
|
flatpak_table_printer_set_column_title (printer, 0, _("Instance"));
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
flatpak_table_printer_set_column_title (printer, i + 1, all_columns[col_idx[i]].title);
|
|
|
|
base_dir = g_build_filename (g_get_user_runtime_dir (), ".flatpak", NULL);
|
|
file = g_file_new_for_path (base_dir);
|
|
enumerator = g_file_enumerate_children (file, "standard::name", G_FILE_QUERY_INFO_NONE, NULL, error);
|
|
if (enumerator == NULL)
|
|
{
|
|
if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
|
{
|
|
/* nothing to show */
|
|
g_clear_error (error);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
while ((dir_info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL)
|
|
{
|
|
g_autofree char *instance = g_file_info_get_attribute_as_string (dir_info, "standard::name");
|
|
g_autoptr(GKeyFile) info = get_instance_info (instance);
|
|
|
|
flatpak_table_printer_add_column (printer, instance);
|
|
|
|
for (i = 0; i < n_cols; i++)
|
|
{
|
|
g_autofree char *col = NULL;
|
|
int len;
|
|
|
|
if (strcmp (all_columns[col_idx[i]].name, "pid") == 0)
|
|
col = get_instance_pid (instance);
|
|
else
|
|
col = get_instance_column (info, all_columns[col_idx[i]].name);
|
|
|
|
len = all_columns[col_idx[i]].len;
|
|
if (len == 0)
|
|
flatpak_table_printer_add_column (printer, col);
|
|
else
|
|
flatpak_table_printer_add_column_len (printer, col, len);
|
|
}
|
|
|
|
flatpak_table_printer_finish_row (printer);
|
|
|
|
g_object_unref (dir_info);
|
|
}
|
|
|
|
flatpak_table_printer_print (printer);
|
|
flatpak_table_printer_free (printer);
|
|
|
|
if (*error)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
flatpak_builtin_ps (int argc,
|
|
char **argv,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GOptionContext) context = NULL;
|
|
g_autofree char *col_help = NULL;
|
|
g_autofree char *cols = NULL;
|
|
|
|
context = g_option_context_new (_(" - Enumerate running sandboxes"));
|
|
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
|
|
col_help = column_help ();
|
|
g_option_context_set_description (context, col_help);
|
|
|
|
if (!flatpak_option_context_parse (context, options, &argc, &argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error))
|
|
return FALSE;
|
|
|
|
if (argc > 1)
|
|
{
|
|
usage_error (context, _("Extra arguments given"), error);
|
|
return FALSE;
|
|
}
|
|
|
|
flatpak_run_gc_ids ();
|
|
|
|
if (opt_show_cols)
|
|
{
|
|
show_columns ();
|
|
return TRUE;
|
|
}
|
|
|
|
if (opt_cols)
|
|
{
|
|
gboolean show_help = FALSE;
|
|
gboolean show_all = FALSE;
|
|
int i;
|
|
|
|
for (i = 0; opt_cols[i]; i++)
|
|
{
|
|
const char *p;
|
|
p = strstr (opt_cols[i], "help");
|
|
if (p &&
|
|
(p == opt_cols[i] || p[-1] == ',') &&
|
|
(p[strlen("help")] == '\0' || p[strlen("help")] == ','))
|
|
{
|
|
show_help = TRUE;
|
|
break;
|
|
}
|
|
|
|
p = strstr (opt_cols[i], "all");
|
|
if (p &&
|
|
(p == opt_cols[i] || p[-1] == ',') &&
|
|
(p[strlen("all")] == '\0' || p[strlen("all")] == ','))
|
|
{
|
|
show_all = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (show_help)
|
|
{
|
|
show_columns ();
|
|
return TRUE;
|
|
}
|
|
else if (show_all)
|
|
{
|
|
cols = g_strdup (ALL_COLUMNS);
|
|
}
|
|
else
|
|
{
|
|
cols = g_strjoinv (",", (char **)opt_cols);
|
|
}
|
|
}
|
|
else
|
|
cols = g_strdup (DEFAULT_COLUMNS);
|
|
|
|
return enumerate_instances (cols, error);
|
|
}
|
|
|
|
gboolean
|
|
flatpak_complete_ps (FlatpakCompletion *completion)
|
|
{
|
|
g_autoptr(GOptionContext) context = NULL;
|
|
|
|
context = g_option_context_new ("");
|
|
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, NULL, NULL))
|
|
return FALSE;
|
|
|
|
switch (completion->argc)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
flatpak_complete_options (completion, global_entries);
|
|
flatpak_complete_options (completion, options);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|