mirror of
https://github.com/wanderleihuttel/vchanger.git
synced 2025-04-19 08:55:14 +00:00
Add vchanger 1.0.3 code
This commit is contained in:
parent
7490e52578
commit
d7a0e39e91
3
AUTHORS
3
AUTHORS
@ -7,3 +7,6 @@ Principle Authors:
|
||||
Josh Fisher
|
||||
|
||||
Contributors:
|
||||
Bill Arlofski
|
||||
Wanderlei Hüttel
|
||||
Steven A. Falco
|
2
COPYING
2
COPYING
@ -1,5 +1,5 @@
|
||||
COPYRIGHTS:
|
||||
Vchanger is Copyright (C) 2008-2015 Josh Fisher.
|
||||
Vchanger is Copyright (C) 2008-2020 Josh Fisher.
|
||||
|
||||
LICENSE:
|
||||
Vchanger is licensed under the GNU GPL version 2, the full text
|
||||
|
21
ChangeLog
21
ChangeLog
@ -1,5 +1,26 @@
|
||||
vchanger ChangeLog
|
||||
|
||||
1.0.3 (2020-05-06)
|
||||
- Redesign locking mechanism for multiple instances using POSIX
|
||||
semaphores.
|
||||
- Use at, rather than nohup, in scripts invoked by udev rules to fix
|
||||
nohup not working as expected on some platforms.
|
||||
(Patch from Steven A. Falco)
|
||||
- Add spec file for Fedora 29 (Provided by Steven A. Falco)
|
||||
- Correct number of slots reported by SIZE command (Fixes bug 17)
|
||||
- Rename logging variables that conflict with cmath's log function (Fixes bug 18)
|
||||
1.0.2 (2018-06-14)
|
||||
- Use named mutex to prevent instances of vchanger invoked by Bacula during
|
||||
a bconsole call from initiating further bconsole calls. Prevents a race
|
||||
condition caused by the need for Bacula to invoke additional instances of
|
||||
vchanger when vchanger invokes bconsole to issue 'update slots' and
|
||||
'label barcodes' commands. (Fixes bug 15)
|
||||
- Prevent load command from loading the same virtual slot into more than
|
||||
one virtual drive. (Fixes bug 13)
|
||||
- Fix bconsole update slots command needs drive to be specified. [Patch
|
||||
from Bill Arlofski] (Fixes bug 14)
|
||||
- Improve generated volume label format. [Patch from Wanderlei Huttel]
|
||||
- Additional logging to help debug udev/UUID assignment problems
|
||||
1.0.1 (2015-06-09)
|
||||
- When looking up the mountpoint of a magazine by UUID with libudev,
|
||||
also look for mountpoint of device alias names in DEVLINKS in addition
|
||||
|
34
ReleaseNotes
34
ReleaseNotes
@ -1,4 +1,34 @@
|
||||
Release Notes for vchanger 1.0.1 2015-06-09
|
||||
Release Notes for vchanger 1.0.3 2020-05-07
|
||||
|
||||
Release 1.0.3
|
||||
|
||||
This is mostly a bug fix release, correcting the number of slots
|
||||
reported by SIZE/LIST commands, a compilation error on FreeBSD,
|
||||
and failure of the launch scripts invoked by udev on some platforms.
|
||||
|
||||
The locking mechanism to allow multiple instances and automatically
|
||||
issuing 'update slots' and other commands to bconsole has been
|
||||
redesigned to use POSIX semaphores.
|
||||
|
||||
Bugs Fixed:
|
||||
17 SIZE/LIST commands return wrong number of slots
|
||||
18 Compilation fails on FreeBSD 13 (head)
|
||||
|
||||
==================================================================
|
||||
|
||||
Release 1.0.2
|
||||
|
||||
This is a bug fix release, fixing three issues found in version 1.0.1
|
||||
and improving volume label formatting for CREATEVOLS command and logging
|
||||
of udev/UUID mountpoint discovery.
|
||||
|
||||
Bugs Fixed:
|
||||
|
||||
13 LOAD command allows loading slot into multiple drives
|
||||
14 Hang when bconsole called to update slots
|
||||
15 Race condition in bconsole call may hang vchanger
|
||||
|
||||
==================================================================
|
||||
|
||||
Release 1.0.1
|
||||
|
||||
@ -6,7 +36,7 @@
|
||||
Additionally, the Windows installer was fixed to correctly install on
|
||||
64-bit Windows and create Start Menu items.
|
||||
|
||||
Bugs Fixed:
|
||||
Bugs Fixed:
|
||||
|
||||
9 Vchanger may hang when issuing commands to Bacula
|
||||
10 uuidlookup.c compilation failure on FreeBSD 9.3
|
||||
|
11
config.h.in
11
config.h.in
@ -15,6 +15,9 @@
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#undef HAVE_CTYPE_H
|
||||
|
||||
/* have header direct.h */
|
||||
#undef HAVE_DIRECT_H
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
@ -69,7 +72,7 @@
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#undef HAVE_LOCALE_H
|
||||
|
||||
/* Define to 1 if you have the `localtime_r' function. */
|
||||
/* have function localtime_r */
|
||||
#undef HAVE_LOCALTIME_R
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
@ -96,6 +99,9 @@
|
||||
/* Define to 1 if you have the `readlink' function. */
|
||||
#undef HAVE_READLINK
|
||||
|
||||
/* Define to 1 if you have the <semaphore.h> header file. */
|
||||
#undef HAVE_SEMAPHORE_H
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
|
||||
@ -148,6 +154,9 @@
|
||||
*/
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#undef HAVE_SYS_MMAN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mount.h> header file. */
|
||||
#undef HAVE_SYS_MOUNT_H
|
||||
|
||||
|
316
config.h.in~
Normal file
316
config.h.in~
Normal file
@ -0,0 +1,316 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Copyright notice */
|
||||
#undef COPYRIGHT_NOTICE
|
||||
|
||||
/* Define to 1 if you have the <alloca.h> header file. */
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Have blkid_evaluate_tag function */
|
||||
#undef HAVE_BLKID_EVALUATE_TAG
|
||||
|
||||
/* Have blkid_get_devname function */
|
||||
#undef HAVE_BLKID_GET_DEVNAME
|
||||
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#undef HAVE_CTYPE_H
|
||||
|
||||
/* have header direct.h */
|
||||
#undef HAVE_DIRECT_H
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
#undef HAVE_DOPRNT
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `getfsstat' function. */
|
||||
#undef HAVE_GETFSSTAT
|
||||
|
||||
/* Define to 1 if you have the `getline' function. */
|
||||
#undef HAVE_GETLINE
|
||||
|
||||
/* Define to 1 if you have the `getmntent' function. */
|
||||
#undef HAVE_GETMNTENT
|
||||
|
||||
/* Define to 1 if you have the `getmntent_r' function. */
|
||||
#undef HAVE_GETMNTENT_R
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have the `getuid' function. */
|
||||
#undef HAVE_GETUID
|
||||
|
||||
/* Define to 1 if you have the <grp.h> header file. */
|
||||
#undef HAVE_GRP_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <io.h> header file. */
|
||||
#undef HAVE_IO_H
|
||||
|
||||
/* Define to 1 if you have the <libgen.h> header file. */
|
||||
#undef HAVE_LIBGEN_H
|
||||
|
||||
/* Define to 1 if you have the <libudev.h> header file. */
|
||||
#undef HAVE_LIBUDEV_H
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#undef HAVE_LOCALE_H
|
||||
|
||||
/* have function localtime_r */
|
||||
#undef HAVE_LOCALTIME_R
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <mntent.h> header file. */
|
||||
#undef HAVE_MNTENT_H
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <optarg.h> header file. */
|
||||
#undef HAVE_OPTARG_H
|
||||
|
||||
/* Define to 1 if you have the `pipe' function. */
|
||||
#undef HAVE_PIPE
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file. */
|
||||
#undef HAVE_PTHREAD_H
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#undef HAVE_PWD_H
|
||||
|
||||
/* Define to 1 if you have the `readlink' function. */
|
||||
#undef HAVE_READLINK
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
|
||||
/* have header shlobj.h */
|
||||
#undef HAVE_SHLOBJ_H
|
||||
|
||||
/* Define to 1 if you have the <signal.h> header file. */
|
||||
#undef HAVE_SIGNAL_H
|
||||
|
||||
/* Define to 1 if you have the `sleep' function. */
|
||||
#undef HAVE_SLEEP
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#undef HAVE_STDARG_H
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `symlink' function. */
|
||||
#undef HAVE_SYMLINK
|
||||
|
||||
/* Define to 1 if you have the `syslog' function. */
|
||||
#undef HAVE_SYSLOG
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#undef HAVE_SYSLOG_H
|
||||
|
||||
/* Define to 1 if you have the <sys/bitypes.h> header file. */
|
||||
#undef HAVE_SYS_BITYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#undef HAVE_SYS_MMAN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mount.h> header file. */
|
||||
#undef HAVE_SYS_MOUNT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/timespec.h> header file. */
|
||||
#undef HAVE_SYS_TIMESPEC_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ucred.h> header file. */
|
||||
#undef HAVE_SYS_UCRED_H
|
||||
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
|
||||
/* Define to 1 if typeof works with your compiler. */
|
||||
#undef HAVE_TYPEOF
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the <utime.h> header file. */
|
||||
#undef HAVE_UTIME_H
|
||||
|
||||
/* Define to 1 if you have the <varargs.h> header file. */
|
||||
#undef HAVE_VARARGS_H
|
||||
|
||||
/* Define to 1 if you have the `vprintf' function. */
|
||||
#undef HAVE_VPRINTF
|
||||
|
||||
/* have header windows.h */
|
||||
#undef HAVE_WINDOWS_H
|
||||
|
||||
/* have header winioctl.h */
|
||||
#undef HAVE_WINIOCTL_H
|
||||
|
||||
/* have header winreg.h */
|
||||
#undef HAVE_WINREG_H
|
||||
|
||||
/* have header winsock.h */
|
||||
#undef HAVE_WINSOCK_H
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT32_T
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT64_T
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef gid_t
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef int32_t
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef int64_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef mode_t
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
#undef off_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define to __typeof__ if your compiler spells it that way. */
|
||||
#undef typeof
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint32_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint64_t
|
216
configure
vendored
216
configure
vendored
@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for vchanger 1.0.1.
|
||||
# Generated by GNU Autoconf 2.69 for vchanger 1.0.3.
|
||||
#
|
||||
# Report bugs to <jfisher@jaybus.com>.
|
||||
#
|
||||
@ -580,8 +580,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='vchanger'
|
||||
PACKAGE_TARNAME='vchanger'
|
||||
PACKAGE_VERSION='1.0.1'
|
||||
PACKAGE_STRING='vchanger 1.0.1'
|
||||
PACKAGE_VERSION='1.0.3'
|
||||
PACKAGE_STRING='vchanger 1.0.3'
|
||||
PACKAGE_BUGREPORT='jfisher@jaybus.com'
|
||||
PACKAGE_URL=''
|
||||
|
||||
@ -1279,7 +1279,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures vchanger 1.0.1 to adapt to many kinds of systems.
|
||||
\`configure' configures vchanger 1.0.3 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@ -1345,7 +1345,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of vchanger 1.0.1:";;
|
||||
short | recursive ) echo "Configuration of vchanger 1.0.3:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@ -1439,7 +1439,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
vchanger configure 1.0.1
|
||||
vchanger configure 1.0.3
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@ -2026,11 +2026,57 @@ $as_echo "$ac_res" >&6; }
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_c_check_func
|
||||
|
||||
# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
|
||||
# ---------------------------------------------
|
||||
# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
|
||||
# accordingly.
|
||||
ac_fn_c_check_decl ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
as_decl_name=`echo $2|sed 's/ *(.*//'`
|
||||
as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
|
||||
$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
|
||||
if eval \${$3+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$4
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#ifndef $as_decl_name
|
||||
#ifdef __cplusplus
|
||||
(void) $as_decl_use;
|
||||
#else
|
||||
(void) $as_decl_name;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
eval "$3=yes"
|
||||
else
|
||||
eval "$3=no"
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
eval ac_res=\$$3
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_c_check_decl
|
||||
cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by vchanger $as_me 1.0.1, which was
|
||||
It was created by vchanger $as_me 1.0.3, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@ -2342,12 +2388,14 @@ as_fn_append ac_header_list " grp.h"
|
||||
as_fn_append ac_header_list " pwd.h"
|
||||
as_fn_append ac_header_list " dirent.h"
|
||||
as_fn_append ac_header_list " fcntl.h"
|
||||
as_fn_append ac_header_list " sys/mman.h"
|
||||
as_fn_append ac_header_list " sys/select.h"
|
||||
as_fn_append ac_header_list " optarg.h"
|
||||
as_fn_append ac_header_list " pthread.h"
|
||||
as_fn_append ac_header_list " libgen.h"
|
||||
as_fn_append ac_header_list " io.h"
|
||||
as_fn_append ac_header_list " signal.h"
|
||||
as_fn_append ac_header_list " semaphore.h"
|
||||
# Check that the precious variables saved in the cache have kept the same
|
||||
# value.
|
||||
ac_cache_corrupted=false
|
||||
@ -2417,7 +2465,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
|
||||
$as_echo "#define COPYRIGHT_NOTICE \"vchanger Copyright (c) 2006-2015 Josh Fisher\"" >>confdefs.h
|
||||
$as_echo "#define COPYRIGHT_NOTICE \"vchanger Copyright (c) 2006-2020 Josh Fisher\"" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
@ -2938,7 +2986,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='vchanger'
|
||||
VERSION='1.0.1'
|
||||
VERSION='1.0.3'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@ -5514,6 +5562,70 @@ else
|
||||
as_fn_error $? "\"could not find libpthread\"" "$LINENO" 5
|
||||
fi
|
||||
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_sys_mman_h" = xyes; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing shm_open" >&5
|
||||
$as_echo_n "checking for library containing shm_open... " >&6; }
|
||||
if ${ac_cv_search_shm_open+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char shm_open ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return shm_open ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_lib in '' rt; do
|
||||
if test -z "$ac_lib"; then
|
||||
ac_res="none required"
|
||||
else
|
||||
ac_res=-l$ac_lib
|
||||
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||
fi
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_search_shm_open=$ac_res
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext
|
||||
if ${ac_cv_search_shm_open+:} false; then :
|
||||
break
|
||||
fi
|
||||
done
|
||||
if ${ac_cv_search_shm_open+:} false; then :
|
||||
|
||||
else
|
||||
ac_cv_search_shm_open=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_shm_open" >&5
|
||||
$as_echo "$ac_cv_search_shm_open" >&6; }
|
||||
ac_res=$ac_cv_search_shm_open
|
||||
if test "$ac_res" != no; then :
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
|
||||
else
|
||||
as_fn_error $? "shm_open() not found" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Support using libudev or libblkid for UUID lookup
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing udev_new" >&5
|
||||
$as_echo_n "checking for library containing udev_new... " >&6; }
|
||||
@ -5960,6 +6072,10 @@ done
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -6011,6 +6127,15 @@ $as_echo "#define HAVE_SHLOBJ_H /**/" >>confdefs.h
|
||||
fi
|
||||
|
||||
|
||||
ac_fn_c_check_header_compile "$LINENO" "direct.h" "ac_cv_header_direct_h" "#include <windows.h>
|
||||
"
|
||||
if test "x$ac_cv_header_direct_h" = xyes; then :
|
||||
|
||||
$as_echo "#define HAVE_DIRECT_H /**/" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Checks for functions.
|
||||
for ac_func in vprintf
|
||||
do :
|
||||
@ -6031,32 +6156,18 @@ fi
|
||||
done
|
||||
|
||||
|
||||
for ac_func in setlocale getmntent getmntent_r getfsstat
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
ac_fn_c_check_decl "$LINENO" "localtime_r" "ac_cv_have_decl_localtime_r" "$ac_includes_default
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
"
|
||||
if test "x$ac_cv_have_decl_localtime_r" = xyes; then :
|
||||
|
||||
$as_echo "#define HAVE_LOCALTIME_R /**/" >>confdefs.h
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "getline" "ac_cv_func_getline"
|
||||
if test "x$ac_cv_func_getline" = xyes; then :
|
||||
$as_echo "#define HAVE_GETLINE 1" >>confdefs.h
|
||||
|
||||
else
|
||||
case " $LIBOBJS " in
|
||||
*" getline.$ac_objext "* ) ;;
|
||||
*) LIBOBJS="$LIBOBJS getline.$ac_objext"
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
|
||||
if test "x$ac_cv_func_gettimeofday" = xyes; then :
|
||||
$as_echo "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h
|
||||
@ -6070,6 +6181,19 @@ esac
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "getline" "ac_cv_func_getline"
|
||||
if test "x$ac_cv_func_getline" = xyes; then :
|
||||
$as_echo "#define HAVE_GETLINE 1" >>confdefs.h
|
||||
|
||||
else
|
||||
case " $LIBOBJS " in
|
||||
*" getline.$ac_objext "* ) ;;
|
||||
*) LIBOBJS="$LIBOBJS getline.$ac_objext"
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "getuid" "ac_cv_func_getuid"
|
||||
if test "x$ac_cv_func_getuid" = xyes; then :
|
||||
$as_echo "#define HAVE_GETUID 1" >>confdefs.h
|
||||
@ -6083,19 +6207,6 @@ esac
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r"
|
||||
if test "x$ac_cv_func_localtime_r" = xyes; then :
|
||||
$as_echo "#define HAVE_LOCALTIME_R 1" >>confdefs.h
|
||||
|
||||
else
|
||||
case " $LIBOBJS " in
|
||||
*" localtime_r.$ac_objext "* ) ;;
|
||||
*) LIBOBJS="$LIBOBJS localtime_r.$ac_objext"
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_func "$LINENO" "pipe" "ac_cv_func_pipe"
|
||||
if test "x$ac_cv_func_pipe" = xyes; then :
|
||||
$as_echo "#define HAVE_PIPE 1" >>confdefs.h
|
||||
@ -6163,6 +6274,19 @@ fi
|
||||
|
||||
|
||||
|
||||
for ac_func in setlocale getmntent getmntent_r getfsstat
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files Makefile src/Makefile doc/Makefile scripts/Makefile"
|
||||
|
||||
|
||||
@ -6700,7 +6824,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by vchanger $as_me 1.0.1, which was
|
||||
This file was extended by vchanger $as_me 1.0.3, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@ -6766,7 +6890,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
vchanger config.status 1.0.1
|
||||
vchanger config.status 1.0.3
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
27
configure.ac
27
configure.ac
@ -1,9 +1,9 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.63])
|
||||
AC_INIT([vchanger], [1.0.1], [jfisher@jaybus.com])
|
||||
AC_DEFINE([COPYRIGHT_NOTICE],["AC_PACKAGE_NAME Copyright (c) 2006-2015 Josh Fisher"],[Copyright notice])
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([vchanger], [1.0.3], [jfisher@jaybus.com])
|
||||
AC_DEFINE([COPYRIGHT_NOTICE],["AC_PACKAGE_NAME Copyright (c) 2006-2020 Josh Fisher"],[Copyright notice])
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
AC_CONFIG_LIBOBJ_DIR([src/compat])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@ -34,6 +34,9 @@ AC_SYS_LARGEFILE
|
||||
|
||||
# Use multithreading
|
||||
AC_SEARCH_LIBS([pthread_create], [pthread], [], [AC_MSG_ERROR(["could not find libpthread"])])
|
||||
AC_CHECK_HEADER([sys/mman.h],
|
||||
[ AC_SEARCH_LIBS([shm_open],[rt],[],[AC_MSG_ERROR([shm_open() not found])])
|
||||
])
|
||||
# Support using libudev or libblkid for UUID lookup
|
||||
AC_SEARCH_LIBS([udev_new],[udev],[AC_CHECK_HEADERS([libudev.h])])
|
||||
AC_CHECK_HEADER([blkid/blkid.h],
|
||||
@ -50,21 +53,27 @@ AC_CHECK_HEADERS_ONCE([stdio.h stdlib.h string.h stdarg.h stddef.h])
|
||||
AC_CHECK_HEADERS_ONCE([time.h sys/time.h sys/timespec.h sys/wait.h limits.h locale.h syslog.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/types.h strings.h alloca.h sys/bitypes.h getopt.h utime.h sys/stat.h])
|
||||
AC_CHECK_HEADERS_ONCE([inttypes.h ctype.h errno.h unistd.h varargs.h mntent.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/param.h sys/mount.h sys/ucred.h grp.h pwd.h dirent.h fcntl.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/select.h optarg.h pthread.h libgen.h io.h signal.h])
|
||||
AC_CHECK_HEADER([windows.h],
|
||||
[AC_DEFINE([HAVE_WINDOWS_H],,[have header windows.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/param.h sys/mount.h sys/ucred.h grp.h pwd.h dirent.h fcntl.h sys/mman.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/select.h optarg.h pthread.h libgen.h io.h signal.h semaphore.h])
|
||||
AC_CHECK_HEADER([windows.h], [AC_DEFINE([HAVE_WINDOWS_H],,[have header windows.h])
|
||||
WINLDADD=-static])
|
||||
AC_SUBST(WINLDADD)
|
||||
AC_CHECK_HEADER([winioctl.h], [AC_DEFINE([HAVE_WINIOCTL_H],,[have header winioctl.h])], [], [#include <windows.h>])
|
||||
AC_CHECK_HEADER([winsock.h], [AC_DEFINE([HAVE_WINSOCK_H],,[have header winsock.h])], [], [#include <windows.h>])
|
||||
AC_CHECK_HEADER([winreg.h], [AC_DEFINE([HAVE_WINREG_H],,[have header winreg.h])], [], [#include <windows.h>])
|
||||
AC_CHECK_HEADER([shlobj.h], [AC_DEFINE([HAVE_SHLOBJ_H],,[have header shlobj.h])], [], [#include <windows.h>])
|
||||
AC_CHECK_HEADER([direct.h], [AC_DEFINE([HAVE_DIRECT_H],,[have header direct.h])], [], [#include <windows.h>])
|
||||
# Checks for functions.
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS([setlocale getmntent getmntent_r getfsstat])
|
||||
|
||||
AC_REPLACE_FUNCS([getline gettimeofday getuid localtime_r pipe readlink sleep symlink syslog])
|
||||
AC_CHECK_DECL([localtime_r], [AC_DEFINE([HAVE_LOCALTIME_R],,[have function localtime_r])], [],
|
||||
[AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#include <time.h>])
|
||||
|
||||
AC_REPLACE_FUNCS([gettimeofday getline getuid pipe readlink sleep symlink syslog])
|
||||
|
||||
AC_CHECK_FUNCS([setlocale getmntent getmntent_r getfsstat])
|
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile scripts/Makefile])
|
||||
|
||||
|
5
contrib/vchanger.logrotate
Normal file
5
contrib/vchanger.logrotate
Normal file
@ -0,0 +1,5 @@
|
||||
/var/log/vchanger/*.log {
|
||||
missingok
|
||||
notifempty
|
||||
sharedscripts
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
# This file contains udev rules for automounting drives assigned to vchanger
|
||||
# This file contains example udev rules for automounting filesystems assigned to vchanger
|
||||
# See vchangerHowto.html for details on generating udev rules for vchanger magazines.
|
||||
#
|
||||
# Rules for magazine 0 (uuid:7b4526c4-d8e9-48ba-b227-f67f855a0dc7)
|
||||
ACTION=="add",SUBSYSTEM=="block", ENV{ID_FS_UUID}=="7b4526c4-d8e9-48ba-b227-f67f855a0dc7", RUN+="/usr/libexec/vchanger/vchanger-launch-mount.sh 7b4526c4-d8e9-48ba-b227-f67f855a0dc7"
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Example vchanger 1.0.0 config file
|
||||
# Example vchanger 1.0.2 config file
|
||||
|
||||
#
|
||||
# Storage Resource Name of the Storage resource defined in bacula-dir.conf
|
||||
@ -10,27 +10,27 @@
|
||||
# User User to run as when invoked by root. This must be the
|
||||
# owner of the volume files controlled by this changer, and
|
||||
# so will need to be the same user that bacula-sd runs as.
|
||||
# [Default: none ]
|
||||
User = bacula
|
||||
# [Default: bacula ]
|
||||
#User = bacula
|
||||
|
||||
#
|
||||
# Group Group to run as when invoked by root. This should be the
|
||||
# owner group of the volume files controlled by this changer,
|
||||
# and should also be the default group pf the user that
|
||||
# and should also be the default group of the user that
|
||||
# bacula-sd runs as.
|
||||
# [Default: none ]
|
||||
group = tape
|
||||
# [Default: tape ]
|
||||
#group = tape
|
||||
|
||||
#
|
||||
# Work Dir Directory where virtual drive and magazine state information
|
||||
# and symlinks for this changer are stored.
|
||||
# [Default: /var/spool/vchanger/[StorageResource] ]
|
||||
# [Default: /var/spool/vchanger/{StorageResource} ]
|
||||
#work dir = "/var/spool/vchanger/vcahnger"
|
||||
|
||||
#
|
||||
# Logfile Path to log file for this changer.
|
||||
# [Default: /var/log/vchanger/[StorageResource].log ]
|
||||
#logfile = "/var/log/vchanger/vchanger.log"
|
||||
# [Default: {WorkDir}/{StorageResource}.log ]
|
||||
#logfile = "/var/spool/vchanger/vchanger.log"
|
||||
|
||||
#
|
||||
# Log Level Sets the level of detail being logged. An integer value from
|
||||
@ -50,7 +50,8 @@ group = tape
|
||||
#
|
||||
# bconsole config Path to the config file bconsole will use when vchanger
|
||||
# invokes bconsole. By default, bconsole will be invoked
|
||||
# without the -c flag.
|
||||
# without the -c flag. The file must be readable by the user
|
||||
# vchanger is run as.
|
||||
# [Default: none ]
|
||||
#bconsole config = /etc/bacula/bconsole.conf
|
||||
|
||||
@ -69,7 +70,9 @@ group = tape
|
||||
# by prefixing the string "UUID:" to the filesystem's UUID.
|
||||
# For magazines specified by UUID, the mountpoint of the
|
||||
# filesystem will be queried from the system. Note that vchanger
|
||||
# does not attempt to mount the filesystem.
|
||||
# does not attempt to mount the magazines that are specified
|
||||
# by filesystem UUID. Vchanger utilizes all magazines that are
|
||||
# already mounted at the time it is invoked.
|
||||
# [Default: none ]
|
||||
#magazine = "uuid:4fcb1422-f15c-4d7a-8a32-a4dcc0af5e00"
|
||||
#Magazine = "/mnt/backup2"
|
||||
|
@ -2,12 +2,12 @@
|
||||
.\" Title: vchanger
|
||||
.\" Author: Josh Fisher <jfisher@jaybus.com>
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 06/03/2015
|
||||
.\" Date: 05/11/2020
|
||||
.\" Manual: vchanger Manual
|
||||
.\" Source: vchanger 1.0.1
|
||||
.\" Source: vchanger 1.0.3
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "VCHANGER" "8" "06/03/2015" "vchanger 1\&.0\&.1" "vchanger Manual"
|
||||
.TH "VCHANGER" "8" "05/11/2020" "vchanger 1\&.0\&.3" "vchanger Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@ -40,7 +40,7 @@ vchanger \- Virtual disk\-based autochanger for Bacula network backup system
|
||||
\fBvchanger\fR [\fIOptions\fR] config REFRESH
|
||||
.SH "DESCRIPTION"
|
||||
.sp
|
||||
The \fBvchanger(8)\fR utility is used to emulate and control a virtual autochanger within the Bacula network backup system environment\&. Backup volumes stored on multiple disk filesystems are mapped to a single set of virtual slots, allowing an unlimited number of virtual drives for concurrent backup jobs and easy, unlimited scaling to any size by simply adding additional disks/filesystems,
|
||||
The \fBvchanger(8)\fR utility is used to emulate and control a virtual autochanger within the Bacula network backup system environment\&. Backup volumes stored on multiple disk filesystems are mapped to a single set of virtual slots\&. This allows an unlimited number of virtual drives and an unlimited number of virtual slots spread across an unlimited number of physical disk drives to be assigned to a single autochanger\&. This allows unlimited scaling of the cirtual autochanger simply by adding additional disk drives\&.
|
||||
.sp
|
||||
Vchanger is primarily deigned for use with removable disk drives\&. Its ability to interact with Bacula and determine removable drive mount points through udev allow for plug\-n\-play operation when attaching and detaching removable disk drives\&.
|
||||
.sp
|
||||
@ -142,9 +142,9 @@ command to Bacula if required\&.
|
||||
.sp
|
||||
\fBBacula Interaction\fR
|
||||
.sp
|
||||
By default, vcahgner will invoke bconsole and issue commands to Bacula when certain operator actions are needed\&. When anything happens that changes the current set of volume files being used, vchanger will invoke bconsole and issue an \fIupdate slots\fR command\&. For example, when the operator attaches a removable drive defined as one of the changer\(cqs magazines, the volume files on the removable drive must be mapped to virtual slots\&. Since the volume\-to\-slot mapping will have changed, Bacula will need to be informed of the change via the \fIupdate slots\fR command\&. The \fBREFRESH\fR command can be invoked to force vchanger to update state info and trigger \fIupdate slots\fR if needed\&.
|
||||
By default, vcahgner will invoke bconsole and issue commands to Bacula when certain operator actions are needed\&. When anything happens that changes the current set of volume files being used, (the virtual slot to volume file mapping), vchanger will invoke bconsole and issue an \fIupdate slots\fR command\&. For example, when the operator attaches a removable drive defined as one of the changer\(cqs magazines, the volume files on the removable drive must be mapped to virtual slots\&. Since the slot\-to\-volume mapping will have changed, Bacula will need to be informed of the change via the \fIupdate slots\fR command\&. The \fBREFRESH\fR command can be invoked to force vchanger to update state info and trigger \fIupdate slots\fR if needed\&.
|
||||
.sp
|
||||
Additionally, when new volumes are created with the \fBCREATEVOLS\fR command, vchanger will invoke bconsole and issue a \fIlabel barcodes\fR command to write volume labels on the newly created volume files\&.
|
||||
Additionally, when new volumes are created with the \fBCREATEVOLS\fR command, vchanger will invoke bconsole and issue a \fIlabel barcodes\fR command to allow Bacula to write volume labels on the newly created volume files\&.
|
||||
.SH "COMMAND LINE OPTIONS"
|
||||
.PP
|
||||
\fB\-u, \-\-user\fR=\fIuid\fR
|
||||
@ -195,7 +195,7 @@ See the vchangerHowto\&.html file included in the doc directory of the source di
|
||||
\fBvchanger\&.conf(5)\fR
|
||||
.SH "COPYRIGHT"
|
||||
.sp
|
||||
Copyright 2006\-2015 Josh Fisher
|
||||
Copyright 2006\-2020 Josh Fisher
|
||||
.sp
|
||||
This is free software; See the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&.
|
||||
.SH "AUTHOR"
|
||||
|
@ -3,7 +3,7 @@ VCHANGER(8)
|
||||
Josh Fisher <jfisher@jaybus.com>
|
||||
:doctype: manpage
|
||||
:man source: vchanger
|
||||
:man version: 1.0.1
|
||||
:man version: 1.0.3
|
||||
:man manual: vchanger Manual
|
||||
|
||||
NAME
|
||||
@ -27,9 +27,11 @@ DESCRIPTION
|
||||
The *vchanger(8)* utility is used to emulate and control a virtual
|
||||
autochanger within the Bacula network backup system environment.
|
||||
Backup volumes stored on multiple disk filesystems are mapped to a
|
||||
single set of virtual slots, allowing an unlimited number of virtual
|
||||
drives for concurrent backup jobs and easy, unlimited scaling to any
|
||||
size by simply adding additional disks/filesystems,
|
||||
single set of virtual slots. This allows an unlimited number of
|
||||
virtual drives and an unlimited number of virtual slots spread
|
||||
across an unlimited number of physical disk drives to be assigned
|
||||
to a single autochanger. This allows unlimited scaling of the cirtual
|
||||
autochanger simply by adding additional disk drives.
|
||||
|
||||
Vchanger is primarily deigned for use with removable disk drives. Its
|
||||
ability to interact with Bacula and determine removable drive mount
|
||||
@ -115,18 +117,19 @@ Additionally, the following extended commands are supported.
|
||||
|
||||
By default, vcahgner will invoke bconsole and issue commands to Bacula
|
||||
when certain operator actions are needed. When anything happens that
|
||||
changes the current set of volume files being used, vchanger will
|
||||
invoke bconsole and issue an 'update slots' command. For example,
|
||||
when the operator attaches a removable drive defined as one of the
|
||||
changer's magazines, the volume files on the removable drive must be
|
||||
mapped to virtual slots. Since the volume-to-slot mapping will have
|
||||
changed, Bacula will need to be informed of the change via the
|
||||
'update slots' command. The *REFRESH* command can be invoked to force
|
||||
vchanger to update state info and trigger 'update slots' if needed.
|
||||
changes the current set of volume files being used, (the virtual slot
|
||||
to volume file mapping), vchanger will invoke bconsole and issue an
|
||||
'update slots' command. For example, when the operator attaches a
|
||||
removable drive defined as one of the changer's magazines, the volume
|
||||
files on the removable drive must be mapped to virtual slots. Since
|
||||
the slot-to-volume mapping will have changed, Bacula will need to be
|
||||
informed of the change via the 'update slots' command. The *REFRESH*
|
||||
command can be invoked to force vchanger to update state info and
|
||||
trigger 'update slots' if needed.
|
||||
|
||||
Additionally, when new volumes are created with the *CREATEVOLS* command,
|
||||
vchanger will invoke bconsole and issue a 'label barcodes' command to
|
||||
write volume labels on the newly created volume files.
|
||||
allow Bacula to write volume labels on the newly created volume files.
|
||||
|
||||
COMMAND LINE OPTIONS
|
||||
--------------------
|
||||
@ -172,7 +175,7 @@ SEE ALSO
|
||||
|
||||
COPYRIGHT
|
||||
---------
|
||||
Copyright 2006-2015 Josh Fisher
|
||||
Copyright 2006-2020 Josh Fisher
|
||||
|
||||
This is free software;
|
||||
See the source for copying conditions.
|
||||
|
@ -2,12 +2,12 @@
|
||||
.\" Title: vchanger.conf
|
||||
.\" Author: Josh Fisher <jfisher@jaybus.com>
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 06/03/2015
|
||||
.\" Date: 05/11/2020
|
||||
.\" Manual: vchanger Manual
|
||||
.\" Source: vchanger.conf 1.0.1
|
||||
.\" Source: vchanger.conf 1.0.3
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "VCHANGER\&.CONF" "5" "06/03/2015" "vchanger\&.conf 1\&.0\&.1" "vchanger Manual"
|
||||
.TH "VCHANGER\&.CONF" "5" "05/11/2020" "vchanger\&.conf 1\&.0\&.3" "vchanger Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@ -134,7 +134,7 @@ See the vchangerHowto\&.html file included in the doc directory of the source di
|
||||
\fBvchanger(8)\fR
|
||||
.SH "COPYRIGHT"
|
||||
.sp
|
||||
Copyright 2006\-2015 Josh Fisher
|
||||
Copyright 2006\-2020 Josh Fisher
|
||||
.sp
|
||||
This is free software; See the source for copying conditions\&. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&.
|
||||
.SH "AUTHOR"
|
||||
|
@ -3,7 +3,7 @@ VCHANGER.CONF(5)
|
||||
Josh Fisher <jfisher@jaybus.com>
|
||||
:doctype: manpage
|
||||
:man source: vchanger.conf
|
||||
:man version: 1.0.1
|
||||
:man version: 1.0.3
|
||||
:man manual: vchanger Manual
|
||||
|
||||
NAME
|
||||
@ -112,7 +112,7 @@ SEE ALSO
|
||||
|
||||
COPYRIGHT
|
||||
---------
|
||||
Copyright 2006-2015 Josh Fisher
|
||||
Copyright 2006-2020 Josh Fisher
|
||||
|
||||
This is free software;
|
||||
See the source for copying conditions.
|
||||
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=windows-1252" http-equiv="content-type">
|
||||
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
|
||||
<title></title>
|
||||
<meta name="CREATED" content="20061109;11301500">
|
||||
<meta name="CHANGEDBY" content="Josh Fisher">
|
||||
@ -28,6 +28,18 @@ UL.no_image { list-style:none; }
|
||||
<p style="font-weight:bold; margin-bottom:0;">Josh Fisher</p>
|
||||
<p><jfisher at jaybus dot com></p>
|
||||
<p style="font-weight:bold;">Revision History</p>
|
||||
<p class="p_zero_bottom">Revision 1.0.3 2020-05-11</p>
|
||||
<p class="p_indent">Documented changes related to version 1.0.3 of the
|
||||
software. This release fixes a few bugs affecting compilation on some
|
||||
platforms and correcting the number of slots reported by the SIZE command.
|
||||
Additionally, the IPC locking mechanism used is changed to use POSIX
|
||||
semaphores</p>
|
||||
<p class="p_zero_bottom">Revision 1.0.2 2018-06-14</p>
|
||||
<p class="p_indent">Documented changes related to version 1.0.2 of the
|
||||
software. This release fixes a few bugs affecting interaction with
|
||||
bconsole, changes the default formatting of the barcode labels for new
|
||||
volumes, and adds additional logging of udev/UUID mountpoint discovery
|
||||
steps.</p>
|
||||
<p class="p_zero_bottom">Revision 1.0.1 2015-06-09</p>
|
||||
<p class="p_indent">Documented changes related to version 1.0.1 of the
|
||||
software. This is a minor bug fix release.</p>
|
||||
@ -97,6 +109,8 @@ UL.no_image { list-style:none; }
|
||||
<ul class="no_image">
|
||||
<li>5.3.1. <a href="#win32_build">Installing the Windows Version
|
||||
from Source</a></li>
|
||||
<li>5.3.2. <a href="#win32_installer_build">Building the Windows
|
||||
installer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@ -161,7 +175,7 @@ UL.no_image { list-style:none; }
|
||||
an open source network backup solution. Bacula can use many types of
|
||||
backup devices, one of them being robotic tape libraries, also known as
|
||||
autochangers. Bacula utilizes these devices through an interface known as
|
||||
the <a href="http://www.bacula.org/7.0.x-manuals/en/main/index.html">Bacula
|
||||
the <a href="http://www.bacula.org/9.6.x-manuals/en/main/Autochanger_Resource.html#SECTION0032130000000000000000">Bacula
|
||||
Autochanger
|
||||
Interface</a>. Because autochangers are controlled in various
|
||||
proprietary ways, the Bacula Autochanger Interface provides a generalized
|
||||
@ -172,7 +186,7 @@ Autochanger
|
||||
Interface to act as a virtual autochanger, using files on disk storage in
|
||||
place of tapes.</p>
|
||||
<h2><a name="copyright"></a>1.1 Copyright And License</h2>
|
||||
<p>This document, Vchanger<em>HOWTO</em>, is Copyright (c) 2008-2015 by <em><span
|
||||
<p>This document, Vchanger<em>HOWTO</em>, is Copyright (c) 2008-2020 by <em><span
|
||||
style="font-style: normal">Josh Fisher</span></em>. Permission is
|
||||
granted to copy, distribute and/or modify this document under the terms of
|
||||
the GNU Free Documentation License, Version 1.1 or any later version
|
||||
@ -197,9 +211,9 @@ Users
|
||||
<p>Thanks, also, to all those who frequent the <a href="https://lists.sourceforge.net/lists/listinfo/bacula-users">Bacula
|
||||
User's e-mail list</a>, and of course to Kern Sibbald and the other <a
|
||||
href="http://www.bacula.org/">Bacula</a> developers.</p>
|
||||
<p>Bacula<sub>®</sub> is a registered trademark of Kern Sibbald.</p>
|
||||
<p>Windows<sub>®</sub> is a registered trademark of Microsoft Corporation in
|
||||
the United States and other countries.</p>
|
||||
<p>Bacula<sub>®</sub> is a registered trademark of Kern Sibbald.</p>
|
||||
<p>Windows<sub>®</sub> is a registered trademark of Microsoft
|
||||
Corporation in the United States and other countries.</p>
|
||||
<h2><a name="feedback"></a>1.4 Feedback</h2>
|
||||
<p><a href="https://lists.sourceforge.net/lists/listinfo/vchanger-users">Vchanger
|
||||
Users
|
||||
@ -211,17 +225,18 @@ Users
|
||||
information about Bacula is available at the Bacula website <a href="http://www.bacula.org/">http://www.bacula.org</a>.</p>
|
||||
<p>An <i>autochanger</i> is a backup storage device consisting of one or
|
||||
more tape drives, a mechanical tape library where a number of tape
|
||||
cartridges are stored, and an individually addressable robotic device
|
||||
capable of physically moving tape cartridges between the tape library and
|
||||
the tape drives. The tape library contains mechanical slots, each of which
|
||||
can hold one tape cartridge. In most cases, the slots are located in one
|
||||
or more mechanical magazines, (tape caddies), that can be inserted into
|
||||
and removed from one or more or the tape library's magazine bays.</p>
|
||||
<p>A <i>virtual autochanger</i> emulates a tape autochanger using disk
|
||||
storage, rather than tapes. Note that in the strictest sense, vchanger is
|
||||
not a tape library emulator, in that it does not implement a device driver
|
||||
with SCSI command interface. Rather it utilizes an API implemented by
|
||||
Bacula to manipulate autochangers.</p>
|
||||
cartridges are stored in slots, and an individually addressable robotic
|
||||
device capable of physically moving tape cartridges between the tape
|
||||
library slots and the tape drives. The tape library contains mechanical
|
||||
slots, each of which can hold one tape cartridge. In most cases, the slots
|
||||
are located in one or more mechanical magazines, (tape caddies), that can
|
||||
be inserted into and removed from one or more or the tape library's
|
||||
magazine bays.</p>
|
||||
<p>A vchanger <i>autochanger</i> emulates a tape autochanger using files on
|
||||
disk storage in place of tapes. Note that in the strictest sense, vchanger
|
||||
is not a tape library emulator, in that it does not implement a device
|
||||
driver with SCSI command interface. Rather it utilizes an API implemented
|
||||
by Bacula to manipulate autochangers.</p>
|
||||
<p>A <em>slot</em> is a physical location in a tape library that may
|
||||
contain one volume (ie. tape cartridge).</p>
|
||||
<p>A <i>magazine</i> is a mechanical tape storage device having a number of
|
||||
@ -241,11 +256,11 @@ Users
|
||||
stream.</p>
|
||||
<p>The term drive, unless otherwise stated, refers to one of an
|
||||
autochanger's drives, a device capable of reading and writing data from/to
|
||||
a single tape or volume file.</p>
|
||||
a single volume at a time.</p>
|
||||
<h1><a name="overview"></a>3. Overview</h1>
|
||||
<p>The Bacula Storage Daemon controls an autochanger by invoking a script or
|
||||
program, passing it command line arguments defined by the <a target="_blank"
|
||||
href="http://www.bacula.org/7.0.x-manuals/en/main/Autochanger_Resource.html#SECTION001830000000000000000">Bacula
|
||||
href="http://www.bacula.org/9.6.x-manuals/en/main/Autochanger_Resource.html#SECTION001830000000000000000">Bacula
|
||||
Autochanger
|
||||
Interface</a>. The interface defines a set of commands and associated
|
||||
arguments to load and unload the autochanger's drives, determine which
|
||||
@ -261,8 +276,8 @@ Autochanger
|
||||
into tape drives, as the mtx-changer script does for tape autochanger
|
||||
hardware, vchanger "loads" disk file volumes from virtual slots into
|
||||
virtual drives by creating symlinks pointing to volume files located on
|
||||
one or more filesystems or directories assigned to the virtual
|
||||
autochanger.</p>
|
||||
one or more virtual magazines, where a virtual magazine is a disk file
|
||||
system or a directory.</p>
|
||||
<p>Using autochanger interface commands, Bacula interacts with a vchanger
|
||||
autochanger in exactly the same way as it interacts with a tape
|
||||
autochanger. Therefore to understand how Bacula interacts with a vchanger
|
||||
@ -308,15 +323,16 @@ Autochanger
|
||||
configuration for a vchanger autochanger looks very much the same,</p>
|
||||
<pre style="margin-left: 2.5em;"># /etc/bacula/bacula-sd.conf<br>Autochanger {<br> Name = vchgr<br> Changer Device = /etc/vchanger/vchgr.conf<br> Changer Command = "/usr/bin/vchanger %c %o %S %a %d"<br> Device = vchgr-0, vchgr-1<br>}<br>Device {<br> Name = vchgr-0<br> Drive Index = 0<br> Autochanger = yes<br> Archive Device = /var/spool/vchanger/vchgr/0<br>}<br>Device {<br> Name = vchgr-1<br> Drive Index = 1<br> Autochanger = yes<br> Archive Device = /var/spool/vchanger/vchgr/1<br>}
|
||||
</pre>
|
||||
<p>One obvious difference is that vchanger is invoked as the <span style="font-style: italic; font-weight: bold;">Changer
|
||||
Command</span> in place of the mtx-changer script, and with the <span style="font-style: italic; font-weight: bold;">Changer
|
||||
Device</span> passed as parameter 1 being the path to a vchanger
|
||||
configuration file, rather than the device node of a tape library robot.
|
||||
The only other difference is the <span style="font-style: italic; font-weight: bold;">Archive
|
||||
Device</span> setting in each of the <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>resources. Rather than the device node of a physical tape drive,
|
||||
the <span style="font-style: italic; font-weight: bold;">Archive Device</span>
|
||||
of a vchanger autochanger's <span style="font-style: italic; font-weight: bold;">Device
|
||||
<p>One obvious difference is that <span style="font-style: italic; font-weight: bold;">Changer
|
||||
Command</span> defines the path to the vchanger binary, rather than the
|
||||
mtx-changer script, with<span style="font-style: italic; font-weight: bold;"></span>
|
||||
parameter 1 being the path to a vchanger configuration file, rather than
|
||||
the device node of a tape library robot. The only other difference is the
|
||||
<span style="font-style: italic; font-weight: bold;">Archive Device</span>
|
||||
setting in each of the <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>resources associated with the <i><b>Autochanger </b></i>resource.
|
||||
Rather than the device node of a physical tape drive, the <span style="font-style: italic; font-weight: bold;">Archive
|
||||
Device</span> of a vchanger autochanger's <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>resource specifies the path to a symlink that will act as a
|
||||
virtual drive. When vchanger is invoked with the LOAD command, it creates
|
||||
this symlink pointing to the volume file associated with the requested
|
||||
@ -392,7 +408,7 @@ Autochanger
|
||||
resource to be used with multiple disk storage <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>resources as a disk-based virtual autochanger.</p>
|
||||
<p>For example, the following placed in the Bacula Storage Daemon
|
||||
configuration defines a "native" disk virtual autochanger named FileChgr1
|
||||
configuration defines a native disk virtual autochanger named FileChgr1
|
||||
with two virtual drives. The two <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>resources (virtual drives) allow two volume files to be open at
|
||||
the same time, and of course more than two <span style="font-style: italic; font-weight: bold;">Device
|
||||
@ -431,10 +447,10 @@ Device {
|
||||
<p>Notice that both <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>resources specify the same <span style="font-style: italic; font-weight: bold;">Archive
|
||||
Device</span> and <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span>. This is because the <span style="font-style: italic; font-weight: bold;">Storage
|
||||
</span>resource in the Director configuration may only specify a single
|
||||
<span style="font-style: italic; font-weight: bold;">Media Type</span>. A
|
||||
volume is given the <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span>. This is because the corresponding <span style="font-style: italic; font-weight: bold;">Autochanger
|
||||
</span>resource in the Director's bacula-dir.conf configuration may only
|
||||
specify a single <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span>. A volume is given the <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span> of the <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>it is written with. Since a location may have several tape drives
|
||||
of the same type, Bacula uses the <span style="font-style: italic; font-weight: bold;">Media
|
||||
@ -451,34 +467,36 @@ Device {
|
||||
Types</span> to prevent Bacula from attempting to load a <span style="font-weight: bold; font-style: italic;">Device</span>
|
||||
with a volume file that does not exist on its <span style="font-weight: bold; font-style: italic;">Archive
|
||||
Device</span>. That in turn means that all of the autochanger's <span style="font-style: italic; font-weight: bold;">Devices</span>
|
||||
could not be associated to a single <span style="font-style: italic; font-weight: bold;">Storage
|
||||
could not be associated to a single <span style="font-style: italic; font-weight: bold;">Autochanger
|
||||
</span>resource<span style="font-style: italic;"> </span>in the
|
||||
Director configuration, and so defeats the purpose. </p>
|
||||
Director configuration. </p>
|
||||
<h2><a name="native_autochanger"></a>3.2. Why vchanger?</h2>
|
||||
<p>Because Bacula currently requires a <span style="font-style: italic; font-weight: bold;">Storage
|
||||
</span>resource to specify a single <span style="font-style: italic; font-weight: bold;">Media
|
||||
</span>and <b>Autochanger</b> resources to specify a single <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span>, the native virtual autochanger is, for practical purposes,
|
||||
limited to utilizing a single directory as volume file storage. If volume
|
||||
files are contained in multiple filesystems, such as removable drives,
|
||||
then those filesystems can only be mounted at that directory one at a
|
||||
time. With vchanger, an unlimited number of filesystems may be
|
||||
simultaneously mounted at different mount point directories with all
|
||||
volume files on all filesystems having the same <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span>. This allows an unlimited number of simultaneously available
|
||||
volume files and an unlimited number of <span style="font-style: italic; font-weight: bold;">Device
|
||||
limited to utilizing a single directory as volume file storage for a
|
||||
particular <i><b>Media Type</b></i>. If volume files are contained in
|
||||
multiple filesystems, such as removable drives, then those filesystems can
|
||||
only be mounted at that directory one at a time. With vchanger, an
|
||||
unlimited number of filesystems may be simultaneously mounted at different
|
||||
mount point directories with all volume files on all filesystems having
|
||||
the same <span style="font-style: italic; font-weight: bold;">Media Type</span>.
|
||||
This allows an unlimited number of simultaneously available volume files
|
||||
and an unlimited number of <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>resources (virtual drives), where any volume file on any
|
||||
filesystem can be "loaded" into any of the autochanger's <span style="font-style: italic; font-weight: bold;">Device
|
||||
</span>resources using only a single <span style="font-style: italic; font-weight: bold;">Storage
|
||||
</span>resource in the Bacula Director. This gives vchanger the
|
||||
following advantages:</p>
|
||||
</span>resources using only a single <span style="font-style: italic; font-weight: bold;">Autochanger
|
||||
</span>resource in the Director's bacula-dir.conf file. This gives
|
||||
vchanger the following advantages:</p>
|
||||
<ul>
|
||||
<li>Available volume storage space can be easily scaled by adding
|
||||
additional filesystems or directories</li>
|
||||
<li>Scaling available volume storage space requires no change to the
|
||||
Bacula configuration and no restart or reload of any Bacula daemons</li>
|
||||
<li>All volumes have the same Media Type and so can be moved between
|
||||
filesystems without any need to update volume information in the Bacula
|
||||
catalog.</li>
|
||||
<li>All volumes have the same <i><b>Media Type</b></i> and so can be
|
||||
moved between filesystems without any need to update volume information
|
||||
in the Bacula catalog (other than an <i>update slots</i> command in
|
||||
bconsole to update the volume's slot number).</li>
|
||||
<li>Filesystems can be specified by UUID and vchanger will query the OS
|
||||
for the mount point when needed. This allows any type of automounting to
|
||||
be used and the filesystems to be mounted at arbitrary paths.</li>
|
||||
@ -489,27 +507,27 @@ Device {
|
||||
interventions to swap removable drives. </li>
|
||||
</ul>
|
||||
<p>By default, vchanger supports integration with Bacula through issuing
|
||||
commands via bconsole. Whenever a change is detected in the volume file to
|
||||
virtual slot mapping, for example when a removable drive is attached or
|
||||
detached, vchanger will issue an <span style="font-style: italic;">update
|
||||
commands via bconsole. Whenever a change is detected in the
|
||||
volume-file-to-virtual-slot mapping, for example when a removable drive is
|
||||
attached or detached, vchanger will issue an <span style="font-style: italic;">update
|
||||
slots</span> command to synchronize Bacula's view of the autochan<span style="font-style: italic;"></span>ger's
|
||||
available volumes. Also, when vchanger is used to add volume files to an
|
||||
autochanger, a <span style="font-style: italic;">label barcodes</span>
|
||||
command is automatically issued to label the new volumes.</p>
|
||||
<p>Vchanger also automates the generation of udev rules and scripts that may
|
||||
be used to automatically mount and unmount the filesystems defined in
|
||||
autochanger configuration files. When a removable drive is attached or
|
||||
detached, a script may be launched by udev to mount or unmount the drive's
|
||||
partition and issue an <span style="font-style: italic;">update slots</span>
|
||||
command via bconsole. These udev rules and scripts allow the attaching and
|
||||
detaching of removable drives used by vchanger to be a true
|
||||
plug-n-play operation.<br>
|
||||
command is automatically issued to label the newly created volumes.</p>
|
||||
<p>Vchanger also provides scripts that may be used to automate the
|
||||
generation of udev rules and automatically mount and unmount the
|
||||
filesystems defined in autochanger configuration files. When a removable
|
||||
drive is attached or detached, a script may be launched by udev to mount
|
||||
or unmount the drive's partition and issue an <span style="font-style: italic;">update
|
||||
slots</span> command via bconsole. These udev rules and scripts allow
|
||||
the attaching and detaching of removable drives used by vchanger to be a
|
||||
true plug-n-play operation.<br>
|
||||
</p>
|
||||
<h1><a name="implementation"></a>4. Virtual Autochanger Implementation</h1>
|
||||
<p>Vchanger implements the following <a target="_blank" href="http://www.bacula.org/7.0.x-manuals/en/main/Autochanger_Resource.html#SECTION001830000000000000000">Bacula
|
||||
<p>Vchanger implements the following <a target="_blank" href="http://www.bacula.org/9.6.x-manuals/en/main/Autochanger_Resource.html#SECTION001830000000000000000">Bacula
|
||||
Autochanger Interface</a> commands:</p>
|
||||
<table style="margin-left: 2rem;" border="0" cellpadding="0" cellspacing="0"
|
||||
width="664">
|
||||
<table style="margin-left: 2rem;" width="664" cellspacing="0" cellpadding="0"
|
||||
border="0">
|
||||
<colgroup><col width="132"> <col width="532"> </colgroup>
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
@ -557,8 +575,8 @@ Device {
|
||||
</table>
|
||||
<p style="margin-top: 3ex;">Vchanger also implements the following
|
||||
undocumented command defined in mtx-changer since Bacula version 5.1.0:</p>
|
||||
<table style="margin-left: 2rem;" border="0" cellpadding="0" cellspacing="0"
|
||||
width="664">
|
||||
<table style="margin-left: 2rem;" width="664" cellspacing="0" cellpadding="0"
|
||||
border="0">
|
||||
<colgroup><col width="132"> <col width="532"> </colgroup>
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
@ -575,7 +593,7 @@ Device {
|
||||
extended commands that are not part of the documented Bacula Autochanger
|
||||
Interface:</p>
|
||||
<table style="page-break-before: auto; page-break-after: auto; margin-left: 2rem;"
|
||||
border="0" cellpadding="0" cellspacing="0" width="664">
|
||||
width="664" cellspacing="0" cellpadding="0" border="0">
|
||||
<colgroup><col width="132"> <col width="532"> </colgroup>
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
@ -607,8 +625,8 @@ Device {
|
||||
</table>
|
||||
<p style="margin-top: 3ex;"><span style="font-style: normal">The Bacula
|
||||
Storage Daemon calls vchanger with 5 positional parameters defined as:</span></p>
|
||||
<table style="margin-left: 2rem;" border="0" cellpadding="0" cellspacing="0"
|
||||
width="664">
|
||||
<table style="margin-left: 2rem;" width="664" cellspacing="0" cellpadding="0"
|
||||
border="0">
|
||||
<colgroup><col width="132"> <col width="532"> </colgroup>
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
@ -675,16 +693,15 @@ Device {
|
||||
drive and magazine state information and where the symlinks to volume
|
||||
files will be created for loaded virtual drives.</p>
|
||||
<h2><a name="virtual_magazines"></a>4.1. Virtual Magazines</h2>
|
||||
<p>Virtual autochangers using vchanger treat the directories and filesystems
|
||||
assigned to them as "virtual magazines", each able to contain a variable
|
||||
number of volume files. This is analogous to the mechanical tape
|
||||
magazines, (tape caddies), that many tape autochangers use. These tape
|
||||
autochangers have one or more bays into which removable tape magazines can
|
||||
be inserted. Each tape magazine contains a fixed number of slots into
|
||||
which individual tape cartridges may be inserted. The principle difference
|
||||
is that tape magazines have a fixed number of physical slots, whereas
|
||||
vchanger virtual magazines have a variable and unlimited number of virtual
|
||||
slots.</p>
|
||||
<p>Vchanger autochangers treat the directories and filesystems assigned to
|
||||
them as "virtual magazines", each able to contain a variable number of
|
||||
volume files. This is analogous to the mechanical tape magazines, (tape
|
||||
caddies), that many tape autochangers use. These tape autochangers have
|
||||
one or more bays into which removable tape magazines can be inserted. Each
|
||||
tape magazine contains a fixed number of slots into which individual tape
|
||||
cartridges may be inserted. The principle difference is that tape
|
||||
magazines have a fixed number of physical slots, whereas vchanger virtual
|
||||
magazines have a variable and unlimited number of virtual slots.</p>
|
||||
<p>Virtual magazines are filesystems or directories that are assigned to an
|
||||
autochanger by including <em style="font-weight: bold;">Magazine</em><span
|
||||
style="font-weight: bold;"> </span>directive lines in the vchanger
|
||||
@ -702,25 +719,34 @@ Device {
|
||||
determined solely by the order in which the <span style="font-style: italic; font-weight: bold;">Magazine
|
||||
</span>definitions appear in the vchanger configuration file. This
|
||||
allows assigning integer numbers to the magazines to ease tracking of
|
||||
multiple magazines. For example, consider an autochanger associated with a
|
||||
<span style="font-style: italic; font-weight: bold;">Storage </span>resource
|
||||
multiple magazines. For example, consider an autochanger associated with
|
||||
an <span style="font-style: italic; font-weight: bold;">Autochanger </span>resource
|
||||
in bacula-dir.conf named "changer1" for which we are using 10 RDX
|
||||
cartridges as its virtual magazines. The default volume naming scheme used
|
||||
by the CREATEVOLS command will name the first volume file created on the
|
||||
first <span style="font-style: italic; font-weight: bold;">Magazine </span>as
|
||||
"changer1_0_0", the 23rd volume created on the second <span style="font-style: italic; font-weight: bold;">Magazine
|
||||
</span>as "changer1_1_22", and so on. When Bacula later requests a
|
||||
"changer1_0000_0000", the 23rd volume created on the second <span style="font-style: italic; font-weight: bold;">Magazine
|
||||
</span>as "changer1_0001_0022", and so on. When Bacula later requests a
|
||||
volume that is on a RDX cartridge that is not currently mounted, this
|
||||
volume file naming scheme will make it very easy to determine which RDX
|
||||
cartridge needs to be attached in order to make the requested volume
|
||||
available.</p>
|
||||
<p>The default volume naming scheme used by the CREATEVOLS command is not
|
||||
required. The CREATEVOLS command accepts a pattern string that may be used
|
||||
to name the volume files it creates. In fact, the CREATEVOLS command is
|
||||
simply a convenience. A volume file may be created by creating an empty
|
||||
file on the magazine using touch, etc., and then issuing a <b><i>label
|
||||
barcodes</i></b> command in bconsole. Volume files may have any
|
||||
arbitrary name. Existing volume files may be moved from one magazine to
|
||||
another, requiring only an <b><i>update slots</i></b> command in bconsole
|
||||
to inform Bacula of the change in slot assignments.</p>
|
||||
<p>On most systems, filesystems to be used as magazines may be specified by
|
||||
filesystem UUID, rather than mountpoint directory. This is useful on
|
||||
systems where udev, Gnome Nautilus, other dbus-enabled automounters, and
|
||||
etc. are used to automatically mount removable drives whenever they are
|
||||
attached. Since vchanger is not normally running as root, it makes no
|
||||
attempt to mount those filesystems. It only queries the system to
|
||||
determine the current mount point of an already mounted filesystem.</p>
|
||||
determine the current mount points of its assigned magazine filesystems.</p>
|
||||
<p>Note that there is nothing special about the directories and filesystems
|
||||
being used as magazines. A directory containing volume files created by
|
||||
Bacula's native disk storage handling can be used as a vchanger magazine.
|
||||
@ -729,17 +755,17 @@ Device {
|
||||
individual volume files can be moved between the two. The only stipulation
|
||||
is that the volume must have the same <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span> as the bacula-dir.conf <span style="font-style: italic; font-weight: bold;">Storage</span>
|
||||
resource that it will be used with. If existing volumes are being moved to
|
||||
a <span style="font-style: italic; font-weight: bold;">Storage</span>
|
||||
resource that<span style="font-style: italic; font-weight: bold;"> </span>has
|
||||
a different <span style="font-style: italic; font-weight: bold;">Media
|
||||
or <b>Autochanger</b> resource that it will be used with. If existing
|
||||
volumes are being moved to a <span style="font-style: italic; font-weight: bold;">Storage</span>
|
||||
or <b>Autochanger </b>resource that<span style="font-style: italic; font-weight: bold;">
|
||||
</span>has a different <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span>, then it will be necessary to manually update the <span style="font-style: italic; font-weight: bold;">Media
|
||||
Type</span> for those volumes.</p>
|
||||
<h2><a name="volume_files"></a>4.2. Volume Files</h2>
|
||||
<p>A volume file is simply a regular file on one of the defined magazine
|
||||
directories or file systems. A file cannot be used by Bacula until a
|
||||
Bacula volume label has been written to it. Bacula supports bulk labeling
|
||||
of volumes using barcodes. Many tape autochangers have barcode reader
|
||||
directories or filesystems. A file cannot be used by Bacula until a Bacula
|
||||
volume label has been written to it. Bacula supports bulk labeling of
|
||||
volumes using barcodes. Many tape autochangers have barcode reader
|
||||
hardware that can read the name of a tape cartridge from a barcode printed
|
||||
on an adhesive paper label attached to the tape cartridge. The tape
|
||||
autochanger can be commanded to read the barcodes and list the names of
|
||||
@ -747,25 +773,26 @@ Device {
|
||||
barcodes</span> command acquires this information from the tape
|
||||
autochanger and writes a Bacula volume label to each unlabeled tape,
|
||||
naming it according to the tape's barcode. Vchanger emulates a barcode
|
||||
reader by using the volume file's filename as the barcode for that volume.</p>
|
||||
reader by using the volume file's filename as the barcode for that volume.
|
||||
</p>
|
||||
<p>While it is recommended to use the default volume naming scheme
|
||||
implemented by the CREATEVOLS command, it is not required and volume files
|
||||
can have any filename. Just keep in mind that vchanger uses the volume
|
||||
file's filename as its barcode label. This means that the filename must
|
||||
match the volume label that was written to the file when the volume was
|
||||
labeled. Volumes cannot be renamed by simply renaming the file to a
|
||||
different filename. They would also have to have a new Bacula volume label
|
||||
written to them.</p>
|
||||
different filename. if renamed, they should also have a new Bacula volume
|
||||
label written to them.</p>
|
||||
<h2><a name="virtual_slots"></a>4.3. Virtual Slots</h2>
|
||||
<p>Each time vchanger is invoked it maps the volume files on all attached
|
||||
magazines to a virtual slot number. State information kept in the
|
||||
<p>Each time vchanger is invoked it maps the volume files on all currently
|
||||
mounted magazines to a virtual slot number. State information kept in the
|
||||
autochanger's work directory is used to keep volume-to-slot mapping as
|
||||
consistent as possible when removable disk drives are attached and
|
||||
detached from the system. Drive state files contain information about the
|
||||
volume last loaded into a virtual drive and are named 'drive_state-N',
|
||||
where N is the drive number. Magazine state files contain information
|
||||
about the magazines that were attached when vchanger was last invoked and
|
||||
are named 'bay_state-N', where N is the magazine index.</p>
|
||||
consistent as possible as removable disk drives are attached and detached
|
||||
from the system. Drive state files contain information about the volume
|
||||
last loaded into a virtual drive and are named 'drive_state-N', where N is
|
||||
the drive number. Magazine state files contain information about the
|
||||
magazines that were attached when vchanger was last invoked and are named
|
||||
'bay_state-N', where N is the magazine index.</p>
|
||||
<p>Whenever anything happens to change the volume-to-slot mapping, Bacula
|
||||
must be informed of the change. This is because Bacula tracks the contents
|
||||
of autochanger slots in its catalog, as it must know which volumes are
|
||||
@ -848,8 +875,8 @@ Device {
|
||||
number of the range of virtual slots mapped to the magazine's volume
|
||||
files, and <span style="font-style: italic;">mountpoint </span>is the
|
||||
magazine's directory or current filesystem mount point.</p>
|
||||
<p>The CREATEVOLS command is used to add new volume files to a magazine and
|
||||
cause Bacula to write volume labels to them.</p>
|
||||
<p>The CREATEVOLS command is used to add new volume files to a magazine and,
|
||||
optionally, cause Bacula to write volume labels to them.</p>
|
||||
<p>The REFRESH command causes vchanger to refresh the current state of
|
||||
magazines and virtual drives and issue a <span style="font-weight: bold; font-style: italic;">update
|
||||
slots</span> command via bconsole if needed. This command is intended to
|
||||
@ -894,8 +921,8 @@ Device {
|
||||
<h2><a name="win32_build"></a>5.3.1. Installing the Windows Version from
|
||||
Source</h2>
|
||||
<p>The Windows version was developed under <a href="http://www.centos.org/">Centos</a>
|
||||
7.0 using the <a href="http://mingw-w64.sourceforge.net/">MinGW-w64</a>
|
||||
(gcc-4.9.1) cross-compiler system. On a Linux system with MinGW-w64
|
||||
7.8 using the <a href="http://mingw-w64.sourceforge.net/">MinGW-w64</a>
|
||||
(gcc-4.9.3) cross-compiler system. On a Linux system with MinGW-w64
|
||||
development tools installed, the Windows version can be built as follows:</p>
|
||||
<p>Unpack the gzip compressed tar archive in your home directory.</p>
|
||||
<pre>[]$ cd ~
|
||||
@ -904,11 +931,12 @@ Device {
|
||||
vchanger</p>
|
||||
<pre>[]$ cd vchanger
|
||||
[]$ ./configure --host=x86_64-w64-mingw32 --build=`./config.guess` --prefix=./win32
|
||||
[]$ make
|
||||
[]$ make install-strip</pre>
|
||||
[]$ make</pre>
|
||||
<p style="margin-top: 0.08in">The win32 executable, vchanger.exe, will be in
|
||||
~/vchanger/win32/bin and the Windows version documentation in
|
||||
~/vchanger/win32/share/doc/vchanger.</p>
|
||||
<h2><a name="win32_installer_build"></a>5.3.2. Building the Windows
|
||||
installer</h2>
|
||||
<p>Building the Windows installer for vchanger requires the makensis
|
||||
ustility from the NSIS project in addition to MinGW-w64. A shell script
|
||||
named win32build in the source distribution will configure and build both
|
||||
@ -929,11 +957,12 @@ Device {
|
||||
<p>The Bacula Storage Daemon does not usually run as root. Since vchanger
|
||||
will be invoked by the Storage Daemon, and so will run as the same user
|
||||
that it does, permissions for magazine filesystems must be set to allow
|
||||
read/write access to that user. This can be done by mounting the new
|
||||
partition somewhere, then setting the appropriate permissions to give
|
||||
read/write access to the user that the Storage Daemon runs as. It may also
|
||||
be necessary to configure SELinux or AppArmour to allow the user that the
|
||||
Storage Daemon runs as to read/write the magazine filesystems.</p>
|
||||
read/write access to the user:group that the bacula-sd Storage Daemon runs
|
||||
as. This can be done by mounting the new partition somewhere, then setting
|
||||
the appropriate permissions to give read/write access to the user that the
|
||||
Storage Daemon runs as. It may also be necessary to configure SELinux or
|
||||
AppArmour to allow the user that the Storage Daemon runs as to have
|
||||
read/write the magazine filesystems.</p>
|
||||
<h2><a name="determining_uuid"></a>6.2. Determining the Magazine's
|
||||
Filesystem UUID</h2>
|
||||
<p>On most POSIX systems, the blkid utility can be used to view the UUID of
|
||||
@ -956,9 +985,9 @@ Device {
|
||||
but this may not suffice for use with daemons, such as the Bacula Storage
|
||||
Daemon that will normally invoke vchanger. The block storage device
|
||||
containing the magazine's filesystem partition must, by some means, be
|
||||
mounted before it can be used by vchanger. Since vchanger will be invoked
|
||||
by the Bacula Storage Daemon, and will not ordinarily run with superuser
|
||||
privileges, it does not itself attempt to mount filesystems. </p>
|
||||
mounted before it can be used by vchanger or Bacula. Since vchanger will
|
||||
be invoked by the Bacula Storage Daemon, and will not ordinarily run with
|
||||
superuser privileges, it does not itself attempt to mount filesystems. </p>
|
||||
<h2><a name="udev"></a>7.1. udev and Hot-swappable Drives</h2>
|
||||
<p><a href="https://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/udev.html">Udev</a>
|
||||
is the subsystem that dynamically assigns device nodes to hot swappable
|
||||
@ -1002,16 +1031,27 @@ UUID=a4902c05-e47d-40e0-9db7-b3d03d08c266 /mnt/vchanger/mag1 ext4 defaults,noaut
|
||||
<pre style="margin-left: 2.5em;">[]# mount /mnt/vchanger/mag0<br>[]# vchanger /etc/vchanger/vchanger.conf refresh</pre>
|
||||
<p>After use, the removable drive can then be removed using:</p>
|
||||
<pre style="margin-left: 2.5em;">[]# umount /mnt/vchanger/mag0<br>[]# vchanger /etc/vchanger/vchanger.conf refresh</pre>
|
||||
<p>It is also possible, when manually mounting magazine partitions, to use
|
||||
the mountpoint path in the <span style="font-style: italic; font-weight: bold;">Magazine
|
||||
</span>directive, rather than the UUID. When a magazine is specified by
|
||||
<p>It is also possible, when manually mounting magazine partitions, to use a
|
||||
mountpoint path in the <span style="font-style: italic; font-weight: bold;">Magazine
|
||||
</span>directive, rather than a UUID. When a magazine is specified by
|
||||
path (rather than by UUID), vchanger assumes the magazine is mounted if
|
||||
that path exists. However, if that directory path exists while the
|
||||
magazine's partition is not mounted, then that directory will be part of
|
||||
the underlying filesystem rather than the unmounted magazine partition's
|
||||
filesystem. For this reason, specifying directory paths in Magazine
|
||||
directives is only recommended for permanently mounted filesystems.
|
||||
Filesystems that are not permanently mounted should be specified by UUID.
|
||||
directives is only recommended for permanently mounted filesystems. For
|
||||
filesystems that are not permanently mounted, specifying magazines by UUID
|
||||
is more flexible, allowing for multiple simultaneously mounted disks and
|
||||
udev mount/unmount scripts that automate the bconsole calls needed to keep
|
||||
Bacula in sync. </p>
|
||||
<p>When specifying a magazine by directory path, rather than filesystem
|
||||
UUID, vchanger will use any files in that directory as volume files. For
|
||||
example, one could specify a single magazine= line in the vchanger
|
||||
configuration file, then mount removable disks there one at a time. At
|
||||
each invocation, vchanger will assign whatever files exist in that
|
||||
directory to its virtual slots. However, this would in turn require
|
||||
manually running 'update slots' in bconsole and would prevent mounting
|
||||
more than one disk at a time, so will require more operator intervention.
|
||||
</p>
|
||||
<h2><a name="udev_mounting"></a>7.3. Using udev To Mount Removable Drive
|
||||
Partitions</h2>
|
||||
@ -1053,6 +1093,10 @@ UUID=a4902c05-e47d-40e0-9db7-b3d03d08c266 /mnt/vchanger/mag1 ext4 defaults,noaut
|
||||
<p>After adding or changing Magazine directives in a vchanger configuration
|
||||
file, configure automounting through udev by:</p>
|
||||
<pre>[]# vchanger-genudevrules >/etc/udev/rules.d/96-vchanger.rules<br>[]# udevadm control --reload-rules</pre>
|
||||
<p>Note that it may be necessary to detach and then reattach currently
|
||||
attached magazine drives following a change in udev rules in order to
|
||||
ensure that the new rules are applied. </p>
|
||||
<p></p>
|
||||
<h2><a name="autofs"></a>7.4. Using autofs To Mount Removable Drive
|
||||
Partitions</h2>
|
||||
<p>The <a href="http://www.autofs.org/">autofs</a> daemon provides a way to
|
||||
@ -1138,21 +1182,23 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
||||
at a directory in an NTFS directory tree. It should be noted that only the
|
||||
mount point directory must be on an NTFS volume. The partition being
|
||||
mounted may have a FAT32 file system or any other file system for which
|
||||
there is a file system driver installed. See “<a href="http://technet.microsoft.com/en-us/library/cc753321.aspx">Assign
|
||||
a mount point folder path to a drive</a>” for instructions on assigning
|
||||
mountpoints for removable drive partitions. Like with drive letters, it is
|
||||
not possible to assign the same mountpoint to more than one drive.</p>
|
||||
there is a file system driver installed. See “<a href="http://technet.microsoft.com/en-us/library/cc753321.aspx">Assign
|
||||
a mount point folder path to a drive</a>” for instructions on
|
||||
assigning mountpoints for removable drive partitions. Like with drive
|
||||
letters, it is not possible to assign the same mountpoint to more than one
|
||||
drive.</p>
|
||||
<p>On Windows, magazine partitions should always be specified by UUID
|
||||
(Volume Serial Number). This ensures that vchanger will be able to find
|
||||
the partition's mountpoint without prior knowledge of which drive letter
|
||||
or mountpoint Windows has currently assigned to the drive.</p>
|
||||
<h1><a name="vchanger_config"></a>8. Configuring vchanger</h1>
|
||||
<p>Each vchanger autochanger is defined by a configuration file. Multiple
|
||||
autochangers may be defined as long as each is given a unique name, its
|
||||
own unique work directory, and its own unique configuration file. By
|
||||
default, vchanger configuration files are placed in the /etc/vchanger
|
||||
directory. The configuration files <b>must be given permissions</b> that
|
||||
allow the user that the Bacula Storage Daemon runs as to have read access.</p>
|
||||
autochangers may be defined as long as each is given a unique <i><b>Storage
|
||||
Resource</b></i> name, its own unique work directory, and its own
|
||||
unique configuration file. By default, vchanger configuration files are
|
||||
placed in the /etc/vchanger directory. The configuration files <b>must be
|
||||
given permissions</b> that allow the user that the Bacula Storage Daemon
|
||||
runs as to have read access.</p>
|
||||
<p style="font-style: normal">A vchanger configuration file consists of
|
||||
keyword = value pairs. Comments are defined by a '#' character, and cause
|
||||
text from the '#' until the next newline character to be ignored. Values
|
||||
@ -1161,7 +1207,8 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
||||
appearing inside of the quoted value must be escaped by prepending with a
|
||||
'\' character. The following keywords are defined for an autochanger
|
||||
configuration file:</p>
|
||||
<table style="margin-left: 2rem; width: 50em;" border="0" cellpadding="0" cellspacing="0">
|
||||
<table style="margin-left: 2rem; width: 50em;" cellspacing="0" cellpadding="0"
|
||||
border="0">
|
||||
<colgroup><col width="172"> <col width="492"> </colgroup>
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
@ -1171,7 +1218,9 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
||||
<td width="492">
|
||||
<p>[Required] The name of the Storage resource, defined in the
|
||||
Bacula Director configuration file, that is associated with this
|
||||
autochanger. <br>
|
||||
autochanger. This also names the vchanger autochanger and is used
|
||||
in constructing the default volume naming prefix used by the
|
||||
CREATEVOLS command.<br>
|
||||
Default: none</p>
|
||||
</td>
|
||||
</tr>
|
||||
@ -1238,7 +1287,9 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
||||
<td width="492">
|
||||
<p>The path to the bconsole binary that vchanger will invoke to
|
||||
issue 'update slots' and 'label barcodes' commands to Bacula. To
|
||||
disable interaction with Bacula, set to the empty string.<br>
|
||||
disable interaction with Bacula via bconsole, set to the empty
|
||||
string. When disabled, 'update slots' and 'label barcodes'
|
||||
commands will need to be issued manually from within bconsole.<br>
|
||||
Default: /usr/sbin/bconsole</p>
|
||||
</td>
|
||||
</tr>
|
||||
@ -1248,7 +1299,9 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
||||
</td>
|
||||
<td width="492">
|
||||
<p>The path to the configuration file to use when invoking bconsole<span
|
||||
style="font-style: normal"></span>.<br>
|
||||
style="font-style: normal"></span>. The user that vchanger is
|
||||
invoked by, usually the user that the Bacula Storage Daemon runs
|
||||
as, must have permissions to read the bconsole.conf file.<br>
|
||||
Default: /etc/bacula/bconsole.conf</p>
|
||||
</td>
|
||||
</tr>
|
||||
@ -1268,11 +1321,11 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
||||
</td>
|
||||
<td width="492">
|
||||
<p>[Required] Defines either the path to a directory or the UUID of
|
||||
a filesystem partition (prepended by the string “UUID:”) that is
|
||||
to be used as a magazine containing volume files . The magazine
|
||||
directive assigns a directory or partition to this autochanger.
|
||||
This directive may appear multiple times to assign multiple
|
||||
magazines.<br>
|
||||
a filesystem partition (prepended by the string
|
||||
“UUID:”) that is to be used as a magazine containing
|
||||
volume files. The Magazine directive assigns a directory or
|
||||
partition to this autochanger. This directive may appear multiple
|
||||
times to assign multiple magazines.<br>
|
||||
Default: none</p>
|
||||
</td>
|
||||
</tr>
|
||||
@ -1286,8 +1339,8 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
||||
directive to the vchanger configuration file. For removable storage, the <span
|
||||
style="font-weight: bold; font-style: italic;">Magazine </span>directive
|
||||
should specify the filesystem UUID (or the mountpoint path if using
|
||||
autofs). If a directory on permanently mounted fixed-disk storage is being
|
||||
used as a magazine, then the <span style="font-weight: bold; font-style: italic;">Magazine
|
||||
autofs or manual mounting). If a directory on permanently mounted
|
||||
fixed-disk storage is being used as a magazine, then the <span style="font-weight: bold; font-style: italic;">Magazine
|
||||
</span>directive should specify the directory path. In either case, the
|
||||
filesystem or directory must by writable by the user that Bacula Storage
|
||||
Daemon runs as. The LISTMAGS vchanger command can be used to determine
|
||||
@ -1351,17 +1404,16 @@ Magazine = UUID:5039284a<span style="font-style: normal">-4312-57d1-92c4-3547100
|
||||
][# chown bacula:tape /mnt/vchanger/5039284a<span style="font-style: normal">-4312-57d1-92c4-354710032c79</span>
|
||||
][# chmod 750 /mnt/vchanger/5039284a<span style="font-style: normal">-4312-57d1-92c4-354710032c79</span>
|
||||
</pre>
|
||||
<p>The Storage resource that this autochanger is associated with is defined
|
||||
in bacula-dir.conf as:</p>
|
||||
<p>The Autochanger resource that this autochanger is associated with is
|
||||
defined in bacula-dir.conf as:</p>
|
||||
<pre># /etc/bacula/bacula-dir.conf<br>...<br># vchanger autochanger vchanger-1
|
||||
Storage {
|
||||
Autochanger {
|
||||
Name = vchanger-1
|
||||
Address = 192.168.1.9
|
||||
SDPort = 9103
|
||||
Password = "password"
|
||||
Device = usb-vchanger-1
|
||||
Media Type = File
|
||||
Autochanger = yes;
|
||||
Maximum Concurrent Jobs = 20
|
||||
}
|
||||
<span style="font-style: normal">...</span>
|
||||
@ -1419,8 +1471,8 @@ Device {
|
||||
volumes<span style="font-style: italic;"></span>. We can now add some
|
||||
volumes with:</p>
|
||||
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf createvols 0 2
|
||||
creating label 'vchanger-1_0_0'
|
||||
creating label 'vchanger-1_0_1'
|
||||
creating label 'vchanger-1_0000_0000'
|
||||
creating label 'vchanger-1_0000_0001'
|
||||
Created 2 volume files on magazine 0
|
||||
</pre>
|
||||
<p>Now the output from a LISTMAGS<span style="font-weight: bold; font-style: italic;">
|
||||
@ -1432,7 +1484,7 @@ Created 2 volume files on magazine 0
|
||||
mapped to virtual slots 1-2. We can issue the LIST command to see what
|
||||
volumes the vchanger-1 autochanger has in its virtual slots.</p>
|
||||
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf list
|
||||
1:vchanger-1_0_0<br>2:vchanger-1_0_1</pre>
|
||||
1:vchanger-1_0000_0000<br>2:vchanger-1_0000_0001</pre>
|
||||
<p>This shows that two volume files are in slots 1 and 2. We can use
|
||||
bconsole to see what Bacula thinks the autochanger status is.</p>
|
||||
<pre>[]# echo "status slots storage=vchanger-1 drive=0" | bconsole
|
||||
@ -1448,9 +1500,9 @@ Device "vchanger-1" has 2 slots.
|
||||
Connecting to Storage daemon vchanger-1 at 192.168.1.9:9103 ...
|
||||
3306 Issuing autochanger "list" command.
|
||||
Slot | Volume Name | Status | Media Type | Pool |
|
||||
------+------------------+-----------+----------------------+--------------------|
|
||||
1 | vchanger-1_0_0 | Append | File | Scratch |
|
||||
2 | vchanger-1_0_1 | Append | File | Scratch | </pre>
|
||||
------+------------------------+-----------+----------------------+--------------------|
|
||||
1 | vchanger-1_0000_0000 | Append | File | Scratch |
|
||||
2 | vchanger-1_0000_0001 | Append | File | Scratch | </pre>
|
||||
<p>This shows that the CREATEVOLS<span style="font-style: italic; font-weight: bold;">
|
||||
</span>command has created two volume files on the first magazine and has
|
||||
successfully labeled them using the <span style="font-style: italic;">l<span
|
||||
@ -1458,13 +1510,13 @@ Connecting to Storage daemon vchanger-1 at 192.168.1.9:9103 ...
|
||||
bconsole.</p>
|
||||
<p>Now attach the second USB drive and add some volumes to it using:</p>
|
||||
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf createvols 1 3
|
||||
creating label 'vchanger-1_1_0'
|
||||
creating label 'vchanger-1_1_1'<br>creating label 'vchanger-1_1_2'<br>Created 3 volume files on magazine 1
|
||||
creating label 'vchanger-1_0001_0000'
|
||||
creating label 'vchanger-1_0001_0001'<br>creating label 'vchanger-1_0001_0002'<br>Created 3 volume files on magazine 1
|
||||
</pre>
|
||||
<p>and confirm that the volumes were added as expected with:</p>
|
||||
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf listmags<br>0:2:1:/mnt/vchanger/9667f83c-6150-44c7-b0d4-57564f174b35
|
||||
1:3:3:/mnt/vchanger/5039284a<span style="font-style: normal">-4312-57d1-92c4-354710032c79</span><br><br>[]# vchanger /etc/vchanger/vchanger-1.conf list
|
||||
1:vchanger-1_0_0<br>2:vchanger-1_0_1<br>3:vchanger-1_1_0<br>4:vchanger-1_1_1<br>5:vchanger-1_1_2<br><br>[]# echo "status slots storage=vchanger-1 drive=0" | bconsole
|
||||
1:vchanger-1_0000_0000<br>2:vchanger-1_0000_0001<br>3:vchanger-1_0001_0000<br>4:vchanger-1_0001_0001<br>5:vchanger-1_0001_0002<br><br>[]# echo "status slots storage=vchanger-1 drive=0" | bconsole
|
||||
Connecting to Director 127.0.0.1:9101
|
||||
1000 OK: bacula-dir Version: 5.2.13 (19 February 2013)
|
||||
Enter a period to cancel a command.
|
||||
@ -1477,11 +1529,11 @@ Device "vchanger-1" has 2 slots.
|
||||
Connecting to Storage daemon vchanger-1 at 192.168.1.9:9103 ...
|
||||
3306 Issuing autochanger "list" command.
|
||||
Slot | Volume Name | Status | Media Type | Pool |
|
||||
------+------------------+-----------+----------------------+--------------------|
|
||||
1 | vchanger-1_0_0 | Append | File | Scratch |<br> 2 | vchanger-1_0_1 | Append | File | Scratch |
|
||||
3 | vchanger-1_1_0 | Append | File | Scratch |
|
||||
4 | vchanger-1_1_1 | Append | File | Scratch |
|
||||
5 | vchanger-1_1_2 | Append | File | Scratch |
|
||||
------+------------------------+-----------+----------------------+--------------------|
|
||||
1 | vchanger-1_0000_0000 | Append | File | Scratch |<br> 2 | vchanger-1_0000_0001 | Append | File | Scratch |
|
||||
3 | vchanger-1_0001_0000 | Append | File | Scratch |
|
||||
4 | vchanger-1_0001_0001 | Append | File | Scratch |
|
||||
5 | vchanger-1_0001_0002 | Append | File | Scratch |
|
||||
</pre>
|
||||
<p>If the first USB drive is now unplugged, the script invoked by udev
|
||||
should unmount the first magazine partition and cause an <span style="font-style: italic; font-weight: bold;">update
|
||||
@ -1493,9 +1545,9 @@ Connecting to Storage daemon vchanger-1 at 192.168.1.9:9103 ...
|
||||
[]# vchanger /etc/vchanger/vchanger-1.conf list
|
||||
1:
|
||||
2:
|
||||
3:vchanger-1_1_0
|
||||
4:vchanger-1_1_1
|
||||
5:vchanger-1_1_2
|
||||
3:vchanger-1_0001_0000
|
||||
4:vchanger-1_0001_0001
|
||||
5:vchanger-1_0001_0002
|
||||
|
||||
[]# echo "status slots storage=vchanger-1 drive=0" | bconsole
|
||||
Connecting to Director 127.0.0.1:9101
|
||||
@ -1510,25 +1562,25 @@ Device "vchanger-1" has 2 slots.
|
||||
Connecting to Storage daemon vchanger-1 at 192.168.1.9:9103 ...
|
||||
3306 Issuing autochanger "list" command.
|
||||
Slot | Volume Name | Status | Media Type | Pool |
|
||||
------+------------------+-----------+----------------------+--------------------|<br> 1*| | ? | ? | ? |<br> 2*| | ? | ? | ? |<br> 3 | vchanger-1_1_0 | Append | File | Scratch |
|
||||
4 | vchanger-1_1_1 | Append | File | Scratch |
|
||||
5 | vchanger-1_1_2 | Append | File | Scratch |
|
||||
------+------------------------+-----------+----------------------+--------------------|<br> 1*| | ? | ? | ? |<br> 2*| | ? | ? | ? |<br> 3 | vchanger-1_0001_0000 | Append | File | Scratch |
|
||||
4 | vchanger-1_0001_0001 | Append | File | Scratch |
|
||||
5 | vchanger-1_0001_0002 | Append | File | Scratch |
|
||||
</pre>
|
||||
<p>Let's now examine what happens when a volume file is "loaded" into a
|
||||
virtual drive.</p>
|
||||
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf load 3 /dev/null 0
|
||||
[]# ls -l /var/spool/vchanger/vchanger-1
|
||||
lrwxrwxrwx 1 bacula tape 29 Mar 1 16:46 0 -> /mnt/vchanger/5039284a<span style="font-style: normal">-4312-57d1-92c4-354710032c79</span>/vchanger-1_1_0
|
||||
lrwxrwxrwx 1 bacula tape 29 Mar 1 16:46 0 -> /mnt/vchanger/5039284a<span style="font-style: normal">-4312-57d1-92c4-354710032c79</span>/vchanger-1_0001_0000
|
||||
-rw-r----- 1 bacula tape 21 Mar 1 16:46 bay_state-1
|
||||
-rw-r----- 1 bacula tape 30 Mar 1 16:46 drive_state-0
|
||||
</pre>
|
||||
<p>The LOAD command created a symlink named '0' in the autochanger's work
|
||||
directory that points to the file 'vchanger-1_1_0' in the filesystem
|
||||
directory that points to the file 'vchanger-1_0001_0000' in the filesystem
|
||||
mounted at /mnt/vchanger/5039284a-4312-57d1-92c4-354710032c79, the volume
|
||||
file that is mapped to virtual slot 3. The symlink named '0' is this
|
||||
autochanger's drive 0. Notice that the path to this symlink was defined in
|
||||
bacula-sd.conf as the <span style="font-weight: bold; font-style: italic;">Archive
|
||||
Device</span> for this autochanger's drive 0. When Bacula opens th the
|
||||
Device</span> for this autochanger's drive 0. When Bacula opens the
|
||||
symlink for reading or writing, it will actually be opening the volume
|
||||
file that the symlink points to. </p>
|
||||
<p>The LOADED command can be used to check the status of a drive.</p>
|
||||
@ -1616,20 +1668,19 @@ Device {
|
||||
<pre># /etc/bacula/bacula-dir.conf
|
||||
# ...
|
||||
# Local USB drive virtual autochanger
|
||||
Storage {
|
||||
Autochanger {
|
||||
Name = vchanger-1 # same as 'Storage Resource' in the vchanger config file
|
||||
Address = sd-server-address
|
||||
Password = "secret_password"
|
||||
Device = usb-changer # name of the Autochanger resource in bacula-sd.conf
|
||||
Media Type = File
|
||||
Autochanger = yes;
|
||||
}
|
||||
# eof</pre>
|
||||
<h1><a name="appendixa"></a>Appendix A. vchanger Commands</h1>
|
||||
<h2><a name="command_list"></a>A.1. LIST Command</h2>
|
||||
<p style="margin-top: 0in; margin-bottom: 0in; font-style: normal">Bacula
|
||||
issues this command to an autochanger to list to stdout the “barcode
|
||||
labels” of volumes in the autochanger's slots. Many tape autochanger
|
||||
issues this command to an autochanger to list to stdout the “barcode
|
||||
labels” of volumes in the autochanger's slots. Many tape autochanger
|
||||
robots have barcode readers such that tapes can be affixed with an
|
||||
adhesive barcode label that identifies the tape. This allows Bacula to
|
||||
automate the process of creating volume labels by utilizing the
|
||||
@ -1640,19 +1691,19 @@ Storage {
|
||||
volume file).</p>
|
||||
<h2><a name="command_listall"></a>A.2. LISTALL Command</h2>
|
||||
<p>It is not clear that Bacula currently uses this command internally, and
|
||||
it is not specified in the <a href="http://www.bacula.org/3.0.x-manuals/en/concepts/concepts/Autochanger_Resource.html#SECTION0018130000000000000000">Bacula
|
||||
it is not specified in the <a href="http://www.bacula.org/9.6.x-manuals/en/concepts/concepts/Autochanger_Resource.html#SECTION0018130000000000000000">Bacula
|
||||
Autochanger Interface</a> documentation. Nevertheless, it is implemented
|
||||
in Bacula's mtx-changer script since version 5.1.0 and is used by some
|
||||
web-based admin utilities, so has been implemented in vchanger. This
|
||||
command is similar to the LIST command except that it also lists current
|
||||
drive status in addition to slot status.</p>
|
||||
<h2><a name="command_load"></a>A.3. LOAD Command</h2>
|
||||
<p style="font-style: normal">The load command is used to “load” a volume
|
||||
file from a virtual slot into a virtual drive. A tape autochanger does
|
||||
this by physically moving the tape located in the requested library slot
|
||||
into a tape drive. Bacula reads and writes volume data from/to the tape
|
||||
drive's device file. With vchanger, a filesystem symlink at a known path
|
||||
is used as a virtual drive in place of a tape drive's device file. A
|
||||
<p style="font-style: normal">The load command is used to “load”
|
||||
a volume file from a virtual slot into a virtual drive. A tape autochanger
|
||||
does this by physically moving the tape located in the requested library
|
||||
slot into a tape drive. Bacula reads and writes volume data from/to the
|
||||
tape drive's device file. With vchanger, a filesystem symlink at a known
|
||||
path is used as a virtual drive in place of a tape drive's device file. A
|
||||
volume file is then loaded by making the target of that symlink point to
|
||||
the volume file mapped to the requested slot. </p>
|
||||
<p style="font-style: normal">Parameter 3 gives the autochanger slot number
|
||||
@ -1663,8 +1714,8 @@ Storage {
|
||||
<p style="font-weight: normal">This command is issued to determine which
|
||||
slot, if any, is loaded into a drive. If a drive is loaded, then the
|
||||
virtual slot number corresponding to the loaded volume file is written to
|
||||
stdout. If the drive is not loaded, the string “0” is written to stdout to
|
||||
inform Bacula that the drive is not loaded.</p>
|
||||
stdout. If the drive is not loaded, the string “0” is written
|
||||
to stdout to inform Bacula that the drive is not loaded.</p>
|
||||
<h2><a name="command_slots"></a>A.5. SLOTS Command</h2>
|
||||
<p style="margin-top: 0in; margin-bottom: 0in; font-style: normal">This
|
||||
command simply prints to stdout the maximum number of volume files that
|
||||
@ -1681,21 +1732,21 @@ Storage {
|
||||
this by deleting the virtual drive's symlink.</p>
|
||||
<h2><a name="command_createvols"></a>A.7. CREATEVOLS Command</h2>
|
||||
<p><span style="font-weight: normal">This is an extended command that is not
|
||||
part of the <a href="http://www.bacula.org/3.0.x-manuals/en/concepts/concepts/Autochanger_Resource.html#SECTION0018130000000000000000">Bacula
|
||||
part of the <a href="http://www.bacula.org/9.6.x-manuals/en/concepts/concepts/Autochanger_Resource.html#SECTION0018130000000000000000">Bacula
|
||||
Autochanger
|
||||
Interface</a></span> <span style="font-weight: normal">API, and is
|
||||
used to add volume files to a magazine filesystem and cause them to be
|
||||
labeled with a Bacula volume label. The format of this command is</span></p>
|
||||
<pre style="margin-top: 0.01in; margin-bottom: 0.2in">vchanger config_file createcols mag_ndx count [start_num] [--label=prefix] [--pool=pool_name]</pre>
|
||||
<p style="margin-top: 0.08in">where:</p>
|
||||
<table style="margin-left: 3rem;" border="0" cellpadding="0" cellspacing="0"
|
||||
width="664">
|
||||
<table style="margin-left: 3rem;" width="664" cellspacing="0" cellpadding="0"
|
||||
border="0">
|
||||
<colgroup><col width="131"> <col width="533"> </colgroup>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<table style="margin-left: 1rem; width: 50em; margin-bottom: 1rem;" border="0"
|
||||
cellpadding="0" cellspacing="0">
|
||||
<table style="margin-left: 1rem; width: 50em; margin-bottom: 1rem;" cellspacing="0"
|
||||
cellpadding="0" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="9em">
|
||||
@ -1746,8 +1797,10 @@ Autochanger
|
||||
</td>
|
||||
<td>
|
||||
<p>An optional prefix string used in naming the created volume
|
||||
files. The default prefix string is the autochanger's name
|
||||
concatenated with '_' plus the magazine index number.</p>
|
||||
files. The filenames created will be the prefix string
|
||||
concatenated with the integer uniqueness number. The default
|
||||
prefix string is the autochanger's name concatenated with '_',
|
||||
followed by the magazine index number, followed by another '_'.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -1769,14 +1822,14 @@ Autochanger
|
||||
this reason, vchanger will also issue the <span style="font-weight: bold; font-style: italic;">update
|
||||
slots</span> command to Bacula whenever new volume files are added.</p>
|
||||
<h2><a name="command_listmags"></a>A.8. LISTMAGS Command</h2>
|
||||
<p>This is an extended command that is not part of the <a href="http://www.bacula.org/3.0.x-manuals/en/concepts/concepts/Autochanger_Resource.html#SECTION0018130000000000000000">Bacula
|
||||
<p>This is an extended command that is not part of the <a href="http://www.bacula.org/9.6.x-manuals/en/concepts/concepts/Autochanger_Resource.html#SECTION0018130000000000000000">Bacula
|
||||
Autochanger
|
||||
Interface</a> API, and is used to list status information about the
|
||||
autochanger's assigned magazines. The format of this command is</p>
|
||||
<pre style="margin-top: 0.01in; margin-bottom: 0.2in">vchanger config_file listmags</pre>
|
||||
<p style="margin-top: 0.08in">where:</p>
|
||||
<table style="margin-left: 1em; margin-bottom: 1em;" border="0" cellpadding="0"
|
||||
cellspacing="0" width="664">
|
||||
<table style="margin-left: 1em; margin-bottom: 1em;" width="664" cellspacing="0"
|
||||
cellpadding="0" border="0">
|
||||
<colgroup><col width="131"> <col width="533"> </colgroup>
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
@ -1793,8 +1846,8 @@ Autochanger
|
||||
to stdout, one line per bay. The format of an output line is:</p>
|
||||
<pre style="margin-top: 0.01in; margin-bottom: 0.2in">mag_ndx:count:start_slot:mountpoint</pre>
|
||||
<p style="margin-top: 0.08in">where:</p>
|
||||
<table style="margin-left: 1em; margin-bottom: 1em;" border="0" cellpadding="0"
|
||||
cellspacing="0" width="664">
|
||||
<table style="margin-left: 1em; margin-bottom: 1em;" width="664" cellspacing="0"
|
||||
cellpadding="0" border="0">
|
||||
<colgroup><col width="131"> <col width="533"> </colgroup>
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
|
@ -3,8 +3,8 @@
|
||||
#
|
||||
Summary: A virtual autochanger for Bacula
|
||||
Name: vchanger
|
||||
Version: 1.0.1
|
||||
Release: 1.el6
|
||||
Version: 1.0.3
|
||||
Release: 1%{dist}
|
||||
License: GPLv2
|
||||
Group: System Environment/Daemons
|
||||
Source: http://sourceforge.net/projects/vchanger/files/vchanger/%{version}/vchanger-%{version}.tar.gz
|
||||
@ -35,6 +35,7 @@ make
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir}/%{name}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man5
|
||||
@ -44,6 +45,7 @@ mkdir -m 0770 -p ${RPM_BUILD_ROOT}%{_localstatedir}/spool/%{name}
|
||||
mkdir -m 0755 -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}
|
||||
make DESTDIR=${RPM_BUILD_ROOT} install-strip
|
||||
install -m 0644 scripts/vchanger.default ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/vchanger
|
||||
install -m 0644 contrib/vchanger.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/vchanger
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
@ -52,6 +54,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/*
|
||||
%{_libexecdir}/%{name}/*
|
||||
%{_sysconfdir}/logrotate.d/*
|
||||
%doc %{_docdir}/%{name}-%{version}/AUTHORS
|
||||
%doc %{_docdir}/%{name}-%{version}/ChangeLog
|
||||
%doc %{_docdir}/%{name}-%{version}/COPYING
|
||||
@ -85,6 +88,10 @@ if [ $1 -eq 1 ] ; then
|
||||
fi
|
||||
|
||||
%changelog
|
||||
* Thu May 6 2020 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.2
|
||||
* Thu Jun 14 2018 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.2
|
||||
* Wed Jun 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.1
|
||||
* Fri Apr 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||
|
@ -3,8 +3,8 @@
|
||||
#
|
||||
Summary: A virtual autochanger for Bacula
|
||||
Name: vchanger
|
||||
Version: 1.0.1
|
||||
Release: 1.el7
|
||||
Version: 1.0.3
|
||||
Release: 1%{dist}
|
||||
License: GPLv2
|
||||
Group: System Environment/Daemons
|
||||
Source: http://sourceforge.net/projects/vchanger/files/vchanger/%{version}/vchanger-%{version}.tar.gz
|
||||
@ -14,6 +14,9 @@ Packager: Josh Fisher <jfisher@jaybus.com>
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
Requires(post): /bin/mkdir, /bin/chown, /usr/bin/getent, /usr/sbin/useradd, /usr/sbin/groupadd
|
||||
|
||||
# For libudev support
|
||||
BuildRequires: systemd-devel
|
||||
|
||||
%description
|
||||
Vchanger implements a virtual autochanger for use with the Bacula open source
|
||||
network backup system. Vchanger emulates a magazine-based tape autoloader
|
||||
@ -35,6 +38,7 @@ make
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir}/%{name}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man5
|
||||
@ -44,6 +48,7 @@ mkdir -m 0770 -p ${RPM_BUILD_ROOT}%{_localstatedir}/spool/%{name}
|
||||
mkdir -m 0755 -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}
|
||||
make DESTDIR=${RPM_BUILD_ROOT} install-strip
|
||||
install -m 0644 scripts/vchanger.default ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/vchanger
|
||||
install -m 0644 contrib/vchanger.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/vchanger
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
@ -52,6 +57,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/*
|
||||
%{_libexecdir}/%{name}/*
|
||||
%{_sysconfdir}/logrotate.d/*
|
||||
%doc %{_docdir}/%{name}-%{version}/AUTHORS
|
||||
%doc %{_docdir}/%{name}-%{version}/ChangeLog
|
||||
%doc %{_docdir}/%{name}-%{version}/COPYING
|
||||
@ -85,6 +91,10 @@ if [ $1 -eq 1 ] ; then
|
||||
fi
|
||||
|
||||
%changelog
|
||||
* Thu May 6 2020 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.2
|
||||
* Thu Jun 14 2018 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.2
|
||||
* Wed Jun 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.1
|
||||
* Fri Apr 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||
|
106
rpm/vchanger.f29.spec
Normal file
106
rpm/vchanger.f29.spec
Normal file
@ -0,0 +1,106 @@
|
||||
#
|
||||
# Spec file for vchanger - Fedora 29
|
||||
#
|
||||
|
||||
%global debug_package %{nil}
|
||||
|
||||
Summary: A virtual autochanger for Bacula
|
||||
Name: vchanger
|
||||
Version: 1.0.3
|
||||
Release: 1%{dist}
|
||||
License: GPLv2
|
||||
Group: System Environment/Daemons
|
||||
Source: http://sourceforge.net/projects/vchanger/files/vchanger/%{version}/vchanger-%{version}.tar.gz
|
||||
URL: http://vchanger.sourceforge.net
|
||||
Vendor: Josh Fisher.
|
||||
Packager: Josh Fisher <jfisher@jaybus.com>
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
Requires(post): /usr/bin/mkdir, /usr/bin/chown, /usr/bin/getent, /usr/sbin/useradd, /usr/sbin/groupadd
|
||||
|
||||
# For libudev support
|
||||
BuildRequires: systemd-devel
|
||||
|
||||
%description
|
||||
Vchanger implements a virtual autochanger for use with the Bacula open source
|
||||
network backup system. Vchanger emulates a magazine-based tape autoloader
|
||||
using disk file system mountpoints as virtual magazines and the files in
|
||||
each virtual magazine as virtual tape volumes. Vchanger is primarily
|
||||
designed to use an unlimited number of removable disk drives as an easily
|
||||
scalable virtual autochanger and allow seamless removal of backups for
|
||||
offsite storage.
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}
|
||||
|
||||
%build
|
||||
CFLAGS="%{optflags} -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE" \
|
||||
%configure
|
||||
make
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir}/%{name}
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man5
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man8
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_docdir}/%{name}-%{version}
|
||||
mkdir -m 0770 -p ${RPM_BUILD_ROOT}%{_localstatedir}/spool/%{name}
|
||||
mkdir -m 0755 -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}
|
||||
make DESTDIR=${RPM_BUILD_ROOT} install-strip
|
||||
install -m 0644 scripts/vchanger.default ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/vchanger
|
||||
install -m 0644 contrib/vchanger.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/vchanger
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/*
|
||||
%{_libexecdir}/%{name}/*
|
||||
%{_sysconfdir}/logrotate.d/*
|
||||
%doc %{_docdir}/%{name}-%{version}/AUTHORS
|
||||
%doc %{_docdir}/%{name}-%{version}/ChangeLog
|
||||
%doc %{_docdir}/%{name}-%{version}/COPYING
|
||||
%doc %{_docdir}/%{name}-%{version}/INSTALL
|
||||
%doc %{_docdir}/%{name}-%{version}/NEWS
|
||||
%doc %{_docdir}/%{name}-%{version}/README
|
||||
%doc %{_docdir}/%{name}-%{version}/ReleaseNotes
|
||||
%doc %{_docdir}/%{name}-%{version}/vchanger-example.conf
|
||||
%doc %{_docdir}/%{name}-%{version}/example-vchanger-udev.rules
|
||||
%doc %{_docdir}/%{name}-%{version}/vchangerHowto.html
|
||||
%{_mandir}/man5/*
|
||||
%{_mandir}/man8/*
|
||||
%config(noreplace) %{_sysconfdir}/sysconfig/vchanger
|
||||
|
||||
%post
|
||||
if [ $1 -eq 1 ] ; then
|
||||
/usr/bin/getent group tape &>/dev/null || /usr/sbin/groupadd -r tape
|
||||
/usr/bin/getent group bacula &>/dev/null || /usr/sbin/groupadd -r bacula
|
||||
/usr/bin/getent passwd bacula &>/dev/null || /usr/sbin/useradd -r -g bacula -d %{_localstatedir}/spool/bacula -s /bin/bash bacula
|
||||
if [ ! -d %{_localstatedir}/spool/vchanger ] ; then
|
||||
/bin/mkdir -p -m 0770 %{_localstatedir}/spool/vchanger
|
||||
/bin/chown bacula:tape %{_localstatedir}/spool/vchanger
|
||||
fi
|
||||
if [ ! -d %{_localstatedir}/log/vchanger ] ; then
|
||||
/bin/mkdir -p -m 0755 %{_localstatedir}/log/vchanger
|
||||
/bin/chown bacula:tape %{_localstatedir}/log/vchanger
|
||||
fi
|
||||
if [ ! -d %{_sysconfdir}/vchanger ] ; then
|
||||
/bin/mkdir -p -m 0755 %{_sysconfdir}/vchanger
|
||||
fi
|
||||
fi
|
||||
|
||||
%changelog
|
||||
* Thu May 6 2020 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.3
|
||||
* Mon Dec 24 2018 Steven A. Falco <stevenfalco@gmail.com>
|
||||
- Various changes for Fedora 29
|
||||
* Thu Jun 14 2018 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.2
|
||||
* Wed Jun 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||
- Updated to release 1.0.1
|
||||
* Fri Apr 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||
- Initial spec file
|
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# vchanger-genudevrules ( vchanger v.1.0.1 ) 2015-06-03
|
||||
# vchanger-genudevrules ( vchanger v.1.0.3 ) 2020-05-06
|
||||
#
|
||||
# Search all autochanger configuration files for magazines being defined
|
||||
# by filesystem UUID and print to stdout the udev rules for launching
|
||||
|
@ -1,12 +1,14 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# vchanger-launch-mount.sh ( vchanger v.1.0.1 ) 2015-06-03
|
||||
# vchanger-launch-mount.sh ( vchanger v.1.0.3 ) 2020-05-06
|
||||
#
|
||||
# This script is used to run the vchanger-mount-uuid.sh script in
|
||||
# another [background] process launched by the at command in order
|
||||
# to prevent delays when invoked by a udev rule.
|
||||
# This script is used to run the vchanger-mount-uuid.sh script as
|
||||
# a detached process and immediately exit. This is to prevent delays
|
||||
# when invoked by a udev rule.
|
||||
#
|
||||
VCHANGER_MOUNT=/usr/libexec/vchanger/vchanger-mount-uuid.sh
|
||||
{
|
||||
$VCHANGER_MOUNT $1
|
||||
} &
|
||||
|
||||
# For some reason, nohup doesn't work, but "at now" does. This may have to
|
||||
# do with cgroups.
|
||||
#nohup $VCHANGER_MOUNT $1 </dev/null >/dev/null 2>&1 &
|
||||
echo "$VCHANGER_MOUNT $1 </dev/null >/dev/null 2>&1" | at now
|
||||
|
@ -1,12 +1,14 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# vchanger-launch-umount.sh ( vchanger v.1.0.1 ) 2015-06-03
|
||||
# vchanger-launch-umount.sh ( vchanger v.1.0.3 ) 2020-05-06
|
||||
#
|
||||
# This script is used to run the vchanger-umount-uuid.sh script in
|
||||
# another [background] process launched by the at command in order
|
||||
# to prevent delays when invoked by a udev rule.
|
||||
#
|
||||
VCHANGER_UMOUNT=/usr/libexec/vchanger/vchanger-umount-uuid.sh
|
||||
{
|
||||
$VCHANGER_UMOUNT $1
|
||||
} &
|
||||
|
||||
# For some reason, nohup doesn't work, but "at now" does. This may have to
|
||||
# do with cgroups.
|
||||
#nohup $VCHANGER_UMOUNT $1 </dev/null >/dev/null 2>&1 &
|
||||
echo "$VCHANGER_UMOUNT $1 </dev/null >/dev/null 2>&1" | at now
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# vchanger-mount-uuid.sh ( vchanger v.1.0.1 ) 2015-06-03
|
||||
# vchanger-mount-uuid.sh ( vchanger v.1.0.3 ) 2020-05-06
|
||||
#
|
||||
# This script is used to mount the filesystem having the
|
||||
# UUID specified in parameter 1 at a fixed path. The path
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# vchanger-umount-uuid.sh ( vchanger v.1.0.1 ) 2015-06-03
|
||||
# vchanger-umount-uuid.sh ( vchanger v.1.0.3 ) 2020-05-06
|
||||
#
|
||||
# This script is used to unmount the filesystem having the
|
||||
# UUID specified in parameter 1. The mountpoint path
|
||||
|
@ -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
|
||||
|
129
src/bconsole.cpp
129
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;
|
||||
}
|
||||
if (write(fno_in, "\n", 1) != 1) {
|
||||
rc = errno;
|
||||
vlog.Error("send to bconsole's stdin failed errno=%d", 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;
|
||||
}
|
||||
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);
|
||||
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_name_len) {
|
||||
for (n = pos; n < dev_name_len && !isblank(dev_name[n]); n++) ;
|
||||
while (rc == -4 && pos < dev_links_len) {
|
||||
for (n = pos; n < dev_links_len && !isblank(dev_links[n]); n++) ;
|
||||
n -= pos;
|
||||
memmove(devlink, dev_name + pos, n);
|
||||
memmove(devlink, dev_links + 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 == 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_ */
|
||||
|
@ -1,5 +1,5 @@
|
||||
#................-
|
||||
#. Date of creation: 2015-06-01
|
||||
#. Date of creation: 2020-05-06
|
||||
#. Name: installer.nsi
|
||||
#................-
|
||||
#..- Package parameters ...
|
||||
@ -9,7 +9,15 @@ SetCompressor lzma
|
||||
!include MUI2.nsh
|
||||
!include WinMessages.nsh
|
||||
!include x64.nsh
|
||||
!insertmacro MUI_LANGUAGE English
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "license.txt"
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
#... Installation Windows Parameters ..
|
||||
!define APPNAME "vchanger"
|
||||
!define COMPANYNAME "Josh Fisher"
|
||||
@ -17,20 +25,20 @@ SetCompressor lzma
|
||||
# These three must be integers
|
||||
!define VERSIONMAJOR 1
|
||||
!define VERSIONMINOR 0
|
||||
!define VERSIONBUILD 1
|
||||
!define VERSIONBUILD 3
|
||||
# These will be displayed by the "Click here for support information" link in "Add/Remove Programs"
|
||||
!define HELPURL "http://sourceforge.net/projects/vchanger/" # "Support Information" link
|
||||
Name "vchanger 1.0.1"
|
||||
VIProductVersion "1.0.1.0"
|
||||
Name "vchanger 1.0.3"
|
||||
VIProductVersion "1.0.3.0"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "vchanger Installer"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "Copyright (c) Josh Fisher 2008-2015"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "Copyright (c) Josh Fisher 2008-2020"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "vchanger Windows Installer"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "1.0.1"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "1.0.3"
|
||||
ShowInstDetails nevershow
|
||||
SilentInstall normal
|
||||
RequestExecutionLevel admin
|
||||
AutoCloseWindow True
|
||||
OutFile "vchanger-1.0.1.exe"
|
||||
OutFile "vchanger-1.0.3.exe"
|
||||
|
||||
PageEx license
|
||||
LicenseData "license.txt"
|
||||
@ -121,13 +129,13 @@ Function .onInit
|
||||
SetShellVarContext all
|
||||
#Determine the bitness of the OS and enable the correct section
|
||||
${If} ${RunningX64}
|
||||
SectionSetFlags SEC0001 ${SECTION_OFF}
|
||||
SectionSetFlags SEC0002 ${SF_SELECTED}
|
||||
SectionSetFlags ${SEC0001} ${SECTION_OFF}
|
||||
SectionSetFlags ${SEC0002} ${SF_SELECTED}
|
||||
StrCpy $INSTDIR "$PROGRAMFILES64\vchanger"
|
||||
SetRegView 64
|
||||
${Else}
|
||||
SectionSetFlags SEC0002 ${SECTION_OFF}
|
||||
SectionSetFlags SEC0001 ${SF_SELECTED}
|
||||
SectionSetFlags ${SEC0002} ${SECTION_OFF}
|
||||
SectionSetFlags ${SEC0001} ${SF_SELECTED}
|
||||
StrCpy $INSTDIR "$PROGRAMFILES32\vchanger"
|
||||
SetRegView 32
|
||||
${EndIf}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# Build for 32-bit and 64-bit Windows binary and create NSIS installer
|
||||
#
|
||||
VERS=1.0.1
|
||||
VERS=1.0.3
|
||||
rm -f ./win32/vchanger-$VERS.exe
|
||||
rm -f ./win32/vchanger.exe
|
||||
rm -f ./win32/vchanger64.exe
|
||||
|
Loading…
x
Reference in New Issue
Block a user