1204076Spjd/*- 2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 3204076Spjd * All rights reserved. 4204076Spjd * 5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 6204076Spjd * the FreeBSD Foundation. 7204076Spjd * 8204076Spjd * Redistribution and use in source and binary forms, with or without 9204076Spjd * modification, are permitted provided that the following conditions 10204076Spjd * are met: 11204076Spjd * 1. Redistributions of source code must retain the above copyright 12204076Spjd * notice, this list of conditions and the following disclaimer. 13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer in the 15204076Spjd * documentation and/or other materials provided with the distribution. 16204076Spjd * 17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27204076Spjd * SUCH DAMAGE. 28204076Spjd */ 29204076Spjd 30204076Spjd#include <sys/cdefs.h> 31204076Spjd__FBSDID("$FreeBSD$"); 32204076Spjd 33204076Spjd#include <sys/param.h> 34204076Spjd 35204076Spjd#include <err.h> 36219620Strociny#include <libutil.h> 37204076Spjd#include <stdio.h> 38204076Spjd#include <string.h> 39204076Spjd#include <unistd.h> 40204076Spjd 41204076Spjd#include <activemap.h> 42204076Spjd 43204076Spjd#include "hast.h" 44204076Spjd#include "hast_proto.h" 45204076Spjd#include "metadata.h" 46204076Spjd#include "nv.h" 47204076Spjd#include "pjdlog.h" 48204076Spjd#include "proto.h" 49204076Spjd#include "subr.h" 50204076Spjd 51204076Spjd/* Path to configuration file. */ 52204076Spjdstatic const char *cfgpath = HAST_CONFIG; 53204076Spjd/* Hastd configuration. */ 54204076Spjdstatic struct hastd_config *cfg; 55204076Spjd/* Control connection. */ 56204076Spjdstatic struct proto_conn *controlconn; 57204076Spjd 58204076Spjdenum { 59204076Spjd CMD_INVALID, 60204076Spjd CMD_CREATE, 61204076Spjd CMD_ROLE, 62204076Spjd CMD_STATUS, 63251025Smarck CMD_DUMP, 64251025Smarck CMD_LIST 65204076Spjd}; 66204076Spjd 67204076Spjdstatic __dead2 void 68204076Spjdusage(void) 69204076Spjd{ 70204076Spjd 71204076Spjd fprintf(stderr, 72204076Spjd "usage: %s create [-d] [-c config] [-e extentsize] [-k keepdirty]\n" 73204076Spjd "\t\t[-m mediasize] name ...\n", 74204076Spjd getprogname()); 75204076Spjd fprintf(stderr, 76204076Spjd " %s role [-d] [-c config] <init | primary | secondary> all | name ...\n", 77204076Spjd getprogname()); 78204076Spjd fprintf(stderr, 79251025Smarck " %s list [-d] [-c config] [all | name ...]\n", 80251025Smarck getprogname()); 81251025Smarck fprintf(stderr, 82204076Spjd " %s status [-d] [-c config] [all | name ...]\n", 83204076Spjd getprogname()); 84204076Spjd fprintf(stderr, 85204076Spjd " %s dump [-d] [-c config] [all | name ...]\n", 86204076Spjd getprogname()); 87204076Spjd exit(EX_USAGE); 88204076Spjd} 89204076Spjd 90204076Spjdstatic int 91204076Spjdcreate_one(struct hast_resource *res, intmax_t mediasize, intmax_t extentsize, 92204076Spjd intmax_t keepdirty) 93204076Spjd{ 94204076Spjd unsigned char *buf; 95204076Spjd size_t mapsize; 96204076Spjd int ec; 97204076Spjd 98204076Spjd ec = 0; 99204076Spjd pjdlog_prefix_set("[%s] ", res->hr_name); 100204076Spjd 101231017Strociny if (provinfo(res, true) == -1) { 102204076Spjd ec = EX_NOINPUT; 103204076Spjd goto end; 104204076Spjd } 105204076Spjd if (mediasize == 0) 106204076Spjd mediasize = res->hr_local_mediasize; 107204076Spjd else if (mediasize > res->hr_local_mediasize) { 108204076Spjd pjdlog_error("Provided mediasize is larger than provider %s size.", 109204076Spjd res->hr_localpath); 110204076Spjd ec = EX_DATAERR; 111204076Spjd goto end; 112204076Spjd } 113204076Spjd if (!powerof2(res->hr_local_sectorsize)) { 114204076Spjd pjdlog_error("Sector size of provider %s is not power of 2 (%u).", 115204076Spjd res->hr_localpath, res->hr_local_sectorsize); 116204076Spjd ec = EX_DATAERR; 117204076Spjd goto end; 118204076Spjd } 119204076Spjd if (extentsize == 0) 120204076Spjd extentsize = HAST_EXTENTSIZE; 121204076Spjd if (extentsize < res->hr_local_sectorsize) { 122204076Spjd pjdlog_error("Extent size (%jd) is less than sector size (%u).", 123204076Spjd (intmax_t)extentsize, res->hr_local_sectorsize); 124204076Spjd ec = EX_DATAERR; 125204076Spjd goto end; 126204076Spjd } 127204076Spjd if ((extentsize % res->hr_local_sectorsize) != 0) { 128204076Spjd pjdlog_error("Extent size (%jd) is not multiple of sector size (%u).", 129204076Spjd (intmax_t)extentsize, res->hr_local_sectorsize); 130204076Spjd ec = EX_DATAERR; 131204076Spjd goto end; 132204076Spjd } 133204076Spjd mapsize = activemap_calc_ondisk_size(mediasize - METADATA_SIZE, 134204076Spjd extentsize, res->hr_local_sectorsize); 135204076Spjd if (keepdirty == 0) 136204076Spjd keepdirty = HAST_KEEPDIRTY; 137204076Spjd res->hr_datasize = mediasize - METADATA_SIZE - mapsize; 138204076Spjd res->hr_extentsize = extentsize; 139204076Spjd res->hr_keepdirty = keepdirty; 140204076Spjd 141204076Spjd res->hr_localoff = METADATA_SIZE + mapsize; 142204076Spjd 143231017Strociny if (metadata_write(res) == -1) { 144204076Spjd ec = EX_IOERR; 145204076Spjd goto end; 146204076Spjd } 147204076Spjd buf = calloc(1, mapsize); 148204076Spjd if (buf == NULL) { 149204076Spjd pjdlog_error("Unable to allocate %zu bytes of memory for initial bitmap.", 150204076Spjd mapsize); 151204076Spjd ec = EX_TEMPFAIL; 152204076Spjd goto end; 153204076Spjd } 154204076Spjd if (pwrite(res->hr_localfd, buf, mapsize, METADATA_SIZE) != 155204076Spjd (ssize_t)mapsize) { 156204076Spjd pjdlog_errno(LOG_ERR, "Unable to store initial bitmap on %s", 157204076Spjd res->hr_localpath); 158204076Spjd free(buf); 159204076Spjd ec = EX_IOERR; 160204076Spjd goto end; 161204076Spjd } 162204076Spjd free(buf); 163204076Spjdend: 164204076Spjd if (res->hr_localfd >= 0) 165204076Spjd close(res->hr_localfd); 166204076Spjd pjdlog_prefix_set("%s", ""); 167204076Spjd return (ec); 168204076Spjd} 169204076Spjd 170204076Spjdstatic void 171204076Spjdcontrol_create(int argc, char *argv[], intmax_t mediasize, intmax_t extentsize, 172204076Spjd intmax_t keepdirty) 173204076Spjd{ 174204076Spjd struct hast_resource *res; 175204076Spjd int ec, ii, ret; 176204076Spjd 177204076Spjd /* Initialize the given resources. */ 178204076Spjd if (argc < 1) 179204076Spjd usage(); 180204076Spjd ec = 0; 181204076Spjd for (ii = 0; ii < argc; ii++) { 182204076Spjd TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 183204076Spjd if (strcmp(argv[ii], res->hr_name) == 0) 184204076Spjd break; 185204076Spjd } 186204076Spjd if (res == NULL) { 187204076Spjd pjdlog_error("Unknown resource %s.", argv[ii]); 188204076Spjd if (ec == 0) 189204076Spjd ec = EX_DATAERR; 190204076Spjd continue; 191204076Spjd } 192204076Spjd ret = create_one(res, mediasize, extentsize, keepdirty); 193204076Spjd if (ret != 0 && ec == 0) 194204076Spjd ec = ret; 195204076Spjd } 196204076Spjd exit(ec); 197204076Spjd} 198204076Spjd 199204076Spjdstatic int 200204076Spjddump_one(struct hast_resource *res) 201204076Spjd{ 202204076Spjd int ret; 203204076Spjd 204204076Spjd ret = metadata_read(res, false); 205204076Spjd if (ret != 0) 206204076Spjd return (ret); 207204076Spjd 208204076Spjd printf("resource: %s\n", res->hr_name); 209219373Spjd printf(" datasize: %ju (%NB)\n", (uintmax_t)res->hr_datasize, 210219373Spjd (intmax_t)res->hr_datasize); 211219373Spjd printf(" extentsize: %d (%NB)\n", res->hr_extentsize, 212219373Spjd (intmax_t)res->hr_extentsize); 213204076Spjd printf(" keepdirty: %d\n", res->hr_keepdirty); 214204076Spjd printf(" localoff: %ju\n", (uintmax_t)res->hr_localoff); 215204076Spjd printf(" resuid: %ju\n", (uintmax_t)res->hr_resuid); 216204076Spjd printf(" localcnt: %ju\n", (uintmax_t)res->hr_primary_localcnt); 217204076Spjd printf(" remotecnt: %ju\n", (uintmax_t)res->hr_primary_remotecnt); 218204076Spjd printf(" prevrole: %s\n", role2str(res->hr_previous_role)); 219204076Spjd 220204076Spjd return (0); 221204076Spjd} 222204076Spjd 223204076Spjdstatic void 224204076Spjdcontrol_dump(int argc, char *argv[]) 225204076Spjd{ 226204076Spjd struct hast_resource *res; 227204076Spjd int ec, ret; 228204076Spjd 229204076Spjd /* Dump metadata of the given resource(s). */ 230204076Spjd 231204076Spjd ec = 0; 232204076Spjd if (argc == 0 || (argc == 1 && strcmp(argv[0], "all") == 0)) { 233204076Spjd TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 234204076Spjd ret = dump_one(res); 235204076Spjd if (ret != 0 && ec == 0) 236204076Spjd ec = ret; 237204076Spjd } 238204076Spjd } else { 239204076Spjd int ii; 240204076Spjd 241204076Spjd for (ii = 0; ii < argc; ii++) { 242204076Spjd TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 243204076Spjd if (strcmp(argv[ii], res->hr_name) == 0) 244204076Spjd break; 245204076Spjd } 246204076Spjd if (res == NULL) { 247204076Spjd pjdlog_error("Unknown resource %s.", argv[ii]); 248204076Spjd if (ec == 0) 249204076Spjd ec = EX_DATAERR; 250204076Spjd continue; 251204076Spjd } 252204076Spjd ret = dump_one(res); 253204076Spjd if (ret != 0 && ec == 0) 254204076Spjd ec = ret; 255204076Spjd } 256204076Spjd } 257204076Spjd exit(ec); 258204076Spjd} 259204076Spjd 260204076Spjdstatic int 261204076Spjdcontrol_set_role(struct nv *nv, const char *newrole) 262204076Spjd{ 263204076Spjd const char *res, *oldrole; 264204076Spjd unsigned int ii; 265204076Spjd int error, ret; 266204076Spjd 267204076Spjd ret = 0; 268204076Spjd 269204076Spjd for (ii = 0; ; ii++) { 270204076Spjd res = nv_get_string(nv, "resource%u", ii); 271204076Spjd if (res == NULL) 272204076Spjd break; 273204076Spjd pjdlog_prefix_set("[%s] ", res); 274204076Spjd error = nv_get_int16(nv, "error%u", ii); 275204076Spjd if (error != 0) { 276204076Spjd if (ret == 0) 277204076Spjd ret = error; 278204076Spjd pjdlog_warning("Received error %d from hastd.", error); 279204076Spjd continue; 280204076Spjd } 281204076Spjd oldrole = nv_get_string(nv, "role%u", ii); 282204076Spjd if (strcmp(oldrole, newrole) == 0) 283204076Spjd pjdlog_debug(2, "Role unchanged (%s).", oldrole); 284204076Spjd else { 285204076Spjd pjdlog_debug(1, "Role changed from %s to %s.", oldrole, 286204076Spjd newrole); 287204076Spjd } 288204076Spjd } 289204076Spjd pjdlog_prefix_set("%s", ""); 290204076Spjd return (ret); 291204076Spjd} 292204076Spjd 293204076Spjdstatic int 294252776Smarckcontrol_list(struct nv *nv) 295204076Spjd{ 296252818Strociny pid_t pid; 297204076Spjd unsigned int ii; 298204076Spjd const char *str; 299204076Spjd int error, ret; 300204076Spjd 301204076Spjd ret = 0; 302204076Spjd 303204076Spjd for (ii = 0; ; ii++) { 304204076Spjd str = nv_get_string(nv, "resource%u", ii); 305204076Spjd if (str == NULL) 306204076Spjd break; 307204076Spjd printf("%s:\n", str); 308204076Spjd error = nv_get_int16(nv, "error%u", ii); 309204076Spjd if (error != 0) { 310204076Spjd if (ret == 0) 311204076Spjd ret = error; 312204076Spjd printf(" error: %d\n", error); 313204076Spjd continue; 314204076Spjd } 315204076Spjd printf(" role: %s\n", nv_get_string(nv, "role%u", ii)); 316204076Spjd printf(" provname: %s\n", 317204076Spjd nv_get_string(nv, "provname%u", ii)); 318204076Spjd printf(" localpath: %s\n", 319204076Spjd nv_get_string(nv, "localpath%u", ii)); 320219373Spjd printf(" extentsize: %u (%NB)\n", 321219373Spjd (unsigned int)nv_get_uint32(nv, "extentsize%u", ii), 322219373Spjd (intmax_t)nv_get_uint32(nv, "extentsize%u", ii)); 323204076Spjd printf(" keepdirty: %u\n", 324204076Spjd (unsigned int)nv_get_uint32(nv, "keepdirty%u", ii)); 325204076Spjd printf(" remoteaddr: %s\n", 326204076Spjd nv_get_string(nv, "remoteaddr%u", ii)); 327219821Spjd str = nv_get_string(nv, "sourceaddr%u", ii); 328219821Spjd if (str != NULL) 329219821Spjd printf(" sourceaddr: %s\n", str); 330204076Spjd printf(" replication: %s\n", 331204076Spjd nv_get_string(nv, "replication%u", ii)); 332204076Spjd str = nv_get_string(nv, "status%u", ii); 333204076Spjd if (str != NULL) 334204076Spjd printf(" status: %s\n", str); 335252818Strociny pid = nv_get_int32(nv, "workerpid%u", ii); 336252818Strociny if (pid != 0) 337252818Strociny printf(" workerpid: %d\n", pid); 338219373Spjd printf(" dirty: %ju (%NB)\n", 339219373Spjd (uintmax_t)nv_get_uint64(nv, "dirty%u", ii), 340219373Spjd (intmax_t)nv_get_uint64(nv, "dirty%u", ii)); 341222228Spjd printf(" statistics:\n"); 342222228Spjd printf(" reads: %ju\n", 343247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_read%u", ii)); 344222228Spjd printf(" writes: %ju\n", 345247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_write%u", ii)); 346222228Spjd printf(" deletes: %ju\n", 347247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_delete%u", ii)); 348222228Spjd printf(" flushes: %ju\n", 349247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_flush%u", ii)); 350222228Spjd printf(" activemap updates: %ju\n", 351247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_activemap_update%u", ii)); 352247867Strociny printf(" local errors: " 353247867Strociny "read: %ju, write: %ju, delete: %ju, flush: %ju\n", 354247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_read_error%u", ii), 355247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_write_error%u", ii), 356247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_delete_error%u", ii), 357247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_flush_error%u", ii)); 358260007Strociny printf(" queues: " 359260007Strociny "local: %ju, send: %ju, recv: %ju, done: %ju, idle: %ju\n", 360260007Strociny (uintmax_t)nv_get_uint64(nv, "local_queue_size%u", ii), 361260007Strociny (uintmax_t)nv_get_uint64(nv, "send_queue_size%u", ii), 362260007Strociny (uintmax_t)nv_get_uint64(nv, "recv_queue_size%u", ii), 363260007Strociny (uintmax_t)nv_get_uint64(nv, "done_queue_size%u", ii), 364260007Strociny (uintmax_t)nv_get_uint64(nv, "idle_queue_size%u", ii)); 365204076Spjd } 366204076Spjd return (ret); 367204076Spjd} 368204076Spjd 369252776Smarckstatic int 370252776Smarckcontrol_status(struct nv *nv) 371252776Smarck{ 372252776Smarck unsigned int ii; 373252776Smarck const char *str; 374252776Smarck int error, hprinted, ret; 375252776Smarck 376252776Smarck hprinted = 0; 377252776Smarck ret = 0; 378252776Smarck 379252776Smarck for (ii = 0; ; ii++) { 380252776Smarck str = nv_get_string(nv, "resource%u", ii); 381252776Smarck if (str == NULL) 382252776Smarck break; 383252776Smarck if (!hprinted) { 384252776Smarck printf("Name\tStatus\t Role\t\tComponents\n"); 385252776Smarck hprinted = 1; 386252776Smarck } 387252776Smarck printf("%s\t", str); 388252776Smarck error = nv_get_int16(nv, "error%u", ii); 389252776Smarck if (error != 0) { 390252776Smarck if (ret == 0) 391252776Smarck ret = error; 392252776Smarck printf("ERR%d\n", error); 393252776Smarck continue; 394252776Smarck } 395252776Smarck str = nv_get_string(nv, "status%u", ii); 396252776Smarck printf("%-9s", (str != NULL) ? str : "-"); 397252776Smarck printf("%-15s", nv_get_string(nv, "role%u", ii)); 398252776Smarck printf("%s\t", 399252776Smarck nv_get_string(nv, "localpath%u", ii)); 400252776Smarck printf("%s\n", 401252776Smarck nv_get_string(nv, "remoteaddr%u", ii)); 402252776Smarck } 403252776Smarck return (ret); 404252776Smarck} 405252776Smarck 406204076Spjdint 407204076Spjdmain(int argc, char *argv[]) 408204076Spjd{ 409204076Spjd struct nv *nv; 410219620Strociny int64_t mediasize, extentsize, keepdirty; 411204076Spjd int cmd, debug, error, ii; 412204076Spjd const char *optstr; 413204076Spjd 414204076Spjd debug = 0; 415204076Spjd mediasize = extentsize = keepdirty = 0; 416204076Spjd 417204076Spjd if (argc == 1) 418204076Spjd usage(); 419204076Spjd 420204076Spjd if (strcmp(argv[1], "create") == 0) { 421204076Spjd cmd = CMD_CREATE; 422204076Spjd optstr = "c:de:k:m:h"; 423204076Spjd } else if (strcmp(argv[1], "role") == 0) { 424204076Spjd cmd = CMD_ROLE; 425204076Spjd optstr = "c:dh"; 426251025Smarck } else if (strcmp(argv[1], "list") == 0) { 427251025Smarck cmd = CMD_LIST; 428251025Smarck optstr = "c:dh"; 429204076Spjd } else if (strcmp(argv[1], "status") == 0) { 430204076Spjd cmd = CMD_STATUS; 431204076Spjd optstr = "c:dh"; 432204076Spjd } else if (strcmp(argv[1], "dump") == 0) { 433204076Spjd cmd = CMD_DUMP; 434204076Spjd optstr = "c:dh"; 435204076Spjd } else 436204076Spjd usage(); 437204076Spjd 438204076Spjd argc--; 439204076Spjd argv++; 440204076Spjd 441204076Spjd for (;;) { 442204076Spjd int ch; 443204076Spjd 444204076Spjd ch = getopt(argc, argv, optstr); 445204076Spjd if (ch == -1) 446204076Spjd break; 447204076Spjd switch (ch) { 448204076Spjd case 'c': 449204076Spjd cfgpath = optarg; 450204076Spjd break; 451204076Spjd case 'd': 452204076Spjd debug++; 453204076Spjd break; 454204076Spjd case 'e': 455231017Strociny if (expand_number(optarg, &extentsize) == -1) 456223976Strociny errx(EX_USAGE, "Invalid extentsize"); 457204076Spjd break; 458204076Spjd case 'k': 459231017Strociny if (expand_number(optarg, &keepdirty) == -1) 460223976Strociny errx(EX_USAGE, "Invalid keepdirty"); 461204076Spjd break; 462204076Spjd case 'm': 463231017Strociny if (expand_number(optarg, &mediasize) == -1) 464223976Strociny errx(EX_USAGE, "Invalid mediasize"); 465204076Spjd break; 466204076Spjd case 'h': 467204076Spjd default: 468204076Spjd usage(); 469204076Spjd } 470204076Spjd } 471204076Spjd argc -= optind; 472204076Spjd argv += optind; 473204076Spjd 474204076Spjd switch (cmd) { 475204076Spjd case CMD_CREATE: 476204076Spjd case CMD_ROLE: 477204076Spjd if (argc == 0) 478204076Spjd usage(); 479204076Spjd break; 480204076Spjd } 481204076Spjd 482217965Spjd pjdlog_init(PJDLOG_MODE_STD); 483204076Spjd pjdlog_debug_set(debug); 484204076Spjd 485210909Sdougb cfg = yy_config_parse(cfgpath, true); 486229509Strociny PJDLOG_ASSERT(cfg != NULL); 487204076Spjd 488204076Spjd switch (cmd) { 489204076Spjd case CMD_CREATE: 490204076Spjd control_create(argc, argv, mediasize, extentsize, keepdirty); 491204076Spjd /* NOTREACHED */ 492229509Strociny PJDLOG_ABORT("What are we doing here?!"); 493204076Spjd break; 494204076Spjd case CMD_DUMP: 495204076Spjd /* Dump metadata from local component of the given resource. */ 496204076Spjd control_dump(argc, argv); 497204076Spjd /* NOTREACHED */ 498229509Strociny PJDLOG_ABORT("What are we doing here?!"); 499204076Spjd break; 500204076Spjd case CMD_ROLE: 501204076Spjd /* Change role for the given resources. */ 502204076Spjd if (argc < 2) 503204076Spjd usage(); 504204076Spjd nv = nv_alloc(); 505204076Spjd nv_add_uint8(nv, HASTCTL_CMD_SETROLE, "cmd"); 506204076Spjd if (strcmp(argv[0], "init") == 0) 507204076Spjd nv_add_uint8(nv, HAST_ROLE_INIT, "role"); 508204076Spjd else if (strcmp(argv[0], "primary") == 0) 509204076Spjd nv_add_uint8(nv, HAST_ROLE_PRIMARY, "role"); 510204076Spjd else if (strcmp(argv[0], "secondary") == 0) 511204076Spjd nv_add_uint8(nv, HAST_ROLE_SECONDARY, "role"); 512204076Spjd else 513204076Spjd usage(); 514204076Spjd for (ii = 0; ii < argc - 1; ii++) 515204076Spjd nv_add_string(nv, argv[ii + 1], "resource%d", ii); 516204076Spjd break; 517251025Smarck case CMD_LIST: 518204076Spjd case CMD_STATUS: 519204076Spjd /* Obtain status of the given resources. */ 520204076Spjd nv = nv_alloc(); 521204076Spjd nv_add_uint8(nv, HASTCTL_CMD_STATUS, "cmd"); 522204076Spjd if (argc == 0) 523204076Spjd nv_add_string(nv, "all", "resource%d", 0); 524204076Spjd else { 525204076Spjd for (ii = 0; ii < argc; ii++) 526204076Spjd nv_add_string(nv, argv[ii], "resource%d", ii); 527204076Spjd } 528204076Spjd break; 529204076Spjd default: 530229509Strociny PJDLOG_ABORT("Impossible command!"); 531204076Spjd } 532204076Spjd 533204076Spjd /* Setup control connection... */ 534231017Strociny if (proto_client(NULL, cfg->hc_controladdr, &controlconn) == -1) { 535204076Spjd pjdlog_exit(EX_OSERR, 536204076Spjd "Unable to setup control connection to %s", 537204076Spjd cfg->hc_controladdr); 538204076Spjd } 539204076Spjd /* ...and connect to hastd. */ 540231017Strociny if (proto_connect(controlconn, HAST_TIMEOUT) == -1) { 541204076Spjd pjdlog_exit(EX_OSERR, "Unable to connect to hastd via %s", 542204076Spjd cfg->hc_controladdr); 543204076Spjd } 544218215Spjd 545221899Spjd if (drop_privs(NULL) != 0) 546218215Spjd exit(EX_CONFIG); 547218215Spjd 548204076Spjd /* Send the command to the server... */ 549231017Strociny if (hast_proto_send(NULL, controlconn, nv, NULL, 0) == -1) { 550204076Spjd pjdlog_exit(EX_UNAVAILABLE, 551204076Spjd "Unable to send command to hastd via %s", 552204076Spjd cfg->hc_controladdr); 553204076Spjd } 554204076Spjd nv_free(nv); 555204076Spjd /* ...and receive reply. */ 556231017Strociny if (hast_proto_recv_hdr(controlconn, &nv) == -1) { 557204076Spjd pjdlog_exit(EX_UNAVAILABLE, 558204076Spjd "cannot receive reply from hastd via %s", 559204076Spjd cfg->hc_controladdr); 560204076Spjd } 561204076Spjd 562204076Spjd error = nv_get_int16(nv, "error"); 563204076Spjd if (error != 0) { 564204076Spjd pjdlog_exitx(EX_SOFTWARE, "Error %d received from hastd.", 565204076Spjd error); 566204076Spjd } 567204076Spjd nv_set_error(nv, 0); 568204076Spjd 569204076Spjd switch (cmd) { 570204076Spjd case CMD_ROLE: 571204076Spjd error = control_set_role(nv, argv[0]); 572204076Spjd break; 573251025Smarck case CMD_LIST: 574252776Smarck error = control_list(nv); 575252776Smarck break; 576204076Spjd case CMD_STATUS: 577204076Spjd error = control_status(nv); 578204076Spjd break; 579204076Spjd default: 580229509Strociny PJDLOG_ABORT("Impossible command!"); 581204076Spjd } 582204076Spjd 583204076Spjd exit(error); 584204076Spjd} 585