lock_daemon.c 36.8 KB
Newer Older
1 2 3
/*
 * lock_daemon.c: lock management daemon
 *
4
 * Copyright (C) 2006-2015 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 * 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/>.
 */

#include <config.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <getopt.h>


#include "lock_daemon.h"
#include "lock_daemon_config.h"
32
#include "admin/admin_server_dispatch.h"
33
#include "virutil.h"
34 35
#include "virfile.h"
#include "virpidfile.h"
36
#include "virprocess.h"
37
#include "virerror.h"
38
#include "virlog.h"
39
#include "viralloc.h"
40
#include "virconf.h"
41
#include "rpc/virnetdaemon.h"
42 43 44
#include "rpc/virnetserver.h"
#include "virrandom.h"
#include "virhash.h"
45
#include "viruuid.h"
46
#include "virstring.h"
47
#include "virgettext.h"
48
#include "virdaemon.h"
49

50 51 52
#include "locking/lock_daemon_dispatch.h"
#include "locking/lock_protocol.h"

53 54 55 56
#include "configmake.h"

#define VIR_FROM_THIS VIR_FROM_LOCKING

57 58
VIR_LOG_INIT("locking.lock_daemon");

59 60
#define VIR_LOCK_DAEMON_NUM_LOCKSPACES 3

61 62
struct _virLockDaemon {
    virMutex lock;
63
    virNetDaemonPtr dmn;
64 65
    virHashTablePtr lockspaces;
    virLockSpacePtr defaultLockspace;
66 67 68 69
};

virLockDaemonPtr lockDaemon = NULL;

70
static bool execRestart;
71

72 73 74 75 76 77
static void *
virLockDaemonClientNew(virNetServerClientPtr client,
                       void *opaque);
static void
virLockDaemonClientFree(void *opaque);

78 79 80 81 82 83 84 85
static void *
virLockDaemonClientNewPostExecRestart(virNetServerClientPtr client,
                                      virJSONValuePtr object,
                                      void *opaque);
static virJSONValuePtr
virLockDaemonClientPreExecRestart(virNetServerClientPtr client,
                                  void *opaque);

86 87 88 89 90 91
static void
virLockDaemonFree(virLockDaemonPtr lockd)
{
    if (!lockd)
        return;

92
    virMutexDestroy(&lockd->lock);
93
    virObjectUnref(lockd->dmn);
94 95
    virHashFree(lockd->lockspaces);
    virLockSpaceFree(lockd->defaultLockspace);
96 97 98 99

    VIR_FREE(lockd);
}

100 101 102 103 104 105 106 107 108 109 110
static inline void
virLockDaemonLock(virLockDaemonPtr lockd)
{
    virMutexLock(&lockd->lock);
}

static inline void
virLockDaemonUnlock(virLockDaemonPtr lockd)
{
    virMutexUnlock(&lockd->lock);
}
111

112
static void virLockDaemonLockSpaceDataFree(void *data)
113 114 115 116
{
    virLockSpaceFree(data);
}

117
static virLockDaemonPtr
118
virLockDaemonNew(virLockDaemonConfigPtr config, bool privileged)
119 120
{
    virLockDaemonPtr lockd;
121
    virNetServerPtr srv = NULL;
122

123
    if (VIR_ALLOC(lockd) < 0)
124 125 126 127 128 129 130 131 132
        return NULL;

    if (virMutexInit(&lockd->lock) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to initialize mutex"));
        VIR_FREE(lockd);
        return NULL;
    }

133 134 135
    if (!(lockd->dmn = virNetDaemonNew()))
        goto error;

136
    if (!(srv = virNetServerNew("virtlockd", 1,
137
                                0, 0, 0, config->max_clients,
138 139 140 141 142
                                config->max_clients, -1, 0,
                                virLockDaemonClientNew,
                                virLockDaemonClientPreExecRestart,
                                virLockDaemonClientFree,
                                (void*)(intptr_t)(privileged ? 0x1 : 0x0))))
143 144
        goto error;

145 146 147 148 149 150
    if (virNetDaemonAddServer(lockd->dmn, srv) < 0)
        goto error;
    virObjectUnref(srv);
    srv = NULL;

    if (!(srv = virNetServerNew("admin", 1,
151
                                0, 0, 0, config->admin_max_clients,
152 153 154 155 156
                                config->admin_max_clients, -1, 0,
                                remoteAdmClientNew,
                                remoteAdmClientPreExecRestart,
                                remoteAdmClientFree,
                                lockd->dmn)))
157
        goto error;
158 159 160

    if (virNetDaemonAddServer(lockd->dmn, srv) < 0)
         goto error;
161 162
    virObjectUnref(srv);
    srv = NULL;
163

164 165 166 167 168 169 170
    if (!(lockd->lockspaces = virHashCreate(VIR_LOCK_DAEMON_NUM_LOCKSPACES,
                                            virLockDaemonLockSpaceDataFree)))
        goto error;

    if (!(lockd->defaultLockspace = virLockSpaceNew(NULL)))
        goto error;

171 172
    return lockd;

173
 error:
174
    virObjectUnref(srv);
175 176 177 178 179
    virLockDaemonFree(lockd);
    return NULL;
}


180
static virNetServerPtr
J
Ján Tomko 已提交
181
virLockDaemonNewServerPostExecRestart(virNetDaemonPtr dmn G_GNUC_UNUSED,
182 183 184 185 186 187 188 189 190 191 192 193
                                      const char *name,
                                      virJSONValuePtr object,
                                      void *opaque)
{
    if (STREQ(name, "virtlockd")) {
        return virNetServerNewPostExecRestart(object,
                                              name,
                                              virLockDaemonClientNew,
                                              virLockDaemonClientNewPostExecRestart,
                                              virLockDaemonClientPreExecRestart,
                                              virLockDaemonClientFree,
                                              opaque);
194 195 196 197 198 199 200 201
    } else if (STREQ(name, "admin")) {
        return virNetServerNewPostExecRestart(object,
                                              name,
                                              remoteAdmClientNew,
                                              remoteAdmClientNewPostExecRestart,
                                              remoteAdmClientPreExecRestart,
                                              remoteAdmClientFree,
                                              dmn);
202 203 204 205 206 207 208 209 210
    } else {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unexpected server name '%s' during restart"),
                       name);
        return NULL;
    }
}


211 212 213 214 215 216 217
static virLockDaemonPtr
virLockDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
{
    virLockDaemonPtr lockd;
    virJSONValuePtr child;
    virJSONValuePtr lockspaces;
    size_t i;
218
    const char *serverNames[] = { "virtlockd" };
219

220
    if (VIR_ALLOC(lockd) < 0)
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
        return NULL;

    if (virMutexInit(&lockd->lock) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to initialize mutex"));
        VIR_FREE(lockd);
        return NULL;
    }

    if (!(lockd->lockspaces = virHashCreate(VIR_LOCK_DAEMON_NUM_LOCKSPACES,
                                            virLockDaemonLockSpaceDataFree)))
        goto error;

    if (!(child = virJSONValueObjectGet(object, "defaultLockspace"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing defaultLockspace data from JSON file"));
        goto error;
    }

    if (!(lockd->defaultLockspace =
          virLockSpaceNewPostExecRestart(child)))
        goto error;

    if (!(lockspaces = virJSONValueObjectGet(object, "lockspaces"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing lockspaces data from JSON file"));
        goto error;
    }

250
    if (!virJSONValueIsArray(lockspaces)) {
251
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
252
                       _("Malformed lockspaces array"));
253 254 255
        goto error;
    }

256
    for (i = 0; i < virJSONValueArraySize(lockspaces); i++) {
257 258 259 260 261 262 263 264 265 266 267 268 269 270
        virLockSpacePtr lockspace;

        child = virJSONValueArrayGet(lockspaces, i);

        if (!(lockspace = virLockSpaceNewPostExecRestart(child)))
            goto error;

        if (virHashAddEntry(lockd->lockspaces,
                            virLockSpaceGetDirectory(lockspace),
                            lockspace) < 0) {
            virLockSpaceFree(lockspace);
        }
    }

271 272 273 274 275 276 277 278 279 280 281 282
    if (virJSONValueObjectHasKey(object, "daemon")) {
        if (!(child = virJSONValueObjectGet(object, "daemon"))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Malformed daemon data from JSON file"));
            goto error;
        }
    } else {
        if (!(child = virJSONValueObjectGet(object, "server"))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing server data from JSON file"));
            goto error;
        }
283 284
    }

285
    if (!(lockd->dmn = virNetDaemonNewPostExecRestart(child,
286
                                                      G_N_ELEMENTS(serverNames),
287 288 289
                                                      serverNames,
                                                      virLockDaemonNewServerPostExecRestart,
                                                      (void*)(intptr_t)(privileged ? 0x1 : 0x0))))
290 291 292 293
        goto error;

    return lockd;

294
 error:
295 296 297 298 299
    virLockDaemonFree(lockd);
    return NULL;
}


300 301 302 303 304
int virLockDaemonAddLockSpace(virLockDaemonPtr lockd,
                              const char *path,
                              virLockSpacePtr lockspace)
{
    int ret;
305
    virLockDaemonLock(lockd);
306
    ret = virHashAddEntry(lockd->lockspaces, path, lockspace);
307
    virLockDaemonUnlock(lockd);
308 309 310 311 312 313 314
    return ret;
}

virLockSpacePtr virLockDaemonFindLockSpace(virLockDaemonPtr lockd,
                                           const char *path)
{
    virLockSpacePtr lockspace;
315
    virLockDaemonLock(lockd);
316 317 318 319
    if (path && STRNEQ(path, ""))
        lockspace = virHashLookup(lockd->lockspaces, path);
    else
        lockspace = lockd->defaultLockspace;
320
    virLockDaemonUnlock(lockd);
321 322 323 324
    return lockspace;
}


325
static void
J
Ján Tomko 已提交
326 327
virLockDaemonErrorHandler(void *opaque G_GNUC_UNUSED,
                          virErrorPtr err G_GNUC_UNUSED)
328 329 330 331 332 333 334 335 336 337 338 339 340 341
{
    /* Don't do anything, since logging infrastructure already
     * took care of reporting the error */
}


/* Display version information. */
static void
virLockDaemonVersion(const char *argv0)
{
    printf("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
}

static void
342
virLockDaemonShutdownHandler(virNetDaemonPtr dmn,
J
Ján Tomko 已提交
343 344
                             siginfo_t *sig G_GNUC_UNUSED,
                             void *opaque G_GNUC_UNUSED)
345
{
346
    virNetDaemonQuit(dmn);
347 348
}

349
static void
350
virLockDaemonExecRestartHandler(virNetDaemonPtr dmn,
J
Ján Tomko 已提交
351 352
                                siginfo_t *sig G_GNUC_UNUSED,
                                void *opaque G_GNUC_UNUSED)
353 354
{
    execRestart = true;
355
    virNetDaemonQuit(dmn);
356 357
}

358
static int
359
virLockDaemonSetupSignals(virNetDaemonPtr dmn)
360
{
361
    if (virNetDaemonAddSignalHandler(dmn, SIGINT, virLockDaemonShutdownHandler, NULL) < 0)
362
        return -1;
363
    if (virNetDaemonAddSignalHandler(dmn, SIGQUIT, virLockDaemonShutdownHandler, NULL) < 0)
364
        return -1;
365
    if (virNetDaemonAddSignalHandler(dmn, SIGTERM, virLockDaemonShutdownHandler, NULL) < 0)
366
        return -1;
367
    if (virNetDaemonAddSignalHandler(dmn, SIGUSR1, virLockDaemonExecRestartHandler, NULL) < 0)
368
        return -1;
369 370 371
    return 0;
}

372

373 374 375 376 377 378
struct virLockDaemonClientReleaseData {
    virLockDaemonClientPtr client;
    bool hadSomeLeases;
    bool gotError;
};

379
static int
380
virLockDaemonClientReleaseLockspace(void *payload,
J
Ján Tomko 已提交
381
                                    const void *name G_GNUC_UNUSED,
382 383 384 385 386 387 388 389 390 391 392 393
                                    void *opaque)
{
    virLockSpacePtr lockspace = payload;
    struct virLockDaemonClientReleaseData *data = opaque;
    int rc;

    rc = virLockSpaceReleaseResourcesForOwner(lockspace,
                                              data->client->clientPid);
    if (rc > 0)
        data->hadSomeLeases = true;
    else if (rc < 0)
        data->gotError = true;
394
    return 0;
395 396 397
}


398 399 400 401 402 403 404 405
static void
virLockDaemonClientFree(void *opaque)
{
    virLockDaemonClientPtr priv = opaque;

    if (!priv)
        return;

406
    VIR_DEBUG("priv=%p client=%lld owner=%lld",
407
              priv,
408 409 410 411 412 413 414 415 416 417 418 419
              (unsigned long long)priv->clientPid,
              (unsigned long long)priv->ownerPid);

    /* If client & owner match, this is the lock holder */
    if (priv->clientPid == priv->ownerPid) {
        size_t i;
        struct virLockDaemonClientReleaseData data = {
            .client = priv, .hadSomeLeases = false, .gotError = false
        };

        /* Release all locks associated with this
         * owner in all lockspaces */
420
        virLockDaemonLock(lockDaemon);
421 422 423 424 425 426
        virHashForEach(lockDaemon->lockspaces,
                       virLockDaemonClientReleaseLockspace,
                       &data);
        virLockDaemonClientReleaseLockspace(lockDaemon->defaultLockspace,
                                            "",
                                            &data);
427
        virLockDaemonUnlock(lockDaemon);
428 429 430 431 432

        /* If the client had some active leases when it
         * closed the connection, we must kill it off
         * to make sure it doesn't do nasty stuff */
        if (data.gotError || data.hadSomeLeases) {
433
            for (i = 0; i < 15; i++) {
434 435 436 437 438 439 440
                int signum;
                if (i == 0)
                    signum = SIGTERM;
                else if (i == 8)
                    signum = SIGKILL;
                else
                    signum = 0;
J
Jim Fehlig 已提交
441
                if (priv->clientPid != 0 && virProcessKill(priv->clientPid, signum) < 0) {
442 443 444 445 446 447
                    if (errno == ESRCH)
                        break;

                    VIR_WARN("Failed to kill off pid %lld",
                             (unsigned long long)priv->clientPid);
                }
448
                g_usleep(200 * 1000);
449 450 451
            }
        }
    }
452 453

    virMutexDestroy(&priv->lock);
454
    VIR_FREE(priv->ownerName);
455 456 457 458 459 460 461 462 463 464 465
    VIR_FREE(priv);
}


static void *
virLockDaemonClientNew(virNetServerClientPtr client,
                       void *opaque)
{
    virLockDaemonClientPtr priv;
    uid_t clientuid;
    gid_t clientgid;
466
    unsigned long long timestamp;
467 468
    bool privileged = opaque != NULL;

469
    if (VIR_ALLOC(priv) < 0)
470 471 472 473
        return NULL;

    if (virMutexInit(&priv->lock) < 0) {
        VIR_FREE(priv);
474
        virReportSystemError(errno, "%s", _("unable to init mutex"));
475 476 477 478 479 480
        return NULL;
    }

    if (virNetServerClientGetUNIXIdentity(client,
                                          &clientuid,
                                          &clientgid,
481 482
                                          &priv->clientPid,
                                          &timestamp) < 0)
483 484 485 486 487 488 489 490
        goto error;

    VIR_DEBUG("New client pid %llu uid %llu",
              (unsigned long long)priv->clientPid,
              (unsigned long long)clientuid);

    if (!privileged) {
        if (geteuid() != clientuid) {
491 492 493
            virReportRestrictedError(_("Disallowing client %llu with uid %llu"),
                                     (unsigned long long)priv->clientPid,
                                     (unsigned long long)clientuid);
494 495 496 497
            goto error;
        }
    } else {
        if (clientuid != 0) {
498 499 500
            virReportRestrictedError(_("Disallowing client %llu with uid %llu"),
                                     (unsigned long long)priv->clientPid,
                                     (unsigned long long)clientuid);
501 502 503 504
            goto error;
        }
    }

505 506 507
    /* there's no closing handshake in the locking protocol */
    virNetServerClientSetQuietEOF(client);

508 509
    return priv;

510
 error:
511 512 513 514 515 516
    virMutexDestroy(&priv->lock);
    VIR_FREE(priv);
    return NULL;
}


517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
static void *
virLockDaemonClientNewPostExecRestart(virNetServerClientPtr client,
                                      virJSONValuePtr object,
                                      void *opaque)
{
    virLockDaemonClientPtr priv = virLockDaemonClientNew(client, opaque);
    unsigned int ownerPid;
    const char *ownerUUID;
    const char *ownerName;

    if (!priv)
        return NULL;

    if (virJSONValueObjectGetBoolean(object, "restricted", &priv->restricted) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing restricted data in JSON document"));
        goto error;
    }
    if (virJSONValueObjectGetNumberUint(object, "ownerPid", &ownerPid) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing ownerPid data in JSON document"));
        goto error;
    }
    priv->ownerPid = (pid_t)ownerPid;
    if (virJSONValueObjectGetNumberUint(object, "ownerId", &priv->ownerId) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing ownerId data in JSON document"));
        goto error;
    }
    if (!(ownerName = virJSONValueObjectGetString(object, "ownerName"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing ownerName data in JSON document"));
        goto error;
    }
551
    priv->ownerName = g_strdup(ownerName);
552 553 554 555 556 557 558 559 560 561 562 563
    if (!(ownerUUID = virJSONValueObjectGetString(object, "ownerUUID"))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing ownerUUID data in JSON document"));
        goto error;
    }
    if (virUUIDParse(ownerUUID, priv->ownerUUID) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing ownerUUID data in JSON document"));
        goto error;
    }
    return priv;

564
 error:
565 566 567 568 569 570
    virLockDaemonClientFree(priv);
    return NULL;
}


static virJSONValuePtr
J
Ján Tomko 已提交
571
virLockDaemonClientPreExecRestart(virNetServerClientPtr client G_GNUC_UNUSED,
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
                                  void *opaque)
{
    virLockDaemonClientPtr priv = opaque;
    virJSONValuePtr object = virJSONValueNewObject();
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    if (virJSONValueObjectAppendBoolean(object, "restricted", priv->restricted) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot set restricted data in JSON document"));
        goto error;
    }
    if (virJSONValueObjectAppendNumberUint(object, "ownerPid", priv->ownerPid) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot set ownerPid data in JSON document"));
        goto error;
    }
    if (virJSONValueObjectAppendNumberUint(object, "ownerId", priv->ownerId) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot set ownerId data in JSON document"));
        goto error;
    }
    if (virJSONValueObjectAppendString(object, "ownerName", priv->ownerName) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot set ownerName data in JSON document"));
        goto error;
    }
    virUUIDFormat(priv->ownerUUID, uuidstr);
    if (virJSONValueObjectAppendString(object, "ownerUUID", uuidstr) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot set ownerUUID data in JSON document"));
        goto error;
    }

    return object;

607
 error:
608 609 610 611 612
    virJSONValueFree(object);
    return NULL;
}


613 614 615 616 617
static int
virLockDaemonExecRestartStatePath(bool privileged,
                                  char **state_file)
{
    if (privileged) {
618
        *state_file = g_strdup(RUNSTATEDIR "/virtlockd-restart-exec.json");
619
    } else {
620
        g_autofree char *rundir = NULL;
621 622
        mode_t old_umask;

623
        rundir = virGetUserRuntimeDirectory();
624 625 626 627

        old_umask = umask(077);
        if (virFileMakePath(rundir) < 0) {
            umask(old_umask);
628
            return -1;
629 630 631
        }
        umask(old_umask);

632
        *state_file = g_strdup_printf("%s/virtlockd-restart-exec.json", rundir);
633 634 635 636 637
    }

    return 0;
}

638 639 640 641 642 643

static char *
virLockDaemonGetExecRestartMagic(void)
{
    char *ret;

644
    ret = g_strdup_printf("%lld", (long long int)getpid());
645 646 647 648 649
    return ret;
}


static int
650 651 652 653
virLockDaemonPostExecRestart(const char *state_file,
                             const char *pid_file,
                             int *pid_file_fd,
                             bool privileged)
654 655 656 657 658 659 660 661 662
{
    const char *gotmagic;
    char *wantmagic = NULL;
    int ret = -1;
    char *state = NULL;
    virJSONValuePtr object = NULL;

    VIR_DEBUG("Running post-restart exec");

663 664 665
    if (!virFileExists(state_file)) {
        VIR_DEBUG("No restart state file %s present",
                  state_file);
666 667 668 669
        ret = 0;
        goto cleanup;
    }

670
    if (virFileReadAll(state_file,
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
                       1024 * 1024 * 10, /* 10 MB */
                       &state) < 0)
        goto cleanup;

    VIR_DEBUG("Loading state %s", state);

    if (!(object = virJSONValueFromString(state)))
        goto cleanup;

    gotmagic = virJSONValueObjectGetString(object, "magic");
    if (!gotmagic) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing magic data in JSON document"));
        goto cleanup;
    }

    if (!(wantmagic = virLockDaemonGetExecRestartMagic()))
        goto cleanup;

    if (STRNEQ(gotmagic, wantmagic)) {
        VIR_WARN("Found restart exec file with old magic %s vs wanted %s",
                 gotmagic, wantmagic);
        ret = 0;
        goto cleanup;
    }

697 698
    /* Re-claim PID file now as we will not be daemonizing */
    if (pid_file &&
699
        (*pid_file_fd = virPidFileAcquirePath(pid_file, false, getpid())) < 0)
700 701
        goto cleanup;

702 703 704 705 706
    if (!(lockDaemon = virLockDaemonNewPostExecRestart(object, privileged)))
        goto cleanup;

    ret = 1;

707
 cleanup:
708
    unlink(state_file);
709 710 711 712 713 714 715 716
    VIR_FREE(wantmagic);
    VIR_FREE(state);
    virJSONValueFree(object);
    return ret;
}


static int
717
virLockDaemonPreExecRestart(const char *state_file,
718
                            virNetDaemonPtr dmn,
719 720 721 722 723
                            char **argv)
{
    virJSONValuePtr child;
    char *state = NULL;
    int ret = -1;
724
    virJSONValuePtr object = virJSONValueNewObject();
725 726 727 728 729 730
    char *magic;
    virHashKeyValuePairPtr pairs = NULL, tmp;
    virJSONValuePtr lockspaces;

    VIR_DEBUG("Running pre-restart exec");

731
    if (!(child = virNetDaemonPreExecRestart(dmn)))
732 733
        goto cleanup;

734
    if (virJSONValueObjectAppend(object, "daemon", child) < 0) {
735 736 737 738 739 740 741 742 743 744 745 746
        virJSONValueFree(child);
        goto cleanup;
    }

    if (!(child = virLockSpacePreExecRestart(lockDaemon->defaultLockspace)))
        goto cleanup;

    if (virJSONValueObjectAppend(object, "defaultLockspace", child) < 0) {
        virJSONValueFree(child);
        goto cleanup;
    }

747 748
    lockspaces = virJSONValueNewArray();

749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
    if (virJSONValueObjectAppend(object, "lockspaces", lockspaces) < 0) {
        virJSONValueFree(lockspaces);
        goto cleanup;
    }


    tmp = pairs = virHashGetItems(lockDaemon->lockspaces, NULL);
    while (tmp && tmp->key) {
        virLockSpacePtr lockspace = (virLockSpacePtr)tmp->value;

        if (!(child = virLockSpacePreExecRestart(lockspace)))
            goto cleanup;

        if (virJSONValueArrayAppend(lockspaces, child) < 0) {
            virJSONValueFree(child);
            goto cleanup;
        }

        tmp++;
    }

    if (!(magic = virLockDaemonGetExecRestartMagic()))
        goto cleanup;

    if (virJSONValueObjectAppendString(object, "magic", magic) < 0) {
        VIR_FREE(magic);
        goto cleanup;
    }

    if (!(state = virJSONValueToString(object, true)))
        goto cleanup;

    VIR_DEBUG("Saving state %s", state);

783
    if (virFileWriteStr(state_file,
784 785 786
                        state, 0700) < 0) {
        virReportSystemError(errno,
                             _("Unable to save state file %s"),
787
                             state_file);
788 789 790
        goto cleanup;
    }

791
    if (execvp(argv[0], argv) < 0) {
792 793 794 795 796 797 798
        virReportSystemError(errno, "%s",
                             _("Unable to restart self"));
        goto cleanup;
    }

    abort(); /* This should be impossible to reach */

799
 cleanup:
800 801 802 803 804 805 806
    VIR_FREE(pairs);
    VIR_FREE(state);
    virJSONValueFree(object);
    return ret;
}


807 808 809 810 811 812 813 814 815
static void
virLockDaemonUsage(const char *argv0, bool privileged)
{
    fprintf(stderr,
            _("\n"
              "Usage:\n"
              "  %s [options]\n"
              "\n"
              "Options:\n"
816
              "  -h | --help            Display program help:\n"
817 818
              "  -v | --verbose         Verbose messages.\n"
              "  -d | --daemon          Run as a daemon & write PID file.\n"
819
              "  -t | --timeout <secs>  Exit after timeout period.\n"
820
              "  -f | --config <file>   Configuration file.\n"
821
              "  -V | --version         Display version information.\n"
822 823 824 825 826 827 828 829 830 831 832 833 834
              "  -p | --pid-file <file> Change name of PID file.\n"
              "\n"
              "libvirt lock management daemon:\n"), argv0);

    if (privileged) {
        fprintf(stderr,
                _("\n"
                  "  Default paths:\n"
                  "\n"
                  "    Configuration file (unless overridden by -f):\n"
                  "      %s/libvirt/virtlockd.conf\n"
                  "\n"
                  "    Sockets:\n"
835
                  "      %s/libvirt/virtlockd-sock\n"
836 837
                  "\n"
                  "    PID file (unless overridden by -p):\n"
838
                  "      %s/virtlockd.pid\n"
839 840
                  "\n"),
                SYSCONFDIR,
841 842
                RUNSTATEDIR,
                RUNSTATEDIR);
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
    } else {
        fprintf(stderr, "%s",
                _("\n"
                  "  Default paths:\n"
                  "\n"
                  "    Configuration file (unless overridden by -f):\n"
                  "      $XDG_CONFIG_HOME/libvirt/virtlockd.conf\n"
                  "\n"
                  "    Sockets:\n"
                  "      $XDG_RUNTIME_DIR/libvirt/virtlockd-sock\n"
                  "\n"
                  "    PID file:\n"
                  "      $XDG_RUNTIME_DIR/libvirt/virtlockd.pid\n"
                  "\n"));
    }
}

int main(int argc, char **argv) {
861 862
    virNetServerPtr lockSrv = NULL;
    virNetServerPtr adminSrv = NULL;
863
    virNetServerProgramPtr lockProgram = NULL;
864
    virNetServerProgramPtr adminProgram = NULL;
865 866 867 868 869 870 871 872 873
    char *remote_config_file = NULL;
    int statuswrite = -1;
    int ret = 1;
    int verbose = 0;
    int godaemon = 0;
    char *run_dir = NULL;
    char *pid_file = NULL;
    int pid_file_fd = -1;
    char *sock_file = NULL;
874
    char *admin_sock_file = NULL;
875
    int timeout = -1;        /* -t: Shutdown timeout */
876
    char *state_file = NULL;
877 878 879 880
    bool implicit_conf = false;
    mode_t old_umask;
    bool privileged = false;
    virLockDaemonConfigPtr config = NULL;
881
    int rv;
882 883

    struct option opts[] = {
884 885
        { "verbose", no_argument, &verbose, 'v'},
        { "daemon", no_argument, &godaemon, 'd'},
886
        { "config", required_argument, NULL, 'f'},
887
        { "timeout", required_argument, NULL, 't'},
888
        { "pid-file", required_argument, NULL, 'p'},
889 890
        { "version", no_argument, NULL, 'V' },
        { "help", no_argument, NULL, 'h' },
891 892 893
        {0, 0, 0, 0}
    };

894
    privileged = geteuid() == 0;
895

896
    if (virGettextInitialize() < 0 ||
897 898 899 900 901 902 903 904
        virErrorInitialize() < 0) {
        fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
        exit(EXIT_FAILURE);
    }

    while (1) {
        int optidx = 0;
        int c;
905
        char *tmp;
906

907
        c = getopt_long(argc, argv, "df:p:t:vVh", opts, &optidx);
908

909
        if (c == -1)
910 911 912 913 914 915 916 917 918 919 920 921 922
            break;

        switch (c) {
        case 0:
            /* Got one of the flags */
            break;
        case 'v':
            verbose = 1;
            break;
        case 'd':
            godaemon = 1;
            break;

923 924 925 926 927 928 929 930 931 932
        case 't':
            if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
                || timeout <= 0
                /* Ensure that we can multiply by 1000 without overflowing.  */
                || timeout > INT_MAX / 1000) {
                VIR_ERROR(_("Invalid value for timeout"));
                exit(EXIT_FAILURE);
            }
            break;

933 934
        case 'p':
            VIR_FREE(pid_file);
935
            pid_file = g_strdup(optarg);
936 937 938 939
            break;

        case 'f':
            VIR_FREE(remote_config_file);
940
            remote_config_file = g_strdup(optarg);
941 942
            break;

943
        case 'V':
944
            virLockDaemonVersion(argv[0]);
945
            exit(EXIT_SUCCESS);
946

947
        case 'h':
948
            virLockDaemonUsage(argv[0], privileged);
949
            exit(EXIT_SUCCESS);
950

951
        case '?':
952
        default:
953
            virLockDaemonUsage(argv[0], privileged);
954 955 956 957
            exit(EXIT_FAILURE);
        }
    }

958
    virFileActivateDirOverrideForProg(argv[0]);
959

960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
    if (!(config = virLockDaemonConfigNew(privileged))) {
        VIR_ERROR(_("Can't create initial configuration"));
        exit(EXIT_FAILURE);
    }

    /* No explicit config, so try and find a default one */
    if (remote_config_file == NULL) {
        implicit_conf = true;
        if (virLockDaemonConfigFilePath(privileged,
                                        &remote_config_file) < 0) {
            VIR_ERROR(_("Can't determine config path"));
            exit(EXIT_FAILURE);
        }
    }

J
Ján Tomko 已提交
975
    /* Read the config file if it exists */
976 977
    if (remote_config_file &&
        virLockDaemonConfigLoadFile(config, remote_config_file, implicit_conf) < 0) {
978 979
        VIR_ERROR(_("Can't load config file: %s: %s"),
                  virGetLastErrorMessage(), remote_config_file);
980 981
        exit(EXIT_FAILURE);
    }
982
    VIR_FREE(remote_config_file);
983

984 985 986 987 988 989 990
    virDaemonSetupLogging("virtlockd",
                          config->log_level,
                          config->log_filters,
                          config->log_outputs,
                          privileged,
                          verbose,
                          godaemon);
991 992

    if (!pid_file &&
993
        virPidFileConstructPath(privileged,
994
                                RUNSTATEDIR,
995 996
                                "virtlockd",
                                &pid_file) < 0) {
997 998 999 1000 1001
        VIR_ERROR(_("Can't determine pid file path."));
        exit(EXIT_FAILURE);
    }
    VIR_DEBUG("Decided on pid file path '%s'", NULLSTR(pid_file));

1002 1003 1004 1005 1006 1007
    if (virDaemonUnixSocketPaths("virtlockd",
                                 privileged,
                                 NULL,
                                 &sock_file,
                                 NULL,
                                 &admin_sock_file) < 0) {
1008 1009 1010
        VIR_ERROR(_("Can't determine socket paths"));
        exit(EXIT_FAILURE);
    }
1011 1012
    VIR_DEBUG("Decided on socket paths '%s' and '%s'",
              sock_file, admin_sock_file);
1013

1014 1015 1016 1017
    if (virLockDaemonExecRestartStatePath(privileged,
                                          &state_file) < 0) {
        VIR_ERROR(_("Can't determine restart state file path"));
        exit(EXIT_FAILURE);
1018
    }
1019 1020
    VIR_DEBUG("Decided on restart state file path '%s'",
              state_file);
1021 1022 1023

    /* Ensure the rundir exists (on tmpfs on some systems) */
    if (privileged) {
1024
        run_dir = g_strdup(RUNSTATEDIR "/libvirt");
1025
    } else {
1026
        run_dir = virGetUserRuntimeDirectory();
1027 1028 1029 1030 1031 1032 1033 1034 1035
    }

    if (privileged)
        old_umask = umask(022);
    else
        old_umask = umask(077);
    VIR_DEBUG("Ensuring run dir '%s' exists", run_dir);
    if (virFileMakePath(run_dir) < 0) {
        VIR_ERROR(_("unable to create rundir %s: %s"), run_dir,
1036
                  g_strerror(errno));
1037
        ret = VIR_DAEMON_ERR_RUNDIR;
1038
        umask(old_umask);
1039 1040 1041 1042
        goto cleanup;
    }
    umask(old_umask);

1043 1044 1045 1046
    if ((rv = virLockDaemonPostExecRestart(state_file,
                                           pid_file,
                                           &pid_file_fd,
                                           privileged)) < 0) {
1047
        ret = VIR_DAEMON_ERR_INIT;
1048 1049 1050
        goto cleanup;
    }

1051 1052 1053
    /* rv == 1 means we successfully restored from the saved internal state
     * (but still need to add @lockProgram into @srv). rv == 0 means that no
     * saved state is present, therefore initialize from scratch here. */
1054
    if (rv == 0) {
J
Ján Tomko 已提交
1055
        g_autoptr(virSystemdActivation) act = NULL;
1056 1057 1058 1059 1060
        virSystemdActivationMap actmap[] = {
            { .name = "virtlockd.socket", .family = AF_UNIX, .path = sock_file },
            { .name = "virtlockd-admin.socket", .family = AF_UNIX, .path = admin_sock_file },
        };

1061 1062 1063
        if (godaemon) {
            if (chdir("/") < 0) {
                VIR_ERROR(_("cannot change to root directory: %s"),
1064
                          g_strerror(errno));
1065 1066 1067
                goto cleanup;
            }

1068
            if ((statuswrite = virDaemonForkIntoBackground(argv[0])) < 0) {
1069
                VIR_ERROR(_("Failed to fork as daemon: %s"),
1070
                          g_strerror(errno));
1071 1072 1073 1074 1075
                goto cleanup;
            }
        }

        /* If we have a pidfile set, claim it now, exiting if already taken */
1076
        if ((pid_file_fd = virPidFileAcquirePath(pid_file, false, getpid())) < 0) {
1077
            ret = VIR_DAEMON_ERR_PIDFILE;
1078 1079 1080
            goto cleanup;
        }

1081
        if (!(lockDaemon = virLockDaemonNew(config, privileged))) {
1082
            ret = VIR_DAEMON_ERR_INIT;
1083 1084
            goto cleanup;
        }
1085

1086
        if (virSystemdGetActivation(actmap,
1087
                                    G_N_ELEMENTS(actmap),
1088
                                    &act) < 0) {
1089
            ret = VIR_DAEMON_ERR_NETWORK;
1090 1091 1092
            goto cleanup;
        }

1093 1094
        lockSrv = virNetDaemonGetServer(lockDaemon->dmn, "virtlockd");
        adminSrv = virNetDaemonGetServer(lockDaemon->dmn, "admin");
1095 1096 1097 1098 1099 1100

        if (virNetServerAddServiceUNIX(lockSrv,
                                       act, "virtlockd.socket",
                                       sock_file, 0700, 0, 0,
                                       NULL,
                                       false, 0, 1) < 0) {
1101
            ret = VIR_DAEMON_ERR_NETWORK;
1102 1103 1104 1105 1106 1107 1108
            goto cleanup;
        }
        if (virNetServerAddServiceUNIX(adminSrv,
                                       act, "virtlockd-admin.socket",
                                       admin_sock_file, 0700, 0, 0,
                                       NULL,
                                       false, 0, 1) < 0) {
1109
            ret = VIR_DAEMON_ERR_NETWORK;
1110 1111 1112
            goto cleanup;
        }

1113 1114
        if (act &&
            virSystemdActivationComplete(act) < 0) {
1115
            ret = VIR_DAEMON_ERR_NETWORK;
1116
            goto cleanup;
1117
        }
1118 1119 1120 1121 1122 1123
    } else {
        lockSrv = virNetDaemonGetServer(lockDaemon->dmn, "virtlockd");
        /* If exec-restarting from old virtlockd, we won't have an
         * admin server present */
        if (virNetDaemonHasServer(lockDaemon->dmn, "admin"))
            adminSrv = virNetDaemonGetServer(lockDaemon->dmn, "admin");
1124 1125
    }

1126 1127
    if (timeout != -1) {
        VIR_DEBUG("Registering shutdown timeout %d", timeout);
1128
        virNetDaemonAutoShutdown(lockDaemon->dmn,
1129 1130 1131
                                 timeout);
    }

1132
    if ((virLockDaemonSetupSignals(lockDaemon->dmn)) < 0) {
1133
        ret = VIR_DAEMON_ERR_SIGNAL;
1134 1135 1136
        goto cleanup;
    }

1137 1138 1139 1140
    if (!(lockProgram = virNetServerProgramNew(VIR_LOCK_SPACE_PROTOCOL_PROGRAM,
                                               VIR_LOCK_SPACE_PROTOCOL_PROGRAM_VERSION,
                                               virLockSpaceProtocolProcs,
                                               virLockSpaceProtocolNProcs))) {
1141
        ret = VIR_DAEMON_ERR_INIT;
1142 1143
        goto cleanup;
    }
1144

1145
    if (virNetServerAddProgram(lockSrv, lockProgram) < 0) {
1146
        ret = VIR_DAEMON_ERR_INIT;
1147 1148 1149
        goto cleanup;
    }

1150 1151 1152 1153 1154
    if (adminSrv != NULL) {
        if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM,
                                                    ADMIN_PROTOCOL_VERSION,
                                                    adminProcs,
                                                    adminNProcs))) {
1155
            ret = VIR_DAEMON_ERR_INIT;
1156 1157 1158
            goto cleanup;
        }
        if (virNetServerAddProgram(adminSrv, adminProgram) < 0) {
1159
            ret = VIR_DAEMON_ERR_INIT;
1160 1161 1162 1163
            goto cleanup;
        }
    }

1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
    /* Disable error func, now logging is setup */
    virSetErrorFunc(NULL, virLockDaemonErrorHandler);


    /* Tell parent of daemon that basic initialization is complete
     * In particular we're ready to accept net connections & have
     * written the pidfile
     */
    if (statuswrite != -1) {
        char status = 0;
        while (write(statuswrite, &status, 1) == -1 &&
               errno == EINTR)
            ;
        VIR_FORCE_CLOSE(statuswrite);
    }

    /* Start accepting new clients from network */

1182 1183
    virNetDaemonUpdateServices(lockDaemon->dmn, true);
    virNetDaemonRun(lockDaemon->dmn);
1184 1185

    if (execRestart &&
1186
        virLockDaemonPreExecRestart(state_file,
1187
                                    lockDaemon->dmn,
1188
                                    argv) < 0)
1189
        ret = VIR_DAEMON_ERR_REEXEC;
1190 1191
    else
        ret = 0;
1192

1193
 cleanup:
1194
    virObjectUnref(lockProgram);
1195 1196 1197
    virObjectUnref(adminProgram);
    virObjectUnref(lockSrv);
    virObjectUnref(adminSrv);
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
    virLockDaemonFree(lockDaemon);
    if (statuswrite != -1) {
        if (ret != 0) {
            /* Tell parent of daemon what failed */
            char status = ret;
            while (write(statuswrite, &status, 1) == -1 &&
                   errno == EINTR)
                ;
        }
        VIR_FORCE_CLOSE(statuswrite);
    }
    if (pid_file_fd != -1)
        virPidFileReleasePath(pid_file, pid_file_fd);
    VIR_FREE(pid_file);
    VIR_FREE(sock_file);
1213
    VIR_FREE(admin_sock_file);
1214
    VIR_FREE(state_file);
1215
    VIR_FREE(run_dir);
1216
    virLockDaemonConfigFree(config);
1217 1218
    return ret;
}