virsh-edit.c 4.5 KB
Newer Older
1 2 3 4 5
/*
 * virsh-edit.c: Implementation of generic virsh *-edit intelligence
 *
 * Copyright (C) 2012 Red Hat, Inc.
 *
O
Osier Yang 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
 * 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/>.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
 *
 * Usage:
 * Define macros:
 * EDIT_GET_XML - expression which produces a pointer to XML string, e.g:
 *      #define EDIT_GET_XML virDomainGetXMLDesc(dom, flags)
 *
 * EDIT_NOT_CHANGED - this action is taken if the XML wasn't changed.
 *      Note, that you don't want to jump to cleanup but edit_cleanup label
 *      where temporary variables are free()-d and temporary file is deleted:
 *      #define EDIT_NOT_CHANGED vshPrint(ctl, _("Domain %s XML not changed"), \
 *                                        virDomainGetName(dom)); \
 *                               ret = true; goto edit_cleanup;
 *      Note that this is a statement.
 *
 * EDIT_DEFINE - expression which redefines the object. The edited XML from
 *      user is in 'doc_edited' variable. Don't overwrite the pointer to the
 *      object, as we may iterate once more over and therefore the pointer
 *      would be invalid. Hence assign object to a different variable.
 *      Moreover, this needs to be an expression where:
 *      - 0 is taken as error (our virDefine* APIs often return NULL on error)
 *      - everything else is taken as success
 *      For example:
 *      #define EDIT_DEFINE (dom_edited = virDomainDefineXML(ctl->conn, doc_edited))
 *
 * EDIT_FREE - statement which vir*Free()-s object defined by EDIT_DEFINE, e.g:
 *      #define EDIT_FREE if (dom_edited) virDomainFree(dom_edited);
 *
 * Michal Privoznik <mprivozn@redhat.com>
 */

#ifndef EDIT_GET_XML
# error Missing EDIT_GET_XML definition
#endif

#ifndef EDIT_NOT_CHANGED
# error Missing EDIT_NOT_CHANGED definition
#endif

#ifndef EDIT_DEFINE
# error Missing EDIT_DEFINE definition
#endif

#ifndef EDIT_FREE
# error Missing EDIT_FREE definition
#endif

do {
    char *tmp = NULL;
    char *doc = NULL;
    char *doc_edited = NULL;
    char *doc_reread = NULL;
E
Eric Blake 已提交
70
    const char *msg = NULL;
71
    bool edit_success = false;
72 73 74 75 76 77 78

    /* Get the XML configuration of the object. */
    doc = (EDIT_GET_XML);
    if (!doc)
        goto edit_cleanup;

    /* Create and open the temporary file. */
E
Eric Blake 已提交
79
    tmp = vshEditWriteToTempFile(ctl, doc);
80 81 82
    if (!tmp)
        goto edit_cleanup;

83
reedit:
84
    /* Start the editor. */
E
Eric Blake 已提交
85
    if (vshEditFile(ctl, tmp) == -1)
86 87 88
        goto edit_cleanup;

    /* Read back the edited file. */
E
Eric Blake 已提交
89
    doc_edited = vshEditReadBackFile(ctl, tmp);
90 91 92 93 94 95 96 97
    if (!doc_edited)
        goto edit_cleanup;

    /* Compare original XML with edited.  Has it changed at all? */
    if (STREQ(doc, doc_edited)) {
        EDIT_NOT_CHANGED;
    }

98 99 100
redefine:
    msg = NULL;

101 102 103 104 105 106 107 108 109
    /* Now re-read the object XML.  Did someone else change it while
     * it was being edited?  This also catches problems such as us
     * losing a connection or the object going away.
     */
    doc_reread = (EDIT_GET_XML);
    if (!doc_reread)
        goto edit_cleanup;

    if (STRNEQ(doc, doc_reread)) {
110 111 112 113
        msg = _("The XML configuration was changed by another user.");
        VIR_FREE(doc);
        doc = doc_reread;
        doc_reread = NULL;
114 115 116 117
    }

    /* Everything checks out, so redefine the object. */
    EDIT_FREE;
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    if (!msg && !(EDIT_DEFINE)) {
        msg = _("Failed.");
    }

    if (msg) {
        int c = vshAskReedit(ctl, msg);
        switch (c) {
        case 'y':
            goto reedit;
            break;

        case 'f':
            goto redefine;
            break;

        case 'n':
            goto edit_cleanup;
            break;

        default:
            vshError(ctl, "%s", msg);
            break;
        }
    }
142

143
    edit_success = true;
144 145 146 147 148 149 150 151 152

edit_cleanup:
    VIR_FREE(doc);
    VIR_FREE(doc_edited);
    VIR_FREE(doc_reread);
    if (tmp) {
        unlink (tmp);
        VIR_FREE(tmp);
    }
153 154 155

    if (!edit_success)
        goto cleanup;
156 157 158 159 160 161 162 163

} while (0);


#undef EDIT_GET_XML
#undef EDIT_NOT_CHANGED
#undef EDIT_DEFINE
#undef EDIT_FREE