mirror of
https://github.com/wanderleihuttel/vchanger.git
synced 2025-10-11 03:46:17 +00:00
Add vchanger 1.0.3 code
This commit is contained in:
@@ -4,11 +4,10 @@ AM_CXXFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
|
||||
AM_LDFLAGS = @WINLDADD@
|
||||
bin_PROGRAMS = vchanger
|
||||
vchanger_SOURCES = compat/getline.c compat/gettimeofday.c \
|
||||
compat/localtime_r.c \
|
||||
compat/readlink.c \
|
||||
compat/readlink.c compat/semaphore.c \
|
||||
compat/symlink.c compat/sleep.c compat/syslog.c \
|
||||
win32_util.c uuidlookup.c bconsole.cpp \
|
||||
tstring.cpp inifile.cpp mypopen.cpp \
|
||||
tstring.cpp inifile.cpp mymutex.cpp mypopen.cpp \
|
||||
vconf.cpp loghandler.cpp errhandler.cpp \
|
||||
util.cpp changerstate.cpp diskchanger.cpp \
|
||||
vchanger.cpp
|
||||
|
@@ -91,12 +91,12 @@ CONFIG_CLEAN_VPATH_FILES =
|
||||
am__installdirs = "$(DESTDIR)$(bindir)"
|
||||
PROGRAMS = $(bin_PROGRAMS)
|
||||
am_vchanger_OBJECTS = getline.$(OBJEXT) gettimeofday.$(OBJEXT) \
|
||||
localtime_r.$(OBJEXT) readlink.$(OBJEXT) symlink.$(OBJEXT) \
|
||||
readlink.$(OBJEXT) semaphore.$(OBJEXT) symlink.$(OBJEXT) \
|
||||
sleep.$(OBJEXT) syslog.$(OBJEXT) win32_util.$(OBJEXT) \
|
||||
uuidlookup.$(OBJEXT) bconsole.$(OBJEXT) tstring.$(OBJEXT) \
|
||||
inifile.$(OBJEXT) mypopen.$(OBJEXT) vconf.$(OBJEXT) \
|
||||
loghandler.$(OBJEXT) errhandler.$(OBJEXT) util.$(OBJEXT) \
|
||||
changerstate.$(OBJEXT) diskchanger.$(OBJEXT) \
|
||||
inifile.$(OBJEXT) mymutex.$(OBJEXT) mypopen.$(OBJEXT) \
|
||||
vconf.$(OBJEXT) loghandler.$(OBJEXT) errhandler.$(OBJEXT) \
|
||||
util.$(OBJEXT) changerstate.$(OBJEXT) diskchanger.$(OBJEXT) \
|
||||
vchanger.$(OBJEXT)
|
||||
vchanger_OBJECTS = $(am_vchanger_OBJECTS)
|
||||
vchanger_LDADD = $(LDADD)
|
||||
@@ -269,11 +269,10 @@ AM_CFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
|
||||
AM_CXXFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
|
||||
AM_LDFLAGS = @WINLDADD@
|
||||
vchanger_SOURCES = compat/getline.c compat/gettimeofday.c \
|
||||
compat/localtime_r.c \
|
||||
compat/readlink.c \
|
||||
compat/readlink.c compat/semaphore.c \
|
||||
compat/symlink.c compat/sleep.c compat/syslog.c \
|
||||
win32_util.c uuidlookup.c bconsole.cpp \
|
||||
tstring.cpp inifile.cpp mypopen.cpp \
|
||||
tstring.cpp inifile.cpp mymutex.cpp mypopen.cpp \
|
||||
vconf.cpp loghandler.cpp errhandler.cpp \
|
||||
util.cpp changerstate.cpp diskchanger.cpp \
|
||||
vchanger.cpp
|
||||
@@ -372,10 +371,11 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getline.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettimeofday.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inifile.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localtime_r.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loghandler.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mymutex.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mypopen.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readlink.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/semaphore.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sleep.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symlink.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syslog.Po@am__quote@
|
||||
@@ -428,20 +428,6 @@ gettimeofday.obj: compat/gettimeofday.c
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gettimeofday.obj `if test -f 'compat/gettimeofday.c'; then $(CYGPATH_W) 'compat/gettimeofday.c'; else $(CYGPATH_W) '$(srcdir)/compat/gettimeofday.c'; fi`
|
||||
|
||||
localtime_r.o: compat/localtime_r.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT localtime_r.o -MD -MP -MF $(DEPDIR)/localtime_r.Tpo -c -o localtime_r.o `test -f 'compat/localtime_r.c' || echo '$(srcdir)/'`compat/localtime_r.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/localtime_r.Tpo $(DEPDIR)/localtime_r.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compat/localtime_r.c' object='localtime_r.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o localtime_r.o `test -f 'compat/localtime_r.c' || echo '$(srcdir)/'`compat/localtime_r.c
|
||||
|
||||
localtime_r.obj: compat/localtime_r.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT localtime_r.obj -MD -MP -MF $(DEPDIR)/localtime_r.Tpo -c -o localtime_r.obj `if test -f 'compat/localtime_r.c'; then $(CYGPATH_W) 'compat/localtime_r.c'; else $(CYGPATH_W) '$(srcdir)/compat/localtime_r.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/localtime_r.Tpo $(DEPDIR)/localtime_r.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compat/localtime_r.c' object='localtime_r.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o localtime_r.obj `if test -f 'compat/localtime_r.c'; then $(CYGPATH_W) 'compat/localtime_r.c'; else $(CYGPATH_W) '$(srcdir)/compat/localtime_r.c'; fi`
|
||||
|
||||
readlink.o: compat/readlink.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT readlink.o -MD -MP -MF $(DEPDIR)/readlink.Tpo -c -o readlink.o `test -f 'compat/readlink.c' || echo '$(srcdir)/'`compat/readlink.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/readlink.Tpo $(DEPDIR)/readlink.Po
|
||||
@@ -456,6 +442,20 @@ readlink.obj: compat/readlink.c
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o readlink.obj `if test -f 'compat/readlink.c'; then $(CYGPATH_W) 'compat/readlink.c'; else $(CYGPATH_W) '$(srcdir)/compat/readlink.c'; fi`
|
||||
|
||||
semaphore.o: compat/semaphore.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT semaphore.o -MD -MP -MF $(DEPDIR)/semaphore.Tpo -c -o semaphore.o `test -f 'compat/semaphore.c' || echo '$(srcdir)/'`compat/semaphore.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/semaphore.Tpo $(DEPDIR)/semaphore.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compat/semaphore.c' object='semaphore.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o semaphore.o `test -f 'compat/semaphore.c' || echo '$(srcdir)/'`compat/semaphore.c
|
||||
|
||||
semaphore.obj: compat/semaphore.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT semaphore.obj -MD -MP -MF $(DEPDIR)/semaphore.Tpo -c -o semaphore.obj `if test -f 'compat/semaphore.c'; then $(CYGPATH_W) 'compat/semaphore.c'; else $(CYGPATH_W) '$(srcdir)/compat/semaphore.c'; fi`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/semaphore.Tpo $(DEPDIR)/semaphore.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compat/semaphore.c' object='semaphore.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o semaphore.obj `if test -f 'compat/semaphore.c'; then $(CYGPATH_W) 'compat/semaphore.c'; else $(CYGPATH_W) '$(srcdir)/compat/semaphore.c'; fi`
|
||||
|
||||
symlink.o: compat/symlink.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT symlink.o -MD -MP -MF $(DEPDIR)/symlink.Tpo -c -o symlink.o `test -f 'compat/symlink.c' || echo '$(srcdir)/'`compat/symlink.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/symlink.Tpo $(DEPDIR)/symlink.Po
|
||||
|
137
src/bconsole.cpp
137
src/bconsole.cpp
@@ -1,6 +1,6 @@
|
||||
/* bconsole.cpp
|
||||
*
|
||||
* Copyright (C) 2008-2014 Josh Fisher
|
||||
* 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
|
||||
@@ -47,18 +47,22 @@
|
||||
#include <ctype.h>
|
||||
#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.
|
||||
*/
|
||||
int issue_bconsole_command(const char *bcmd)
|
||||
static int issue_bconsole_command(const char *bcmd)
|
||||
{
|
||||
int pid, rc, n, len, fno_in = -1, fno_out = -1;
|
||||
struct timeval tv;
|
||||
@@ -66,7 +70,6 @@ int issue_bconsole_command(const char *bcmd)
|
||||
tString cmd, tmp;
|
||||
char buf[4096];
|
||||
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
/* Build command line */
|
||||
cmd = conf.bconsole;
|
||||
if (cmd.empty()) return 0;
|
||||
@@ -76,11 +79,11 @@ int issue_bconsole_command(const char *bcmd)
|
||||
}
|
||||
cmd += " -n -u 30";
|
||||
/* Start bconsole process */
|
||||
log.Debug("bconsole: running '%s'", bcmd);
|
||||
vlog.Debug("running '%s'", cmd.c_str());
|
||||
pid = mypopen_raw(cmd.c_str(), &fno_in, &fno_out, NULL);
|
||||
if (pid < 0) {
|
||||
rc = errno;
|
||||
log.Error("bconsole: run failed errno=%d", rc);
|
||||
vlog.Error("bconsole run failed errno=%d", rc);
|
||||
errno = rc;
|
||||
return rc;
|
||||
}
|
||||
@@ -91,7 +94,7 @@ int issue_bconsole_command(const char *bcmd)
|
||||
FD_SET(fno_in, &rfd);
|
||||
rc = select(fno_in + 1, NULL, &rfd, NULL, &tv);
|
||||
if (rc == 0) {
|
||||
log.Error("bconsole: timed out waiting to send command");
|
||||
vlog.Error("timeout waiting to send command to bconsole");
|
||||
close(fno_in);
|
||||
close(fno_out);
|
||||
errno = ETIMEDOUT;
|
||||
@@ -99,20 +102,21 @@ int issue_bconsole_command(const char *bcmd)
|
||||
}
|
||||
if (rc < 0) {
|
||||
rc = errno;
|
||||
log.Error("bconsole: errno=%d waiting to send command", rc);
|
||||
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;
|
||||
log.Error("bconsole: send to bconsole's stdin failed errno=%d", rc);
|
||||
vlog.Error("send to bconsole's stdin failed errno=%d", rc);
|
||||
close(fno_in);
|
||||
close(fno_out);
|
||||
errno = rc;
|
||||
@@ -120,57 +124,90 @@ int issue_bconsole_command(const char *bcmd)
|
||||
}
|
||||
n += rc;
|
||||
}
|
||||
close(fno_in);
|
||||
|
||||
/* Read stdout from bconsole */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
tmp.clear();
|
||||
while (true) {
|
||||
tv.tv_sec = 30;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&rfd);
|
||||
FD_SET(fno_out, &rfd);
|
||||
rc = select(fno_out + 1, &rfd, NULL, NULL, &tv);
|
||||
if (rc == 0) {
|
||||
log.Error("bconsole: timed out waiting for bconsole output");
|
||||
close(fno_out);
|
||||
errno = ETIMEDOUT;
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
if (rc < 0) {
|
||||
rc = errno;
|
||||
log.Error("bconsole: errno=%d waiting for bconsole output", rc);
|
||||
close(fno_out);
|
||||
errno = rc;
|
||||
return rc;
|
||||
}
|
||||
rc = read(fno_out, buf, 4095);
|
||||
if (rc < 0) {
|
||||
rc = errno;
|
||||
log.Error("bconsole: errno=%d reading bconsole stdout", rc);
|
||||
close(fno_out);
|
||||
errno = rc;
|
||||
return rc;
|
||||
} else if (rc > 0) {
|
||||
buf[rc] = 0;
|
||||
tmp += buf;
|
||||
} else break;
|
||||
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;
|
||||
}
|
||||
close(fno_out);
|
||||
log.Debug("bconsole: output:\n%s", tmp.c_str());
|
||||
|
||||
/* Wait for bconsole process to finish */
|
||||
close(fno_in);
|
||||
pid = waitpid(pid, &rc, 0);
|
||||
if (!WIFEXITED(rc)) {
|
||||
log.Error("bconsole: abnormal exit of bconsole process");
|
||||
vlog.Error("abnormal exit of bconsole process");
|
||||
close(fno_out);
|
||||
return EPIPE;
|
||||
}
|
||||
if (WEXITSTATUS(rc)) {
|
||||
log.Error("bconsole: exited with rc=%d", 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;
|
||||
#else
|
||||
return EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
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
|
||||
|
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2008-2014 Josh Fisher
|
||||
* vchanger copyright (C) 2008-2017 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
@@ -24,6 +24,6 @@
|
||||
#ifndef BCONSOLE_H_
|
||||
#define BCONSOLE_H_
|
||||
|
||||
int issue_bconsole_command(const char *bcmd);
|
||||
void IssueBconsoleCommands(bool update_slots, bool label_barcodes);
|
||||
|
||||
#endif /* BCONSOLE_H_ */
|
||||
|
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2008-2015 Josh Fisher
|
||||
* vchanger copyright (C) 2008-2018 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
@@ -173,7 +173,7 @@ int MagazineState::save()
|
||||
|
||||
if (mag_bay < 0) {
|
||||
verr.SetErrorWithErrno(EINVAL, "cannot save state of invalid magazine %d", mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EINVAL;
|
||||
}
|
||||
/* Build path to state file */
|
||||
@@ -191,7 +191,7 @@ int MagazineState::save()
|
||||
rc = errno;
|
||||
umask(old_mask);
|
||||
verr.SetErrorWithErrno(rc, "cannot open magazine %d state file for writing", mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
/* Save magazine device (directory or UUID), number of volumes, and start of
|
||||
@@ -203,12 +203,12 @@ int MagazineState::save()
|
||||
unlink(sname);
|
||||
umask(old_mask);
|
||||
verr.SetErrorWithErrno(rc, "cannot write to magazine %d state file", mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
fclose(FS);
|
||||
umask(old_mask);
|
||||
log.Notice("saved state of magazine %d", mag_bay);
|
||||
vlog.Notice("saved state of magazine %d", mag_bay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ int MagazineState::restore()
|
||||
|
||||
if (mag_bay < 0) {
|
||||
verr.SetErrorWithErrno(EINVAL, "cannot restore state of invalid magazine %d", mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EINVAL;
|
||||
}
|
||||
clear();
|
||||
@@ -250,7 +250,7 @@ int MagazineState::restore()
|
||||
/* No read permission? */
|
||||
rc = errno;
|
||||
verr.SetErrorWithErrno(rc, "cannot open magazine %d state file for reading", mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
if (tGetLine(line, FS) == NULL) {
|
||||
@@ -259,7 +259,7 @@ int MagazineState::restore()
|
||||
/* error reading bay state file */
|
||||
fclose(FS);
|
||||
verr.SetErrorWithErrno(rc, "error reading magazine %d state file", mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ int MagazineState::restore()
|
||||
p = 0;
|
||||
if (tParseCSV(word, line, p) <= 0) {
|
||||
/* bay state file should not be empty, assume it didn't exist */
|
||||
log.Warning("WARNING! magazine %d state file was empty, deleting it", mag_bay);
|
||||
vlog.Warning("WARNING! magazine %d state file was empty, deleting it", mag_bay);
|
||||
unlink(sname);
|
||||
return 0;
|
||||
}
|
||||
@@ -285,7 +285,7 @@ int MagazineState::restore()
|
||||
/* Bay state file is corrupt.
|
||||
* Treat as if it was not mounted at last invocation */
|
||||
clear();
|
||||
log.Warning("WARNING! magazine %d state file corrupt, deleting it", mag_bay);
|
||||
vlog.Warning("WARNING! magazine %d state file corrupt, deleting it", mag_bay);
|
||||
unlink(sname);
|
||||
return 0;
|
||||
}
|
||||
@@ -293,7 +293,7 @@ int MagazineState::restore()
|
||||
/* Corrupt bay state file, assume it doesn't exist */
|
||||
clear();
|
||||
unlink(sname);
|
||||
log.Warning("WARNING! magazine %d state file has invalid number of slots field, deleting it", mag_bay);
|
||||
vlog.Warning("WARNING! magazine %d state file has invalid number of slots field, deleting it", mag_bay);
|
||||
return 0;
|
||||
}
|
||||
prev_num_slots = (int)strtol(word.c_str(), NULL, 10);
|
||||
@@ -302,7 +302,7 @@ int MagazineState::restore()
|
||||
clear();
|
||||
prev_num_slots = 0;
|
||||
unlink(sname);
|
||||
log.Warning("WARNING! magazine %d state file has invalid number of slots field, deleting it", mag_bay);
|
||||
vlog.Warning("WARNING! magazine %d state file has invalid number of slots field, deleting it", mag_bay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ int MagazineState::restore()
|
||||
* Treat as if it was not mounted at last invocation */
|
||||
clear();
|
||||
prev_num_slots = 0;
|
||||
log.Warning("WARNING! magazine %d state file corrupt, deleting it", mag_bay);
|
||||
vlog.Warning("WARNING! magazine %d state file corrupt, deleting it", mag_bay);
|
||||
unlink(sname);
|
||||
return 0;
|
||||
}
|
||||
@@ -321,7 +321,7 @@ int MagazineState::restore()
|
||||
clear();
|
||||
prev_num_slots = 0;
|
||||
unlink(sname);
|
||||
log.Warning("WARNING! magazine %d state file has invalid virtual slot assignment field, deleting it",
|
||||
vlog.Warning("WARNING! magazine %d state file has invalid virtual slot assignment field, deleting it",
|
||||
mag_bay);
|
||||
return 0;
|
||||
}
|
||||
@@ -332,11 +332,11 @@ int MagazineState::restore()
|
||||
prev_num_slots = 0;
|
||||
prev_start_slot = 0;
|
||||
unlink(sname);
|
||||
log.Warning("WARNING! magazine %d state file has invalid virtual slot assignment field, deleting it",
|
||||
vlog.Warning("WARNING! magazine %d state file has invalid virtual slot assignment field, deleting it",
|
||||
mag_bay);
|
||||
return 0;
|
||||
}
|
||||
log.Notice("restored state of magazine %d", mag_bay);
|
||||
vlog.Notice("restored state of magazine %d", mag_bay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ int MagazineState::UpdateMagazineFormat()
|
||||
fs = fopen(lname.c_str(), "r");
|
||||
if (fs == NULL) {
|
||||
verr.SetErrorWithErrno(errno, "failed to find loaded%d file when updating magazine %d", drv, mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
de = readdir(dir);
|
||||
continue;
|
||||
}
|
||||
@@ -397,7 +397,7 @@ int MagazineState::UpdateMagazineFormat()
|
||||
fclose(fs);
|
||||
if (str.empty()) {
|
||||
verr.SetError(-1, "loaded%d file empty when updating magazine %d", drv, mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
de = readdir(dir);
|
||||
continue;
|
||||
}
|
||||
@@ -406,7 +406,7 @@ int MagazineState::UpdateMagazineFormat()
|
||||
if (rename(fname.c_str(), vname.c_str())) {
|
||||
verr.SetError(EINVAL, "unable to rename 'drive%d' on magazine %d",
|
||||
drv, mag_bay);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
}
|
||||
}
|
||||
de = readdir(dir);
|
||||
@@ -445,7 +445,7 @@ int MagazineState::UpdateMagazineFormat()
|
||||
tFormat(fname, "%s%sindex", mountpoint.c_str(), DIR_DELIM);
|
||||
unlink(fname.c_str());
|
||||
|
||||
log.Warning("magaine %d updated from old format", mag_bay);
|
||||
vlog.Warning("magaine %d updated from old format", mag_bay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ int MagazineState::Mount()
|
||||
}
|
||||
if (rc) {
|
||||
verr.SetError(rc, "system error determining mountpoint from UUID");
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
mountpoint.clear();
|
||||
return -1;
|
||||
}
|
||||
@@ -510,7 +510,7 @@ int MagazineState::Mount()
|
||||
/* Ensure access to magazine mountpoint */
|
||||
if (access(mountpoint.c_str(), W_OK) != 0) {
|
||||
verr.SetError(rc, "no write access to directory %s", mountpoint.c_str());
|
||||
log.Error("%s", verr.GetErrorMsg());
|
||||
vlog.Error("%s", verr.GetErrorMsg());
|
||||
mountpoint.clear();
|
||||
return -5;
|
||||
}
|
||||
@@ -529,7 +529,7 @@ int MagazineState::Mount()
|
||||
/* could not open mountpoint dir */
|
||||
rc = errno;
|
||||
verr.SetErrorWithErrno(rc, "cannot open directory '%s'", mountpoint.c_str());
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
mountpoint.clear();
|
||||
if (rc == ENOTDIR || rc == ENOENT) return -3;
|
||||
if (rc == EACCES) return -5;
|
||||
@@ -659,7 +659,7 @@ int MagazineState::CreateVolume(const char *vol_label_in)
|
||||
}
|
||||
if (rc != ENOENT) {
|
||||
verr.SetErrorWithErrno(rc, "error %d accessing volumes on magazine %d", rc, mag_bay);
|
||||
log.Error("MagazineState::CreateVolume: %s", verr.GetErrorMsg());
|
||||
vlog.Error("MagazineState::CreateVolume: %s", verr.GetErrorMsg());
|
||||
return -1;
|
||||
}
|
||||
/* Create new volume file on magazine */
|
||||
@@ -667,7 +667,7 @@ int MagazineState::CreateVolume(const char *vol_label_in)
|
||||
if (!fs) {
|
||||
rc = errno;
|
||||
verr.SetErrorWithErrno(rc, "error %d creating volume on magazine %d", rc, mag_bay);
|
||||
log.Error("MagazineState::CreateVolume: %s", verr.GetErrorMsg());
|
||||
vlog.Error("MagazineState::CreateVolume: %s", verr.GetErrorMsg());
|
||||
return -1;
|
||||
}
|
||||
fclose(fs);
|
||||
@@ -676,7 +676,7 @@ int MagazineState::CreateVolume(const char *vol_label_in)
|
||||
new_mslot.label = label;
|
||||
mslot.push_back(new_mslot);
|
||||
++num_slots;
|
||||
log.Notice("created volume '%s' on magazine %d (%s)", label.c_str(), mag_bay, mag_dev.c_str());
|
||||
vlog.Notice("created volume '%s' on magazine %d (%s)", label.c_str(), mag_bay, mag_dev.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -784,7 +784,7 @@ void DynamicConfig::save()
|
||||
/* Unable to open dynamic.conf file for writing */
|
||||
rc = errno;
|
||||
umask(old_mask);
|
||||
log.Error("ERROR! cannot open dynamic.conf file for writing (errno=%d)", rc);
|
||||
vlog.Error("ERROR! cannot open dynamic.conf file for writing (errno=%d)", rc);
|
||||
return;
|
||||
}
|
||||
/* Save max slot number in use to dynamic configuration */
|
||||
@@ -794,12 +794,12 @@ void DynamicConfig::save()
|
||||
fclose(FS);
|
||||
unlink(sname);
|
||||
umask(old_mask);
|
||||
log.Error("ERROR! i/o error writing dynamic.conf file (errno=%d)", rc);
|
||||
vlog.Error("ERROR! i/o error writing dynamic.conf file (errno=%d)", rc);
|
||||
return;
|
||||
}
|
||||
fclose(FS);
|
||||
umask(old_mask);
|
||||
log.Notice("saved dynamic configuration (max used slot: %d)", max_slot);
|
||||
vlog.Notice("saved dynamic configuration (max used slot: %d)", max_slot);
|
||||
}
|
||||
|
||||
|
||||
@@ -827,7 +827,7 @@ void DynamicConfig::restore()
|
||||
if (!FS) {
|
||||
/* No read permission? */
|
||||
rc = errno;
|
||||
log.Error("ERROR! cannot open dynamic.conf file for restore (errno=%d)", rc);
|
||||
vlog.Error("ERROR! cannot open dynamic.conf file for restore (errno=%d)", rc);
|
||||
return;
|
||||
}
|
||||
if (tGetLine(line, FS) == NULL) {
|
||||
@@ -835,7 +835,7 @@ void DynamicConfig::restore()
|
||||
if (!feof(FS)) {
|
||||
/* error reading bay state file */
|
||||
fclose(FS);
|
||||
log.Error("ERROR! i/o error reading dynamic.conf file (errno=%d)", rc);
|
||||
vlog.Error("ERROR! i/o error reading dynamic.conf file (errno=%d)", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
197
src/compat/semaphore.c
Normal file
197
src/compat/semaphore.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/* semaphore.c
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2020 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* vchanger 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 vchanger. See the file "COPYING". If not,
|
||||
* write to: The Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef HAVE_SEMAPHORE_H
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include "targetver.h"
|
||||
#include <windows.h>
|
||||
#include <limits.h>
|
||||
#include "win32_util.h"
|
||||
#endif
|
||||
/*
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
*/
|
||||
#include "compat/semaphore.h"
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Emulate POSIX.1-2001 sem_open() function using win32/win64 CreateSemaphoreW() function.
|
||||
* On success address of semaphore, else NULL on error.
|
||||
*-------------------------------------------------*/
|
||||
sem_t* sem_open(const char *name, int oflag, ...)
|
||||
{
|
||||
DWORD rc;
|
||||
long mode, value;
|
||||
wchar_t *wname = NULL;
|
||||
size_t wname_sz = 0;
|
||||
sem_t *fd;
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, oflag);
|
||||
mode = (long)va_arg(vl, unsigned int);
|
||||
value = (long)va_arg(vl, unsigned int);
|
||||
va_end(vl);
|
||||
|
||||
/* Convert path strings to UTF16 encoding */
|
||||
if (!AnsiToUTF16(name, &wname, &wname_sz)) {
|
||||
rc = ERROR_BAD_PATHNAME;
|
||||
errno = w32errno(rc);
|
||||
return NULL;
|
||||
}
|
||||
fd = (sem_t*)CreateSemaphoreW(NULL, value, LONG_MAX, wname);
|
||||
free(wname);
|
||||
if (fd == NULL) {
|
||||
errno = w32errno(GetLastError());
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Emulate POSIX.1-2001 sem_close() function using win32/win64 CloseHandle() function.
|
||||
* On success returns zero, else negative on error.
|
||||
*-------------------------------------------------*/
|
||||
int sem_close(sem_t *sem)
|
||||
{
|
||||
if (sem == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
CloseHandle((HANDLE)sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Emulate POSIX.1-2001 sem_unnlink() function by doing nothing. Windows will
|
||||
* automatically unlink the object when the last open handle is closed.
|
||||
* Returns zero.
|
||||
*-------------------------------------------------*/
|
||||
int sem_unlink(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Emulate POSIX.1-2001 sem_post() function using win32/win64 ReleaseSemaphore() function.
|
||||
* On success returns zero, else negative on error.
|
||||
*-------------------------------------------------*/
|
||||
int sem_post(sem_t *sem)
|
||||
{
|
||||
if (sem == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
ReleaseSemaphore((HANDLE)sem, 1, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Emulate POSIX.1-2001 sem_wait() function using win32/win64 WaitForSingleObjectEx() function.
|
||||
* On success returns zero, else negative on error.
|
||||
*-------------------------------------------------*/
|
||||
int sem_wait(sem_t *sem)
|
||||
{
|
||||
DWORD reason;
|
||||
if (sem == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
reason = WaitForSingleObjectEx((HANDLE)sem, INFINITE, FALSE);
|
||||
if (reason == 0) return 0;
|
||||
switch (reason) {
|
||||
case WAIT_IO_COMPLETION:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
errno = ETIMEDOUT;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Emulate POSIX.1-2001 sem_timedwait() function using win32/win64 WaitForSingleObjectEx()
|
||||
* function.
|
||||
* On success returns zero, else negative on error.
|
||||
*-------------------------------------------------*/
|
||||
int sem_timedwait(sem_t *sem, const struct timespec *timeout)
|
||||
{
|
||||
DWORD reason, mt;
|
||||
if (sem == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* semaphore.h functions use absolute time and Windows needs a time interval */
|
||||
timeout->tv_sec -= time(NULL);
|
||||
mt = timeout->tv_sec * 1000 + (timeout->tv_nsec / 1000000);
|
||||
reason = WaitForSingleObjectEx((HANDLE)sem, mt, FALSE);
|
||||
if (reason == WAIT_OBJECT_0) return 0;
|
||||
switch (reason) {
|
||||
case WAIT_IO_COMPLETION:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
errno = ETIMEDOUT;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Emulate POSIX.1-2001 sem_trywait() function using win32/win64 WaitForSingleObjectEx()
|
||||
* function.
|
||||
* On success returns zero, else negative on error.
|
||||
*-------------------------------------------------*/
|
||||
int sem_trywait(sem_t *sem)
|
||||
{
|
||||
DWORD reason;
|
||||
if (sem == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
reason = WaitForSingleObjectEx((HANDLE)sem, 0, FALSE);
|
||||
if (reason == 0) return 0;
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
54
src/compat/semaphore.h
Normal file
54
src/compat/semaphore.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* semaphore.h
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2020 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* vchanger 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 vchanger. See the file "COPYING". If not,
|
||||
* write to: The Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _SEMAPHORE_H
|
||||
#define _SEMAPHORE_H
|
||||
|
||||
#ifndef HAVE_SEMAPHORE_H
|
||||
/* For systems without symlink() function, use internal version */
|
||||
|
||||
typedef union
|
||||
{
|
||||
char __size[32];
|
||||
long int __align;
|
||||
} sem_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
sem_t* sem_open(const char *name, int oflag, ...);
|
||||
int sem_post(sem_t *sem);
|
||||
int sem_wait(sem_t *sem);
|
||||
int sem_trywait(sem_t *sem);
|
||||
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
|
||||
int sem_close(sem_t *sem);
|
||||
int sem_unlink(const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SEMAPHORE_H */
|
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2008-2015 Josh Fisher
|
||||
* vchanger copyright (C) 2008-2020 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
@@ -65,20 +65,13 @@
|
||||
#include "loghandler.h"
|
||||
#include "bconsole.h"
|
||||
#include "diskchanger.h"
|
||||
#include "vconf.h"
|
||||
|
||||
|
||||
/*=================================================
|
||||
* Class DiskChanger
|
||||
*=================================================*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
* destructor
|
||||
*-------------------------------------------------*/
|
||||
DiskChanger::~DiskChanger()
|
||||
{
|
||||
Unlock();
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Protected method to read previous state of magazine bays.
|
||||
@@ -148,6 +141,7 @@ void DiskChanger::InitializeVirtSlots()
|
||||
|
||||
/* Create all known slots as initially empty */
|
||||
vslot.clear();
|
||||
vs.clear();
|
||||
for (s = 0; s <= dconf.max_slot; s++) {
|
||||
vs.vs = s;
|
||||
vslot.push_back(vs);
|
||||
@@ -155,7 +149,7 @@ void DiskChanger::InitializeVirtSlots()
|
||||
/* Re-create virtual slots that existed previously if possible */
|
||||
for (m = 0; m < (int)magazine.size(); m++) {
|
||||
/* Create slots if needed to match max slot used by previous magazines */
|
||||
last = magazine[m].prev_start_slot + magazine[m].prev_num_slots;
|
||||
last = magazine[m].prev_start_slot + magazine[m].prev_num_slots - 1;
|
||||
if (last >= (int)vslot.size()) {
|
||||
vs.clear();
|
||||
while ((int)vslot.size() <= last) {
|
||||
@@ -165,11 +159,11 @@ void DiskChanger::InitializeVirtSlots()
|
||||
}
|
||||
/* Check this magazine's slots */
|
||||
if (magazine[m].empty()) {
|
||||
log.Info("magazine %d is not mounted", m);
|
||||
vlog.Info("magazine %d is not mounted", m);
|
||||
/* magazine is not currently mounted, so will have no slots assigned */
|
||||
if (magazine[m].prev_start_slot) {
|
||||
/* Since it was previously mounted, an 'update slots' is needed */
|
||||
log.Warning("update slots needed. magazine %d no longer mounted; previous: %d volumes in slots %d-%d", m,
|
||||
vlog.Warning("update slots needed. magazine %d no longer mounted; previous: %d volumes in slots %d-%d", m,
|
||||
magazine[m].prev_num_slots, magazine[m].prev_start_slot,
|
||||
magazine[m].prev_start_slot + magazine[m].prev_num_slots - 1);
|
||||
needs_update = true;
|
||||
@@ -177,12 +171,12 @@ void DiskChanger::InitializeVirtSlots()
|
||||
continue;
|
||||
}
|
||||
/* Magazine is currently mounted, so check for change in slot assignment */
|
||||
log.Info("magazine %d has %d volumes on %s", m, magazine[m].num_slots,
|
||||
vlog.Info("magazine %d has %d volumes on %s", m, magazine[m].num_slots,
|
||||
magazine[m].mountpoint.c_str());
|
||||
if (magazine[m].num_slots != magazine[m].prev_num_slots) {
|
||||
/* Number of volumes has changed or magazine was not previously mounted, so
|
||||
* needs new slot assignment and also 'update slots' will be needed */
|
||||
log.Warning("update slots needed. magazine %d has %d volumes, previously had %d", m,
|
||||
vlog.Warning("update slots needed. magazine %d has %d volumes, previously had %d", m,
|
||||
magazine[m].num_slots, magazine[m].prev_num_slots);
|
||||
needs_update = true;
|
||||
continue;
|
||||
@@ -194,7 +188,7 @@ void DiskChanger::InitializeVirtSlots()
|
||||
/* Magazine is mounted, was previously mounted, and has the same volume count,
|
||||
* so attempt to assign to the same slots previously assigned */
|
||||
found = false;
|
||||
for (v = magazine[m].prev_start_slot; v < (int)vslot.size(); v++) {
|
||||
for (v = magazine[m].prev_start_slot; v < magazine[m].prev_start_slot + magazine[m].prev_num_slots; v++) {
|
||||
if (!vslot[v].empty()) {
|
||||
found = true;
|
||||
break;
|
||||
@@ -204,7 +198,7 @@ void DiskChanger::InitializeVirtSlots()
|
||||
/* Slot used previously has already been assigned to another magazine.
|
||||
* Magazine will need to be assigned a new slot range, so an
|
||||
* 'update slots' will also be needed. */
|
||||
log.Warning("update slots needed. magazine %d previous slots %d-%d are not available", m,
|
||||
vlog.Warning("update slots needed. magazine %d previous slots %d-%d are not available", m,
|
||||
magazine[m].prev_start_slot, magazine[m].prev_start_slot + magazine[m].prev_num_slots - 1);
|
||||
needs_update = true;
|
||||
continue;
|
||||
@@ -216,7 +210,7 @@ void DiskChanger::InitializeVirtSlots()
|
||||
vslot[v].mag_bay = m;
|
||||
vslot[v].mag_slot = s;
|
||||
}
|
||||
log.Notice("%d volumes on magazine %d assigned slots %d-%d", magazine[m].num_slots, m,
|
||||
vlog.Notice("%d volumes on magazine %d assigned slots %d-%d", magazine[m].num_slots, m,
|
||||
magazine[m].start_slot, magazine[m].start_slot + magazine[m].num_slots - 1);
|
||||
}
|
||||
|
||||
@@ -230,7 +224,7 @@ void DiskChanger::InitializeVirtSlots()
|
||||
vslot[v].mag_bay = m;
|
||||
vslot[v].mag_slot = s;
|
||||
}
|
||||
log.Notice("%d volumes on magazine %d assigned slots %d-%d", magazine[m].num_slots, m,
|
||||
vlog.Notice("%d volumes on magazine %d assigned slots %d-%d", magazine[m].num_slots, m,
|
||||
magazine[m].start_slot, magazine[m].start_slot + magazine[m].num_slots - 1);
|
||||
}
|
||||
|
||||
@@ -263,7 +257,7 @@ int DiskChanger::InitializeDrives()
|
||||
if (!d) {
|
||||
rc = errno;
|
||||
verr.SetErrorWithErrno(rc, "error %d accessing work directory", rc);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
de = readdir(d);
|
||||
@@ -297,7 +291,7 @@ int DiskChanger::InitializeDrives()
|
||||
drive.push_back(ds);
|
||||
/* Attempt to restore drive's last state */
|
||||
if (RestoreDriveState(n)) {
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -351,7 +345,7 @@ int DiskChanger::CreateDriveSymlink(int drv)
|
||||
lname[rc] = 0;
|
||||
if (fname == lname) {
|
||||
/* symlink already exists */
|
||||
log.Info("found symlink for drive %d -> %s", drv, fname.c_str());
|
||||
vlog.Info("found symlink for drive %d -> %s", drv, fname.c_str());
|
||||
return 0;
|
||||
}
|
||||
/* Symlink points to wrong mountpoint, so delete and re-create */
|
||||
@@ -362,7 +356,7 @@ int DiskChanger::CreateDriveSymlink(int drv)
|
||||
verr.SetErrorWithErrno(rc, "error %d creating symlink for drive %d", rc, drv);
|
||||
return rc;
|
||||
}
|
||||
log.Notice("created symlink for drive %d -> %s", drv, fname.c_str());
|
||||
vlog.Notice("created symlink for drive %d -> %s", drv, fname.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -389,7 +383,7 @@ int DiskChanger::RemoveDriveSymlink(int drv)
|
||||
verr.SetErrorWithErrno(errno, "error %d deleting symlink for drive %d: ", rc, drv);
|
||||
return rc;
|
||||
}
|
||||
log.Notice("deleted symlink for drive %d", drv);
|
||||
vlog.Notice("deleted symlink for drive %d", drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -416,7 +410,7 @@ int DiskChanger::SaveDriveState(int drv)
|
||||
tFormat(sname, "%s%sdrive_state-%d", conf.work_dir.c_str(), DIR_DELIM, drv);
|
||||
if (drive[drv].empty()) {
|
||||
if (access(sname.c_str(), F_OK) == 0) {
|
||||
log.Notice("deleted state file for drive %d", drv);
|
||||
vlog.Notice("deleted state file for drive %d", drv);
|
||||
}
|
||||
unlink(sname.c_str());
|
||||
return 0;
|
||||
@@ -443,7 +437,7 @@ int DiskChanger::SaveDriveState(int drv)
|
||||
}
|
||||
fclose(FS);
|
||||
umask(old_mask);
|
||||
log.Notice("wrote state file for drive %d", drv);
|
||||
vlog.Notice("wrote state file for drive %d", drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -477,7 +471,7 @@ int DiskChanger::RestoreDriveState(int drv)
|
||||
if (stat(sname.c_str(), &st)) {
|
||||
/* drive state file not found, so drive is not loaded */
|
||||
RemoveDriveSymlink(drv);
|
||||
log.Info("drive %d previously unloaded", drv);
|
||||
vlog.Info("drive %d previously unloaded", drv);
|
||||
return 0;
|
||||
}
|
||||
/* Read loaded volume info from state file */
|
||||
@@ -526,7 +520,7 @@ int DiskChanger::RestoreDriveState(int drv)
|
||||
}
|
||||
if (v >= (int)vslot.size()) {
|
||||
/* Volume last loaded is no longer available. Change state to unloaded. */
|
||||
log.Notice("volume %s no longer available, unloading drive %d",
|
||||
vlog.Notice("volume %s no longer available, unloading drive %d",
|
||||
labl.c_str(), drv);
|
||||
unlink(sname.c_str());
|
||||
RemoveDriveSymlink(drv);
|
||||
@@ -538,7 +532,7 @@ int DiskChanger::RestoreDriveState(int drv)
|
||||
if ((rc = CreateDriveSymlink(drv)) != 0) {
|
||||
/* Unable to create symlink */
|
||||
drive[drv].vs = -1;
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -546,7 +540,7 @@ int DiskChanger::RestoreDriveState(int drv)
|
||||
vslot[v].drv = drv;
|
||||
m = vslot[v].mag_bay;
|
||||
ms = vslot[v].mag_slot;
|
||||
log.Notice("drive %d previously loaded from slot %d (%s)", drv, v, magazine[m].GetVolumeLabel(ms));
|
||||
vlog.Notice("drive %d previously loaded from slot %d (%s)", drv, v, magazine[m].GetVolumeLabel(ms));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -562,7 +556,6 @@ int DiskChanger::RestoreDriveState(int drv)
|
||||
int DiskChanger::Initialize()
|
||||
{
|
||||
/* Make sure we have a lock on this changer */
|
||||
if (Lock()) return verr.GetError();
|
||||
magazine.clear();
|
||||
vslot.clear();
|
||||
drive.clear();
|
||||
@@ -591,38 +584,38 @@ int DiskChanger::LoadDrive(int drv, int slot)
|
||||
{
|
||||
int rc, m, ms;
|
||||
|
||||
if (!changer_lock) {
|
||||
verr.SetError(EINVAL, "changer not initialized");
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EINVAL;
|
||||
}
|
||||
if (drv < 0) {
|
||||
verr.SetError(EINVAL, "invalid drive number %d", drv);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EINVAL;
|
||||
}
|
||||
SetMaxDrive(drv);
|
||||
if (slot < 1 || slot >= (int)vslot.size()) {
|
||||
verr.SetError(EINVAL, "cannot load drive %d from invalid slot %d", drv, slot);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EINVAL;
|
||||
}
|
||||
if (!drive[drv].empty()) {
|
||||
if (drive[drv].vs == slot) return 0; /* already loaded from this slot */
|
||||
verr.SetError(EBUSY, "drive %d already loaded from slot %d", drv, slot);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EBUSY;
|
||||
}
|
||||
if (vslot[slot].drv >= 0) {
|
||||
verr.SetError(EINVAL, "requested slot %d already loaded in drive %d", slot, drv);
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return ENOENT;
|
||||
}
|
||||
if (vslot[slot].empty()) {
|
||||
verr.SetError(EINVAL, "cannot load drive %d from empty slot %d", drv, slot);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return ENOENT;
|
||||
}
|
||||
/* Create symlink for drive pointing to volume file */
|
||||
drive[drv].vs = slot;
|
||||
if ((rc = CreateDriveSymlink(drv))) {
|
||||
drive[drv].vs = -1;
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
/* Save state of newly loaded drive */
|
||||
@@ -630,14 +623,14 @@ int DiskChanger::LoadDrive(int drv, int slot)
|
||||
/* Error writing drive state file */
|
||||
RemoveDriveSymlink(drv);
|
||||
drive[drv].vs = -1;
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
/* Assign virtual slot to drive */
|
||||
vslot[slot].drv = drv;
|
||||
m = vslot[slot].mag_bay;
|
||||
ms = vslot[slot].mag_slot;
|
||||
log.Notice("loaded drive %d from slot %d (%s)", drv, slot, magazine[m].GetVolumeLabel(ms));
|
||||
vlog.Notice("loaded drive %d from slot %d (%s)", drv, slot, magazine[m].GetVolumeLabel(ms));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -652,14 +645,9 @@ int DiskChanger::UnloadDrive(int drv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!changer_lock) {
|
||||
verr.SetError(EINVAL, "changer not initialized");
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EINVAL;
|
||||
}
|
||||
if (drv < 0) {
|
||||
verr.SetError(EINVAL, "invalid drive number %d", drv);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EINVAL;
|
||||
}
|
||||
SetMaxDrive(drv);
|
||||
@@ -669,7 +657,7 @@ int DiskChanger::UnloadDrive(int drv)
|
||||
}
|
||||
/* Remove drive's symlink */
|
||||
if ((rc = RemoveDriveSymlink(drv)) != 0) {
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
/* Remove virtual slot assignment */
|
||||
@@ -677,10 +665,10 @@ int DiskChanger::UnloadDrive(int drv)
|
||||
drive[drv].vs = -1;
|
||||
/* Update drive state file (will delete state file due to negative slot number) */
|
||||
if ((rc = SaveDriveState(drv)) != 0) {
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return rc;
|
||||
}
|
||||
log.Notice("unloaded drive %d", drv);
|
||||
vlog.Notice("unloaded drive %d", drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -699,26 +687,21 @@ int DiskChanger::CreateVolumes(int bay, int count, int start, const char *label_
|
||||
tString label, label_prefix(label_prefix_in);
|
||||
int i;
|
||||
|
||||
if (!changer_lock) {
|
||||
verr.SetError(EINVAL, "changer not initialized");
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return -1;
|
||||
}
|
||||
if (bay < 0 || bay >= (int)magazine.size()) {
|
||||
verr.SetError(EINVAL, "invalid magazine");
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return -1;
|
||||
}
|
||||
if (count < 1) count = 1;
|
||||
tStrip(tRemoveEOL(label_prefix));
|
||||
if (label_prefix.empty()) {
|
||||
/* Default prefix is storage-name_magazine-number */
|
||||
tFormat(label_prefix, "%s_%d_", conf.storage_name.c_str(), bay);
|
||||
tFormat(label_prefix, "%s_%04d_", conf.storage_name.c_str(), bay);
|
||||
}
|
||||
if (start < 0) {
|
||||
/* Find highest uniqueness number for this filename prefix */
|
||||
for (i = magazine[bay].num_slots * 5; i > 0; i--) {
|
||||
tFormat(label, "%s_%d", label_prefix.c_str(), i);
|
||||
tFormat(label, "%s%04d", label_prefix.c_str(), i);
|
||||
if (magazine[bay].GetVolumeSlot(label) >= 0) break;
|
||||
}
|
||||
start = i;
|
||||
@@ -733,6 +716,7 @@ int DiskChanger::CreateVolumes(int bay, int count, int start, const char *label_
|
||||
}
|
||||
fprintf(stdout, "creating label '%s'\n", label.c_str());
|
||||
if (magazine[bay].CreateVolume(label)) {
|
||||
/* On failure, update magazine state if any were created */
|
||||
if (i) magazine[bay].save();
|
||||
return -1;
|
||||
}
|
||||
@@ -743,61 +727,7 @@ int DiskChanger::CreateVolumes(int bay, int count, int start, const char *label_
|
||||
/* New mag state will require 'update slots' and 'label barcodes' in Bacula */
|
||||
needs_update = true;
|
||||
needs_label = true;
|
||||
log.Notice("update slots needed. %d volumes added to magazine %d",count , bay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Method to cause Bacula to update its catalog to reflect
|
||||
* changes in the available volumes
|
||||
*-------------------------------------------------*/
|
||||
int DiskChanger::UpdateBacula()
|
||||
{
|
||||
int rc;
|
||||
FILE *update_lock;
|
||||
tString cmd;
|
||||
char lockfile[4096];
|
||||
|
||||
/* Check if update needed */
|
||||
if (!needs_update && !needs_label) return 0; /* Nothing to do */
|
||||
/* Create update lock lockfile */
|
||||
snprintf(lockfile, sizeof(lockfile), "%s%s%s.updatelock", conf.work_dir.c_str(), DIR_DELIM,
|
||||
conf.storage_name.c_str());
|
||||
rc = exclusive_fopen(lockfile, &update_lock);
|
||||
if (rc == EEXIST) {
|
||||
/* Update already in progress in another process, so skip */
|
||||
return 0;
|
||||
}
|
||||
if (rc) {
|
||||
/* error creating lockfile, so skip */
|
||||
log.Error("bconsole: errno=%d creating update lockfile", rc);
|
||||
if (needs_update)
|
||||
log.Error("WARNING! 'update slots' needed in bconsole");
|
||||
if (needs_label)
|
||||
log.Error("WARNING! 'label barcodes' needed in bconsole");
|
||||
return 0;
|
||||
}
|
||||
log.Debug("created update lockfile for pid %d", getpid());
|
||||
/* Perform update slots command in bconsole */
|
||||
if (needs_update) {
|
||||
/* Issue update slots command in bconsole */
|
||||
tFormat(cmd, "update slots storage=\"%s\"", conf.storage_name.c_str());
|
||||
if(issue_bconsole_command(cmd.c_str())) {
|
||||
log.Error("WARNING! 'update slots' needed in bconsole");
|
||||
}
|
||||
}
|
||||
/* Perform label barcodes command in bconsole */
|
||||
if (needs_label) {
|
||||
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())) {
|
||||
log.Error("WARNING! 'label barcodes' needed in bconsole");
|
||||
}
|
||||
}
|
||||
/* Obtain changer lock before removing update lock */
|
||||
fclose(update_lock);
|
||||
unlink(lockfile);
|
||||
log.Debug("removed update lockfile for pid %d", getpid());
|
||||
vlog.Notice("%d volumes added to magazine %d",count , bay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -809,7 +739,7 @@ const char* DiskChanger::GetVolumeLabel(int slot)
|
||||
{
|
||||
if (slot <= 0 || slot >= (int)vslot.size()) {
|
||||
verr.SetError(-1, "volume label request from invalid slot %d", slot);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return NULL;
|
||||
}
|
||||
if (vslot[slot].empty()) return "";
|
||||
@@ -825,7 +755,7 @@ const char* DiskChanger::GetVolumePath(tString &path, int slot)
|
||||
path.clear();
|
||||
if (slot <= 0 || slot >= (int)vslot.size()) {
|
||||
verr.SetError(-1, "volume path request from invalid slot %d", slot);
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return NULL;
|
||||
}
|
||||
if (vslot[slot].empty()) return path.c_str();
|
||||
@@ -833,78 +763,6 @@ const char* DiskChanger::GetVolumePath(tString &path, int slot)
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Protected method to lock changer device using a lock file such that
|
||||
* only one process at a time may execute changer commands on the
|
||||
* same autochanger. If another process has the lock, then this process
|
||||
* will sleep 1 second before trying again. This try/wait loop will continue
|
||||
* until the lock is obtained or 'timeout' seconds have expired. If
|
||||
* timeout = 0 then only tries to obtain lock once. If timeout < 0
|
||||
* then doesn't return until the lock is obtained.
|
||||
* On success, returns true. Otherwise on error or timeout, sets
|
||||
* lasterr negative and returns false.
|
||||
*------------------------------------------------*/
|
||||
int DiskChanger::Lock(long timeout_seconds)
|
||||
{
|
||||
int rc;
|
||||
time_t timeout = 0;
|
||||
char lockfile[4096];
|
||||
|
||||
if (changer_lock) return 0;
|
||||
|
||||
if (timeout_seconds < 0) {
|
||||
timeout_seconds = 3600 * 24 * 365;
|
||||
}
|
||||
if (timeout_seconds > 0) {
|
||||
timeout = time(NULL) + timeout_seconds;
|
||||
}
|
||||
snprintf(lockfile, sizeof(lockfile), "%s%s%s.lock", conf.work_dir.c_str(), DIR_DELIM,
|
||||
conf.storage_name.c_str());
|
||||
rc = exclusive_fopen(lockfile, &changer_lock);
|
||||
if (rc == EEXIST && timeout == 0) {
|
||||
/* timeout=0 means do not wait */
|
||||
verr.SetErrorWithErrno(rc, "cannot open lockfile");
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return -1;
|
||||
}
|
||||
while (rc == EEXIST) {
|
||||
/* sleep before trying again */
|
||||
sleep(1);
|
||||
if (time(NULL) > timeout) {
|
||||
verr.SetError(EBUSY, "timeout waiting for lockfile");
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return EACCES;
|
||||
}
|
||||
rc = exclusive_fopen(lockfile, &changer_lock);
|
||||
}
|
||||
if (rc) {
|
||||
verr.SetErrorWithErrno(rc, "cannot open lockfile");
|
||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
||||
return -1;
|
||||
}
|
||||
/* Write PID to lockfile and leave open for exclusive R/W */
|
||||
fprintf(changer_lock, "%d", getpid());
|
||||
fflush(changer_lock);
|
||||
log.Debug("created lockfile for pid %d", getpid());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Protected method to unlock changer device
|
||||
*------------------------------------------------*/
|
||||
void DiskChanger::Unlock()
|
||||
{
|
||||
char lockfile[4096];
|
||||
if (!changer_lock) return;
|
||||
fclose(changer_lock);
|
||||
changer_lock = NULL;
|
||||
snprintf(lockfile, sizeof(lockfile), "%s%s%s.lock", conf.work_dir.c_str(), DIR_DELIM,
|
||||
conf.storage_name.c_str());
|
||||
log.Debug("removing lockfile for pid %d", getpid());
|
||||
unlink(lockfile);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Method returns true if magazine is not mounted,
|
||||
* else returns false.
|
||||
|
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2008-2015 Josh Fisher
|
||||
* vchanger copyright (C) 2008-2020 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
@@ -30,13 +30,12 @@
|
||||
class DiskChanger
|
||||
{
|
||||
public:
|
||||
DiskChanger() : changer_lock(NULL), needs_update(false), needs_label(false) {}
|
||||
virtual ~DiskChanger();
|
||||
DiskChanger() : needs_update(false), needs_label(false) {}
|
||||
virtual ~DiskChanger() {};
|
||||
int Initialize();
|
||||
int LoadDrive(int drv, int slot);
|
||||
int UnloadDrive(int drv);
|
||||
int CreateVolumes(int bay, int count, int start = -1, const char *label_prefix = "");
|
||||
int UpdateBacula();
|
||||
const char* GetVolumeLabel(int slot);
|
||||
const char* GetVolumePath(tString &fname, int slot);
|
||||
bool MagazineEmpty(int bay) const;
|
||||
@@ -54,8 +53,6 @@ public:
|
||||
inline const char* GetErrorMsg() const { return verr.GetErrorMsg(); }
|
||||
inline bool NeedsUpdate() const { return needs_update; }
|
||||
inline bool NeedsLabel() const { return needs_label; }
|
||||
int Lock(long timeout = 30);
|
||||
void Unlock();
|
||||
protected:
|
||||
void InitializeMagazines();
|
||||
int FindEmptySlotRange(int count);
|
||||
@@ -67,7 +64,6 @@ protected:
|
||||
int SaveDriveState(int drv);
|
||||
int RestoreDriveState(int drv);
|
||||
protected:
|
||||
FILE *changer_lock;
|
||||
bool needs_update;
|
||||
bool needs_label;
|
||||
ErrorHandler verr;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* loghandler.cpp
|
||||
*
|
||||
* Copyright (C) 2013-2014 Josh Fisher
|
||||
* Copyright (C) 2013-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
|
||||
@@ -22,6 +22,9 @@
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
@@ -34,13 +37,11 @@
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#ifndef HAVE_LOCALTIME_R
|
||||
#include "compat/localtime_r.h"
|
||||
#endif
|
||||
#define LOGHANDLER_SOURCE 1
|
||||
#include "loghandler.h"
|
||||
|
||||
LogHandler log;
|
||||
LogHandler vlog;
|
||||
|
||||
LogHandler::LogHandler() : use_syslog(false), max_debug_level(LOG_WARNING), errfs(stderr)
|
||||
{
|
||||
@@ -179,7 +180,7 @@ void LogHandler::WriteLog(int priority, const char *fmt, va_list vl)
|
||||
size_t n;
|
||||
struct tm bt;
|
||||
time_t t;
|
||||
char buf[1024];
|
||||
char ftim[128], buf[4096];
|
||||
Lock();
|
||||
if (priority > max_debug_level || priority < LOG_EMERG || !fmt) {
|
||||
Unlock();
|
||||
@@ -187,8 +188,8 @@ void LogHandler::WriteLog(int priority, const char *fmt, va_list vl)
|
||||
}
|
||||
t = time(NULL);
|
||||
localtime_r(&t, &bt);
|
||||
strftime(buf, 100, "%b %d %T: ", &bt);
|
||||
strncpy(buf + strlen(buf), fmt, sizeof(buf) - strlen(buf));
|
||||
strftime(ftim, 100, "%b %d %T: ", &bt);
|
||||
snprintf(buf, sizeof(buf), "%s [%d]: %s", ftim, getpid(), fmt);
|
||||
if (use_syslog) vsyslog(priority, buf, vl);
|
||||
else {
|
||||
n = strlen(buf);
|
||||
@@ -204,3 +205,17 @@ void LogHandler::WriteLog(int priority, const char *fmt, va_list vl)
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
* C wrapper to write to LogHandler object
|
||||
***************************************************************************************/
|
||||
|
||||
extern "C" void LogHandler_write(int level, const char *fmt, ...)
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl, fmt);
|
||||
vlog.WriteLog(level, fmt, vl);
|
||||
va_end(vl);
|
||||
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* loghandler.h
|
||||
*
|
||||
* Copyright (C) 2013-2014 Josh Fisher
|
||||
* Copyright (C) 2013-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
|
||||
@@ -32,6 +32,15 @@
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void LogHandler_write(int level, const char *format, ...);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
class LogHandler
|
||||
{
|
||||
public:
|
||||
@@ -50,6 +59,7 @@ public:
|
||||
void Debug(const char *fmt, ... );
|
||||
void MajorDebug(const char *fmt, ... );
|
||||
inline bool UsingSyslog() { return use_syslog; }
|
||||
friend void LogHandler_write(int level, const char *format, ...);
|
||||
protected:
|
||||
void Lock();
|
||||
void Unlock();
|
||||
@@ -64,7 +74,8 @@ protected:
|
||||
};
|
||||
|
||||
#ifndef LOGHANDLER_SOURCE
|
||||
extern LogHandler log;
|
||||
extern LogHandler vlog;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _LOGHANDLER_H_ */
|
||||
|
131
src/mymutex.cpp
Normal file
131
src/mymutex.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/* mymutex.cpp
|
||||
*
|
||||
* Copyright (C) 2017-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include "targetver.h"
|
||||
#include <windows.h>
|
||||
#include "win32_util.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SEMAPHORE_H
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#include "compat/semaphore.h"
|
||||
#include "loghandler.h"
|
||||
#include "mypopen.h"
|
||||
|
||||
|
||||
/*
|
||||
* Function to create a mutex owned by the caller. Waits up to max_wait seconds
|
||||
* for the mutex to be created. If max_wait is negative, waits indefinitely. If
|
||||
* max_wait is zero, tries once to create mutex and does not block.
|
||||
* On success, returns the handle of a named mutex. On error, returns zero and
|
||||
* sets errno appropriately.
|
||||
*/
|
||||
void* mymutex_create(const char *storage_name)
|
||||
{
|
||||
char lockname[4096];
|
||||
|
||||
if (!storage_name || !storage_name[0]) {
|
||||
/* Only create named mutex */
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
snprintf(lockname, sizeof(lockname), "vchanger-%s", storage_name);
|
||||
#else
|
||||
snprintf(lockname, sizeof(lockname), "/vchanger-%s", storage_name);
|
||||
#endif
|
||||
return (void*)sem_open(lockname, O_CREAT, 0770, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function to lock an opened mutex given by fd.
|
||||
* On success, returns zero. On error, returns -1 and
|
||||
* sets errno appropriately.
|
||||
*/
|
||||
int mymutex_lock(void *fd, time_t wait_sec)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (wait_sec == 0) return sem_trywait((sem_t*)fd);
|
||||
ts.tv_sec = time(NULL) + wait_sec; /* semaphore.h functions use absolute time */
|
||||
ts.tv_nsec = 0;
|
||||
return sem_timedwait((sem_t*)fd, &ts);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function to unlock an opened mutex given by fd.
|
||||
* On success, returns zero. On error, returns -1 and
|
||||
* sets errno appropriately.
|
||||
*/
|
||||
int mymutex_unlock(void *fd)
|
||||
{
|
||||
return sem_post((sem_t*)fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function to destroy a mutex owned by the caller.
|
||||
* On success, returns zero. On error, returns -1 and
|
||||
* sets errno appropriately.
|
||||
*/
|
||||
void mymutex_destroy(const char *name, void *fd)
|
||||
{
|
||||
if (fd) {
|
||||
sem_post((sem_t*)fd);
|
||||
sem_close((sem_t*)fd);
|
||||
}
|
||||
if (name && name[0]) sem_unlink(name);
|
||||
}
|
||||
|
32
src/mymutex.h
Normal file
32
src/mymutex.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* mymutex.h
|
||||
*
|
||||
* Copyright (C) 2017-2020 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MYMUTEX_H_
|
||||
#define _MYMUTEX_H_ 1
|
||||
|
||||
#ifndef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
void* mymutex_create(const char *storage_name);
|
||||
int mymutex_lock(void* fd, time_t wait_sec);
|
||||
int mymutex_unlock(void* fd);
|
||||
int mymutex_destroy(const char *storage_name, void* fd);
|
||||
|
||||
#endif /* _MYPOPEN_H_ */
|
@@ -179,7 +179,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
/* Build argv array from command line string */
|
||||
if (mypopen_args(cline, argv, argc, argbuf, sizeof(argbuf))) {
|
||||
/* Invalid args, so terminate child */
|
||||
log.Debug("popen: invalid cmdline args for child");
|
||||
vlog.Debug("popen: invalid cmdline args for child");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -193,7 +193,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
/* error creating pipe */
|
||||
return -1;
|
||||
}
|
||||
log.Debug("popen: child stdin uses pipe (%d -> %d)", pipe_in[0], pipe_in[1]);
|
||||
vlog.Debug("popen: child stdin uses pipe (%d -> %d)", pipe_in[0], pipe_in[1]);
|
||||
} else if (*fno_stdin == STDIN_FILENO) {
|
||||
/* Caller specified stdin so just let child inherit it */
|
||||
fno_stdin = NULL;
|
||||
@@ -212,7 +212,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
log.Debug("popen: child stdout uses pipe (%d -> %d)", pipe_out[0], pipe_out[1]);
|
||||
vlog.Debug("popen: child stdout uses pipe (%d -> %d)", pipe_out[0], pipe_out[1]);
|
||||
} else {
|
||||
if (*fno_stdout == STDOUT_FILENO) fno_stdout = NULL;
|
||||
else fsync(*fno_stdout);
|
||||
@@ -231,7 +231,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
log.Debug("popen: child stderr uses pipe (%d -> %d)", pipe_err[0], pipe_err[1]);
|
||||
vlog.Debug("popen: child stderr uses pipe (%d -> %d)", pipe_err[0], pipe_err[1]);
|
||||
} else {
|
||||
if (*fno_stderr == STDERR_FILENO) fno_stderr = NULL;
|
||||
else fsync(*fno_stderr);
|
||||
@@ -239,7 +239,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
}
|
||||
|
||||
/* fork a child process to run the command in */
|
||||
log.Debug("popen: forking now");
|
||||
vlog.Debug("popen: forking now");
|
||||
pid = fork();
|
||||
switch (pid)
|
||||
{
|
||||
@@ -251,7 +251,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
|
||||
case 0: /* child is running */
|
||||
/* close pipe ends always used by parent */
|
||||
log.Debug("popen: child closing pipe ends %d,%d,%d used by parent", pipe_in[1], pipe_out[0], pipe_err[0]);
|
||||
vlog.Debug("popen: child closing pipe ends %d,%d,%d used by parent", pipe_in[1], pipe_out[0], pipe_err[0]);
|
||||
if (pipe_in[1] >= 0) close(pipe_in[1]);
|
||||
if (pipe_out[0] >= 0) close(pipe_out[0]);
|
||||
if (pipe_err[0] >= 0) close(pipe_err[0]);
|
||||
@@ -259,7 +259,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
if (fno_stdin) {
|
||||
if (*fno_stdin < 0) {
|
||||
/* Read end of pipe will be child's stdin */
|
||||
log.Debug("popen: child will read stdin from %d", pipe_in[0]);
|
||||
vlog.Debug("popen: child will read stdin from %d", pipe_in[0]);
|
||||
dup2(pipe_in[0], STDIN_FILENO);
|
||||
close(pipe_in[0]);
|
||||
} else {
|
||||
@@ -272,7 +272,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
if (fno_stdout) {
|
||||
if (*fno_stdout < 0) {
|
||||
/* Write end of pipe will be child's stdout */
|
||||
log.Debug("popen: child will write stdout to %d", pipe_out[1]);
|
||||
vlog.Debug("popen: child will write stdout to %d", pipe_out[1]);
|
||||
dup2(pipe_out[1], STDOUT_FILENO);
|
||||
close(pipe_out[1]);
|
||||
} else {
|
||||
@@ -285,7 +285,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
if (fno_stderr) {
|
||||
if (*fno_stderr < 0) {
|
||||
/* Write end of pipe will be child's stderr */
|
||||
log.Debug("popen: child will write stderr to %d", pipe_err[1]);
|
||||
vlog.Debug("popen: child will write stderr to %d", pipe_err[1]);
|
||||
dup2(pipe_err[1], STDERR_FILENO);
|
||||
close(pipe_err[1]);
|
||||
} else {
|
||||
@@ -295,7 +295,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
}
|
||||
}
|
||||
/* now run the command */
|
||||
log.Debug("popen: child executing '%s'", argv[0]);
|
||||
vlog.Debug("popen: child executing '%s'", argv[0]);
|
||||
execvp(argv[0], argv);
|
||||
/* only gets here if execvp fails */
|
||||
return -1;
|
||||
@@ -304,7 +304,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
/* parent is running this */
|
||||
|
||||
/* close pipe ends always used by child */
|
||||
log.Debug("popen: parent closing pipe ends %d,%d,%d used by child", pipe_in[0], pipe_out[1], pipe_err[1]);
|
||||
vlog.Debug("popen: parent closing pipe ends %d,%d,%d used by child", pipe_in[0], pipe_out[1], pipe_err[1]);
|
||||
if (pipe_in[0] >= 0) close(pipe_in[0]);
|
||||
if (pipe_out[1] >= 0) close(pipe_out[1]);
|
||||
if (pipe_err[1] >= 0) close(pipe_err[1]);
|
||||
@@ -314,25 +314,25 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
if (*fno_stdin < 0) {
|
||||
/* Caller will be writing to child's stdin through pipe */
|
||||
*fno_stdin = pipe_in[1];
|
||||
log.Debug("popen: parent writes child's stdin to %d", pipe_in[1]);
|
||||
vlog.Debug("popen: parent writes child's stdin to %d", pipe_in[1]);
|
||||
}
|
||||
}
|
||||
if (fno_stdout) {
|
||||
if (*fno_stdout < 0) {
|
||||
/* Caller will be reading from child's stdout through pipe */
|
||||
*fno_stdout = pipe_out[0];
|
||||
log.Debug("popen: parent reads child's stdout from %d", pipe_out[0]);
|
||||
vlog.Debug("popen: parent reads child's stdout from %d", pipe_out[0]);
|
||||
}
|
||||
}
|
||||
if (fno_stderr) {
|
||||
if (*fno_stderr < 0) {
|
||||
/* Caller will be reading from child's stderr through pipe */
|
||||
*fno_stderr = pipe_err[0];
|
||||
log.Debug("popen: parent reads child's stderr from %d", pipe_err[0]);
|
||||
vlog.Debug("popen: parent reads child's stderr from %d", pipe_err[0]);
|
||||
}
|
||||
}
|
||||
//sleep(2);
|
||||
log.Debug("popen: parent returning pid=%d of child", pid);
|
||||
vlog.Debug("popen: parent returning pid=%d of child", pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
/* Build argv array from command line string */
|
||||
if (mypopen_args(cline, argv, argc, argbuf, sizeof(argbuf))) {
|
||||
/* Invalid args, so terminate child */
|
||||
log.Debug("popen: invalid cmdline args for child");
|
||||
vlog.Debug("popen: invalid cmdline args for child");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -375,7 +375,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
return -1;
|
||||
}
|
||||
child_in = pipe_in[0];
|
||||
log.Debug("popen: child stdin uses pipe (%d -> %d)", pipe_in[0], pipe_in[1]);
|
||||
vlog.Debug("popen: child stdin uses pipe (%d -> %d)", pipe_in[0], pipe_in[1]);
|
||||
} else {
|
||||
if (*fno_stdin != STDIN_FILENO) {
|
||||
/* Caller supplied an open file to use as child's stdin */
|
||||
@@ -397,7 +397,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
return -1;
|
||||
}
|
||||
child_out = pipe_out[1];
|
||||
log.Debug("popen: child stdout uses pipe (%d -> %d)", pipe_out[0], pipe_out[1]);
|
||||
vlog.Debug("popen: child stdout uses pipe (%d -> %d)", pipe_out[0], pipe_out[1]);
|
||||
} else {
|
||||
if (*fno_stdout != STDOUT_FILENO) {
|
||||
/* Caller supplied open file to use as child's stdout */
|
||||
@@ -419,7 +419,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
return -1;
|
||||
}
|
||||
child_err = pipe_err[1];
|
||||
log.Debug("popen: child stderr uses pipe (%d -> %d)", pipe_err[0], pipe_err[1]);
|
||||
vlog.Debug("popen: child stderr uses pipe (%d -> %d)", pipe_err[0], pipe_err[1]);
|
||||
} else {
|
||||
if (*fno_stderr != STDERR_FILENO) {
|
||||
/* Caller supplied an open file to use as child's stderr */
|
||||
@@ -547,7 +547,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
||||
if (pipe_out[0] >= 0) *fno_stdout = pipe_out[0];
|
||||
if (pipe_err[0] >= 0) *fno_stderr = pipe_err[0];
|
||||
|
||||
log.Debug("popen: parent returning pid=%d of child", pid);
|
||||
vlog.Debug("popen: parent returning pid=%d of child", pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2008-2013 Josh Fisher
|
||||
* vchanger copyright (C) 2008-2018 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
@@ -41,6 +41,7 @@
|
||||
#endif
|
||||
|
||||
#include "uuidlookup.h"
|
||||
#include "loghandler.h"
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
|
||||
@@ -230,6 +231,7 @@ static int GetDevMountpoint(char *mountp, size_t mountp_sz, const char *devname)
|
||||
*/
|
||||
static int GetDevMountpoint(char *mountp, size_t mountp_sz, const char *devname)
|
||||
{
|
||||
LogHandler_write(LOG_ERROR, "build does not support getmntent() or getfsstat() calls");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -256,8 +258,8 @@ int GetMountpointFromUUID(char *mountp, size_t mountp_sz, const char *uuid_str)
|
||||
struct udev_list_entry *devices, *dev_list_entry;
|
||||
struct udev_device *dev;
|
||||
int rc = -3;
|
||||
const char *dev_name, *path, *uuid;
|
||||
size_t n, pos, dev_name_len;
|
||||
const char *dev_name, *dev_links, *path, *uuid;
|
||||
size_t n, pos, dev_links_len;
|
||||
char devlink[4096];
|
||||
|
||||
if (!mountp || !mountp_sz) return -2;
|
||||
@@ -280,29 +282,50 @@ int GetMountpointFromUUID(char *mountp, size_t mountp_sz, const char *uuid_str)
|
||||
dev_name = udev_device_get_property_value(dev, "DEVNAME");
|
||||
if (dev_name == NULL) {
|
||||
/* Failed to get kernel device node */
|
||||
LogHandler_write(LOG_DEBUG, "filesystem %s has no udev assigned device node",
|
||||
uuid_str);
|
||||
break;
|
||||
}
|
||||
LogHandler_write(LOG_DEBUG, "filesystem %s has udev assigned device %s",
|
||||
uuid_str, dev_name);
|
||||
/* Lookup mountpoint of the kernel device node */
|
||||
rc = GetDevMountpoint(mountp, mountp_sz, dev_name);
|
||||
if (rc == 0) break;
|
||||
/* If not mounted as the DEVNAME, also check if mounted as
|
||||
* a device alias name from DEVLINKS */
|
||||
dev_name = udev_device_get_property_value(dev, "DEVLINKS");
|
||||
if (dev_name == NULL) {
|
||||
/* Failed to get device alias links */
|
||||
if (rc == 0) {
|
||||
/* Found mountpoint */
|
||||
LogHandler_write(LOG_DEBUG, "filesystem %s (device %s) mounted at %s", uuid_str, dev_name, mountp);
|
||||
break;
|
||||
}
|
||||
dev_name_len = strlen(dev_name);
|
||||
pos = 0;
|
||||
while (rc == -4 && pos < dev_name_len) {
|
||||
for (n = pos; n < dev_name_len && !isblank(dev_name[n]); n++) ;
|
||||
n -= pos;
|
||||
memmove(devlink, dev_name + pos, n);
|
||||
devlink[n] = 0;
|
||||
rc = GetDevMountpoint(mountp, mountp_sz, devlink);
|
||||
pos += n;
|
||||
while (pos < dev_name_len && isblank(dev_name[pos])) ++pos;
|
||||
if (rc == -4) {
|
||||
/* If not mounted as the DEVNAME, also check if mounted as
|
||||
* a device alias name from DEVLINKS */
|
||||
dev_links = udev_device_get_property_value(dev, "DEVLINKS");
|
||||
if (dev_links == NULL) {
|
||||
/* No device alias links found */
|
||||
break;
|
||||
}
|
||||
LogHandler_write(LOG_DEBUG, "device %s not found in system mounts, searching all udev device aliases",
|
||||
dev_name);
|
||||
/* For each device alias, look for a mountpoint */
|
||||
dev_links_len = strlen(dev_links);
|
||||
pos = 0;
|
||||
while (rc == -4 && pos < dev_links_len) {
|
||||
for (n = pos; n < dev_links_len && !isblank(dev_links[n]); n++) ;
|
||||
n -= pos;
|
||||
memmove(devlink, dev_links + pos, n);
|
||||
devlink[n] = 0;
|
||||
rc = GetDevMountpoint(mountp, mountp_sz, devlink);
|
||||
if (rc == 0) {
|
||||
/* Device alias is mounted */
|
||||
LogHandler_write(LOG_DEBUG, "filesystem %s (device %s) mounted at %s", uuid_str, devlink,
|
||||
mountp);
|
||||
break;
|
||||
}
|
||||
rc = -4; /* Ignore other errors from attempt to get alias's mountpoint */
|
||||
pos += n;
|
||||
while (pos < dev_links_len && isblank(dev_links[pos])) ++pos;
|
||||
}
|
||||
}
|
||||
if (rc == -4) LogHandler_write(LOG_DEBUG, "filesystem %s (device %s) not mounted", uuid_str, dev_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -340,7 +363,11 @@ int GetMountpointFromUUID(char *mountp, size_t mountp_sz, const char *uuid_str)
|
||||
#else
|
||||
dev_name = blkid_get_devname(NULL, "UUID", uuid_str);
|
||||
#endif
|
||||
if (!dev_name) return -3; /* no device with UUID found */
|
||||
if (!dev_name) {
|
||||
LogHandler_write(LOG_DEBUG, "filesystem %s not found", uuid_str);
|
||||
return -3;
|
||||
}
|
||||
LogHandler_write(LOG_DEBUG, "libblkid found filesystem %s at device %s", uuid_str, dev_name);
|
||||
|
||||
/* find mount point for device */
|
||||
rc = GetDevMountpoint(mountp, mountp_sz, dev_name);
|
||||
@@ -355,6 +382,7 @@ int GetMountpointFromUUID(char *mountp, size_t mountp_sz, const char *uuid_str)
|
||||
*/
|
||||
int GetMountpointFromUUID(char *mountp, size_t mountp_sz, const char *uuid_str)
|
||||
{
|
||||
LogHandler_write(LOG_DEBUG, "GetMountpointFromUUID: UUID lookups not supported by this build");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
171
src/vchanger.cpp
171
src/vchanger.cpp
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* This file is part of the vchanger package
|
||||
*
|
||||
* vchanger copyright (C) 2008-2015 Josh Fisher
|
||||
* vchanger copyright (C) 2008-2020 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
@@ -31,6 +31,9 @@
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@@ -53,7 +56,10 @@
|
||||
#include "util.h"
|
||||
#include "compat_defs.h"
|
||||
#include "loghandler.h"
|
||||
#include "errhandler.h"
|
||||
#include "diskchanger.h"
|
||||
#include "mymutex.h"
|
||||
#include "bconsole.h"
|
||||
|
||||
DiskChanger changer;
|
||||
|
||||
@@ -80,6 +86,7 @@ typedef struct _cmdparams_s
|
||||
{
|
||||
bool print_version;
|
||||
bool print_help;
|
||||
bool force;
|
||||
int command;
|
||||
int slot;
|
||||
int drive;
|
||||
@@ -115,12 +122,15 @@ static void print_help(void)
|
||||
" changer defined by vchanger configuration file\n"
|
||||
" 'config_file' using 'slot', 'device', and 'drive'\n"
|
||||
" vchanger [options] config_file LISTMAGS\n"
|
||||
" vchanger extension to list info on all defined magazines.\n"
|
||||
" API extension to list info on all defined magazines.\n"
|
||||
" vchanger [options] config_file CREATEVOLS mag_ndx count [start] [CREATEVOLS options]\n"
|
||||
" vchanger extension to create 'count' empty volume files on the magazine at\n"
|
||||
" index 'mag_ndx'. If specified, 'start' is the lowest integer to use when\n"
|
||||
" API extension to create 'count' empty volume files on the magazine at\n"
|
||||
" index 'mag_ndx'. If specified, 'start' is the lowest integer to use in\n"
|
||||
" appending integers to the label prefix when generating volume names.\n"
|
||||
" vchanger [options] config_file REFRESH\n"
|
||||
" API extension to issue an Update Slots command in bconsole if a change\n"
|
||||
" in the virtual slot to volume file mapping is detected. The --force flag\n"
|
||||
" forces the bconsole call regardless detected changes.\n"
|
||||
" vchanger --version\n"
|
||||
" print version info\n"
|
||||
" vchanger --help\n"
|
||||
@@ -131,13 +141,13 @@ static void print_help(void)
|
||||
"\nCREATEVOLS command options:\n"
|
||||
" -l, --label=string string to use as a prefix for determining the\n"
|
||||
" barcode label of the volume files created. Labels\n"
|
||||
" will be of the form 'string'_N, where N is an\n"
|
||||
" integer. By default the prefix will be generated\n"
|
||||
" using the changer name and the position of the\n"
|
||||
" magazine's declaration in the configuration file.\n"
|
||||
" --pool=string Overrides the default pool, defined in the vchanger\n"
|
||||
" config file, that new volumes should be placed into\n"
|
||||
" when labeling newly created volumes.\n"
|
||||
" will be of the form 'string'N, where N is a\n"
|
||||
" 4 digit integer with leading zeros. The magazine\n"
|
||||
" name is used as the prefix string by default.\n"
|
||||
" --pool=string Overrides the default pool that new volumes should\n"
|
||||
" be placed into when labeling newly created volumes.\n"
|
||||
"\nREFRESH command options:\n"
|
||||
" --force Force a bconsole update slots command to be invoked\n"
|
||||
"\nReport bugs to %s.\n", PACKAGE_BUGREPORT);
|
||||
}
|
||||
|
||||
@@ -147,6 +157,7 @@ static void print_help(void)
|
||||
#define LONGONLYOPT_VERSION 0
|
||||
#define LONGONLYOPT_HELP 1
|
||||
#define LONGONLYOPT_POOL 2
|
||||
#define LONGONLYOPT_FORCE 3
|
||||
|
||||
static int parse_cmdline(int argc, char *argv[])
|
||||
{
|
||||
@@ -158,10 +169,12 @@ static int parse_cmdline(int argc, char *argv[])
|
||||
{ "group", 1, 0, 'g' },
|
||||
{ "label", 1, 0, 'l' },
|
||||
{ "pool", 1, 0, LONGONLYOPT_POOL },
|
||||
{ "force", 0, 0, LONGONLYOPT_FORCE },
|
||||
{ 0, 0, 0, 0 } };
|
||||
|
||||
cmdl.print_version = false;
|
||||
cmdl.print_help = false;
|
||||
cmdl.force = false;
|
||||
cmdl.command = 0;
|
||||
cmdl.slot = 0;
|
||||
cmdl.drive = 0;
|
||||
@@ -198,6 +211,9 @@ static int parse_cmdline(int argc, char *argv[])
|
||||
case LONGONLYOPT_POOL:
|
||||
cmdl.pool = optarg;
|
||||
break;
|
||||
case LONGONLYOPT_FORCE:
|
||||
cmdl.force = true;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown option %s\n", optarg);
|
||||
return -1;
|
||||
@@ -237,6 +253,11 @@ static int parse_cmdline(int argc, char *argv[])
|
||||
fprintf(stderr, "flag --pool not valid for this command\n");
|
||||
return -1;
|
||||
}
|
||||
/* Make sure only REFRESH command has --force flag */
|
||||
if (cmdl.force && cmdl.command != CMD_REFRESH) {
|
||||
fprintf(stderr, "flag --force not valid for this command\n");
|
||||
return -1;
|
||||
}
|
||||
/* Check param 3 exists */
|
||||
++ndx;
|
||||
if (ndx >= argc) {
|
||||
@@ -378,7 +399,7 @@ static int do_list_cmd()
|
||||
fprintf(stdout, "%d:%s\n", slot, changer.GetVolumeLabel(slot));
|
||||
}
|
||||
}
|
||||
log.Info(" SUCCESS sent list to stdout");
|
||||
vlog.Info(" SUCCESS sent list to stdout");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -390,7 +411,7 @@ static int do_list_cmd()
|
||||
static int do_slots_cmd()
|
||||
{
|
||||
fprintf(stdout, "%d\n", changer.NumSlots());
|
||||
log.Info(" SUCCESS reporting %d slots", changer.NumSlots());
|
||||
vlog.Info(" SUCCESS reporting %d slots", changer.NumSlots());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -403,10 +424,10 @@ static int do_load_cmd()
|
||||
{
|
||||
if (changer.LoadDrive(cmdl.drive, cmdl.slot)) {
|
||||
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
||||
log.Error(" ERROR loading slot %d into drive %d", cmdl.slot, cmdl.drive);
|
||||
vlog.Error(" ERROR loading slot %d into drive %d", cmdl.slot, cmdl.drive);
|
||||
return 1;
|
||||
}
|
||||
log.Info(" SUCCESS loading slot %d into drive %d", cmdl.slot, cmdl.drive);
|
||||
vlog.Info(" SUCCESS loading slot %d into drive %d", cmdl.slot, cmdl.drive);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -419,10 +440,10 @@ static int do_unload_cmd()
|
||||
{
|
||||
if (changer.UnloadDrive(cmdl.drive)) {
|
||||
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
||||
log.Error(" ERROR unloading slot %d from drive %d", cmdl.slot, cmdl.drive);
|
||||
vlog.Error(" ERROR unloading slot %d from drive %d", cmdl.slot, cmdl.drive);
|
||||
return 1;
|
||||
}
|
||||
log.Info(" SUCCESS unloading slot %d from drive %d", cmdl.slot, cmdl.drive);
|
||||
vlog.Info(" SUCCESS unloading slot %d from drive %d", cmdl.slot, cmdl.drive);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -437,10 +458,11 @@ static int do_loaded_cmd()
|
||||
int slot = changer.GetDriveSlot(cmdl.drive);
|
||||
if (slot < 0) slot = 0;
|
||||
fprintf(stdout, "%d\n", slot);
|
||||
log.Info(" SUCCESS reporting drive %d loaded from slot %d", cmdl.drive, slot);
|
||||
vlog.Info(" SUCCESS reporting drive %d loaded from slot %d", cmdl.drive, slot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* LISTALL Command
|
||||
* Prints state of drives (loaded or empty), followed by state
|
||||
@@ -471,7 +493,7 @@ static int do_list_all()
|
||||
fprintf(stdout, "S:%d:E\n", n);
|
||||
}
|
||||
}
|
||||
log.Info(" SUCCESS sent listall to stdout");
|
||||
vlog.Info(" SUCCESS sent listall to stdout");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -487,7 +509,7 @@ static int do_list_magazines()
|
||||
|
||||
if (changer.NumMagazines() == 0) {
|
||||
fprintf(stdout, "No magazines are defined\n");
|
||||
log.Info(" SUCCESS no magazines are defined");
|
||||
vlog.Info(" SUCCESS no magazines are defined");
|
||||
return 0;
|
||||
}
|
||||
for (n = 0; n < changer.NumMagazines(); n++) {
|
||||
@@ -498,10 +520,11 @@ static int do_list_magazines()
|
||||
changer.GetMagazineStartSlot(n), changer.GetMagazineMountpoint(n));
|
||||
}
|
||||
}
|
||||
log.Info(" SUCCESS listing magazine info to stdout");
|
||||
vlog.Info(" SUCCESS listing magazine info to stdout");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
* CREATEVOLS (Create Volumes) Command
|
||||
* Creates volume files on the specified magazine
|
||||
@@ -511,12 +534,12 @@ static int do_create_vols()
|
||||
/* Create new volume files on magazine */
|
||||
if (changer.CreateVolumes(cmdl.mag_bay, cmdl.count, cmdl.slot, cmdl.label_prefix.c_str())) {
|
||||
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
||||
log.Error(" ERROR");
|
||||
vlog.Error(" ERROR: %s", changer.GetErrorMsg());
|
||||
return -1;
|
||||
}
|
||||
fprintf(stdout, "Created %d volume files on magazine %d\n",
|
||||
cmdl.count, cmdl.mag_bay);
|
||||
log.Info(" SUCCESS");
|
||||
vlog.Info(" SUCCESS");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -529,13 +552,14 @@ int main(int argc, char *argv[])
|
||||
int rc;
|
||||
FILE *fs = NULL;
|
||||
int32_t error_code;
|
||||
void *command_mux = NULL, *bconsole_mux = NULL;
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
setlocale(LC_ALL, "");
|
||||
#endif
|
||||
|
||||
/* Log initially to stderr */
|
||||
log.OpenLog(stderr, LOG_ERR);
|
||||
vlog.OpenLog(stderr, LOG_ERR);
|
||||
/* parse the command line */
|
||||
if ((error_code = parse_cmdline(argc, argv)) != 0) {
|
||||
print_help();
|
||||
@@ -551,6 +575,7 @@ int main(int argc, char *argv[])
|
||||
print_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read vchanger config file */
|
||||
if (!conf.Read(cmdl.config_file)) {
|
||||
return 1;
|
||||
@@ -573,89 +598,137 @@ int main(int argc, char *argv[])
|
||||
fprintf(stderr, "Error opening opening log file\n");
|
||||
return 1;
|
||||
}
|
||||
log.OpenLog(fs, conf.log_level);
|
||||
vlog.OpenLog(fs, conf.log_level);
|
||||
}
|
||||
/* Validate and commit configuration parameters */
|
||||
if (!conf.Validate()) {
|
||||
fprintf(stderr, "ERROR! configuration file error\n");
|
||||
return 1;
|
||||
}
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
/* Ignore SIGPIPE signals */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
/* Initialize changer. A lock file is created to serialize access
|
||||
|
||||
/* Open/create named mutex */
|
||||
command_mux = mymutex_create("vchanger-command");
|
||||
if (command_mux == 0) {
|
||||
vlog.Error("ERROR! failed to create named mutex errno=%d", errno);
|
||||
fprintf(stderr, "ERROR! failed to create named mutex errno=%d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
/* Lock mutex to perform command */
|
||||
if (mymutex_lock(command_mux, 300)) {
|
||||
vlog.Error("ERROR! failed to lock named mutex errno=%d", errno);
|
||||
fprintf(stderr, "ERROR! failed to lock named mutex errno=%d\n", errno);
|
||||
mymutex_destroy("vchanger-command", command_mux);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize changer. A named mutex is created to serialize access
|
||||
* to the changer. As a result, changer initialization may block
|
||||
* for up to 30 seconds, and may fail if a timeout is reached */
|
||||
if (changer.Initialize()) {
|
||||
vlog.Error("%s", changer.GetErrorMsg());
|
||||
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
||||
mymutex_destroy("vchanger-command", command_mux);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Perform command */
|
||||
switch (cmdl.command) {
|
||||
case CMD_LIST:
|
||||
log.Debug("==== preforming LIST command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming LIST command");
|
||||
error_code = do_list_cmd();
|
||||
break;
|
||||
case CMD_SLOTS:
|
||||
log.Debug("==== preforming SLOTS command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming SLOTS command");
|
||||
error_code = do_slots_cmd();
|
||||
break;
|
||||
case CMD_LOAD:
|
||||
log.Debug("==== preforming LOAD command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming LOAD command");
|
||||
error_code = do_load_cmd();
|
||||
break;
|
||||
case CMD_UNLOAD:
|
||||
log.Debug("==== preforming UNLOAD command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming UNLOAD command");
|
||||
error_code = do_unload_cmd();
|
||||
break;
|
||||
case CMD_LOADED:
|
||||
log.Debug("==== preforming LOADED command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming LOADED command");
|
||||
error_code = do_loaded_cmd();
|
||||
break;
|
||||
case CMD_LISTALL:
|
||||
log.Debug("==== preforming LISTALL command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming LISTALL command");
|
||||
error_code = do_list_all();
|
||||
break;
|
||||
case CMD_LISTMAGS:
|
||||
log.Debug("==== preforming LISTMAGS command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming LISTMAGS command");
|
||||
error_code = do_list_magazines();
|
||||
break;
|
||||
case CMD_CREATEVOLS:
|
||||
log.Debug("==== preforming CREATEVOLS command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming CREATEVOLS command");
|
||||
error_code = do_create_vols();
|
||||
break;
|
||||
case CMD_REFRESH:
|
||||
log.Debug("==== preforming REFRESH command pid=%d", getpid());
|
||||
vlog.Debug("==== preforming REFRESH command");
|
||||
error_code = 0;
|
||||
log.Info(" SUCCESS pid=%d", getpid());
|
||||
break;
|
||||
}
|
||||
changer.Unlock();
|
||||
|
||||
/* If there was an error, then exit */
|
||||
if (error_code) return error_code;
|
||||
if (error_code) {
|
||||
mymutex_destroy("vchanger-command", command_mux);
|
||||
return error_code;
|
||||
}
|
||||
|
||||
/* If not updating Bacula, then exit */
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
conf.bconsole = ""; /* Issuing bconsole commands not implemented on Windows */
|
||||
#endif
|
||||
if (conf.bconsole.empty()) {
|
||||
/* Bacula interaction via bconsole is disabled, so log warnings */
|
||||
if (changer.NeedsUpdate())
|
||||
log.Error("WARNING! 'update slots' needed in bconsole pid=%d", getpid());
|
||||
vlog.Error("WARNING! 'update slots' needed in bconsole pid=%d", getpid());
|
||||
if (changer.NeedsLabel())
|
||||
log.Error("WARNING! 'label barcodes' needed in bconsole pid=%d", getpid());
|
||||
vlog.Error("WARNING! 'label barcodes' needed in bconsole pid=%d", getpid());
|
||||
mymutex_destroy("vchanger-command", command_mux);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update Bacula via bconsole */
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
changer.UpdateBacula();
|
||||
#else
|
||||
/* Auto-update of bacula not working for Windows */
|
||||
if (changer.NeedsUpdate())
|
||||
log.Error("WARNING! 'update slots' needed in bconsole");
|
||||
if (changer.NeedsLabel())
|
||||
log.Error("WARNING! 'label barcodes' needed in bconsole");
|
||||
#endif
|
||||
|
||||
/* Create named mutex to prevent further bconsole commands when bconsole
|
||||
* commands have already been initiated */
|
||||
bconsole_mux = mymutex_create("vchanger-bconsole");
|
||||
if (bconsole_mux == 0) {
|
||||
vlog.Error("ERROR! failed to create named mutex errno=%d", errno);
|
||||
fprintf(stderr, "ERROR! failed to create named mutex errno=%d\n", errno);
|
||||
mymutex_destroy("vchanger-command", command_mux);
|
||||
return 1;
|
||||
}
|
||||
/* Lock mutex to perform command */
|
||||
if (mymutex_lock(bconsole_mux, 0)) {
|
||||
/* If bconsole mutex is locked because another instance has previously invoked
|
||||
* bconsole, then this instance is the result of bconsole itself invoking
|
||||
* additional vchanger processes to handle the previous instance's bconsole
|
||||
* command. So tto prevent a race condition, this instance must not invoke
|
||||
* further bconsole processes. */
|
||||
vlog.Info("invoked from bconsole - skipping further bconsole commands", errno);
|
||||
mymutex_destroy("vchanger-bconsole", bconsole_mux);
|
||||
mymutex_destroy("vchanger-command", command_mux);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unlock the command mutex long enough to issue bconsole commands.
|
||||
* Note that the bconsole mutex is left locked to prevent a race condition
|
||||
* should the invoked bconsole process need to invoke additional
|
||||
* instances of vchanger. */
|
||||
mymutex_unlock(command_mux);
|
||||
IssueBconsoleCommands(changer.NeedsUpdate() | cmdl.force, changer.NeedsLabel());
|
||||
mymutex_lock(command_mux, 300);
|
||||
|
||||
/* Cleanup */
|
||||
mymutex_destroy("vchanger-bconsole", command_mux);
|
||||
mymutex_destroy("vchanger-command", bconsole_mux);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2008-2014 Josh Fisher
|
||||
* vchanger copyright (C) 2008-2018 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
@@ -45,26 +45,21 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include "targetver.h"
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef HAVE_SHLOBJ_H
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
#ifdef HAVE_DIRECT_H
|
||||
#include <direct.h>
|
||||
#define DIR_DELIM "\\"
|
||||
#define DIR_DELIM_C '\\'
|
||||
#define MAG_VOLUME_MASK 0
|
||||
#else
|
||||
#define DIR_DELIM "/"
|
||||
#define DIR_DELIM_C '/'
|
||||
#define MAG_VOLUME_MASK S_IWGRP|S_IRWXO
|
||||
#endif
|
||||
|
||||
#include "compat_defs.h"
|
||||
#include "loghandler.h"
|
||||
#include "util.h"
|
||||
#define __VCONF_SOURCE 1
|
||||
#include "vconf.h"
|
||||
|
||||
/* Global configuration object */
|
||||
VchangerConfig conf;
|
||||
|
||||
/*-------------------------------------------
|
||||
* Config file keywords and defaults
|
||||
@@ -145,19 +140,19 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
|
||||
tmp_ini.ClearKeywordValues();
|
||||
if (!cfile || !cfile[0]) {
|
||||
log.Error("config file not specified");
|
||||
vlog.Error("config file not specified");
|
||||
return false;
|
||||
}
|
||||
/* Does config file exist */
|
||||
if (access(cfile, R_OK)) {
|
||||
log.Error("could not access config file %s", cfile);
|
||||
vlog.Error("could not access config file %s", cfile);
|
||||
return false;
|
||||
}
|
||||
/* Read config file values */
|
||||
rc = tmp_ini.Read(cfile);
|
||||
if (rc) {
|
||||
if (rc > 0) log.Error("Parse error in %s at line %d", cfile, rc);
|
||||
else log.Error("could not open config file %s", cfile);
|
||||
if (rc > 0) vlog.Error("Parse error in %s at line %d", cfile, rc);
|
||||
else vlog.Error("could not open config file %s", cfile);
|
||||
return false;
|
||||
}
|
||||
/* Update keyword values */
|
||||
@@ -168,7 +163,7 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
storage_name = (const char*)keyword[VK_STORAGE_NAME];
|
||||
tStrip(storage_name);
|
||||
if (storage_name.empty()) {
|
||||
log.Error("config file keyword '%s' must specify a non-empty string", VK_STORAGE_NAME);
|
||||
vlog.Error("config file keyword '%s' must specify a non-empty string", VK_STORAGE_NAME);
|
||||
return false;
|
||||
}
|
||||
/* Update defaults for this changer name */
|
||||
@@ -181,7 +176,7 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
work_dir = (const char*)keyword[VK_WORK_DIR];
|
||||
tStrip(work_dir);
|
||||
if (work_dir.empty()) {
|
||||
log.Error("config file keyword '%s' must specify a non-empty string", VK_WORK_DIR);
|
||||
vlog.Error("config file keyword '%s' must specify a non-empty string", VK_WORK_DIR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -191,7 +186,7 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
logfile = (const char*)keyword[VK_LOGFILE];
|
||||
tStrip(logfile);
|
||||
if (logfile.empty()) {
|
||||
log.Error("config file keyword '%s' must specify a non-empty string", VK_LOGFILE);
|
||||
vlog.Error("config file keyword '%s' must specify a non-empty string", VK_LOGFILE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -200,7 +195,7 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
if (keyword[VK_LOG_LEVEL].IsSet()) {
|
||||
log_level = (int)keyword[VK_LOG_LEVEL];
|
||||
if (log_level < 0 || log_level > 7) {
|
||||
log.Error("config file keyword '%s' must specify a value between 0 and 7 inclusive", VK_LOG_LEVEL);
|
||||
vlog.Error("config file keyword '%s' must specify a value between 0 and 7 inclusive", VK_LOG_LEVEL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +205,7 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
user = (const char*)keyword[VK_USER];
|
||||
tStrip(user);
|
||||
if (user.empty()) {
|
||||
log.Error("keyword '%s' value cannot be empty", VK_USER);
|
||||
vlog.Error("keyword '%s' value cannot be empty", VK_USER);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -220,7 +215,7 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
group = (const char*)keyword[VK_GROUP];
|
||||
tStrip(group);
|
||||
if (group.empty()) {
|
||||
log.Error("keyword '%s' value cannot be empty", VK_GROUP);
|
||||
vlog.Error("keyword '%s' value cannot be empty", VK_GROUP);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -242,7 +237,7 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
def_pool = (const char*)keyword[VK_DEF_POOL];
|
||||
tStrip(def_pool);
|
||||
if (def_pool.empty()) {
|
||||
log.Error("keyword '%s' value cannot be empty", VK_DEF_POOL);
|
||||
vlog.Error("keyword '%s' value cannot be empty", VK_DEF_POOL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -252,13 +247,13 @@ bool VchangerConfig::Read(const char *cfile)
|
||||
magazine = keyword[VK_MAGAZINE];
|
||||
}
|
||||
if (magazine.empty()) {
|
||||
log.Error("config file keyword '%s' must appear at least once", VK_MAGAZINE);
|
||||
vlog.Error("config file keyword '%s' must appear at least once", VK_MAGAZINE);
|
||||
return false;
|
||||
}
|
||||
for (n = 0; n < (int)magazine.size(); n++) {
|
||||
tStrip(magazine[n]);
|
||||
if (magazine[n].empty()) {
|
||||
log.Error("config file keyword '%s' cannot be set to the empty string", VK_MAGAZINE);
|
||||
vlog.Error("config file keyword '%s' cannot be set to the empty string", VK_MAGAZINE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -283,13 +278,13 @@ bool VchangerConfig::Validate()
|
||||
#else
|
||||
if (_mkdir(work_dir.c_str())) {
|
||||
#endif
|
||||
log.Error("could not create work directory '%s'", work_dir.c_str());
|
||||
vlog.Error("could not create work directory '%s'", work_dir.c_str());
|
||||
umask(old_mask);
|
||||
return false;
|
||||
}
|
||||
umask(old_mask);
|
||||
} else {
|
||||
log.Error("could not access work directory '%s'", work_dir.c_str());
|
||||
vlog.Error("could not access work directory '%s'", work_dir.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -299,7 +294,7 @@ bool VchangerConfig::Validate()
|
||||
if (!bconsole_config.empty()) {
|
||||
if (access(bconsole_config.c_str(), R_OK)) {
|
||||
/* If bconsole config doesn't exist or is not readable, disable use of bconsole */
|
||||
log.Warning("cannot read bconsole config file. Disabling Bacula interaction.");
|
||||
vlog.Warning("cannot read bconsole config file. Disabling Bacula interaction.");
|
||||
bconsole.clear();
|
||||
bconsole_config.clear();
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* This file is part of vchanger by Josh Fisher.
|
||||
*
|
||||
* vchanger copyright (C) 2008-2014 Josh Fisher
|
||||
* vchanger copyright (C) 2008-2018 Josh Fisher
|
||||
*
|
||||
* vchanger is free software.
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
@@ -65,6 +65,7 @@ extern char DEFAULT_STATEDIR[4096];
|
||||
#else
|
||||
char DEFAULT_LOGDIR[4096];
|
||||
char DEFAULT_STATEDIR[4096];
|
||||
VchangerConfig conf;
|
||||
#endif
|
||||
|
||||
#endif /* _VCONF_H_ */
|
||||
|
Reference in New Issue
Block a user