/* bconsole.cpp * * Copyright (C) 2008-2018 Josh Fisher * * This program is free software. You may redistribute it and/or modify * it under the terms of the GNU General Public License, as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. See the file "COPYING". If not, * see . */ #include "config.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #else #ifdef HAVE_WINSOCK_H #include #endif #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #include "compat_defs.h" #include "util.h" #include "loghandler.h" #include "mymutex.h" #include "mypopen.h" #include "vconf.h" #include "bconsole.h" #ifndef HAVE_WINDOWS_H /* * Function to issue command in Bacula console. * Returns zero on success, or errno if there was an error running the command * or a timeout occurred. */ static int issue_bconsole_command(const char *bcmd) { int pid, rc, n, len, fno_in = -1, fno_out = -1; struct timeval tv; fd_set rfd; tString cmd, tmp; char buf[4096]; /* Build command line */ cmd = conf.bconsole; if (cmd.empty()) return 0; if (!conf.bconsole_config.empty()) { cmd += " -c "; cmd += conf.bconsole_config; } cmd += " -n -u 30"; /* Start bconsole process */ vlog.Debug("running '%s'", cmd.c_str()); pid = mypopen_raw(cmd.c_str(), &fno_in, &fno_out, NULL); if (pid < 0) { rc = errno; vlog.Error("bconsole run failed errno=%d", rc); errno = rc; return rc; } /* Wait for bconsole to accept input */ tv.tv_sec = 30; tv.tv_usec = 0; FD_ZERO(&rfd); FD_SET(fno_in, &rfd); rc = select(fno_in + 1, NULL, &rfd, NULL, &tv); if (rc == 0) { vlog.Error("timeout waiting to send command to bconsole"); close(fno_in); close(fno_out); errno = ETIMEDOUT; return ETIMEDOUT; } if (rc < 0) { rc = errno; vlog.Error("errno=%d waiting to send command to bconsole", rc); close(fno_in); close(fno_out); errno = rc; return rc; } /* Send command to bconsole's stdin */ vlog.Debug("sending bconsole command '%s'", bcmd); len = strlen(bcmd); n = 0; while (n < len) { rc = write(fno_in, bcmd + n, len - n); if (rc < 0) { rc = errno; vlog.Error("send to bconsole's stdin failed errno=%d", rc); close(fno_in); close(fno_out); errno = rc; return rc; } n += rc; } if (write(fno_in, "\n", 1) != 1) { rc = errno; vlog.Error("send to bconsole's stdin failed errno=%d", rc); close(fno_in); close(fno_out); errno = rc; return rc; } /* Wait for bconsole process to finish */ close(fno_in); pid = waitpid(pid, &rc, 0); if (!WIFEXITED(rc)) { vlog.Error("abnormal exit of bconsole process"); close(fno_out); return EPIPE; } if (WEXITSTATUS(rc)) { vlog.Error("bconsole: exited with rc=%d", WEXITSTATUS(rc)); close(fno_out); return WEXITSTATUS(rc); } /* Read stdout from bconsole */ vlog.Debug("bconsole: bconsole terminated normally"); memset(buf, 0, sizeof(buf)); tmp.clear(); rc = read(fno_out, buf, 4095); while (rc > 0) { buf[rc] = 0; tmp += buf; rc = read(fno_out, buf, 4095); } if (rc < 0) { rc = errno; vlog.Error("errno=%d reading bconsole stdout", rc); close(fno_out); errno = rc; return rc; } close(fno_out); vlog.Debug("bconsole output:\n%s", tmp.c_str()); return 0; } /* * Function to fork a new process and issue commands in Bacula console to * perform update slots and/or label new volumes using barcodes. */ void IssueBconsoleCommands(bool update_slots, bool label_barcodes) { tString cmd; /* Check if update needed */ if (!update_slots && !label_barcodes) return; /* Nothing to do */ /* Perform update slots command in bconsole */ if (update_slots) { tFormat(cmd, "update slots storage=\"%s\" drive=\"0\"", conf.storage_name.c_str()); if(issue_bconsole_command(cmd.c_str())) { vlog.Error("WARNING! 'update slots' needed in bconsole"); } else { vlog.Info("bconsole update slots command success"); } } /* Perform label barcodes command in bconsole */ if (label_barcodes) { tFormat(cmd, "label storage=\"%s\" pool=\"%s\" barcodes\nyes\nyes\n", conf.storage_name.c_str(), conf.def_pool.c_str()); if (issue_bconsole_command(cmd.c_str())) { vlog.Error("WARNING! 'label barcodes' needed in bconsole"); } else { vlog.Info("bconsole label barcodes command success"); } } } #else /* * Bconsole interaction is not currently supported on Windows */ void IssueBconsoleCommands(bool update_slots, bool label_barcodes) { return; } #endif