hastctl.c revision 251025
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: stable/9/sbin/hastctl/hastctl.c 251025 2013-05-27 13:49:55Z marck $"); 32204076Spjd 33204076Spjd#include <sys/param.h> 34204076Spjd#include <sys/disk.h> 35204076Spjd#include <sys/ioctl.h> 36204076Spjd#include <sys/stat.h> 37204076Spjd#include <sys/sysctl.h> 38204076Spjd 39204076Spjd#include <err.h> 40204076Spjd#include <errno.h> 41204076Spjd#include <fcntl.h> 42219620Strociny#include <libutil.h> 43204076Spjd#include <limits.h> 44204076Spjd#include <signal.h> 45204076Spjd#include <stdio.h> 46204076Spjd#include <stdlib.h> 47204076Spjd#include <string.h> 48204076Spjd#include <sysexits.h> 49204076Spjd#include <unistd.h> 50204076Spjd 51204076Spjd#include <activemap.h> 52204076Spjd 53204076Spjd#include "hast.h" 54204076Spjd#include "hast_proto.h" 55204076Spjd#include "metadata.h" 56204076Spjd#include "nv.h" 57204076Spjd#include "pjdlog.h" 58204076Spjd#include "proto.h" 59204076Spjd#include "subr.h" 60204076Spjd 61204076Spjd/* Path to configuration file. */ 62204076Spjdstatic const char *cfgpath = HAST_CONFIG; 63204076Spjd/* Hastd configuration. */ 64204076Spjdstatic struct hastd_config *cfg; 65204076Spjd/* Control connection. */ 66204076Spjdstatic struct proto_conn *controlconn; 67204076Spjd 68204076Spjdenum { 69204076Spjd CMD_INVALID, 70204076Spjd CMD_CREATE, 71204076Spjd CMD_ROLE, 72204076Spjd CMD_STATUS, 73251025Smarck CMD_DUMP, 74251025Smarck CMD_LIST 75204076Spjd}; 76204076Spjd 77204076Spjdstatic __dead2 void 78204076Spjdusage(void) 79204076Spjd{ 80204076Spjd 81204076Spjd fprintf(stderr, 82204076Spjd "usage: %s create [-d] [-c config] [-e extentsize] [-k keepdirty]\n" 83204076Spjd "\t\t[-m mediasize] name ...\n", 84204076Spjd getprogname()); 85204076Spjd fprintf(stderr, 86204076Spjd " %s role [-d] [-c config] <init | primary | secondary> all | name ...\n", 87204076Spjd getprogname()); 88204076Spjd fprintf(stderr, 89251025Smarck " %s list [-d] [-c config] [all | name ...]\n", 90251025Smarck getprogname()); 91251025Smarck fprintf(stderr, 92204076Spjd " %s status [-d] [-c config] [all | name ...]\n", 93204076Spjd getprogname()); 94204076Spjd fprintf(stderr, 95204076Spjd " %s dump [-d] [-c config] [all | name ...]\n", 96204076Spjd getprogname()); 97204076Spjd exit(EX_USAGE); 98204076Spjd} 99204076Spjd 100204076Spjdstatic int 101204076Spjdcreate_one(struct hast_resource *res, intmax_t mediasize, intmax_t extentsize, 102204076Spjd intmax_t keepdirty) 103204076Spjd{ 104204076Spjd unsigned char *buf; 105204076Spjd size_t mapsize; 106204076Spjd int ec; 107204076Spjd 108204076Spjd ec = 0; 109204076Spjd pjdlog_prefix_set("[%s] ", res->hr_name); 110204076Spjd 111231017Strociny if (provinfo(res, true) == -1) { 112204076Spjd ec = EX_NOINPUT; 113204076Spjd goto end; 114204076Spjd } 115204076Spjd if (mediasize == 0) 116204076Spjd mediasize = res->hr_local_mediasize; 117204076Spjd else if (mediasize > res->hr_local_mediasize) { 118204076Spjd pjdlog_error("Provided mediasize is larger than provider %s size.", 119204076Spjd res->hr_localpath); 120204076Spjd ec = EX_DATAERR; 121204076Spjd goto end; 122204076Spjd } 123204076Spjd if (!powerof2(res->hr_local_sectorsize)) { 124204076Spjd pjdlog_error("Sector size of provider %s is not power of 2 (%u).", 125204076Spjd res->hr_localpath, res->hr_local_sectorsize); 126204076Spjd ec = EX_DATAERR; 127204076Spjd goto end; 128204076Spjd } 129204076Spjd if (extentsize == 0) 130204076Spjd extentsize = HAST_EXTENTSIZE; 131204076Spjd if (extentsize < res->hr_local_sectorsize) { 132204076Spjd pjdlog_error("Extent size (%jd) is less than sector size (%u).", 133204076Spjd (intmax_t)extentsize, res->hr_local_sectorsize); 134204076Spjd ec = EX_DATAERR; 135204076Spjd goto end; 136204076Spjd } 137204076Spjd if ((extentsize % res->hr_local_sectorsize) != 0) { 138204076Spjd pjdlog_error("Extent size (%jd) is not multiple of sector size (%u).", 139204076Spjd (intmax_t)extentsize, res->hr_local_sectorsize); 140204076Spjd ec = EX_DATAERR; 141204076Spjd goto end; 142204076Spjd } 143204076Spjd mapsize = activemap_calc_ondisk_size(mediasize - METADATA_SIZE, 144204076Spjd extentsize, res->hr_local_sectorsize); 145204076Spjd if (keepdirty == 0) 146204076Spjd keepdirty = HAST_KEEPDIRTY; 147204076Spjd res->hr_datasize = mediasize - METADATA_SIZE - mapsize; 148204076Spjd res->hr_extentsize = extentsize; 149204076Spjd res->hr_keepdirty = keepdirty; 150204076Spjd 151204076Spjd res->hr_localoff = METADATA_SIZE + mapsize; 152204076Spjd 153231017Strociny if (metadata_write(res) == -1) { 154204076Spjd ec = EX_IOERR; 155204076Spjd goto end; 156204076Spjd } 157204076Spjd buf = calloc(1, mapsize); 158204076Spjd if (buf == NULL) { 159204076Spjd pjdlog_error("Unable to allocate %zu bytes of memory for initial bitmap.", 160204076Spjd mapsize); 161204076Spjd ec = EX_TEMPFAIL; 162204076Spjd goto end; 163204076Spjd } 164204076Spjd if (pwrite(res->hr_localfd, buf, mapsize, METADATA_SIZE) != 165204076Spjd (ssize_t)mapsize) { 166204076Spjd pjdlog_errno(LOG_ERR, "Unable to store initial bitmap on %s", 167204076Spjd res->hr_localpath); 168204076Spjd free(buf); 169204076Spjd ec = EX_IOERR; 170204076Spjd goto end; 171204076Spjd } 172204076Spjd free(buf); 173204076Spjdend: 174204076Spjd if (res->hr_localfd >= 0) 175204076Spjd close(res->hr_localfd); 176204076Spjd pjdlog_prefix_set("%s", ""); 177204076Spjd return (ec); 178204076Spjd} 179204076Spjd 180204076Spjdstatic void 181204076Spjdcontrol_create(int argc, char *argv[], intmax_t mediasize, intmax_t extentsize, 182204076Spjd intmax_t keepdirty) 183204076Spjd{ 184204076Spjd struct hast_resource *res; 185204076Spjd int ec, ii, ret; 186204076Spjd 187204076Spjd /* Initialize the given resources. */ 188204076Spjd if (argc < 1) 189204076Spjd usage(); 190204076Spjd ec = 0; 191204076Spjd for (ii = 0; ii < argc; ii++) { 192204076Spjd TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 193204076Spjd if (strcmp(argv[ii], res->hr_name) == 0) 194204076Spjd break; 195204076Spjd } 196204076Spjd if (res == NULL) { 197204076Spjd pjdlog_error("Unknown resource %s.", argv[ii]); 198204076Spjd if (ec == 0) 199204076Spjd ec = EX_DATAERR; 200204076Spjd continue; 201204076Spjd } 202204076Spjd ret = create_one(res, mediasize, extentsize, keepdirty); 203204076Spjd if (ret != 0 && ec == 0) 204204076Spjd ec = ret; 205204076Spjd } 206204076Spjd exit(ec); 207204076Spjd} 208204076Spjd 209204076Spjdstatic int 210204076Spjddump_one(struct hast_resource *res) 211204076Spjd{ 212204076Spjd int ret; 213204076Spjd 214204076Spjd ret = metadata_read(res, false); 215204076Spjd if (ret != 0) 216204076Spjd return (ret); 217204076Spjd 218204076Spjd printf("resource: %s\n", res->hr_name); 219219373Spjd printf(" datasize: %ju (%NB)\n", (uintmax_t)res->hr_datasize, 220219373Spjd (intmax_t)res->hr_datasize); 221219373Spjd printf(" extentsize: %d (%NB)\n", res->hr_extentsize, 222219373Spjd (intmax_t)res->hr_extentsize); 223204076Spjd printf(" keepdirty: %d\n", res->hr_keepdirty); 224204076Spjd printf(" localoff: %ju\n", (uintmax_t)res->hr_localoff); 225204076Spjd printf(" resuid: %ju\n", (uintmax_t)res->hr_resuid); 226204076Spjd printf(" localcnt: %ju\n", (uintmax_t)res->hr_primary_localcnt); 227204076Spjd printf(" remotecnt: %ju\n", (uintmax_t)res->hr_primary_remotecnt); 228204076Spjd printf(" prevrole: %s\n", role2str(res->hr_previous_role)); 229204076Spjd 230204076Spjd return (0); 231204076Spjd} 232204076Spjd 233204076Spjdstatic void 234204076Spjdcontrol_dump(int argc, char *argv[]) 235204076Spjd{ 236204076Spjd struct hast_resource *res; 237204076Spjd int ec, ret; 238204076Spjd 239204076Spjd /* Dump metadata of the given resource(s). */ 240204076Spjd 241204076Spjd ec = 0; 242204076Spjd if (argc == 0 || (argc == 1 && strcmp(argv[0], "all") == 0)) { 243204076Spjd TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 244204076Spjd ret = dump_one(res); 245204076Spjd if (ret != 0 && ec == 0) 246204076Spjd ec = ret; 247204076Spjd } 248204076Spjd } else { 249204076Spjd int ii; 250204076Spjd 251204076Spjd for (ii = 0; ii < argc; ii++) { 252204076Spjd TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { 253204076Spjd if (strcmp(argv[ii], res->hr_name) == 0) 254204076Spjd break; 255204076Spjd } 256204076Spjd if (res == NULL) { 257204076Spjd pjdlog_error("Unknown resource %s.", argv[ii]); 258204076Spjd if (ec == 0) 259204076Spjd ec = EX_DATAERR; 260204076Spjd continue; 261204076Spjd } 262204076Spjd ret = dump_one(res); 263204076Spjd if (ret != 0 && ec == 0) 264204076Spjd ec = ret; 265204076Spjd } 266204076Spjd } 267204076Spjd exit(ec); 268204076Spjd} 269204076Spjd 270204076Spjdstatic int 271204076Spjdcontrol_set_role(struct nv *nv, const char *newrole) 272204076Spjd{ 273204076Spjd const char *res, *oldrole; 274204076Spjd unsigned int ii; 275204076Spjd int error, ret; 276204076Spjd 277204076Spjd ret = 0; 278204076Spjd 279204076Spjd for (ii = 0; ; ii++) { 280204076Spjd res = nv_get_string(nv, "resource%u", ii); 281204076Spjd if (res == NULL) 282204076Spjd break; 283204076Spjd pjdlog_prefix_set("[%s] ", res); 284204076Spjd error = nv_get_int16(nv, "error%u", ii); 285204076Spjd if (error != 0) { 286204076Spjd if (ret == 0) 287204076Spjd ret = error; 288204076Spjd pjdlog_warning("Received error %d from hastd.", error); 289204076Spjd continue; 290204076Spjd } 291204076Spjd oldrole = nv_get_string(nv, "role%u", ii); 292204076Spjd if (strcmp(oldrole, newrole) == 0) 293204076Spjd pjdlog_debug(2, "Role unchanged (%s).", oldrole); 294204076Spjd else { 295204076Spjd pjdlog_debug(1, "Role changed from %s to %s.", oldrole, 296204076Spjd newrole); 297204076Spjd } 298204076Spjd } 299204076Spjd pjdlog_prefix_set("%s", ""); 300204076Spjd return (ret); 301204076Spjd} 302204076Spjd 303204076Spjdstatic int 304204076Spjdcontrol_status(struct nv *nv) 305204076Spjd{ 306204076Spjd unsigned int ii; 307204076Spjd const char *str; 308204076Spjd int error, ret; 309204076Spjd 310204076Spjd ret = 0; 311204076Spjd 312204076Spjd for (ii = 0; ; ii++) { 313204076Spjd str = nv_get_string(nv, "resource%u", ii); 314204076Spjd if (str == NULL) 315204076Spjd break; 316204076Spjd printf("%s:\n", str); 317204076Spjd error = nv_get_int16(nv, "error%u", ii); 318204076Spjd if (error != 0) { 319204076Spjd if (ret == 0) 320204076Spjd ret = error; 321204076Spjd printf(" error: %d\n", error); 322204076Spjd continue; 323204076Spjd } 324204076Spjd printf(" role: %s\n", nv_get_string(nv, "role%u", ii)); 325204076Spjd printf(" provname: %s\n", 326204076Spjd nv_get_string(nv, "provname%u", ii)); 327204076Spjd printf(" localpath: %s\n", 328204076Spjd nv_get_string(nv, "localpath%u", ii)); 329219373Spjd printf(" extentsize: %u (%NB)\n", 330219373Spjd (unsigned int)nv_get_uint32(nv, "extentsize%u", ii), 331219373Spjd (intmax_t)nv_get_uint32(nv, "extentsize%u", ii)); 332204076Spjd printf(" keepdirty: %u\n", 333204076Spjd (unsigned int)nv_get_uint32(nv, "keepdirty%u", ii)); 334204076Spjd printf(" remoteaddr: %s\n", 335204076Spjd nv_get_string(nv, "remoteaddr%u", ii)); 336219821Spjd str = nv_get_string(nv, "sourceaddr%u", ii); 337219821Spjd if (str != NULL) 338219821Spjd printf(" sourceaddr: %s\n", str); 339204076Spjd printf(" replication: %s\n", 340204076Spjd nv_get_string(nv, "replication%u", ii)); 341204076Spjd str = nv_get_string(nv, "status%u", ii); 342204076Spjd if (str != NULL) 343204076Spjd printf(" status: %s\n", str); 344219373Spjd printf(" dirty: %ju (%NB)\n", 345219373Spjd (uintmax_t)nv_get_uint64(nv, "dirty%u", ii), 346219373Spjd (intmax_t)nv_get_uint64(nv, "dirty%u", ii)); 347222228Spjd printf(" statistics:\n"); 348222228Spjd printf(" reads: %ju\n", 349247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_read%u", ii)); 350222228Spjd printf(" writes: %ju\n", 351247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_write%u", ii)); 352222228Spjd printf(" deletes: %ju\n", 353247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_delete%u", ii)); 354222228Spjd printf(" flushes: %ju\n", 355247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_flush%u", ii)); 356222228Spjd printf(" activemap updates: %ju\n", 357247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_activemap_update%u", ii)); 358247867Strociny printf(" local errors: " 359247867Strociny "read: %ju, write: %ju, delete: %ju, flush: %ju\n", 360247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_read_error%u", ii), 361247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_write_error%u", ii), 362247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_delete_error%u", ii), 363247867Strociny (uintmax_t)nv_get_uint64(nv, "stat_flush_error%u", ii)); 364204076Spjd } 365204076Spjd return (ret); 366204076Spjd} 367204076Spjd 368204076Spjdint 369204076Spjdmain(int argc, char *argv[]) 370204076Spjd{ 371204076Spjd struct nv *nv; 372219620Strociny int64_t mediasize, extentsize, keepdirty; 373204076Spjd int cmd, debug, error, ii; 374204076Spjd const char *optstr; 375204076Spjd 376204076Spjd debug = 0; 377204076Spjd mediasize = extentsize = keepdirty = 0; 378204076Spjd 379204076Spjd if (argc == 1) 380204076Spjd usage(); 381204076Spjd 382204076Spjd if (strcmp(argv[1], "create") == 0) { 383204076Spjd cmd = CMD_CREATE; 384204076Spjd optstr = "c:de:k:m:h"; 385204076Spjd } else if (strcmp(argv[1], "role") == 0) { 386204076Spjd cmd = CMD_ROLE; 387204076Spjd optstr = "c:dh"; 388251025Smarck } else if (strcmp(argv[1], "list") == 0) { 389251025Smarck cmd = CMD_LIST; 390251025Smarck optstr = "c:dh"; 391204076Spjd } else if (strcmp(argv[1], "status") == 0) { 392204076Spjd cmd = CMD_STATUS; 393204076Spjd optstr = "c:dh"; 394204076Spjd } else if (strcmp(argv[1], "dump") == 0) { 395204076Spjd cmd = CMD_DUMP; 396204076Spjd optstr = "c:dh"; 397204076Spjd } else 398204076Spjd usage(); 399204076Spjd 400204076Spjd argc--; 401204076Spjd argv++; 402204076Spjd 403204076Spjd for (;;) { 404204076Spjd int ch; 405204076Spjd 406204076Spjd ch = getopt(argc, argv, optstr); 407204076Spjd if (ch == -1) 408204076Spjd break; 409204076Spjd switch (ch) { 410204076Spjd case 'c': 411204076Spjd cfgpath = optarg; 412204076Spjd break; 413204076Spjd case 'd': 414204076Spjd debug++; 415204076Spjd break; 416204076Spjd case 'e': 417231017Strociny if (expand_number(optarg, &extentsize) == -1) 418223976Strociny errx(EX_USAGE, "Invalid extentsize"); 419204076Spjd break; 420204076Spjd case 'k': 421231017Strociny if (expand_number(optarg, &keepdirty) == -1) 422223976Strociny errx(EX_USAGE, "Invalid keepdirty"); 423204076Spjd break; 424204076Spjd case 'm': 425231017Strociny if (expand_number(optarg, &mediasize) == -1) 426223976Strociny errx(EX_USAGE, "Invalid mediasize"); 427204076Spjd break; 428204076Spjd case 'h': 429204076Spjd default: 430204076Spjd usage(); 431204076Spjd } 432204076Spjd } 433204076Spjd argc -= optind; 434204076Spjd argv += optind; 435204076Spjd 436204076Spjd switch (cmd) { 437204076Spjd case CMD_CREATE: 438204076Spjd case CMD_ROLE: 439204076Spjd if (argc == 0) 440204076Spjd usage(); 441204076Spjd break; 442204076Spjd } 443204076Spjd 444217965Spjd pjdlog_init(PJDLOG_MODE_STD); 445204076Spjd pjdlog_debug_set(debug); 446204076Spjd 447210909Sdougb cfg = yy_config_parse(cfgpath, true); 448229509Strociny PJDLOG_ASSERT(cfg != NULL); 449204076Spjd 450204076Spjd switch (cmd) { 451204076Spjd case CMD_CREATE: 452204076Spjd control_create(argc, argv, mediasize, extentsize, keepdirty); 453204076Spjd /* NOTREACHED */ 454229509Strociny PJDLOG_ABORT("What are we doing here?!"); 455204076Spjd break; 456204076Spjd case CMD_DUMP: 457204076Spjd /* Dump metadata from local component of the given resource. */ 458204076Spjd control_dump(argc, argv); 459204076Spjd /* NOTREACHED */ 460229509Strociny PJDLOG_ABORT("What are we doing here?!"); 461204076Spjd break; 462204076Spjd case CMD_ROLE: 463204076Spjd /* Change role for the given resources. */ 464204076Spjd if (argc < 2) 465204076Spjd usage(); 466204076Spjd nv = nv_alloc(); 467204076Spjd nv_add_uint8(nv, HASTCTL_CMD_SETROLE, "cmd"); 468204076Spjd if (strcmp(argv[0], "init") == 0) 469204076Spjd nv_add_uint8(nv, HAST_ROLE_INIT, "role"); 470204076Spjd else if (strcmp(argv[0], "primary") == 0) 471204076Spjd nv_add_uint8(nv, HAST_ROLE_PRIMARY, "role"); 472204076Spjd else if (strcmp(argv[0], "secondary") == 0) 473204076Spjd nv_add_uint8(nv, HAST_ROLE_SECONDARY, "role"); 474204076Spjd else 475204076Spjd usage(); 476204076Spjd for (ii = 0; ii < argc - 1; ii++) 477204076Spjd nv_add_string(nv, argv[ii + 1], "resource%d", ii); 478204076Spjd break; 479251025Smarck case CMD_LIST: 480204076Spjd case CMD_STATUS: 481204076Spjd /* Obtain status of the given resources. */ 482204076Spjd nv = nv_alloc(); 483204076Spjd nv_add_uint8(nv, HASTCTL_CMD_STATUS, "cmd"); 484204076Spjd if (argc == 0) 485204076Spjd nv_add_string(nv, "all", "resource%d", 0); 486204076Spjd else { 487204076Spjd for (ii = 0; ii < argc; ii++) 488204076Spjd nv_add_string(nv, argv[ii], "resource%d", ii); 489204076Spjd } 490204076Spjd break; 491204076Spjd default: 492229509Strociny PJDLOG_ABORT("Impossible command!"); 493204076Spjd } 494204076Spjd 495204076Spjd /* Setup control connection... */ 496231017Strociny if (proto_client(NULL, cfg->hc_controladdr, &controlconn) == -1) { 497204076Spjd pjdlog_exit(EX_OSERR, 498204076Spjd "Unable to setup control connection to %s", 499204076Spjd cfg->hc_controladdr); 500204076Spjd } 501204076Spjd /* ...and connect to hastd. */ 502231017Strociny if (proto_connect(controlconn, HAST_TIMEOUT) == -1) { 503204076Spjd pjdlog_exit(EX_OSERR, "Unable to connect to hastd via %s", 504204076Spjd cfg->hc_controladdr); 505204076Spjd } 506218215Spjd 507221899Spjd if (drop_privs(NULL) != 0) 508218215Spjd exit(EX_CONFIG); 509218215Spjd 510204076Spjd /* Send the command to the server... */ 511231017Strociny if (hast_proto_send(NULL, controlconn, nv, NULL, 0) == -1) { 512204076Spjd pjdlog_exit(EX_UNAVAILABLE, 513204076Spjd "Unable to send command to hastd via %s", 514204076Spjd cfg->hc_controladdr); 515204076Spjd } 516204076Spjd nv_free(nv); 517204076Spjd /* ...and receive reply. */ 518231017Strociny if (hast_proto_recv_hdr(controlconn, &nv) == -1) { 519204076Spjd pjdlog_exit(EX_UNAVAILABLE, 520204076Spjd "cannot receive reply from hastd via %s", 521204076Spjd cfg->hc_controladdr); 522204076Spjd } 523204076Spjd 524204076Spjd error = nv_get_int16(nv, "error"); 525204076Spjd if (error != 0) { 526204076Spjd pjdlog_exitx(EX_SOFTWARE, "Error %d received from hastd.", 527204076Spjd error); 528204076Spjd } 529204076Spjd nv_set_error(nv, 0); 530204076Spjd 531204076Spjd switch (cmd) { 532204076Spjd case CMD_ROLE: 533204076Spjd error = control_set_role(nv, argv[0]); 534204076Spjd break; 535251025Smarck case CMD_LIST: 536204076Spjd case CMD_STATUS: 537204076Spjd error = control_status(nv); 538204076Spjd break; 539204076Spjd default: 540229509Strociny PJDLOG_ABORT("Impossible command!"); 541204076Spjd } 542204076Spjd 543204076Spjd exit(error); 544204076Spjd} 545