[PATCH 07/11] virsh: Split cmds to manage secret from virsh.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Commands to manage secret are moved from virsh.c to virsh-secret.c,
with a few helpers for secret command use.

* virsh.c: Remove secret commands and a few helpers.
* virsh-secret.c: New file, filled with secret commands and its helpers.
---
 tools/virsh-secret.c |  358 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/virsh.c        |  340 +-----------------------------------------------
 2 files changed, 360 insertions(+), 338 deletions(-)
 create mode 100644 tools/virsh-secret.c

diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c
new file mode 100644
index 0000000..9ec3186
--- /dev/null
+++ b/tools/virsh-secret.c
@@ -0,0 +1,358 @@
+/*
+ * virsh-domain.c: Commands to manage secret
+ *
+ * Copyright (C) 2005, 2007-2012 Red Hat, Inc
+ *
+ * This library 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/>.
+ *
+ *  Daniel Veillard <veillard@xxxxxxxxxx>
+ *  Karel Zak <kzak@xxxxxxxxxx>
+ *  Daniel P. Berrange <berrange@xxxxxxxxxx>
+ *
+ */
+
+static virSecretPtr
+vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name)
+{
+    virSecretPtr secret = NULL;
+    const char *n = NULL;
+    const char *optname = "secret";
+
+    if (!cmd_has_option(ctl, cmd, optname))
+        return NULL;
+
+    if (vshCommandOptString(cmd, optname, &n) <= 0)
+        return NULL;
+
+    vshDebug(ctl, VSH_ERR_DEBUG,
+             "%s: found option <%s>: %s\n", cmd->def->name, optname, n);
+
+    if (name != NULL)
+        *name = n;
+
+    secret = virSecretLookupByUUIDString(ctl->conn, n);
+
+    if (secret == NULL)
+        vshError(ctl, _("failed to get secret '%s'"), n);
+
+    return secret;
+}
+
+/*
+ * "secret-define" command
+ */
+static const vshCmdInfo info_secret_define[] = {
+    {"help", N_("define or modify a secret from an XML file")},
+    {"desc", N_("Define or modify a secret.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_define[] = {
+    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdSecretDefine(vshControl *ctl, const vshCmd *cmd)
+{
+    const char *from = NULL;
+    char *buffer;
+    virSecretPtr res;
+    char uuid[VIR_UUID_STRING_BUFLEN];
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    if (vshCommandOptString(cmd, "file", &from) <= 0)
+        return false;
+
+    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
+        return false;
+
+    res = virSecretDefineXML(ctl->conn, buffer, 0);
+    VIR_FREE(buffer);
+
+    if (res == NULL) {
+        vshError(ctl, _("Failed to set attributes from %s"), from);
+        return false;
+    }
+    if (virSecretGetUUIDString(res, &(uuid[0])) < 0) {
+        vshError(ctl, "%s", _("Failed to get UUID of created secret"));
+        virSecretFree(res);
+        return false;
+    }
+    vshPrint(ctl, _("Secret %s created\n"), uuid);
+    virSecretFree(res);
+    return true;
+}
+
+/*
+ * "secret-dumpxml" command
+ */
+static const vshCmdInfo info_secret_dumpxml[] = {
+    {"help", N_("secret attributes in XML")},
+    {"desc", N_("Output attributes of a secret as an XML dump to stdout.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_dumpxml[] = {
+    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd)
+{
+    virSecretPtr secret;
+    bool ret = false;
+    char *xml;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    secret = vshCommandOptSecret(ctl, cmd, NULL);
+    if (secret == NULL)
+        return false;
+
+    xml = virSecretGetXMLDesc(secret, 0);
+    if (xml == NULL)
+        goto cleanup;
+    vshPrint(ctl, "%s", xml);
+    VIR_FREE(xml);
+    ret = true;
+
+cleanup:
+    virSecretFree(secret);
+    return ret;
+}
+
+/*
+ * "secret-set-value" command
+ */
+static const vshCmdInfo info_secret_set_value[] = {
+    {"help", N_("set a secret value")},
+    {"desc", N_("Set a secret value.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_set_value[] = {
+    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
+    {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd)
+{
+    virSecretPtr secret;
+    size_t value_size;
+    const char *base64 = NULL;
+    char *value;
+    int res;
+    bool ret = false;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    secret = vshCommandOptSecret(ctl, cmd, NULL);
+    if (secret == NULL)
+        return false;
+
+    if (vshCommandOptString(cmd, "base64", &base64) <= 0)
+        goto cleanup;
+
+    if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) {
+        vshError(ctl, "%s", _("Invalid base64 data"));
+        goto cleanup;
+    }
+    if (value == NULL) {
+        vshError(ctl, "%s", _("Failed to allocate memory"));
+        return false;
+    }
+
+    res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0);
+    memset(value, 0, value_size);
+    VIR_FREE(value);
+
+    if (res != 0) {
+        vshError(ctl, "%s", _("Failed to set secret value"));
+        goto cleanup;
+    }
+    vshPrint(ctl, "%s", _("Secret value set\n"));
+    ret = true;
+
+cleanup:
+    virSecretFree(secret);
+    return ret;
+}
+
+/*
+ * "secret-get-value" command
+ */
+static const vshCmdInfo info_secret_get_value[] = {
+    {"help", N_("Output a secret value")},
+    {"desc", N_("Output a secret value to stdout.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_get_value[] = {
+    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd)
+{
+    virSecretPtr secret;
+    char *base64;
+    unsigned char *value;
+    size_t value_size;
+    bool ret = false;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    secret = vshCommandOptSecret(ctl, cmd, NULL);
+    if (secret == NULL)
+        return false;
+
+    value = virSecretGetValue(secret, &value_size, 0);
+    if (value == NULL)
+        goto cleanup;
+
+    base64_encode_alloc((char *)value, value_size, &base64);
+    memset(value, 0, value_size);
+    VIR_FREE(value);
+
+    if (base64 == NULL) {
+        vshError(ctl, "%s", _("Failed to allocate memory"));
+        goto cleanup;
+    }
+    vshPrint(ctl, "%s", base64);
+    memset(base64, 0, strlen(base64));
+    VIR_FREE(base64);
+    ret = true;
+
+cleanup:
+    virSecretFree(secret);
+    return ret;
+}
+
+/*
+ * "secret-undefine" command
+ */
+static const vshCmdInfo info_secret_undefine[] = {
+    {"help", N_("undefine a secret")},
+    {"desc", N_("Undefine a secret.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_secret_undefine[] = {
+    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
+{
+    virSecretPtr secret;
+    bool ret = false;
+    const char *uuid;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    secret = vshCommandOptSecret(ctl, cmd, &uuid);
+    if (secret == NULL)
+        return false;
+
+    if (virSecretUndefine(secret) < 0) {
+        vshError(ctl, _("Failed to delete secret %s"), uuid);
+        goto cleanup;
+    }
+    vshPrint(ctl, _("Secret %s deleted\n"), uuid);
+    ret = true;
+
+cleanup:
+    virSecretFree(secret);
+    return ret;
+}
+
+/*
+ * "secret-list" command
+ */
+static const vshCmdInfo info_secret_list[] = {
+    {"help", N_("list secrets")},
+    {"desc", N_("Returns a list of secrets")},
+    {NULL, NULL}
+};
+
+static bool
+cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
+{
+    int maxuuids = 0, i;
+    char **uuids = NULL;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    maxuuids = virConnectNumOfSecrets(ctl->conn);
+    if (maxuuids < 0) {
+        vshError(ctl, "%s", _("Failed to list secrets"));
+        return false;
+    }
+    uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids);
+
+    maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids);
+    if (maxuuids < 0) {
+        vshError(ctl, "%s", _("Failed to list secrets"));
+        VIR_FREE(uuids);
+        return false;
+    }
+
+    qsort(uuids, maxuuids, sizeof(char *), vshNameSorter);
+
+    vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage"));
+    vshPrintExtra(ctl, "-----------------------------------------------------------\n");
+
+    for (i = 0; i < maxuuids; i++) {
+        virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]);
+        const char *usageType = NULL;
+
+        if (!sec) {
+            VIR_FREE(uuids[i]);
+            continue;
+        }
+
+        switch (virSecretGetUsageType(sec)) {
+        case VIR_SECRET_USAGE_TYPE_VOLUME:
+            usageType = _("Volume");
+            break;
+        }
+
+        if (usageType) {
+            vshPrint(ctl, "%-36s %s %s\n",
+                     uuids[i], usageType,
+                     virSecretGetUsageID(sec));
+        } else {
+            vshPrint(ctl, "%-36s %s\n",
+                     uuids[i], _("Unused"));
+        }
+        virSecretFree(sec);
+        VIR_FREE(uuids[i]);
+    }
+    VIR_FREE(uuids);
+    return true;
+}
diff --git a/tools/virsh.c b/tools/virsh.c
index 4844e31..cddb6e3 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -339,9 +339,6 @@ static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
 #define vshCommandOptDomain(_ctl, _cmd, _name)                      \
     vshCommandOptDomainBy(_ctl, _cmd, _name, VSH_BYID|VSH_BYUUID|VSH_BYNAME)
 
-static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd,
-                                        const char **name);
-
 static void vshPrintExtra(vshControl *ctl, const char *format, ...)
     ATTRIBUTE_FMT_PRINTF(2, 3);
 static void vshDebug(vshControl *ctl, int level, const char *format, ...)
@@ -1342,314 +1339,6 @@ cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
- * "secret-define" command
- */
-static const vshCmdInfo info_secret_define[] = {
-    {"help", N_("define or modify a secret from an XML file")},
-    {"desc", N_("Define or modify a secret.")},
-    {NULL, NULL}
-};
-
-static const vshCmdOptDef opts_secret_define[] = {
-    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")},
-    {NULL, 0, 0, NULL}
-};
-
-static bool
-cmdSecretDefine(vshControl *ctl, const vshCmd *cmd)
-{
-    const char *from = NULL;
-    char *buffer;
-    virSecretPtr res;
-    char uuid[VIR_UUID_STRING_BUFLEN];
-
-    if (!vshConnectionUsability(ctl, ctl->conn))
-        return false;
-
-    if (vshCommandOptString(cmd, "file", &from) <= 0)
-        return false;
-
-    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
-        return false;
-
-    res = virSecretDefineXML(ctl->conn, buffer, 0);
-    VIR_FREE(buffer);
-
-    if (res == NULL) {
-        vshError(ctl, _("Failed to set attributes from %s"), from);
-        return false;
-    }
-    if (virSecretGetUUIDString(res, &(uuid[0])) < 0) {
-        vshError(ctl, "%s", _("Failed to get UUID of created secret"));
-        virSecretFree(res);
-        return false;
-    }
-    vshPrint(ctl, _("Secret %s created\n"), uuid);
-    virSecretFree(res);
-    return true;
-}
-
-/*
- * "secret-dumpxml" command
- */
-static const vshCmdInfo info_secret_dumpxml[] = {
-    {"help", N_("secret attributes in XML")},
-    {"desc", N_("Output attributes of a secret as an XML dump to stdout.")},
-    {NULL, NULL}
-};
-
-static const vshCmdOptDef opts_secret_dumpxml[] = {
-    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
-    {NULL, 0, 0, NULL}
-};
-
-static bool
-cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd)
-{
-    virSecretPtr secret;
-    bool ret = false;
-    char *xml;
-
-    if (!vshConnectionUsability(ctl, ctl->conn))
-        return false;
-
-    secret = vshCommandOptSecret(ctl, cmd, NULL);
-    if (secret == NULL)
-        return false;
-
-    xml = virSecretGetXMLDesc(secret, 0);
-    if (xml == NULL)
-        goto cleanup;
-    vshPrint(ctl, "%s", xml);
-    VIR_FREE(xml);
-    ret = true;
-
-cleanup:
-    virSecretFree(secret);
-    return ret;
-}
-
-/*
- * "secret-set-value" command
- */
-static const vshCmdInfo info_secret_set_value[] = {
-    {"help", N_("set a secret value")},
-    {"desc", N_("Set a secret value.")},
-    {NULL, NULL}
-};
-
-static const vshCmdOptDef opts_secret_set_value[] = {
-    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
-    {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")},
-    {NULL, 0, 0, NULL}
-};
-
-static bool
-cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd)
-{
-    virSecretPtr secret;
-    size_t value_size;
-    const char *base64 = NULL;
-    char *value;
-    int res;
-    bool ret = false;
-
-    if (!vshConnectionUsability(ctl, ctl->conn))
-        return false;
-
-    secret = vshCommandOptSecret(ctl, cmd, NULL);
-    if (secret == NULL)
-        return false;
-
-    if (vshCommandOptString(cmd, "base64", &base64) <= 0)
-        goto cleanup;
-
-    if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) {
-        vshError(ctl, "%s", _("Invalid base64 data"));
-        goto cleanup;
-    }
-    if (value == NULL) {
-        vshError(ctl, "%s", _("Failed to allocate memory"));
-        return false;
-    }
-
-    res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0);
-    memset(value, 0, value_size);
-    VIR_FREE(value);
-
-    if (res != 0) {
-        vshError(ctl, "%s", _("Failed to set secret value"));
-        goto cleanup;
-    }
-    vshPrint(ctl, "%s", _("Secret value set\n"));
-    ret = true;
-
-cleanup:
-    virSecretFree(secret);
-    return ret;
-}
-
-/*
- * "secret-get-value" command
- */
-static const vshCmdInfo info_secret_get_value[] = {
-    {"help", N_("Output a secret value")},
-    {"desc", N_("Output a secret value to stdout.")},
-    {NULL, NULL}
-};
-
-static const vshCmdOptDef opts_secret_get_value[] = {
-    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
-    {NULL, 0, 0, NULL}
-};
-
-static bool
-cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd)
-{
-    virSecretPtr secret;
-    char *base64;
-    unsigned char *value;
-    size_t value_size;
-    bool ret = false;
-
-    if (!vshConnectionUsability(ctl, ctl->conn))
-        return false;
-
-    secret = vshCommandOptSecret(ctl, cmd, NULL);
-    if (secret == NULL)
-        return false;
-
-    value = virSecretGetValue(secret, &value_size, 0);
-    if (value == NULL)
-        goto cleanup;
-
-    base64_encode_alloc((char *)value, value_size, &base64);
-    memset(value, 0, value_size);
-    VIR_FREE(value);
-
-    if (base64 == NULL) {
-        vshError(ctl, "%s", _("Failed to allocate memory"));
-        goto cleanup;
-    }
-    vshPrint(ctl, "%s", base64);
-    memset(base64, 0, strlen(base64));
-    VIR_FREE(base64);
-    ret = true;
-
-cleanup:
-    virSecretFree(secret);
-    return ret;
-}
-
-/*
- * "secret-undefine" command
- */
-static const vshCmdInfo info_secret_undefine[] = {
-    {"help", N_("undefine a secret")},
-    {"desc", N_("Undefine a secret.")},
-    {NULL, NULL}
-};
-
-static const vshCmdOptDef opts_secret_undefine[] = {
-    {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")},
-    {NULL, 0, 0, NULL}
-};
-
-static bool
-cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
-{
-    virSecretPtr secret;
-    bool ret = false;
-    const char *uuid;
-
-    if (!vshConnectionUsability(ctl, ctl->conn))
-        return false;
-
-    secret = vshCommandOptSecret(ctl, cmd, &uuid);
-    if (secret == NULL)
-        return false;
-
-    if (virSecretUndefine(secret) < 0) {
-        vshError(ctl, _("Failed to delete secret %s"), uuid);
-        goto cleanup;
-    }
-    vshPrint(ctl, _("Secret %s deleted\n"), uuid);
-    ret = true;
-
-cleanup:
-    virSecretFree(secret);
-    return ret;
-}
-
-/*
- * "secret-list" command
- */
-static const vshCmdInfo info_secret_list[] = {
-    {"help", N_("list secrets")},
-    {"desc", N_("Returns a list of secrets")},
-    {NULL, NULL}
-};
-
-static bool
-cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
-{
-    int maxuuids = 0, i;
-    char **uuids = NULL;
-
-    if (!vshConnectionUsability(ctl, ctl->conn))
-        return false;
-
-    maxuuids = virConnectNumOfSecrets(ctl->conn);
-    if (maxuuids < 0) {
-        vshError(ctl, "%s", _("Failed to list secrets"));
-        return false;
-    }
-    uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids);
-
-    maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids);
-    if (maxuuids < 0) {
-        vshError(ctl, "%s", _("Failed to list secrets"));
-        VIR_FREE(uuids);
-        return false;
-    }
-
-    qsort(uuids, maxuuids, sizeof(char *), vshNameSorter);
-
-    vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage"));
-    vshPrintExtra(ctl, "-----------------------------------------------------------\n");
-
-    for (i = 0; i < maxuuids; i++) {
-        virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]);
-        const char *usageType = NULL;
-
-        if (!sec) {
-            VIR_FREE(uuids[i]);
-            continue;
-        }
-
-        switch (virSecretGetUsageType(sec)) {
-        case VIR_SECRET_USAGE_TYPE_VOLUME:
-            usageType = _("Volume");
-            break;
-        }
-
-        if (usageType) {
-            vshPrint(ctl, "%-36s %s %s\n",
-                     uuids[i], usageType,
-                     virSecretGetUsageID(sec));
-        } else {
-            vshPrint(ctl, "%-36s %s\n",
-                     uuids[i], _("Unused"));
-        }
-        virSecretFree(sec);
-        VIR_FREE(uuids[i]);
-    }
-    VIR_FREE(uuids);
-    return true;
-}
-
-
-/*
  * "version" command
  */
 static const vshCmdInfo info_version[] = {
@@ -4881,33 +4570,6 @@ vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
     return dom;
 }
 
-static virSecretPtr
-vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name)
-{
-    virSecretPtr secret = NULL;
-    const char *n = NULL;
-    const char *optname = "secret";
-
-    if (!cmd_has_option(ctl, cmd, optname))
-        return NULL;
-
-    if (vshCommandOptString(cmd, optname, &n) <= 0)
-        return NULL;
-
-    vshDebug(ctl, VSH_ERR_DEBUG,
-             "%s: found option <%s>: %s\n", cmd->def->name, optname, n);
-
-    if (name != NULL)
-        *name = n;
-
-    secret = virSecretLookupByUUIDString(ctl->conn, n);
-
-    if (secret == NULL)
-        vshError(ctl, _("failed to get secret '%s'"), n);
-
-    return secret;
-}
-
 /*
  * Executes command(s) and returns return code from last command
  */
@@ -6494,6 +6156,8 @@ static const vshCmdDef nwfilterCmds[] = {
     {NULL, NULL, NULL, NULL, 0}
 };
 
+#include "virsh-secret.c"
+
 static const vshCmdDef secretCmds[] = {
     {"secret-define", cmdSecretDefine, opts_secret_define,
      info_secret_define, 0},
-- 
1.7.7.3

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]