mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
systemctl: hook up new install logic
This adds a number of new options to systemctl, for presets, reenabling, masking/unmask, and runtime operations.
This commit is contained in:
parent
4b7a6af440
commit
729e3769c3
@ -1203,7 +1203,9 @@ systemctl_SOURCES = \
|
||||
src/cgroup-util.c \
|
||||
src/exit-status.c \
|
||||
src/unit-name.c \
|
||||
src/pager.c
|
||||
src/pager.c \
|
||||
src/install.c \
|
||||
src/spawn-agent.c
|
||||
|
||||
systemctl_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
|
13
TODO
13
TODO
@ -47,8 +47,6 @@ Features:
|
||||
|
||||
* make sure systemd-ask-password-wall does not shutdown systemd-ask-password-console too early
|
||||
|
||||
* support presets
|
||||
|
||||
* kernel: add /proc/sys file exposing CAP_LAST_CAP?
|
||||
|
||||
* kernel: add device_type = "fb", "fbcon" to class "graphics"
|
||||
@ -86,17 +84,6 @@ Features:
|
||||
|
||||
* show enablement status in systemctl status
|
||||
|
||||
* teach systemctl to enable unit files in arbitrary directories
|
||||
|
||||
* In systemctl make sure both is-enabled and is-active print a string, or neither.
|
||||
|
||||
* Implement:
|
||||
systemctl mask <unit>
|
||||
systemctl unmask <unit>
|
||||
Also support --temp to make this temporary by placing mask links in /run.
|
||||
|
||||
* perhaps add "systemctl reenable" as combination of "systemctl disable" and "systemctl enable"
|
||||
|
||||
* add support for /bin/mount -s
|
||||
|
||||
* GC unreferenced jobs (such as .device jobs)
|
||||
|
@ -351,27 +351,31 @@
|
||||
immediate reboot.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--defaults</option></term>
|
||||
|
||||
<listitem><para>When used with
|
||||
<command>disable</command>, ensures
|
||||
that only the symlinks created by
|
||||
<command>enable</command> are removed,
|
||||
not all symlinks pointing to the unit
|
||||
file that shall be
|
||||
disabled.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--root=</option></term>
|
||||
|
||||
<listitem><para>When used with
|
||||
<command>enable</command>/
|
||||
<command>disable</command>/
|
||||
<command>is-enabled</command>,
|
||||
use alternative root path for systemd
|
||||
install.</para></listitem>
|
||||
<command>enable</command>/<command>disable</command>/<command>is-enabled</command> (and
|
||||
related commands), use alternative
|
||||
root path when looking for unit
|
||||
files.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--runtime</option></term>
|
||||
|
||||
<listitem><para>When used with
|
||||
<command>enable</command>/<command>disable</command>/<command>is-enabled</command> (and related commands), make
|
||||
changes only temporarily, so that they
|
||||
are dropped on the next reboot. This
|
||||
will have the effect that changes are
|
||||
not made in subdirectories of
|
||||
<filename>/etc</filename> but in
|
||||
<filename>/run</filename>, with
|
||||
identical immediate effects, however,
|
||||
since the latter is lost on reboot,
|
||||
the changes are lost
|
||||
too.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -674,14 +678,11 @@
|
||||
configuration directory, and hence
|
||||
undoes the changes made by
|
||||
<command>enable</command>. Note
|
||||
however that this by default removes
|
||||
however that this removes
|
||||
all symlinks to the unit files
|
||||
(i.e. including manual additions), not
|
||||
just those actually created by
|
||||
<command>enable</command>. If only the
|
||||
symlinks that are suggested by default
|
||||
shall be removed, pass
|
||||
<option>--defaults</option>. This
|
||||
<command>enable</command>. This call
|
||||
implicitly reloads the systemd daemon
|
||||
configuration after completing the
|
||||
disabling of the units. Note that this
|
||||
@ -713,8 +714,85 @@
|
||||
(as with
|
||||
<command>enable</command>). Returns an
|
||||
exit code of 0 if at least one is
|
||||
enabled, non-zero
|
||||
otherwise.</para></listitem>
|
||||
enabled, non-zero otherwise. Prints
|
||||
the current enable status. To suppress
|
||||
this output use
|
||||
<option>--quiet</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>reenable [NAME...]</command></term>
|
||||
|
||||
<listitem><para>Reenable one or more
|
||||
unit files, as specified on the
|
||||
command line. This is a combination of
|
||||
<command>disable</command> and
|
||||
<command>enable</command> and is
|
||||
useful to reset the symlinks a unit is
|
||||
enabled with to the defaults
|
||||
configured in the
|
||||
<literal>[Install]</literal> section
|
||||
of the unit file.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>preset [NAME...]</command></term>
|
||||
|
||||
<listitem><para>Reset one or more unit
|
||||
files, as specified on the command
|
||||
line, to the defaults configured in a
|
||||
preset file. This has the same effect
|
||||
as <command>disable</command> or
|
||||
<command>enable</command>, depending
|
||||
how the unit is listed in the preset
|
||||
files.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>mask [NAME...]</command></term>
|
||||
|
||||
<listitem><para>Mask one or more unit
|
||||
files, as specified on the command
|
||||
line. This will link these units to
|
||||
<filename>/dev/null</filename>, making
|
||||
it impossible to start them. This is a stronger version
|
||||
of <command>disable</command>, since
|
||||
it prohibits all kinds of activation
|
||||
of the unit, including manual
|
||||
activation. Use this option with
|
||||
care.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>unmask [NAME...]</command></term>
|
||||
|
||||
<listitem><para>Unmask one or more
|
||||
unit files, as specified on the
|
||||
command line. This will undo the
|
||||
effect of
|
||||
<command>mask</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>link [NAME...]</command></term>
|
||||
|
||||
<listitem><para>Link a unit file that
|
||||
is not in the unit file search paths
|
||||
into the unit file search path. This
|
||||
requires an absolute path to a unit
|
||||
file. The effect of this can be undone
|
||||
with <command>disable</command>. The
|
||||
effect of this command is that a unit
|
||||
file is available for
|
||||
<command>start</command> and other
|
||||
commands although it isn't installed
|
||||
directly in the unit search
|
||||
path.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -145,6 +145,7 @@
|
||||
" <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"carries_install_info\" type=\"b\" directrion=\"out\"/>\n" \
|
||||
" <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"DisableUnitFiles\">\n" \
|
||||
@ -156,6 +157,7 @@
|
||||
" <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"carries_install_info\" type=\"b\" directrion=\"out\"/>\n" \
|
||||
" <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"LinkUnitFiles\">\n" \
|
||||
@ -168,6 +170,7 @@
|
||||
" <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"carries_install_info\" type=\"b\" directrion=\"out\"/>\n" \
|
||||
" <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"MaskUnitFiles\">\n" \
|
||||
@ -422,7 +425,12 @@ static const char *message_get_sender_with_fallback(DBusMessage *m) {
|
||||
return ":no-sender";
|
||||
}
|
||||
|
||||
static DBusMessage *message_from_file_changes(DBusMessage *m, UnitFileChange *changes, unsigned n_changes) {
|
||||
static DBusMessage *message_from_file_changes(
|
||||
DBusMessage *m,
|
||||
UnitFileChange *changes,
|
||||
unsigned n_changes,
|
||||
int carries_install_info) {
|
||||
|
||||
DBusMessageIter iter, sub, sub2;
|
||||
DBusMessage *reply;
|
||||
unsigned i;
|
||||
@ -435,6 +443,14 @@ static DBusMessage *message_from_file_changes(DBusMessage *m, UnitFileChange *ch
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
|
||||
if (carries_install_info >= 0) {
|
||||
dbus_bool_t b;
|
||||
|
||||
b = carries_install_info;
|
||||
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
|
||||
goto oom;
|
||||
}
|
||||
|
||||
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
|
||||
goto oom;
|
||||
|
||||
@ -446,9 +462,9 @@ static DBusMessage *message_from_file_changes(DBusMessage *m, UnitFileChange *ch
|
||||
source = strempty(changes[i].source);
|
||||
|
||||
if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
|
||||
!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &type) ||
|
||||
!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &path) ||
|
||||
!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &source) ||
|
||||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
|
||||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
|
||||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
|
||||
!dbus_message_iter_close_container(&sub, &sub2))
|
||||
goto oom;
|
||||
}
|
||||
@ -1304,6 +1320,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
|
||||
UnitFileChange *changes = NULL;
|
||||
unsigned n_changes = 0;
|
||||
dbus_bool_t runtime, force;
|
||||
bool carries_install_info = -1;
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
goto oom;
|
||||
@ -1323,15 +1340,18 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
|
||||
return bus_send_error_reply(connection, message, NULL, -EIO);
|
||||
}
|
||||
|
||||
if (streq(member, "EnableUnitFiles"))
|
||||
if (streq(member, "EnableUnitFiles")) {
|
||||
r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
|
||||
else if (streq(member, "ReenableUnitFiles"))
|
||||
carries_install_info = r;
|
||||
} else if (streq(member, "ReenableUnitFiles")) {
|
||||
r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
|
||||
else if (streq(member, "LinkUnitFiles"))
|
||||
carries_install_info = r;
|
||||
} else if (streq(member, "LinkUnitFiles"))
|
||||
r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
|
||||
else if (streq(member, "PresetUnitFiles"))
|
||||
else if (streq(member, "PresetUnitFiles")) {
|
||||
r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
|
||||
else if (streq(member, "MaskUnitFiles"))
|
||||
carries_install_info = r;
|
||||
} else if (streq(member, "MaskUnitFiles"))
|
||||
r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
|
||||
else
|
||||
assert_not_reached("Uh? Wrong method");
|
||||
@ -1344,7 +1364,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
}
|
||||
|
||||
reply = message_from_file_changes(message, changes, n_changes);
|
||||
reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
if (!reply)
|
||||
@ -1392,7 +1412,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
}
|
||||
|
||||
reply = message_from_file_changes(message, changes, n_changes);
|
||||
reply = message_from_file_changes(message, changes, n_changes, -1);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
if (!reply)
|
||||
|
@ -596,16 +596,16 @@ Hashmap *hashmap_copy(Hashmap *h) {
|
||||
char **hashmap_get_strv(Hashmap *h) {
|
||||
char **sv;
|
||||
Iterator it;
|
||||
char *path;
|
||||
char *item;
|
||||
int n;
|
||||
|
||||
sv = malloc((h->n_entries+1) * sizeof(char *));
|
||||
if (sv == NULL)
|
||||
sv = new(char*, h->n_entries+1);
|
||||
if (!sv)
|
||||
return NULL;
|
||||
|
||||
n = 0;
|
||||
HASHMAP_FOREACH(path, h, it)
|
||||
sv[n++] = path;
|
||||
HASHMAP_FOREACH(item, h, it)
|
||||
sv[n++] = item;
|
||||
sv[n] = NULL;
|
||||
|
||||
return sv;
|
||||
|
@ -126,8 +126,6 @@ static int add_file_change(
|
||||
UnitFileChange *c;
|
||||
unsigned i;
|
||||
|
||||
assert(type >= 0);
|
||||
assert(type < _UNIT_FILE_CHANGE_TYPE_MAX);
|
||||
assert(path);
|
||||
assert(!changes == !n_changes);
|
||||
|
||||
@ -1414,6 +1412,10 @@ int unit_file_enable(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* This will return the number of symlink rules that were
|
||||
supposed to be created, not the ones actually created. This is
|
||||
useful to determine whether the passed files hat any
|
||||
installation data at all. */
|
||||
r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
|
||||
|
||||
finish:
|
||||
@ -1514,6 +1516,7 @@ int unit_file_reenable(
|
||||
|
||||
r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
|
||||
|
||||
/* Returns number of symlinks that where supposed to be installed. */
|
||||
q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
|
||||
if (r == 0)
|
||||
r = q;
|
||||
@ -1763,6 +1766,7 @@ int unit_file_preset(
|
||||
if (r == 0)
|
||||
r = q;
|
||||
|
||||
/* Returns number of symlinks that where supposed to be installed. */
|
||||
q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
|
||||
if (r == 0)
|
||||
r = q;
|
||||
|
@ -62,6 +62,14 @@
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="ListUnits"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.systemd1"
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="ListUnitFiles"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.systemd1"
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="GetUnitFileState"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.systemd1"
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="ListJobs"/>
|
||||
|
@ -39,13 +39,13 @@ void pager_open(void) {
|
||||
if (pager_pid > 0)
|
||||
return;
|
||||
|
||||
if (isatty(STDOUT_FILENO) <= 0)
|
||||
return;
|
||||
|
||||
if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER")))
|
||||
if (!*pager || streq(pager, "cat"))
|
||||
return;
|
||||
|
||||
if (isatty(STDOUT_FILENO) <= 0)
|
||||
return;
|
||||
|
||||
/* Determine and cache number of columns before we spawn the
|
||||
* pager so that we get the value from the actual tty */
|
||||
columns();
|
||||
|
120
src/spawn-agent.c
Normal file
120
src/spawn-agent.c
Normal file
@ -0,0 +1,120 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd 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
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "spawn-agent.h"
|
||||
|
||||
static pid_t agent_pid = 0;
|
||||
|
||||
void agent_open(void) {
|
||||
pid_t parent_pid;
|
||||
|
||||
if (agent_pid > 0)
|
||||
return;
|
||||
|
||||
/* We check STDIN here, not STDOUT, since this is about input,
|
||||
* not output */
|
||||
if (!isatty(STDIN_FILENO))
|
||||
return;
|
||||
|
||||
parent_pid = getpid();
|
||||
|
||||
/* Spawns a temporary TTY agent, making sure it goes away when
|
||||
* we go away */
|
||||
|
||||
agent_pid = fork();
|
||||
if (agent_pid < 0) {
|
||||
log_error("Failed to fork agent: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
if (agent_pid == 0) {
|
||||
/* In the child */
|
||||
|
||||
int fd;
|
||||
bool stdout_is_tty, stderr_is_tty;
|
||||
|
||||
/* Make sure the agent goes away when the parent dies */
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* to set the death signal */
|
||||
if (getppid() != parent_pid)
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
||||
/* Don't leak fds to the agent */
|
||||
close_all_fds(NULL, 0);
|
||||
|
||||
stdout_is_tty = isatty(STDOUT_FILENO);
|
||||
stderr_is_tty = isatty(STDERR_FILENO);
|
||||
|
||||
if (!stdout_is_tty || !stderr_is_tty) {
|
||||
/* Detach from stdout/stderr. and reopen
|
||||
* /dev/tty for them. This is important to
|
||||
* ensure that when systemctl is started via
|
||||
* popen() or a similar call that expects to
|
||||
* read EOF we actually do generate EOF and
|
||||
* not delay this indefinitely by because we
|
||||
* keep an unused copy of stdin around. */
|
||||
fd = open("/dev/tty", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
log_error("Failed to open /dev/tty: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!stdout_is_tty)
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
|
||||
if (!stderr_is_tty)
|
||||
dup2(fd, STDERR_FILENO);
|
||||
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
execl(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
|
||||
|
||||
log_error("Unable to execute agent: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void agent_close(void) {
|
||||
|
||||
if (agent_pid <= 0)
|
||||
return;
|
||||
|
||||
/* Inform agent that we are done */
|
||||
kill(agent_pid, SIGTERM);
|
||||
kill(agent_pid, SIGCONT);
|
||||
wait_for_terminate(agent_pid, NULL);
|
||||
agent_pid = 0;
|
||||
}
|
28
src/spawn-agent.h
Normal file
28
src/spawn-agent.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foospawnagenthfoo
|
||||
#define foospawnagenthfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd 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
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
void agent_open(void);
|
||||
void agent_close(void);
|
||||
|
||||
#endif
|
1740
src/systemctl.c
1740
src/systemctl.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user