Add two new features to chio(1):
- The ability to specify elements by volume tag instead of their actual physical location. e.g., instead of: chio move slot 3 slot 4 you would now use: chio move voltag FOO slot 4 - The ability to return an element to its previous location, as specified by the source element. e.g., instead of: chio move drive 0 slot 4 you would now use: chio return drive 0 or chio return voltag FOO These features will obviously only work with changers that support volume tags and/or source element IDs. chio(1) should fail gracefully if the user attempts to use these new features and the source element ID or volume tag are not found. PR: bin/21178 Submitted by: "C. Stephen Gunn" <csg@waterspout.com> Reviewed by: ken
This commit is contained in:
parent
18ebc2eaa1
commit
f944dc77e7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=66019
@ -69,20 +69,27 @@ to the desired changer device.
|
|||||||
.Pp
|
.Pp
|
||||||
A medium changer apparatus is made up of
|
A medium changer apparatus is made up of
|
||||||
.Em elements .
|
.Em elements .
|
||||||
There are four element types:
|
There are five element types:
|
||||||
.Em picker
|
.Em picker
|
||||||
(medium transport),
|
(medium transport),
|
||||||
.Em slot
|
.Em slot
|
||||||
(storage),
|
(storage),
|
||||||
.Em portal
|
.Em portal
|
||||||
(import/export), and
|
(import/export),
|
||||||
.Em drive
|
.Em drive
|
||||||
(data transfer). In this command description, the shorthand
|
(data transfer), and
|
||||||
|
.Em voltag
|
||||||
|
(select by volume identifier). The
|
||||||
|
.Em voltag
|
||||||
|
pseudo-element type allows the selection of tapes by their volume tag
|
||||||
|
(typically a barcode on the tape).
|
||||||
|
.Pp
|
||||||
|
In this command description, the shorthand
|
||||||
.Em ET
|
.Em ET
|
||||||
will be used to represent an element type, and
|
will be used to represent an element type, and
|
||||||
.Em EU
|
.Em EU
|
||||||
will be used to represent an element unit. For example, to represent
|
will be used to represent an element unit.
|
||||||
the first robotic arm in the changer, the
|
For example, to represent the first robotic arm in the changer, the
|
||||||
.Em ET
|
.Em ET
|
||||||
would be
|
would be
|
||||||
.Dq picker
|
.Dq picker
|
||||||
@ -137,6 +144,15 @@ Note that not all medium changers support the
|
|||||||
.Ic exchange
|
.Ic exchange
|
||||||
operation; the changer must have multiple free pickers or emulate
|
operation; the changer must have multiple free pickers or emulate
|
||||||
multiple free pickers with transient storage.
|
multiple free pickers with transient storage.
|
||||||
|
.It Xo Nm return
|
||||||
|
.Ar <from ET> <from EU>
|
||||||
|
.Xc
|
||||||
|
Return the media unit to its source element.
|
||||||
|
This command will query the status of the specified media unit, and
|
||||||
|
will move it to the element specified in its source attribute.
|
||||||
|
This is a convenient way to return media from a drive or portal
|
||||||
|
to its previous element in the changer.
|
||||||
|
.Pp
|
||||||
.It Xo Nm position
|
.It Xo Nm position
|
||||||
.Ar <to ET> <to EU>
|
.Ar <to ET> <to EU>
|
||||||
.Op Ar inv
|
.Op Ar inv
|
||||||
@ -246,6 +262,11 @@ Element supports receiving media (importing) from an outside human operator.
|
|||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
.It Nm chio move slot 3 drive 0
|
.It Nm chio move slot 3 drive 0
|
||||||
Move the media in slot 3 (fourth slot) to drive 0 (first drive).
|
Move the media in slot 3 (fourth slot) to drive 0 (first drive).
|
||||||
|
.It Nm chio move voltag VOLUME01 drive 0
|
||||||
|
Move the media with the barcode VOLUME01 to drive 0 (first drive).
|
||||||
|
.It Nm chio return drive 0
|
||||||
|
Remove the tape from drive 0 (first drive) and return it to its original
|
||||||
|
location in the rack.
|
||||||
.It Nm chio setpicker 2
|
.It Nm chio setpicker 2
|
||||||
Configure the changer to use picker 2 (third picker) for operations.
|
Configure the changer to use picker 2 (third picker) for operations.
|
||||||
.El
|
.El
|
||||||
@ -265,4 +286,7 @@ program and SCSI changer driver were written by
|
|||||||
for And Communications, http://www.and.com/.
|
for And Communications, http://www.and.com/.
|
||||||
.br
|
.br
|
||||||
Additional work by
|
Additional work by
|
||||||
.An Hans Huebner Aq hans@artcom.de
|
.An Hans Huebner
|
||||||
|
.Aq hans@artcom.de
|
||||||
|
and Steve Gunn
|
||||||
|
.Aq csg@waterspout.com
|
||||||
|
283
bin/chio/chio.c
283
bin/chio/chio.c
@ -32,6 +32,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr.
|
* Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr.
|
||||||
|
* Addidional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
@ -64,6 +65,9 @@ static int parse_special __P((char *));
|
|||||||
static int is_special __P((char *));
|
static int is_special __P((char *));
|
||||||
static const char *bits_to_string __P((int, const char *));
|
static const char *bits_to_string __P((int, const char *));
|
||||||
|
|
||||||
|
static void find_element __P((char *, u_int16_t *, u_int16_t *));
|
||||||
|
static struct changer_element_status *get_element_status __P((u_int16_t, u_int16_t));
|
||||||
|
|
||||||
static int do_move __P((char *, int, char **));
|
static int do_move __P((char *, int, char **));
|
||||||
static int do_exchange __P((char *, int, char **));
|
static int do_exchange __P((char *, int, char **));
|
||||||
static int do_position __P((char *, int, char **));
|
static int do_position __P((char *, int, char **));
|
||||||
@ -72,14 +76,20 @@ static int do_getpicker __P((char *, int, char **));
|
|||||||
static int do_setpicker __P((char *, int, char **));
|
static int do_setpicker __P((char *, int, char **));
|
||||||
static int do_status __P((char *, int, char **));
|
static int do_status __P((char *, int, char **));
|
||||||
static int do_ielem __P((char *, int, char **));
|
static int do_ielem __P((char *, int, char **));
|
||||||
|
static int do_return __P((char *, int, char **));
|
||||||
static int do_voltag __P((char *, int, char **));
|
static int do_voltag __P((char *, int, char **));
|
||||||
|
|
||||||
|
#ifndef CHET_VT
|
||||||
|
#define CHET_VT 10 /* Completely Arbitrary */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Valid changer element types. */
|
/* Valid changer element types. */
|
||||||
const struct element_type elements[] = {
|
const struct element_type elements[] = {
|
||||||
{ "drive", CHET_DT },
|
{ "drive", CHET_DT },
|
||||||
{ "picker", CHET_MT },
|
{ "picker", CHET_MT },
|
||||||
{ "portal", CHET_IE },
|
{ "portal", CHET_IE },
|
||||||
{ "slot", CHET_ST },
|
{ "slot", CHET_ST },
|
||||||
|
{ "voltag", CHET_VT }, /* Select tapes by barcode */
|
||||||
{ NULL, 0 },
|
{ NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -93,6 +103,7 @@ const struct changer_command commands[] = {
|
|||||||
{ "position", do_position },
|
{ "position", do_position },
|
||||||
{ "setpicker", do_setpicker },
|
{ "setpicker", do_setpicker },
|
||||||
{ "status", do_status },
|
{ "status", do_status },
|
||||||
|
{ "return", do_return },
|
||||||
{ "voltag", do_voltag },
|
{ "voltag", do_voltag },
|
||||||
{ NULL, 0 },
|
{ NULL, 0 },
|
||||||
};
|
};
|
||||||
@ -195,14 +206,24 @@ do_move(cname, argc, argv)
|
|||||||
cmd.cm_fromtype = parse_element_type(*argv);
|
cmd.cm_fromtype = parse_element_type(*argv);
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
/* <from EU> */
|
/* Check for voltag virtual type */
|
||||||
cmd.cm_fromunit = parse_element_unit(*argv);
|
if (CHET_VT == cmd.cm_fromtype) {
|
||||||
|
find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit);
|
||||||
|
} else {
|
||||||
|
/* <from EU> */
|
||||||
|
cmd.cm_fromunit = parse_element_unit(*argv);
|
||||||
|
}
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
/* <to ET> */
|
/* <to ET> */
|
||||||
cmd.cm_totype = parse_element_type(*argv);
|
cmd.cm_totype = parse_element_type(*argv);
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
|
/* Check for voltag virtual type, and report error */
|
||||||
|
if (CHET_VT == cmd.cm_totype)
|
||||||
|
errx(1,"%s: voltag only makes sense as an element source",
|
||||||
|
cname);
|
||||||
|
|
||||||
/* <to EU> */
|
/* <to EU> */
|
||||||
cmd.cm_tounit = parse_element_unit(*argv);
|
cmd.cm_tounit = parse_element_unit(*argv);
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
@ -266,16 +287,26 @@ do_exchange(cname, argc, argv)
|
|||||||
cmd.ce_srctype = parse_element_type(*argv);
|
cmd.ce_srctype = parse_element_type(*argv);
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
/* <src EU> */
|
/* Check for voltag virtual type */
|
||||||
cmd.ce_srcunit = parse_element_unit(*argv);
|
if (CHET_VT == cmd.ce_srctype) {
|
||||||
|
find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit);
|
||||||
|
} else {
|
||||||
|
/* <from EU> */
|
||||||
|
cmd.ce_srcunit = parse_element_unit(*argv);
|
||||||
|
}
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
/* <dst1 ET> */
|
/* <dst1 ET> */
|
||||||
cmd.ce_fdsttype = parse_element_type(*argv);
|
cmd.ce_fdsttype = parse_element_type(*argv);
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
/* <dst1 EU> */
|
/* Check for voltag virtual type */
|
||||||
cmd.ce_fdstunit = parse_element_unit(*argv);
|
if (CHET_VT == cmd.ce_fdsttype) {
|
||||||
|
find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit);
|
||||||
|
} else {
|
||||||
|
/* <from EU> */
|
||||||
|
cmd.ce_fdstunit = parse_element_unit(*argv);
|
||||||
|
}
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -293,6 +324,10 @@ do_exchange(cname, argc, argv)
|
|||||||
cmd.ce_sdsttype = parse_element_type(*argv);
|
cmd.ce_sdsttype = parse_element_type(*argv);
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
|
if (CHET_VT == cmd.ce_sdsttype)
|
||||||
|
errx(1,"%s %s: voltag only makes sense as an element source",
|
||||||
|
cname, *argv);
|
||||||
|
|
||||||
/* <dst2 EU> */
|
/* <dst2 EU> */
|
||||||
cmd.ce_sdstunit = parse_element_unit(*argv);
|
cmd.ce_sdstunit = parse_element_unit(*argv);
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
@ -652,9 +687,9 @@ do_status(cname, argc, argv)
|
|||||||
cesr.cesr_element_base = base;
|
cesr.cesr_element_base = base;
|
||||||
cesr.cesr_element_count = count;
|
cesr.cesr_element_count = count;
|
||||||
/* Allocate storage for the status structures. */
|
/* Allocate storage for the status structures. */
|
||||||
cesr.cesr_element_status
|
cesr.cesr_element_status =
|
||||||
= (struct changer_element_status *)
|
(struct changer_element_status *)
|
||||||
malloc(count * sizeof(struct changer_element_status));
|
calloc(count, sizeof(struct changer_element_status));
|
||||||
|
|
||||||
if (!cesr.cesr_element_status)
|
if (!cesr.cesr_element_status)
|
||||||
errx(1, "can't allocate status storage");
|
errx(1, "can't allocate status storage");
|
||||||
@ -934,6 +969,236 @@ bits_to_string(v, cp)
|
|||||||
|
|
||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* do_return()
|
||||||
|
*
|
||||||
|
* Given an element reference, ask the changer/picker to move that
|
||||||
|
* element back to its source slot.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
do_return(cname, argc, argv)
|
||||||
|
char *cname;
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
struct changer_element_status *ces;
|
||||||
|
struct changer_move cmd;
|
||||||
|
u_int16_t type, element;
|
||||||
|
|
||||||
|
++argv; --argc;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
warnx("%s: too few arguments", cname);
|
||||||
|
goto usage;
|
||||||
|
} else if (argc > 3) {
|
||||||
|
warnx("%s: too many arguments", cname);
|
||||||
|
goto usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = parse_element_type(*argv);
|
||||||
|
++argv; --argc;
|
||||||
|
|
||||||
|
/* Handle voltag virtual Changer Element Type */
|
||||||
|
if (CHET_VT == type) {
|
||||||
|
find_element(*argv, &type, &element);
|
||||||
|
} else {
|
||||||
|
element = parse_element_unit(*argv);
|
||||||
|
}
|
||||||
|
++argv; --argc;
|
||||||
|
|
||||||
|
ces = get_element_status(type, element); /* Get the status */
|
||||||
|
|
||||||
|
if (NULL == ces)
|
||||||
|
errx(1, "%s: null element status pointer", cname);
|
||||||
|
|
||||||
|
if (!(ces->ces_flags & CES_SOURCE_VALID))
|
||||||
|
errx(1, "%s: no source information", cname);
|
||||||
|
|
||||||
|
(void) memset(&cmd, 0, sizeof(cmd));
|
||||||
|
|
||||||
|
cmd.cm_fromtype = type;
|
||||||
|
cmd.cm_fromunit = element;
|
||||||
|
cmd.cm_totype = ces->ces_source_type;
|
||||||
|
cmd.cm_tounit = ces->ces_source_addr;
|
||||||
|
|
||||||
|
if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1)
|
||||||
|
err(1, "%s: CHIOMOVE", changer_name);
|
||||||
|
free(ces);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
usage:
|
||||||
|
(void) fprintf(stderr, "usage: %s %s "
|
||||||
|
"<from ET> <from EU>\n", __progname, cname);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_element_status()
|
||||||
|
*
|
||||||
|
* return a *cesr for the specified changer element. This
|
||||||
|
* routing will malloc()/calloc() the memory. The caller
|
||||||
|
* should free() it when done.
|
||||||
|
*/
|
||||||
|
static struct changer_element_status *
|
||||||
|
get_element_status(type, element)
|
||||||
|
u_int16_t type;
|
||||||
|
u_int16_t element;
|
||||||
|
{
|
||||||
|
struct changer_element_status_request cesr;
|
||||||
|
struct changer_element_status *ces;
|
||||||
|
|
||||||
|
ces = (struct changer_element_status *)
|
||||||
|
calloc(1, sizeof(struct changer_element_status));
|
||||||
|
|
||||||
|
if (NULL == ces)
|
||||||
|
errx(1, "can't allocate status storage");
|
||||||
|
|
||||||
|
(void)memset(&cesr, 0, sizeof(cesr));
|
||||||
|
|
||||||
|
cesr.cesr_element_type = type;
|
||||||
|
cesr.cesr_element_base = element;
|
||||||
|
cesr.cesr_element_count = 1; /* Only this one element */
|
||||||
|
cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */
|
||||||
|
cesr.cesr_element_status = ces;
|
||||||
|
|
||||||
|
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
|
||||||
|
free(ces);
|
||||||
|
err(1, "%s: CHIOGSTATUS", changer_name);
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
|
return ces;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find_element()
|
||||||
|
*
|
||||||
|
* Given a <voltag> find the chager element and unit, or exit
|
||||||
|
* with an error if it isn't found. We grab the changer status
|
||||||
|
* and iterate until we find a match, or crap out.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
find_element(voltag, et, eu)
|
||||||
|
char *voltag;
|
||||||
|
u_int16_t *et;
|
||||||
|
u_int16_t *eu;
|
||||||
|
{
|
||||||
|
struct changer_params cp;
|
||||||
|
struct changer_element_status_request cesr;
|
||||||
|
struct changer_element_status *ch_ces, *ces;
|
||||||
|
int elem, total_elem, found = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the changer parameters, we're interested in the counts
|
||||||
|
* for all types of elements to perform our search.
|
||||||
|
*/
|
||||||
|
if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp))
|
||||||
|
err(1, "%s: CHIOGPARAMS", changer_name);
|
||||||
|
|
||||||
|
/* Allocate some memory for the results */
|
||||||
|
total_elem = (cp.cp_nslots + cp.cp_ndrives
|
||||||
|
+ cp.cp_npickers + cp.cp_nportals);
|
||||||
|
|
||||||
|
ch_ces = (struct changer_element_status *)
|
||||||
|
calloc(total_elem, sizeof(struct changer_element_status));
|
||||||
|
|
||||||
|
if (NULL == ch_ces)
|
||||||
|
errx(1, "can't allocate status storage");
|
||||||
|
|
||||||
|
ces = ch_ces;
|
||||||
|
|
||||||
|
/* Read in the changer slots */
|
||||||
|
if (cp.cp_nslots > 0) {
|
||||||
|
cesr.cesr_element_type = CHET_ST;
|
||||||
|
cesr.cesr_element_base = 0;
|
||||||
|
cesr.cesr_element_count = cp.cp_nslots;
|
||||||
|
cesr.cesr_flags |= CESR_VOLTAGS;
|
||||||
|
cesr.cesr_element_status = ces;
|
||||||
|
|
||||||
|
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
|
||||||
|
free(ch_ces);
|
||||||
|
err(1, "%s: CHIOGSTATUS", changer_name);
|
||||||
|
}
|
||||||
|
ces += cp.cp_nslots;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in the drive information */
|
||||||
|
if (cp.cp_ndrives > 0 ) {
|
||||||
|
|
||||||
|
(void) memset(&cesr, 0, sizeof(cesr));
|
||||||
|
cesr.cesr_element_type = CHET_DT;
|
||||||
|
cesr.cesr_element_base = 0;
|
||||||
|
cesr.cesr_element_count = cp.cp_ndrives;
|
||||||
|
cesr.cesr_flags |= CESR_VOLTAGS;
|
||||||
|
cesr.cesr_element_status = ces;
|
||||||
|
|
||||||
|
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
|
||||||
|
free(ch_ces);
|
||||||
|
err(1, "%s: CHIOGSTATUS", changer_name);
|
||||||
|
}
|
||||||
|
ces += cp.cp_ndrives;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in the portal information */
|
||||||
|
if (cp.cp_nportals > 0 ) {
|
||||||
|
(void) memset(&cesr, 0, sizeof(cesr));
|
||||||
|
cesr.cesr_element_type = CHET_IE;
|
||||||
|
cesr.cesr_element_base = 0;
|
||||||
|
cesr.cesr_element_count = cp.cp_nportals;
|
||||||
|
cesr.cesr_flags |= CESR_VOLTAGS;
|
||||||
|
cesr.cesr_element_status = ces;
|
||||||
|
|
||||||
|
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
|
||||||
|
free(ch_ces);
|
||||||
|
err(1, "%s: CHIOGSTATUS", changer_name);
|
||||||
|
}
|
||||||
|
ces += cp.cp_nportals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in the picker information */
|
||||||
|
if (cp.cp_npickers > 0) {
|
||||||
|
(void) memset(&cesr, 0, sizeof(cesr));
|
||||||
|
cesr.cesr_element_type = CHET_MT;
|
||||||
|
cesr.cesr_element_base = 0;
|
||||||
|
cesr.cesr_element_count = cp.cp_npickers;
|
||||||
|
cesr.cesr_flags |= CESR_VOLTAGS;
|
||||||
|
cesr.cesr_element_status = ces;
|
||||||
|
|
||||||
|
if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
|
||||||
|
free(ch_ces);
|
||||||
|
err(1, "%s: CHIOGSTATUS", changer_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now search the list the specified <voltag>
|
||||||
|
*/
|
||||||
|
for (elem = 0; elem <= total_elem; ++elem) {
|
||||||
|
|
||||||
|
ces = &ch_ces[elem];
|
||||||
|
|
||||||
|
/* Make sure we have a tape in this element */
|
||||||
|
if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL))
|
||||||
|
!= (CES_STATUS_ACCESS|CES_STATUS_FULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check to see if it is our target */
|
||||||
|
if (strcasecmp(voltag, ces->ces_pvoltag.cv_volid) == 0) {
|
||||||
|
*et = ces->ces_type;
|
||||||
|
*eu = ces->ces_addr;
|
||||||
|
++found;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
errx(1, "%s: unable to locate voltag: %s", changer_name,
|
||||||
|
voltag);
|
||||||
|
}
|
||||||
|
free(ch_ces);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cleanup()
|
cleanup()
|
||||||
|
Loading…
Reference in New Issue
Block a user