mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-09-30 05:05:27 +00:00
tools: improve error reporting
Add better error reporting in the security context and pw-container. Add manpage for pw-container.
This commit is contained in:
parent
81181e255f
commit
69cc3832d4
|
@ -7,6 +7,7 @@ Manual pages:
|
|||
- \subpage page_man_pw-cat_1
|
||||
- \subpage page_man_pw-cli_1
|
||||
- \subpage page_man_pw-config_1
|
||||
- \subpage page_man_pw-container_1
|
||||
- \subpage page_man_pw-dot_1
|
||||
- \subpage page_man_pw-dump_1
|
||||
- \subpage page_man_pw-jack_1
|
||||
|
|
71
doc/dox/programs/pw-container.1.md
Normal file
71
doc/dox/programs/pw-container.1.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
\page page_man_pw-container_1 pw-container
|
||||
|
||||
The PipeWire container utility
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**pw-container** \[*options*\] \[*PROGRAM*\]
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Run a program in a new security context [1].
|
||||
|
||||
**pw-container** will create a new temporary unix socket and uses the
|
||||
SecurityContext extension API to create a server on this socket with
|
||||
the given properties. Clients created from this server socket will have
|
||||
the security properties attached to them.
|
||||
|
||||
This can be used to simulate the behaviour of Flatpak or other containers.
|
||||
|
||||
Without any arguments, **pw-container** simply creates the new socket
|
||||
and prints the address on stdout. Other PipeWire programs can then be run
|
||||
with `PIPEWIRE_REMOTE=<socket-address>` to connect through this security
|
||||
context.
|
||||
|
||||
When *PROGRAM* is given, the `PIPEWIRE_REMOTE` env variable will be set
|
||||
and *PROGRAM* will be passed to system(). Argument to *PROGRAM* need to be
|
||||
properly quoted.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
\par -P | \--properties=VALUE
|
||||
Set extra context properties as a JSON object.
|
||||
|
||||
\par -r | \--remote=NAME
|
||||
The name the *remote* instance to connect to. If left unspecified, a
|
||||
connection is made to the default PipeWire instance.
|
||||
|
||||
\par -h | \--help
|
||||
Show help.
|
||||
|
||||
\par \--version
|
||||
Show version information.
|
||||
|
||||
# EXIT STATUS
|
||||
|
||||
If the security context was successfuly created, **pw-container** does
|
||||
not exit until terminated with a signal. It exits with status 0 if terminated by
|
||||
SIGINT or SIGTERM in this case.
|
||||
|
||||
Otherwise, it exits with nonzero exit status.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
**pw-container** 'pw-dump i 0'
|
||||
|
||||
Run pw-dump of the Core object. Note the difference in the object permissions
|
||||
when running pw-dump with and without **pw-container**.
|
||||
|
||||
**pw-container** 'pw-dump pw-dump'
|
||||
|
||||
Run pw-dump of itself. Note the difference in the Client security tokens when
|
||||
running pw-dump with and without **pw-container**.
|
||||
|
||||
# AUTHORS
|
||||
|
||||
The PipeWire Developers <$(PACKAGE_BUGREPORT)>;
|
||||
PipeWire is available from <$(PACKAGE_URL)>
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
[1] https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/security-context-v1.xml - Creating a security context
|
|
@ -97,6 +97,7 @@ manpage_docs = [
|
|||
'dox/programs/pw-cat.1.md',
|
||||
'dox/programs/pw-cli.1.md',
|
||||
'dox/programs/pw-config.1.md',
|
||||
'dox/programs/pw-container.1.md',
|
||||
'dox/programs/pw-dot.1.md',
|
||||
'dox/programs/pw-dump.1.md',
|
||||
'dox/programs/pw-jack.1.md',
|
||||
|
|
|
@ -39,9 +39,9 @@ static int security_context_create(void *object,
|
|||
int res = 0;
|
||||
|
||||
if ((client = impl->context->current_client) == NULL)
|
||||
goto not_allowed;
|
||||
goto invalid_state;
|
||||
if (client->protocol != impl->protocol)
|
||||
goto not_allowed;
|
||||
goto invalid_state;
|
||||
|
||||
/* we can't make a nested security context */
|
||||
p = pw_impl_client_get_properties(client);
|
||||
|
@ -49,13 +49,17 @@ static int security_context_create(void *object,
|
|||
goto not_allowed;
|
||||
|
||||
if (pw_protocol_add_fd_server(impl->protocol, impl->context->core,
|
||||
listen_fd, close_fd, props) == NULL)
|
||||
listen_fd, close_fd, props) == NULL) {
|
||||
res = -errno;
|
||||
|
||||
pw_resource_errorf(d->resource, res, "can't add fd server: %m");
|
||||
}
|
||||
return res;
|
||||
|
||||
invalid_state:
|
||||
pw_resource_errorf(d->resource, -EIO, "invalid client protocol");
|
||||
return -EIO;
|
||||
not_allowed:
|
||||
pw_log_warn("can't make security context");
|
||||
pw_resource_errorf(d->resource, -EPERM, "Nested security context is not allowed");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,12 @@ struct data {
|
|||
struct pw_registry *registry;
|
||||
struct spa_hook registry_listener;
|
||||
|
||||
struct pw_properties *props;
|
||||
|
||||
struct pw_security_context *sec;
|
||||
|
||||
int pending_create;
|
||||
int create_result;
|
||||
int pending;
|
||||
int done;
|
||||
};
|
||||
|
@ -65,6 +69,9 @@ static void on_core_error(void *_data, uint32_t id, int seq, int res, const char
|
|||
pw_log_error("error id:%u seq:%d res:%d (%s): %s",
|
||||
id, seq, res, spa_strerror(res), message);
|
||||
|
||||
if (seq == SPA_RESULT_ASYNC_SEQ(data->pending_create))
|
||||
data->create_result = res;
|
||||
|
||||
if (id == PW_ID_CORE && res == -EPIPE) {
|
||||
data->done = true;
|
||||
pw_main_loop_quit(data->loop);
|
||||
|
@ -113,14 +120,19 @@ static void do_quit(void *data, int signal_number)
|
|||
pw_main_loop_quit(d->loop);
|
||||
}
|
||||
|
||||
static void show_help(const char *name, bool error)
|
||||
static void show_help(struct data *d, const char *name, bool error)
|
||||
{
|
||||
fprintf(error ? stderr : stdout, "%s [options] [application]\n"
|
||||
FILE *out = error ? stderr : stdout;
|
||||
fprintf(out, "%s [options] [application]\n"
|
||||
" -h, --help Show this help\n"
|
||||
" --version Show version\n"
|
||||
" -r, --remote Remote daemon name\n"
|
||||
" -P, --properties Context properties\n",
|
||||
name);
|
||||
fprintf(out, "\nDefault Context properties:\n");
|
||||
pw_properties_serialize_dict(out, &d->props->dict,
|
||||
PW_PROPERTIES_FLAG_NL | PW_PROPERTIES_FLAG_ENCLOSE);
|
||||
fprintf(out, "\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -138,9 +150,8 @@ int main(int argc, char *argv[])
|
|||
int c, res, listen_fd, close_fd[2];
|
||||
char temp[PATH_MAX] = "/tmp/pipewire-XXXXXX";
|
||||
struct sockaddr_un sockaddr = {0};
|
||||
struct pw_properties *props;
|
||||
|
||||
props = pw_properties_new(
|
||||
data.props = pw_properties_new(
|
||||
PW_KEY_SEC_ENGINE, "org.flatpak",
|
||||
PW_KEY_ACCESS, "restricted",
|
||||
NULL);
|
||||
|
@ -151,7 +162,7 @@ int main(int argc, char *argv[])
|
|||
while ((c = getopt_long(argc, argv, "hVr:P:", long_options, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
show_help(argv[0], false);
|
||||
show_help(&data, argv[0], false);
|
||||
return 0;
|
||||
case 'V':
|
||||
printf("%s\n"
|
||||
|
@ -165,10 +176,10 @@ int main(int argc, char *argv[])
|
|||
opt_remote = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
pw_properties_update_string(props, optarg, strlen(optarg));
|
||||
pw_properties_update_string(data.props, optarg, strlen(optarg));
|
||||
break;
|
||||
default:
|
||||
show_help(argv[0], true);
|
||||
show_help(&data, argv[0], true);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -212,13 +223,13 @@ int main(int argc, char *argv[])
|
|||
roundtrip(&data);
|
||||
|
||||
if (data.sec == NULL) {
|
||||
fprintf(stderr, "no security context object found");
|
||||
fprintf(stderr, "no security context object found\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = mkstemp(temp);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "can't make temp file with template %s: %m", temp);
|
||||
fprintf(stderr, "can't make temp file with template %s: %m\n", temp);
|
||||
return -1;
|
||||
}
|
||||
close(res);
|
||||
|
@ -226,31 +237,43 @@ int main(int argc, char *argv[])
|
|||
|
||||
listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) {
|
||||
fprintf(stderr, "can't make unix socket: %m");
|
||||
fprintf(stderr, "can't make unix socket: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", temp);
|
||||
if (bind(listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) != 0) {
|
||||
fprintf(stderr, "can't bind unix socket to %s: %m", temp);
|
||||
fprintf(stderr, "can't bind unix socket to %s: %m\n", temp);
|
||||
return -1;
|
||||
}
|
||||
if (listen(listen_fd, 0) != 0) {
|
||||
fprintf(stderr, "can't listen unix socket: %m");
|
||||
fprintf(stderr, "can't listen unix socket: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = pipe2(close_fd, O_CLOEXEC);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "can't create pipe: %m");
|
||||
fprintf(stderr, "can't create pipe: %m\n");
|
||||
return -1;
|
||||
}
|
||||
setenv("PIPEWIRE_REMOTE", temp, 1);
|
||||
|
||||
pw_security_context_create(data.sec, listen_fd, close_fd[1], &props->dict);
|
||||
data.create_result = 0;
|
||||
data.pending_create = pw_security_context_create(data.sec,
|
||||
listen_fd, close_fd[1], &data.props->dict);
|
||||
|
||||
roundtrip(&data);
|
||||
if (SPA_RESULT_IS_ASYNC(data.pending_create)) {
|
||||
pw_log_debug("create: %d", data.pending_create);
|
||||
roundtrip(&data);
|
||||
}
|
||||
pw_log_debug("create result: %d", data.create_result);
|
||||
|
||||
if (data.create_result < 0) {
|
||||
fprintf(stderr, "can't create security context: %s\n",
|
||||
spa_strerror(data.create_result));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
system(argv[optind++]);
|
||||
|
@ -266,7 +289,7 @@ int main(int argc, char *argv[])
|
|||
spa_hook_remove(&data.core_listener);
|
||||
pw_context_destroy(data.context);
|
||||
pw_main_loop_destroy(data.loop);
|
||||
pw_properties_free(props);
|
||||
pw_properties_free(data.props);
|
||||
pw_deinit();
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue