hastctl.c revision 302408
1218885Sdim/*- 2218885Sdim * Copyright (c) 2009-2010 The FreeBSD Foundation 3218885Sdim * All rights reserved. 4218885Sdim * 5218885Sdim * This software was developed by Pawel Jakub Dawidek under sponsorship from 6218885Sdim * the FreeBSD Foundation. 7218885Sdim * 8218885Sdim * Redistribution and use in source and binary forms, with or without 9218885Sdim * modification, are permitted provided that the following conditions 10218885Sdim * are met: 11218885Sdim * 1. Redistributions of source code must retain the above copyright 12218885Sdim * notice, this list of conditions and the following disclaimer. 13218885Sdim * 2. Redistributions in binary form must reproduce the above copyright 14218885Sdim * notice, this list of conditions and the following disclaimer in the 15218885Sdim * documentation and/or other materials provided with the distribution. 16218885Sdim * 17218885Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18234353Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19239462Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20218885Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21239462Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22239462Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23239462Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24239462Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25218885Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26239462Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27239462Sdim * SUCH DAMAGE. 28218885Sdim */ 29249423Sdim 30249423Sdim#include <sys/cdefs.h> 31239462Sdim__FBSDID("$FreeBSD: stable/11/sbin/hastctl/hastctl.c 257155 2013-10-26 08:38:21Z trociny $"); 32218885Sdim 33218885Sdim#include <sys/param.h> 34249423Sdim 35218885Sdim#include <err.h> 36218885Sdim#include <libutil.h> 37218885Sdim#include <stdio.h> 38239462Sdim#include <string.h> 39239462Sdim#include <unistd.h> 40239462Sdim 41239462Sdim#include <activemap.h> 42239462Sdim 43239462Sdim#include "hast.h" 44239462Sdim#include "hast_proto.h" 45239462Sdim#include "metadata.h" 46239462Sdim#include "nv.h" 47239462Sdim#include "pjdlog.h" 48239462Sdim#include "proto.h" 49239462Sdim#include "subr.h" 50239462Sdim 51239462Sdim/* Path to configuration file. */ 52239462Sdimstatic const char *cfgpath = HAST_CONFIG; 53239462Sdim/* Hastd configuration. */ 54239462Sdimstatic struct hastd_config *cfg; 55239462Sdim/* Control connection. */ 56239462Sdimstatic struct proto_conn *controlconn; 57239462Sdim 58239462Sdimenum { 59239462Sdim CMD_INVALID, 60239462Sdim CMD_CREATE, 61239462Sdim CMD_ROLE, 62239462Sdim CMD_STATUS, 63239462Sdim CMD_DUMP, 64239462Sdim CMD_LIST 65239462Sdim}; 66239462Sdim 67239462Sdimstatic __dead2 void 68239462Sdimusage(void) 69239462Sdim{ 70239462Sdim 71239462Sdim fprintf(stderr, 72239462Sdim "usage: %s create [-d] [-c config] [-e extentsize] [-k keepdirty]\n" 73239462Sdim "\t\t[-m mediasize] name ...\n", 74239462Sdim getprogname()); 75239462Sdim fprintf(stderr, 76239462Sdim " %s role [-d] [-c config] <init | primary | secondary> all | name ...\n", 77239462Sdim getprogname()); 78239462Sdim fprintf(stderr, 79239462Sdim " %s list [-d] [-c config] [all | name ...]\n", 80239462Sdim getprogname()); 81239462Sdim fprintf(stderr, 82239462Sdim " %s status [-d] [-c config] [all | name ...]\n", 83239462Sdim getprogname()); 84239462Sdim fprintf(stderr, 85239462Sdim " %s dump [-d] [-c config] [all | name ...]\n", 86239462Sdim getprogname()); 87239462Sdim exit(EX_USAGE); 88239462Sdim} 89239462Sdim 90239462Sdimstatic int 91239462Sdimcreate_one(struct hast_resource *res, intmax_t mediasize, intmax_t extentsize, 92239462Sdim intmax_t keepdirty) 93239462Sdim{ 94239462Sdim unsigned char *buf; 95239462Sdim size_t mapsize; 96239462Sdim int ec; 97239462Sdim 98239462Sdim ec = 0; 99239462Sdim pjdlog_prefix_set("[%s] ", res->hr_name); 100239462Sdim 101239462Sdim if (provinfo(res, true) == -1) { 102239462Sdim ec = EX_NOINPUT; 103239462Sdim goto end; 104239462Sdim } 105239462Sdim if (mediasize == 0) 106239462Sdim mediasize = res->hr_local_mediasize; 107239462Sdim else if (mediasize > res->hr_local_mediasize) { 108239462Sdim pjdlog_error("Provided mediasize is larger than provider %s size.", 109239462Sdim res->hr_localpath); 110239462Sdim ec = EX_DATAERR; 111239462Sdim goto end; 112239462Sdim } 113239462Sdim if (!powerof2(res->hr_local_sectorsize)) { 114239462Sdim pjdlog_error("Sector size of provider %s is not power of 2 (%u).", 115239462Sdim res->hr_localpath, res->hr_local_sectorsize); 116239462Sdim ec = EX_DATAERR; 117239462Sdim goto end; 118239462Sdim } 119239462Sdim if (extentsize == 0) 120239462Sdim extentsize = HAST_EXTENTSIZE; 121239462Sdim if (extentsize < res->hr_local_sectorsize) { 122239462Sdim pjdlog_error("Extent size (%jd) is less than sector size (%u).", 123218885Sdim (intmax_t)extentsize, res->hr_local_sectorsize); 124218885Sdim ec = EX_DATAERR; 125218885Sdim goto end; 126218885Sdim } 127218885Sdim if ((extentsize % res->hr_local_sectorsize) != 0) { 128218885Sdim pjdlog_error("Extent size (%jd) is not multiple of sector size (%u).", 129218885Sdim (intmax_t)extentsize, res->hr_local_sectorsize); 130218885Sdim ec = EX_DATAERR; 131218885Sdim goto end; 132218885Sdim } 133218885Sdim mapsize = activemap_calc_ondisk_size(mediasize - METADATA_SIZE, 134218885Sdim extentsize, res->hr_local_sectorsize); 135218885Sdim if (keepdirty == 0) 136218885Sdim keepdirty = HAST_KEEPDIRTY; 137218885Sdim res->hr_datasize = mediasize - METADATA_SIZE - mapsize; 138218885Sdim res->hr_extentsize = extentsize; 139218885Sdim res->hr_keepdirty = keepdirty; 140218885Sdim 141218885Sdim res->hr_localoff = METADATA_SIZE + mapsize; 142218885Sdim 143218885Sdim if (metadata_write(res) == -1) { 144234353Sdim ec = EX_IOERR; 145243830Sdim goto end; 146218885Sdim } 147218885Sdim buf = calloc(1, mapsize); 148218885Sdim if (buf == NULL) { 149218885Sdim pjdlog_error("Unable to allocate %zu bytes of memory for initial bitmap.", 150218885Sdim mapsize); 151218885Sdim ec = EX_TEMPFAIL; 152234353Sdim goto end; 153239462Sdim } 154218885Sdim if (pwrite(res->hr_localfd, buf, mapsize, METADATA_SIZE) != 155218885Sdim (ssize_t)mapsize) { 156218885Sdim pjdlog_errno(LOG_ERR, "Unable to store initial bitmap on %s", 157218885Sdim res->hr_localpath); 158218885Sdim free(buf); 159218885Sdim ec = EX_IOERR; 160218885Sdim goto end; 161218885Sdim } 162218885Sdim free(buf); 163218885Sdimend: 164218885Sdim if (res->hr_localfd >= 0) 165234353Sdim close(res->hr_localfd); 166218885Sdim pjdlog_prefix_set("%s", ""); 167218885Sdim return (ec); 168218885Sdim} 169218885Sdim 170218885Sdimstatic void 171218885Sdimcontrol_create(int argc, char *argv[], intmax_t mediasize, intmax_t extentsize, 172218885Sdim intmax_t keepdirty) 173218885Sdim{ 174218885Sdim struct hast_resource *res; 175218885Sdim int ec, ii, ret; 176239462Sdim 177218885Sdim /* Initialize the given resources. */ 178239462Sdim if (argc < 1) 179218885Sdim usage(); 180218885Sdim ec = 0; 181226633Sdim for (ii = 0; ii < argc; ii++) { 182218885Sdim TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 183218885Sdim if (strcmp(argv[ii], res->hr_name) == 0) 184218885Sdim break; 185218885Sdim } 186218885Sdim if (res == NULL) { 187218885Sdim pjdlog_error("Unknown resource %s.", argv[ii]); 188218885Sdim if (ec == 0) 189218885Sdim ec = EX_DATAERR; 190218885Sdim continue; 191218885Sdim } 192218885Sdim ret = create_one(res, mediasize, extentsize, keepdirty); 193218885Sdim if (ret != 0 && ec == 0) 194218885Sdim ec = ret; 195218885Sdim } 196218885Sdim exit(ec); 197218885Sdim} 198218885Sdim 199218885Sdimstatic int 200218885Sdimdump_one(struct hast_resource *res) 201218885Sdim{ 202218885Sdim int ret; 203218885Sdim 204218885Sdim ret = metadata_read(res, false); 205218885Sdim if (ret != 0) 206218885Sdim return (ret); 207218885Sdim 208218885Sdim printf("resource: %s\n", res->hr_name); 209218885Sdim printf(" datasize: %ju (%NB)\n", (uintmax_t)res->hr_datasize, 210218885Sdim (intmax_t)res->hr_datasize); 211218885Sdim printf(" extentsize: %d (%NB)\n", res->hr_extentsize, 212218885Sdim (intmax_t)res->hr_extentsize); 213218885Sdim printf(" keepdirty: %d\n", res->hr_keepdirty); 214218885Sdim printf(" localoff: %ju\n", (uintmax_t)res->hr_localoff); 215218885Sdim printf(" resuid: %ju\n", (uintmax_t)res->hr_resuid); 216218885Sdim printf(" localcnt: %ju\n", (uintmax_t)res->hr_primary_localcnt); 217218885Sdim printf(" remotecnt: %ju\n", (uintmax_t)res->hr_primary_remotecnt); 218218885Sdim printf(" prevrole: %s\n", role2str(res->hr_previous_role)); 219239462Sdim 220218885Sdim return (0); 221218885Sdim} 222234353Sdim 223218885Sdimstatic void 224218885Sdimcontrol_dump(int argc, char *argv[]) 225218885Sdim{ 226218885Sdim struct hast_resource *res; 227218885Sdim int ec, ret; 228218885Sdim 229218885Sdim /* Dump metadata of the given resource(s). */ 230218885Sdim 231218885Sdim ec = 0; 232218885Sdim if (argc == 0 || (argc == 1 && strcmp(argv[0], "all") == 0)) { 233218885Sdim TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 234234353Sdim ret = dump_one(res); 235218885Sdim if (ret != 0 && ec == 0) 236218885Sdim ec = ret; 237218885Sdim } 238218885Sdim } else { 239218885Sdim int ii; 240218885Sdim 241218885Sdim for (ii = 0; ii < argc; ii++) { 242218885Sdim TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 243234353Sdim if (strcmp(argv[ii], res->hr_name) == 0) 244234353Sdim break; 245218885Sdim } 246218885Sdim if (res == NULL) { 247218885Sdim pjdlog_error("Unknown resource %s.", argv[ii]); 248218885Sdim if (ec == 0) 249218885Sdim ec = EX_DATAERR; 250234353Sdim continue; 251218885Sdim } 252218885Sdim ret = dump_one(res); 253218885Sdim if (ret != 0 && ec == 0) 254218885Sdim ec = ret; 255218885Sdim } 256218885Sdim } 257218885Sdim exit(ec); 258218885Sdim} 259218885Sdim 260218885Sdimstatic int 261218885Sdimcontrol_set_role(struct nv *nv, const char *newrole) 262218885Sdim{ 263218885Sdim const char *res, *oldrole; 264218885Sdim unsigned int ii; 265218885Sdim int error, ret; 266218885Sdim 267218885Sdim ret = 0; 268218885Sdim 269239462Sdim for (ii = 0; ; ii++) { 270239462Sdim res = nv_get_string(nv, "resource%u", ii); 271239462Sdim if (res == NULL) 272218885Sdim break; 273218885Sdim pjdlog_prefix_set("[%s] ", res); 274218885Sdim error = nv_get_int16(nv, "error%u", ii); 275218885Sdim if (error != 0) { 276218885Sdim if (ret == 0) 277239462Sdim ret = error; 278218885Sdim pjdlog_warning("Received error %d from hastd.", error); 279218885Sdim continue; 280218885Sdim } 281218885Sdim oldrole = nv_get_string(nv, "role%u", ii); 282218885Sdim if (strcmp(oldrole, newrole) == 0) 283218885Sdim pjdlog_debug(2, "Role unchanged (%s).", oldrole); 284218885Sdim else { 285218885Sdim pjdlog_debug(1, "Role changed from %s to %s.", oldrole, 286218885Sdim newrole); 287218885Sdim } 288218885Sdim } 289218885Sdim pjdlog_prefix_set("%s", ""); 290218885Sdim return (ret); 291218885Sdim} 292218885Sdim 293218885Sdimstatic int 294218885Sdimcontrol_list(struct nv *nv) 295218885Sdim{ 296218885Sdim pid_t pid; 297218885Sdim unsigned int ii; 298218885Sdim const char *str; 299218885Sdim int error, ret; 300218885Sdim 301218885Sdim ret = 0; 302218885Sdim 303218885Sdim for (ii = 0; ; ii++) { 304239462Sdim str = nv_get_string(nv, "resource%u", ii); 305218885Sdim if (str == NULL) 306218885Sdim break; 307218885Sdim printf("%s:\n", str); 308218885Sdim error = nv_get_int16(nv, "error%u", ii); 309218885Sdim if (error != 0) { 310218885Sdim if (ret == 0) 311218885Sdim ret = error; 312218885Sdim printf(" error: %d\n", error); 313234353Sdim continue; 314218885Sdim } 315218885Sdim printf(" role: %s\n", nv_get_string(nv, "role%u", ii)); 316234353Sdim printf(" provname: %s\n", 317218885Sdim nv_get_string(nv, "provname%u", ii)); 318218885Sdim printf(" localpath: %s\n", 319218885Sdim nv_get_string(nv, "localpath%u", ii)); 320218885Sdim printf(" extentsize: %u (%NB)\n", 321218885Sdim (unsigned int)nv_get_uint32(nv, "extentsize%u", ii), 322218885Sdim (intmax_t)nv_get_uint32(nv, "extentsize%u", ii)); 323226633Sdim printf(" keepdirty: %u\n", 324218885Sdim (unsigned int)nv_get_uint32(nv, "keepdirty%u", ii)); 325218885Sdim printf(" remoteaddr: %s\n", 326234353Sdim nv_get_string(nv, "remoteaddr%u", ii)); 327218885Sdim str = nv_get_string(nv, "sourceaddr%u", ii); 328218885Sdim if (str != NULL) 329218885Sdim printf(" sourceaddr: %s\n", str); 330218885Sdim printf(" replication: %s\n", 331226633Sdim nv_get_string(nv, "replication%u", ii)); 332226633Sdim str = nv_get_string(nv, "status%u", ii); 333226633Sdim if (str != NULL) 334226633Sdim printf(" status: %s\n", str); 335226633Sdim pid = nv_get_int32(nv, "workerpid%u", ii); 336226633Sdim if (pid != 0) 337218885Sdim printf(" workerpid: %d\n", pid); 338234353Sdim printf(" dirty: %ju (%NB)\n", 339234353Sdim (uintmax_t)nv_get_uint64(nv, "dirty%u", ii), 340226633Sdim (intmax_t)nv_get_uint64(nv, "dirty%u", ii)); 341226633Sdim printf(" statistics:\n"); 342234353Sdim printf(" reads: %ju\n", 343234353Sdim (uintmax_t)nv_get_uint64(nv, "stat_read%u", ii)); 344218885Sdim printf(" writes: %ju\n", 345218885Sdim (uintmax_t)nv_get_uint64(nv, "stat_write%u", ii)); 346218885Sdim printf(" deletes: %ju\n", 347234353Sdim (uintmax_t)nv_get_uint64(nv, "stat_delete%u", ii)); 348226633Sdim printf(" flushes: %ju\n", 349234353Sdim (uintmax_t)nv_get_uint64(nv, "stat_flush%u", ii)); 350234353Sdim printf(" activemap updates: %ju\n", 351226633Sdim (uintmax_t)nv_get_uint64(nv, "stat_activemap_update%u", ii)); 352226633Sdim printf(" local errors: " 353226633Sdim "read: %ju, write: %ju, delete: %ju, flush: %ju\n", 354218885Sdim (uintmax_t)nv_get_uint64(nv, "stat_read_error%u", ii), 355218885Sdim (uintmax_t)nv_get_uint64(nv, "stat_write_error%u", ii), 356218885Sdim (uintmax_t)nv_get_uint64(nv, "stat_delete_error%u", ii), 357218885Sdim (uintmax_t)nv_get_uint64(nv, "stat_flush_error%u", ii)); 358218885Sdim printf(" queues: " 359218885Sdim "local: %ju, send: %ju, recv: %ju, done: %ju, idle: %ju\n", 360234353Sdim (uintmax_t)nv_get_uint64(nv, "local_queue_size%u", ii), 361234353Sdim (uintmax_t)nv_get_uint64(nv, "send_queue_size%u", ii), 362234353Sdim (uintmax_t)nv_get_uint64(nv, "recv_queue_size%u", ii), 363234353Sdim (uintmax_t)nv_get_uint64(nv, "done_queue_size%u", ii), 364226633Sdim (uintmax_t)nv_get_uint64(nv, "idle_queue_size%u", ii)); 365226633Sdim } 366226633Sdim return (ret); 367218885Sdim} 368218885Sdim 369218885Sdimstatic int 370239462Sdimcontrol_status(struct nv *nv) 371218885Sdim{ 372218885Sdim unsigned int ii; 373218885Sdim const char *str; 374218885Sdim int error, hprinted, ret; 375218885Sdim 376218885Sdim hprinted = 0; 377234353Sdim ret = 0; 378234353Sdim 379234353Sdim for (ii = 0; ; ii++) { 380234353Sdim str = nv_get_string(nv, "resource%u", ii); 381234353Sdim if (str == NULL) 382234353Sdim break; 383234353Sdim if (!hprinted) { 384234353Sdim printf("Name\tStatus\t Role\t\tComponents\n"); 385234353Sdim hprinted = 1; 386234353Sdim } 387234353Sdim printf("%s\t", str); 388234353Sdim error = nv_get_int16(nv, "error%u", ii); 389234353Sdim if (error != 0) { 390234353Sdim if (ret == 0) 391218885Sdim ret = error; 392218885Sdim printf("ERR%d\n", error); 393218885Sdim continue; 394218885Sdim } 395218885Sdim str = nv_get_string(nv, "status%u", ii); 396218885Sdim printf("%-9s", (str != NULL) ? str : "-"); 397218885Sdim printf("%-15s", nv_get_string(nv, "role%u", ii)); 398218885Sdim printf("%s\t", 399218885Sdim nv_get_string(nv, "localpath%u", ii)); 400218885Sdim printf("%s\n", 401218885Sdim nv_get_string(nv, "remoteaddr%u", ii)); 402218885Sdim } 403218885Sdim return (ret); 404234353Sdim} 405218885Sdim 406218885Sdimint 407218885Sdimmain(int argc, char *argv[]) 408234353Sdim{ 409234353Sdim struct nv *nv; 410218885Sdim int64_t mediasize, extentsize, keepdirty; 411218885Sdim int cmd, debug, error, ii; 412218885Sdim const char *optstr; 413234353Sdim 414218885Sdim debug = 0; 415218885Sdim mediasize = extentsize = keepdirty = 0; 416218885Sdim 417218885Sdim if (argc == 1) 418218885Sdim usage(); 419218885Sdim 420218885Sdim if (strcmp(argv[1], "create") == 0) { 421234353Sdim cmd = CMD_CREATE; 422218885Sdim optstr = "c:de:k:m:h"; 423234353Sdim } else if (strcmp(argv[1], "role") == 0) { 424218885Sdim cmd = CMD_ROLE; 425218885Sdim optstr = "c:dh"; 426218885Sdim } else if (strcmp(argv[1], "list") == 0) { 427218885Sdim cmd = CMD_LIST; 428218885Sdim optstr = "c:dh"; 429218885Sdim } else if (strcmp(argv[1], "status") == 0) { 430218885Sdim cmd = CMD_STATUS; 431218885Sdim optstr = "c:dh"; 432234353Sdim } else if (strcmp(argv[1], "dump") == 0) { 433234353Sdim cmd = CMD_DUMP; 434234353Sdim optstr = "c:dh"; 435218885Sdim } else 436226633Sdim usage(); 437226633Sdim 438234353Sdim argc--; 439234353Sdim argv++; 440226633Sdim 441239462Sdim for (;;) { 442239462Sdim int ch; 443239462Sdim 444239462Sdim ch = getopt(argc, argv, optstr); 445234353Sdim if (ch == -1) 446239462Sdim break; 447239462Sdim switch (ch) { 448218885Sdim case 'c': 449239462Sdim cfgpath = optarg; 450239462Sdim break; 451239462Sdim case 'd': 452239462Sdim debug++; 453218885Sdim break; 454239462Sdim case 'e': 455239462Sdim if (expand_number(optarg, &extentsize) == -1) 456218885Sdim errx(EX_USAGE, "Invalid extentsize"); 457239462Sdim break; 458234353Sdim case 'k': 459226633Sdim if (expand_number(optarg, &keepdirty) == -1) 460239462Sdim errx(EX_USAGE, "Invalid keepdirty"); 461239462Sdim break; 462239462Sdim case 'm': 463218885Sdim if (expand_number(optarg, &mediasize) == -1) 464234353Sdim errx(EX_USAGE, "Invalid mediasize"); 465218885Sdim break; 466218885Sdim case 'h': 467218885Sdim default: 468218885Sdim usage(); 469234353Sdim } 470218885Sdim } 471218885Sdim argc -= optind; 472218885Sdim argv += optind; 473218885Sdim 474218885Sdim switch (cmd) { 475218885Sdim case CMD_CREATE: 476218885Sdim case CMD_ROLE: 477218885Sdim if (argc == 0) 478218885Sdim usage(); 479218885Sdim break; 480218885Sdim } 481239462Sdim 482239462Sdim pjdlog_init(PJDLOG_MODE_STD); 483239462Sdim pjdlog_debug_set(debug); 484239462Sdim 485218885Sdim cfg = yy_config_parse(cfgpath, true); 486239462Sdim PJDLOG_ASSERT(cfg != NULL); 487218885Sdim 488218885Sdim switch (cmd) { 489218885Sdim case CMD_CREATE: 490234353Sdim control_create(argc, argv, mediasize, extentsize, keepdirty); 491218885Sdim /* NOTREACHED */ 492218885Sdim PJDLOG_ABORT("What are we doing here?!"); 493218885Sdim break; 494234353Sdim case CMD_DUMP: 495234353Sdim /* Dump metadata from local component of the given resource. */ 496234353Sdim control_dump(argc, argv); 497234353Sdim /* NOTREACHED */ 498234353Sdim PJDLOG_ABORT("What are we doing here?!"); 499234353Sdim break; 500218885Sdim case CMD_ROLE: 501218885Sdim /* Change role for the given resources. */ 502218885Sdim if (argc < 2) 503234353Sdim usage(); 504234353Sdim nv = nv_alloc(); 505226633Sdim nv_add_uint8(nv, HASTCTL_CMD_SETROLE, "cmd"); 506218885Sdim if (strcmp(argv[0], "init") == 0) 507218885Sdim nv_add_uint8(nv, HAST_ROLE_INIT, "role"); 508218885Sdim else if (strcmp(argv[0], "primary") == 0) 509218885Sdim nv_add_uint8(nv, HAST_ROLE_PRIMARY, "role"); 510218885Sdim else if (strcmp(argv[0], "secondary") == 0) 511218885Sdim nv_add_uint8(nv, HAST_ROLE_SECONDARY, "role"); 512218885Sdim else 513218885Sdim usage(); 514218885Sdim for (ii = 0; ii < argc - 1; ii++) 515218885Sdim nv_add_string(nv, argv[ii + 1], "resource%d", ii); 516218885Sdim break; 517218885Sdim case CMD_LIST: 518218885Sdim case CMD_STATUS: 519218885Sdim /* Obtain status of the given resources. */ 520218885Sdim nv = nv_alloc(); 521218885Sdim nv_add_uint8(nv, HASTCTL_CMD_STATUS, "cmd"); 522218885Sdim if (argc == 0) 523218885Sdim nv_add_string(nv, "all", "resource%d", 0); 524218885Sdim else { 525218885Sdim for (ii = 0; ii < argc; ii++) 526218885Sdim nv_add_string(nv, argv[ii], "resource%d", ii); 527234353Sdim } 528218885Sdim break; 529218885Sdim default: 530218885Sdim PJDLOG_ABORT("Impossible command!"); 531218885Sdim } 532218885Sdim 533218885Sdim /* Setup control connection... */ 534218885Sdim if (proto_client(NULL, cfg->hc_controladdr, &controlconn) == -1) { 535218885Sdim pjdlog_exit(EX_OSERR, 536218885Sdim "Unable to setup control connection to %s", 537218885Sdim cfg->hc_controladdr); 538234353Sdim } 539218885Sdim /* ...and connect to hastd. */ 540218885Sdim if (proto_connect(controlconn, HAST_TIMEOUT) == -1) { 541218885Sdim pjdlog_exit(EX_OSERR, "Unable to connect to hastd via %s", 542218885Sdim cfg->hc_controladdr); 543218885Sdim } 544218885Sdim 545218885Sdim if (drop_privs(NULL) != 0) 546218885Sdim exit(EX_CONFIG); 547218885Sdim 548218885Sdim /* Send the command to the server... */ 549218885Sdim if (hast_proto_send(NULL, controlconn, nv, NULL, 0) == -1) { 550218885Sdim pjdlog_exit(EX_UNAVAILABLE, 551218885Sdim "Unable to send command to hastd via %s", 552218885Sdim cfg->hc_controladdr); 553218885Sdim } 554218885Sdim nv_free(nv); 555218885Sdim /* ...and receive reply. */ 556226633Sdim if (hast_proto_recv_hdr(controlconn, &nv) == -1) { 557218885Sdim pjdlog_exit(EX_UNAVAILABLE, 558218885Sdim "cannot receive reply from hastd via %s", 559218885Sdim cfg->hc_controladdr); 560239462Sdim } 561218885Sdim 562218885Sdim error = nv_get_int16(nv, "error"); 563221345Sdim if (error != 0) { 564218885Sdim pjdlog_exitx(EX_SOFTWARE, "Error %d received from hastd.", 565234353Sdim error); 566218885Sdim } 567218885Sdim nv_set_error(nv, 0); 568218885Sdim 569218885Sdim switch (cmd) { 570218885Sdim case CMD_ROLE: 571218885Sdim error = control_set_role(nv, argv[0]); 572218885Sdim break; 573218885Sdim case CMD_LIST: 574218885Sdim error = control_list(nv); 575218885Sdim break; 576239462Sdim case CMD_STATUS: 577218885Sdim error = control_status(nv); 578218885Sdim break; 579218885Sdim default: 580218885Sdim PJDLOG_ABORT("Impossible command!"); 581218885Sdim } 582218885Sdim 583218885Sdim exit(error); 584218885Sdim} 585218885Sdim