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
|
Josh Fisher
|
||||||
|
|
||||||
Contributors:
|
Contributors:
|
||||||
|
Bill Arlofski
|
||||||
|
Wanderlei Hüttel
|
||||||
|
Steven A. Falco
|
2
COPYING
2
COPYING
@ -1,5 +1,5 @@
|
|||||||
COPYRIGHTS:
|
COPYRIGHTS:
|
||||||
Vchanger is Copyright (C) 2008-2015 Josh Fisher.
|
Vchanger is Copyright (C) 2008-2020 Josh Fisher.
|
||||||
|
|
||||||
LICENSE:
|
LICENSE:
|
||||||
Vchanger is licensed under the GNU GPL version 2, the full text
|
Vchanger is licensed under the GNU GPL version 2, the full text
|
||||||
|
21
ChangeLog
21
ChangeLog
@ -1,5 +1,26 @@
|
|||||||
vchanger ChangeLog
|
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)
|
1.0.1 (2015-06-09)
|
||||||
- When looking up the mountpoint of a magazine by UUID with libudev,
|
- When looking up the mountpoint of a magazine by UUID with libudev,
|
||||||
also look for mountpoint of device alias names in DEVLINKS in addition
|
also look for mountpoint of device alias names in DEVLINKS in addition
|
||||||
|
32
ReleaseNotes
32
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
|
Release 1.0.1
|
||||||
|
|
||||||
|
11
config.h.in
11
config.h.in
@ -15,6 +15,9 @@
|
|||||||
/* Define to 1 if you have the <ctype.h> header file. */
|
/* Define to 1 if you have the <ctype.h> header file. */
|
||||||
#undef HAVE_CTYPE_H
|
#undef HAVE_CTYPE_H
|
||||||
|
|
||||||
|
/* have header direct.h */
|
||||||
|
#undef HAVE_DIRECT_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <dirent.h> header file. */
|
/* Define to 1 if you have the <dirent.h> header file. */
|
||||||
#undef HAVE_DIRENT_H
|
#undef HAVE_DIRENT_H
|
||||||
|
|
||||||
@ -69,7 +72,7 @@
|
|||||||
/* Define to 1 if you have the <locale.h> header file. */
|
/* Define to 1 if you have the <locale.h> header file. */
|
||||||
#undef HAVE_LOCALE_H
|
#undef HAVE_LOCALE_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `localtime_r' function. */
|
/* have function localtime_r */
|
||||||
#undef HAVE_LOCALTIME_R
|
#undef HAVE_LOCALTIME_R
|
||||||
|
|
||||||
/* Define to 1 if you have the <memory.h> header file. */
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
@ -96,6 +99,9 @@
|
|||||||
/* Define to 1 if you have the `readlink' function. */
|
/* Define to 1 if you have the `readlink' function. */
|
||||||
#undef HAVE_READLINK
|
#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. */
|
/* Define to 1 if you have the `setlocale' function. */
|
||||||
#undef HAVE_SETLOCALE
|
#undef HAVE_SETLOCALE
|
||||||
|
|
||||||
@ -148,6 +154,9 @@
|
|||||||
*/
|
*/
|
||||||
#undef HAVE_SYS_DIR_H
|
#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. */
|
/* Define to 1 if you have the <sys/mount.h> header file. */
|
||||||
#undef HAVE_SYS_MOUNT_H
|
#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
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# 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>.
|
# Report bugs to <jfisher@jaybus.com>.
|
||||||
#
|
#
|
||||||
@ -580,8 +580,8 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='vchanger'
|
PACKAGE_NAME='vchanger'
|
||||||
PACKAGE_TARNAME='vchanger'
|
PACKAGE_TARNAME='vchanger'
|
||||||
PACKAGE_VERSION='1.0.1'
|
PACKAGE_VERSION='1.0.3'
|
||||||
PACKAGE_STRING='vchanger 1.0.1'
|
PACKAGE_STRING='vchanger 1.0.3'
|
||||||
PACKAGE_BUGREPORT='jfisher@jaybus.com'
|
PACKAGE_BUGREPORT='jfisher@jaybus.com'
|
||||||
PACKAGE_URL=''
|
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.
|
# 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.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
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]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@ -1345,7 +1345,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of vchanger 1.0.1:";;
|
short | recursive ) echo "Configuration of vchanger 1.0.3:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@ -1439,7 +1439,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
vchanger configure 1.0.1
|
vchanger configure 1.0.3
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
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
|
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||||
|
|
||||||
} # ac_fn_c_check_func
|
} # 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
|
cat >config.log <<_ACEOF
|
||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
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
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $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 " pwd.h"
|
||||||
as_fn_append ac_header_list " dirent.h"
|
as_fn_append ac_header_list " dirent.h"
|
||||||
as_fn_append ac_header_list " fcntl.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 " sys/select.h"
|
||||||
as_fn_append ac_header_list " optarg.h"
|
as_fn_append ac_header_list " optarg.h"
|
||||||
as_fn_append ac_header_list " pthread.h"
|
as_fn_append ac_header_list " pthread.h"
|
||||||
as_fn_append ac_header_list " libgen.h"
|
as_fn_append ac_header_list " libgen.h"
|
||||||
as_fn_append ac_header_list " io.h"
|
as_fn_append ac_header_list " io.h"
|
||||||
as_fn_append ac_header_list " signal.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
|
# Check that the precious variables saved in the cache have kept the same
|
||||||
# value.
|
# value.
|
||||||
ac_cache_corrupted=false
|
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.
|
# Define the identity of the package.
|
||||||
PACKAGE='vchanger'
|
PACKAGE='vchanger'
|
||||||
VERSION='1.0.1'
|
VERSION='1.0.3'
|
||||||
|
|
||||||
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
cat >>confdefs.h <<_ACEOF
|
||||||
@ -5514,6 +5562,70 @@ else
|
|||||||
as_fn_error $? "\"could not find libpthread\"" "$LINENO" 5
|
as_fn_error $? "\"could not find libpthread\"" "$LINENO" 5
|
||||||
fi
|
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
|
# Support using libudev or libblkid for UUID lookup
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing udev_new" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing udev_new" >&5
|
||||||
$as_echo_n "checking for library containing udev_new... " >&6; }
|
$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
|
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.
|
# Checks for functions.
|
||||||
for ac_func in vprintf
|
for ac_func in vprintf
|
||||||
do :
|
do :
|
||||||
@ -6031,32 +6156,18 @@ fi
|
|||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
for ac_func in setlocale getmntent getmntent_r getfsstat
|
|
||||||
do :
|
ac_fn_c_check_decl "$LINENO" "localtime_r" "ac_cv_have_decl_localtime_r" "$ac_includes_default
|
||||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
#include <pthread.h>
|
||||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
#include <time.h>
|
||||||
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
|
"
|
||||||
cat >>confdefs.h <<_ACEOF
|
if test "x$ac_cv_have_decl_localtime_r" = xyes; then :
|
||||||
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
|
||||||
_ACEOF
|
$as_echo "#define HAVE_LOCALTIME_R /**/" >>confdefs.h
|
||||||
|
|
||||||
fi
|
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"
|
ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
|
||||||
if test "x$ac_cv_func_gettimeofday" = xyes; then :
|
if test "x$ac_cv_func_gettimeofday" = xyes; then :
|
||||||
$as_echo "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h
|
$as_echo "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h
|
||||||
@ -6070,6 +6181,19 @@ esac
|
|||||||
|
|
||||||
fi
|
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"
|
ac_fn_c_check_func "$LINENO" "getuid" "ac_cv_func_getuid"
|
||||||
if test "x$ac_cv_func_getuid" = xyes; then :
|
if test "x$ac_cv_func_getuid" = xyes; then :
|
||||||
$as_echo "#define HAVE_GETUID 1" >>confdefs.h
|
$as_echo "#define HAVE_GETUID 1" >>confdefs.h
|
||||||
@ -6083,19 +6207,6 @@ esac
|
|||||||
|
|
||||||
fi
|
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"
|
ac_fn_c_check_func "$LINENO" "pipe" "ac_cv_func_pipe"
|
||||||
if test "x$ac_cv_func_pipe" = xyes; then :
|
if test "x$ac_cv_func_pipe" = xyes; then :
|
||||||
$as_echo "#define HAVE_PIPE 1" >>confdefs.h
|
$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"
|
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
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
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
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@ -6766,7 +6890,7 @@ _ACEOF
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
vchanger config.status 1.0.1
|
vchanger config.status 1.0.3
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
27
configure.ac
27
configure.ac
@ -1,9 +1,9 @@
|
|||||||
# -*- Autoconf -*-
|
# -*- Autoconf -*-
|
||||||
# Process this file with autoconf to produce a configure script.
|
# Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
AC_PREREQ([2.63])
|
AC_PREREQ([2.69])
|
||||||
AC_INIT([vchanger], [1.0.1], [jfisher@jaybus.com])
|
AC_INIT([vchanger], [1.0.3], [jfisher@jaybus.com])
|
||||||
AC_DEFINE([COPYRIGHT_NOTICE],["AC_PACKAGE_NAME Copyright (c) 2006-2015 Josh Fisher"],[Copyright notice])
|
AC_DEFINE([COPYRIGHT_NOTICE],["AC_PACKAGE_NAME Copyright (c) 2006-2020 Josh Fisher"],[Copyright notice])
|
||||||
AC_CONFIG_SRCDIR([src])
|
AC_CONFIG_SRCDIR([src])
|
||||||
AC_CONFIG_LIBOBJ_DIR([src/compat])
|
AC_CONFIG_LIBOBJ_DIR([src/compat])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
@ -34,6 +34,9 @@ AC_SYS_LARGEFILE
|
|||||||
|
|
||||||
# Use multithreading
|
# Use multithreading
|
||||||
AC_SEARCH_LIBS([pthread_create], [pthread], [], [AC_MSG_ERROR(["could not find libpthread"])])
|
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
|
# Support using libudev or libblkid for UUID lookup
|
||||||
AC_SEARCH_LIBS([udev_new],[udev],[AC_CHECK_HEADERS([libudev.h])])
|
AC_SEARCH_LIBS([udev_new],[udev],[AC_CHECK_HEADERS([libudev.h])])
|
||||||
AC_CHECK_HEADER([blkid/blkid.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([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([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([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/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])
|
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_CHECK_HEADER([windows.h], [AC_DEFINE([HAVE_WINDOWS_H],,[have header windows.h])
|
||||||
[AC_DEFINE([HAVE_WINDOWS_H],,[have header windows.h])
|
|
||||||
WINLDADD=-static])
|
WINLDADD=-static])
|
||||||
AC_SUBST(WINLDADD)
|
AC_SUBST(WINLDADD)
|
||||||
AC_CHECK_HEADER([winioctl.h], [AC_DEFINE([HAVE_WINIOCTL_H],,[have header winioctl.h])], [], [#include <windows.h>])
|
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([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([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([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.
|
# Checks for functions.
|
||||||
AC_FUNC_VPRINTF
|
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])
|
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)
|
# 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"
|
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
|
# 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
|
# User User to run as when invoked by root. This must be the
|
||||||
# owner of the volume files controlled by this changer, and
|
# owner of the volume files controlled by this changer, and
|
||||||
# so will need to be the same user that bacula-sd runs as.
|
# so will need to be the same user that bacula-sd runs as.
|
||||||
# [Default: none ]
|
# [Default: bacula ]
|
||||||
User = bacula
|
#User = bacula
|
||||||
|
|
||||||
#
|
#
|
||||||
# Group Group to run as when invoked by root. This should be the
|
# Group Group to run as when invoked by root. This should be the
|
||||||
# owner group of the volume files controlled by this changer,
|
# 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.
|
# bacula-sd runs as.
|
||||||
# [Default: none ]
|
# [Default: tape ]
|
||||||
group = tape
|
#group = tape
|
||||||
|
|
||||||
#
|
#
|
||||||
# Work Dir Directory where virtual drive and magazine state information
|
# Work Dir Directory where virtual drive and magazine state information
|
||||||
# and symlinks for this changer are stored.
|
# and symlinks for this changer are stored.
|
||||||
# [Default: /var/spool/vchanger/[StorageResource] ]
|
# [Default: /var/spool/vchanger/{StorageResource} ]
|
||||||
#work dir = "/var/spool/vchanger/vcahnger"
|
#work dir = "/var/spool/vchanger/vcahnger"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Logfile Path to log file for this changer.
|
# Logfile Path to log file for this changer.
|
||||||
# [Default: /var/log/vchanger/[StorageResource].log ]
|
# [Default: {WorkDir}/{StorageResource}.log ]
|
||||||
#logfile = "/var/log/vchanger/vchanger.log"
|
#logfile = "/var/spool/vchanger/vchanger.log"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Log Level Sets the level of detail being logged. An integer value from
|
# 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
|
# bconsole config Path to the config file bconsole will use when vchanger
|
||||||
# invokes bconsole. By default, bconsole will be invoked
|
# 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 ]
|
# [Default: none ]
|
||||||
#bconsole config = /etc/bacula/bconsole.conf
|
#bconsole config = /etc/bacula/bconsole.conf
|
||||||
|
|
||||||
@ -69,7 +70,9 @@ group = tape
|
|||||||
# by prefixing the string "UUID:" to the filesystem's UUID.
|
# by prefixing the string "UUID:" to the filesystem's UUID.
|
||||||
# For magazines specified by UUID, the mountpoint of the
|
# For magazines specified by UUID, the mountpoint of the
|
||||||
# filesystem will be queried from the system. Note that vchanger
|
# 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 ]
|
# [Default: none ]
|
||||||
#magazine = "uuid:4fcb1422-f15c-4d7a-8a32-a4dcc0af5e00"
|
#magazine = "uuid:4fcb1422-f15c-4d7a-8a32-a4dcc0af5e00"
|
||||||
#Magazine = "/mnt/backup2"
|
#Magazine = "/mnt/backup2"
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
.\" Title: vchanger
|
.\" Title: vchanger
|
||||||
.\" Author: Josh Fisher <jfisher@jaybus.com>
|
.\" Author: Josh Fisher <jfisher@jaybus.com>
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 06/03/2015
|
.\" Date: 05/11/2020
|
||||||
.\" Manual: vchanger Manual
|
.\" Manual: vchanger Manual
|
||||||
.\" Source: vchanger 1.0.1
|
.\" Source: vchanger 1.0.3
|
||||||
.\" Language: English
|
.\" 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
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@ -40,7 +40,7 @@ vchanger \- Virtual disk\-based autochanger for Bacula network backup system
|
|||||||
\fBvchanger\fR [\fIOptions\fR] config REFRESH
|
\fBvchanger\fR [\fIOptions\fR] config REFRESH
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
.sp
|
.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
|
.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\&.
|
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
|
.sp
|
||||||
@ -142,9 +142,9 @@ command to Bacula if required\&.
|
|||||||
.sp
|
.sp
|
||||||
\fBBacula Interaction\fR
|
\fBBacula Interaction\fR
|
||||||
.sp
|
.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
|
.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"
|
.SH "COMMAND LINE OPTIONS"
|
||||||
.PP
|
.PP
|
||||||
\fB\-u, \-\-user\fR=\fIuid\fR
|
\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
|
\fBvchanger\&.conf(5)\fR
|
||||||
.SH "COPYRIGHT"
|
.SH "COPYRIGHT"
|
||||||
.sp
|
.sp
|
||||||
Copyright 2006\-2015 Josh Fisher
|
Copyright 2006\-2020 Josh Fisher
|
||||||
.sp
|
.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\&.
|
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"
|
.SH "AUTHOR"
|
||||||
|
@ -3,7 +3,7 @@ VCHANGER(8)
|
|||||||
Josh Fisher <jfisher@jaybus.com>
|
Josh Fisher <jfisher@jaybus.com>
|
||||||
:doctype: manpage
|
:doctype: manpage
|
||||||
:man source: vchanger
|
:man source: vchanger
|
||||||
:man version: 1.0.1
|
:man version: 1.0.3
|
||||||
:man manual: vchanger Manual
|
:man manual: vchanger Manual
|
||||||
|
|
||||||
NAME
|
NAME
|
||||||
@ -27,9 +27,11 @@ DESCRIPTION
|
|||||||
The *vchanger(8)* utility is used to emulate and control a virtual
|
The *vchanger(8)* utility is used to emulate and control a virtual
|
||||||
autochanger within the Bacula network backup system environment.
|
autochanger within the Bacula network backup system environment.
|
||||||
Backup volumes stored on multiple disk filesystems are mapped to a
|
Backup volumes stored on multiple disk filesystems are mapped to a
|
||||||
single set of virtual slots, allowing an unlimited number of virtual
|
single set of virtual slots. This allows an unlimited number of
|
||||||
drives for concurrent backup jobs and easy, unlimited scaling to any
|
virtual drives and an unlimited number of virtual slots spread
|
||||||
size by simply adding additional disks/filesystems,
|
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
|
Vchanger is primarily deigned for use with removable disk drives. Its
|
||||||
ability to interact with Bacula and determine removable drive mount
|
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
|
By default, vcahgner will invoke bconsole and issue commands to Bacula
|
||||||
when certain operator actions are needed. When anything happens that
|
when certain operator actions are needed. When anything happens that
|
||||||
changes the current set of volume files being used, vchanger will
|
changes the current set of volume files being used, (the virtual slot
|
||||||
invoke bconsole and issue an 'update slots' command. For example,
|
to volume file mapping), vchanger will invoke bconsole and issue an
|
||||||
when the operator attaches a removable drive defined as one of the
|
'update slots' command. For example, when the operator attaches a
|
||||||
changer's magazines, the volume files on the removable drive must be
|
removable drive defined as one of the changer's magazines, the volume
|
||||||
mapped to virtual slots. Since the volume-to-slot mapping will have
|
files on the removable drive must be mapped to virtual slots. Since
|
||||||
changed, Bacula will need to be informed of the change via the
|
the slot-to-volume mapping will have changed, Bacula will need to be
|
||||||
'update slots' command. The *REFRESH* command can be invoked to force
|
informed of the change via the 'update slots' command. The *REFRESH*
|
||||||
vchanger to update state info and trigger 'update slots' if needed.
|
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,
|
Additionally, when new volumes are created with the *CREATEVOLS* command,
|
||||||
vchanger will invoke bconsole and issue a 'label barcodes' command to
|
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
|
COMMAND LINE OPTIONS
|
||||||
--------------------
|
--------------------
|
||||||
@ -172,7 +175,7 @@ SEE ALSO
|
|||||||
|
|
||||||
COPYRIGHT
|
COPYRIGHT
|
||||||
---------
|
---------
|
||||||
Copyright 2006-2015 Josh Fisher
|
Copyright 2006-2020 Josh Fisher
|
||||||
|
|
||||||
This is free software;
|
This is free software;
|
||||||
See the source for copying conditions.
|
See the source for copying conditions.
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
.\" Title: vchanger.conf
|
.\" Title: vchanger.conf
|
||||||
.\" Author: Josh Fisher <jfisher@jaybus.com>
|
.\" Author: Josh Fisher <jfisher@jaybus.com>
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 06/03/2015
|
.\" Date: 05/11/2020
|
||||||
.\" Manual: vchanger Manual
|
.\" Manual: vchanger Manual
|
||||||
.\" Source: vchanger.conf 1.0.1
|
.\" Source: vchanger.conf 1.0.3
|
||||||
.\" Language: English
|
.\" 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
|
.\" * 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
|
\fBvchanger(8)\fR
|
||||||
.SH "COPYRIGHT"
|
.SH "COPYRIGHT"
|
||||||
.sp
|
.sp
|
||||||
Copyright 2006\-2015 Josh Fisher
|
Copyright 2006\-2020 Josh Fisher
|
||||||
.sp
|
.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\&.
|
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"
|
.SH "AUTHOR"
|
||||||
|
@ -3,7 +3,7 @@ VCHANGER.CONF(5)
|
|||||||
Josh Fisher <jfisher@jaybus.com>
|
Josh Fisher <jfisher@jaybus.com>
|
||||||
:doctype: manpage
|
:doctype: manpage
|
||||||
:man source: vchanger.conf
|
:man source: vchanger.conf
|
||||||
:man version: 1.0.1
|
:man version: 1.0.3
|
||||||
:man manual: vchanger Manual
|
:man manual: vchanger Manual
|
||||||
|
|
||||||
NAME
|
NAME
|
||||||
@ -112,7 +112,7 @@ SEE ALSO
|
|||||||
|
|
||||||
COPYRIGHT
|
COPYRIGHT
|
||||||
---------
|
---------
|
||||||
Copyright 2006-2015 Josh Fisher
|
Copyright 2006-2020 Josh Fisher
|
||||||
|
|
||||||
This is free software;
|
This is free software;
|
||||||
See the source for copying conditions.
|
See the source for copying conditions.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<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>
|
<title></title>
|
||||||
<meta name="CREATED" content="20061109;11301500">
|
<meta name="CREATED" content="20061109;11301500">
|
||||||
<meta name="CHANGEDBY" content="Josh Fisher">
|
<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 style="font-weight:bold; margin-bottom:0;">Josh Fisher</p>
|
||||||
<p><jfisher at jaybus dot com></p>
|
<p><jfisher at jaybus dot com></p>
|
||||||
<p style="font-weight:bold;">Revision History</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_zero_bottom">Revision 1.0.1 2015-06-09</p>
|
||||||
<p class="p_indent">Documented changes related to version 1.0.1 of the
|
<p class="p_indent">Documented changes related to version 1.0.1 of the
|
||||||
software. This is a minor bug fix release.</p>
|
software. This is a minor bug fix release.</p>
|
||||||
@ -97,6 +109,8 @@ UL.no_image { list-style:none; }
|
|||||||
<ul class="no_image">
|
<ul class="no_image">
|
||||||
<li>5.3.1. <a href="#win32_build">Installing the Windows Version
|
<li>5.3.1. <a href="#win32_build">Installing the Windows Version
|
||||||
from Source</a></li>
|
from Source</a></li>
|
||||||
|
<li>5.3.2. <a href="#win32_installer_build">Building the Windows
|
||||||
|
installer</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -161,7 +175,7 @@ UL.no_image { list-style:none; }
|
|||||||
an open source network backup solution. Bacula can use many types of
|
an open source network backup solution. Bacula can use many types of
|
||||||
backup devices, one of them being robotic tape libraries, also known as
|
backup devices, one of them being robotic tape libraries, also known as
|
||||||
autochangers. Bacula utilizes these devices through an interface 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
|
Autochanger
|
||||||
Interface</a>. Because autochangers are controlled in various
|
Interface</a>. Because autochangers are controlled in various
|
||||||
proprietary ways, the Bacula Autochanger Interface provides a generalized
|
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
|
Interface to act as a virtual autochanger, using files on disk storage in
|
||||||
place of tapes.</p>
|
place of tapes.</p>
|
||||||
<h2><a name="copyright"></a>1.1 Copyright And License</h2>
|
<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
|
style="font-style: normal">Josh Fisher</span></em>. Permission is
|
||||||
granted to copy, distribute and/or modify this document under the terms of
|
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
|
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
|
<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
|
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>
|
href="http://www.bacula.org/">Bacula</a> developers.</p>
|
||||||
<p>Bacula<sub>®</sub> is a registered trademark of Kern Sibbald.</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
|
<p>Windows<sub>®</sub> is a registered trademark of Microsoft
|
||||||
the United States and other countries.</p>
|
Corporation in the United States and other countries.</p>
|
||||||
<h2><a name="feedback"></a>1.4 Feedback</h2>
|
<h2><a name="feedback"></a>1.4 Feedback</h2>
|
||||||
<p><a href="https://lists.sourceforge.net/lists/listinfo/vchanger-users">Vchanger
|
<p><a href="https://lists.sourceforge.net/lists/listinfo/vchanger-users">Vchanger
|
||||||
Users
|
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>
|
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
|
<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
|
more tape drives, a mechanical tape library where a number of tape
|
||||||
cartridges are stored, and an individually addressable robotic device
|
cartridges are stored in slots, and an individually addressable robotic
|
||||||
capable of physically moving tape cartridges between the tape library and
|
device capable of physically moving tape cartridges between the tape
|
||||||
the tape drives. The tape library contains mechanical slots, each of which
|
library slots and the tape drives. The tape library contains mechanical
|
||||||
can hold one tape cartridge. In most cases, the slots are located in one
|
slots, each of which can hold one tape cartridge. In most cases, the slots
|
||||||
or more mechanical magazines, (tape caddies), that can be inserted into
|
are located in one or more mechanical magazines, (tape caddies), that can
|
||||||
and removed from one or more or the tape library's magazine bays.</p>
|
be inserted into and removed from one or more or the tape library's
|
||||||
<p>A <i>virtual autochanger</i> emulates a tape autochanger using disk
|
magazine bays.</p>
|
||||||
storage, rather than tapes. Note that in the strictest sense, vchanger is
|
<p>A vchanger <i>autochanger</i> emulates a tape autochanger using files on
|
||||||
not a tape library emulator, in that it does not implement a device driver
|
disk storage in place of tapes. Note that in the strictest sense, vchanger
|
||||||
with SCSI command interface. Rather it utilizes an API implemented by
|
is not a tape library emulator, in that it does not implement a device
|
||||||
Bacula to manipulate autochangers.</p>
|
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
|
<p>A <em>slot</em> is a physical location in a tape library that may
|
||||||
contain one volume (ie. tape cartridge).</p>
|
contain one volume (ie. tape cartridge).</p>
|
||||||
<p>A <i>magazine</i> is a mechanical tape storage device having a number of
|
<p>A <i>magazine</i> is a mechanical tape storage device having a number of
|
||||||
@ -241,11 +256,11 @@ Users
|
|||||||
stream.</p>
|
stream.</p>
|
||||||
<p>The term drive, unless otherwise stated, refers to one of an
|
<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
|
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>
|
<h1><a name="overview"></a>3. Overview</h1>
|
||||||
<p>The Bacula Storage Daemon controls an autochanger by invoking a script or
|
<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"
|
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
|
Autochanger
|
||||||
Interface</a>. The interface defines a set of commands and associated
|
Interface</a>. The interface defines a set of commands and associated
|
||||||
arguments to load and unload the autochanger's drives, determine which
|
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
|
into tape drives, as the mtx-changer script does for tape autochanger
|
||||||
hardware, vchanger "loads" disk file volumes from virtual slots into
|
hardware, vchanger "loads" disk file volumes from virtual slots into
|
||||||
virtual drives by creating symlinks pointing to volume files located on
|
virtual drives by creating symlinks pointing to volume files located on
|
||||||
one or more filesystems or directories assigned to the virtual
|
one or more virtual magazines, where a virtual magazine is a disk file
|
||||||
autochanger.</p>
|
system or a directory.</p>
|
||||||
<p>Using autochanger interface commands, Bacula interacts with a vchanger
|
<p>Using autochanger interface commands, Bacula interacts with a vchanger
|
||||||
autochanger in exactly the same way as it interacts with a tape
|
autochanger in exactly the same way as it interacts with a tape
|
||||||
autochanger. Therefore to understand how Bacula interacts with a vchanger
|
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>
|
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 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>
|
</pre>
|
||||||
<p>One obvious difference is that vchanger is invoked as the <span style="font-style: italic; font-weight: bold;">Changer
|
<p>One obvious difference is that <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
|
Command</span> defines the path to the vchanger binary, rather than the
|
||||||
Device</span> passed as parameter 1 being the path to a vchanger
|
mtx-changer script, with<span style="font-style: italic; font-weight: bold;"></span>
|
||||||
configuration file, rather than the device node of a tape library robot.
|
parameter 1 being the path to a vchanger configuration file, rather than
|
||||||
The only other difference is the <span style="font-style: italic; font-weight: bold;">Archive
|
the device node of a tape library robot. The only other difference is the
|
||||||
Device</span> setting in each of the <span style="font-style: italic; font-weight: bold;">Device
|
<span style="font-style: italic; font-weight: bold;">Archive Device</span>
|
||||||
</span>resources. Rather than the device node of a physical tape drive,
|
setting in each of the <span style="font-style: italic; font-weight: bold;">Device
|
||||||
the <span style="font-style: italic; font-weight: bold;">Archive Device</span>
|
</span>resources associated with the <i><b>Autochanger </b></i>resource.
|
||||||
of a vchanger autochanger's <span style="font-style: italic; font-weight: bold;">Device
|
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
|
</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
|
virtual drive. When vchanger is invoked with the LOAD command, it creates
|
||||||
this symlink pointing to the volume file associated with the requested
|
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
|
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>
|
</span>resources as a disk-based virtual autochanger.</p>
|
||||||
<p>For example, the following placed in the Bacula Storage Daemon
|
<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
|
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
|
</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
|
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
|
<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
|
</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
|
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
|
Type</span>. This is because the corresponding <span style="font-style: italic; font-weight: bold;">Autochanger
|
||||||
</span>resource in the Director configuration may only specify a single
|
</span>resource in the Director's bacula-dir.conf configuration may only
|
||||||
<span style="font-style: italic; font-weight: bold;">Media Type</span>. A
|
specify a single <span style="font-style: italic; font-weight: bold;">Media
|
||||||
volume is given the <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
|
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
|
</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
|
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>
|
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
|
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>
|
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
|
</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>
|
<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
|
<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,
|
Type</span>, the native virtual autochanger is, for practical purposes,
|
||||||
limited to utilizing a single directory as volume file storage. If volume
|
limited to utilizing a single directory as volume file storage for a
|
||||||
files are contained in multiple filesystems, such as removable drives,
|
particular <i><b>Media Type</b></i>. If volume files are contained in
|
||||||
then those filesystems can only be mounted at that directory one at a
|
multiple filesystems, such as removable drives, then those filesystems can
|
||||||
time. With vchanger, an unlimited number of filesystems may be
|
only be mounted at that directory one at a time. With vchanger, an
|
||||||
simultaneously mounted at different mount point directories with all
|
unlimited number of filesystems may be simultaneously mounted at different
|
||||||
volume files on all filesystems having the same <span style="font-style: italic; font-weight: bold;">Media
|
mount point directories with all volume files on all filesystems having
|
||||||
Type</span>. This allows an unlimited number of simultaneously available
|
the same <span style="font-style: italic; font-weight: bold;">Media Type</span>.
|
||||||
volume files and an unlimited number of <span style="font-style: italic; font-weight: bold;">Device
|
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
|
</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
|
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>resources using only a single <span style="font-style: italic; font-weight: bold;">Autochanger
|
||||||
</span>resource in the Bacula Director. This gives vchanger the
|
</span>resource in the Director's bacula-dir.conf file. This gives
|
||||||
following advantages:</p>
|
vchanger the following advantages:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Available volume storage space can be easily scaled by adding
|
<li>Available volume storage space can be easily scaled by adding
|
||||||
additional filesystems or directories</li>
|
additional filesystems or directories</li>
|
||||||
<li>Scaling available volume storage space requires no change to the
|
<li>Scaling available volume storage space requires no change to the
|
||||||
Bacula configuration and no restart or reload of any Bacula daemons</li>
|
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
|
<li>All volumes have the same <i><b>Media Type</b></i> and so can be
|
||||||
filesystems without any need to update volume information in the Bacula
|
moved between filesystems without any need to update volume information
|
||||||
catalog.</li>
|
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
|
<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
|
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>
|
be used and the filesystems to be mounted at arbitrary paths.</li>
|
||||||
@ -489,27 +507,27 @@ Device {
|
|||||||
interventions to swap removable drives. </li>
|
interventions to swap removable drives. </li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>By default, vchanger supports integration with Bacula through issuing
|
<p>By default, vchanger supports integration with Bacula through issuing
|
||||||
commands via bconsole. Whenever a change is detected in the volume file to
|
commands via bconsole. Whenever a change is detected in the
|
||||||
virtual slot mapping, for example when a removable drive is attached or
|
volume-file-to-virtual-slot mapping, for example when a removable drive is
|
||||||
detached, vchanger will issue an <span style="font-style: italic;">update
|
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
|
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
|
available volumes. Also, when vchanger is used to add volume files to an
|
||||||
autochanger, a <span style="font-style: italic;">label barcodes</span>
|
autochanger, a <span style="font-style: italic;">label barcodes</span>
|
||||||
command is automatically issued to label the new volumes.</p>
|
command is automatically issued to label the newly created volumes.</p>
|
||||||
<p>Vchanger also automates the generation of udev rules and scripts that may
|
<p>Vchanger also provides scripts that may be used to automate the
|
||||||
be used to automatically mount and unmount the filesystems defined in
|
generation of udev rules and automatically mount and unmount the
|
||||||
autochanger configuration files. When a removable drive is attached or
|
filesystems defined in autochanger configuration files. When a removable
|
||||||
detached, a script may be launched by udev to mount or unmount the drive's
|
drive is attached or detached, a script may be launched by udev to mount
|
||||||
partition and issue an <span style="font-style: italic;">update slots</span>
|
or unmount the drive's partition and issue an <span style="font-style: italic;">update
|
||||||
command via bconsole. These udev rules and scripts allow the attaching and
|
slots</span> command via bconsole. These udev rules and scripts allow
|
||||||
detaching of removable drives used by vchanger to be a true
|
the attaching and detaching of removable drives used by vchanger to be a
|
||||||
plug-n-play operation.<br>
|
true plug-n-play operation.<br>
|
||||||
</p>
|
</p>
|
||||||
<h1><a name="implementation"></a>4. Virtual Autochanger Implementation</h1>
|
<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>
|
Autochanger Interface</a> commands:</p>
|
||||||
<table style="margin-left: 2rem;" border="0" cellpadding="0" cellspacing="0"
|
<table style="margin-left: 2rem;" width="664" cellspacing="0" cellpadding="0"
|
||||||
width="664">
|
border="0">
|
||||||
<colgroup><col width="132"> <col width="532"> </colgroup>
|
<colgroup><col width="132"> <col width="532"> </colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
@ -557,8 +575,8 @@ Device {
|
|||||||
</table>
|
</table>
|
||||||
<p style="margin-top: 3ex;">Vchanger also implements the following
|
<p style="margin-top: 3ex;">Vchanger also implements the following
|
||||||
undocumented command defined in mtx-changer since Bacula version 5.1.0:</p>
|
undocumented command defined in mtx-changer since Bacula version 5.1.0:</p>
|
||||||
<table style="margin-left: 2rem;" border="0" cellpadding="0" cellspacing="0"
|
<table style="margin-left: 2rem;" width="664" cellspacing="0" cellpadding="0"
|
||||||
width="664">
|
border="0">
|
||||||
<colgroup><col width="132"> <col width="532"> </colgroup>
|
<colgroup><col width="132"> <col width="532"> </colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
@ -575,7 +593,7 @@ Device {
|
|||||||
extended commands that are not part of the documented Bacula Autochanger
|
extended commands that are not part of the documented Bacula Autochanger
|
||||||
Interface:</p>
|
Interface:</p>
|
||||||
<table style="page-break-before: auto; page-break-after: auto; margin-left: 2rem;"
|
<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>
|
<colgroup><col width="132"> <col width="532"> </colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
@ -607,8 +625,8 @@ Device {
|
|||||||
</table>
|
</table>
|
||||||
<p style="margin-top: 3ex;"><span style="font-style: normal">The Bacula
|
<p style="margin-top: 3ex;"><span style="font-style: normal">The Bacula
|
||||||
Storage Daemon calls vchanger with 5 positional parameters defined as:</span></p>
|
Storage Daemon calls vchanger with 5 positional parameters defined as:</span></p>
|
||||||
<table style="margin-left: 2rem;" border="0" cellpadding="0" cellspacing="0"
|
<table style="margin-left: 2rem;" width="664" cellspacing="0" cellpadding="0"
|
||||||
width="664">
|
border="0">
|
||||||
<colgroup><col width="132"> <col width="532"> </colgroup>
|
<colgroup><col width="132"> <col width="532"> </colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
@ -675,16 +693,15 @@ Device {
|
|||||||
drive and magazine state information and where the symlinks to volume
|
drive and magazine state information and where the symlinks to volume
|
||||||
files will be created for loaded virtual drives.</p>
|
files will be created for loaded virtual drives.</p>
|
||||||
<h2><a name="virtual_magazines"></a>4.1. Virtual Magazines</h2>
|
<h2><a name="virtual_magazines"></a>4.1. Virtual Magazines</h2>
|
||||||
<p>Virtual autochangers using vchanger treat the directories and filesystems
|
<p>Vchanger autochangers treat the directories and filesystems assigned to
|
||||||
assigned to them as "virtual magazines", each able to contain a variable
|
them as "virtual magazines", each able to contain a variable number of
|
||||||
number of volume files. This is analogous to the mechanical tape
|
volume files. This is analogous to the mechanical tape magazines, (tape
|
||||||
magazines, (tape caddies), that many tape autochangers use. These tape
|
caddies), that many tape autochangers use. These tape autochangers have
|
||||||
autochangers have one or more bays into which removable tape magazines can
|
one or more bays into which removable tape magazines can be inserted. Each
|
||||||
be inserted. Each tape magazine contains a fixed number of slots into
|
tape magazine contains a fixed number of slots into which individual tape
|
||||||
which individual tape cartridges may be inserted. The principle difference
|
cartridges may be inserted. The principle difference is that tape
|
||||||
is that tape magazines have a fixed number of physical slots, whereas
|
magazines have a fixed number of physical slots, whereas vchanger virtual
|
||||||
vchanger virtual magazines have a variable and unlimited number of virtual
|
magazines have a variable and unlimited number of virtual slots.</p>
|
||||||
slots.</p>
|
|
||||||
<p>Virtual magazines are filesystems or directories that are assigned to an
|
<p>Virtual magazines are filesystems or directories that are assigned to an
|
||||||
autochanger by including <em style="font-weight: bold;">Magazine</em><span
|
autochanger by including <em style="font-weight: bold;">Magazine</em><span
|
||||||
style="font-weight: bold;"> </span>directive lines in the vchanger
|
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
|
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
|
</span>definitions appear in the vchanger configuration file. This
|
||||||
allows assigning integer numbers to the magazines to ease tracking of
|
allows assigning integer numbers to the magazines to ease tracking of
|
||||||
multiple magazines. For example, consider an autochanger associated with a
|
multiple magazines. For example, consider an autochanger associated with
|
||||||
<span style="font-style: italic; font-weight: bold;">Storage </span>resource
|
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
|
in bacula-dir.conf named "changer1" for which we are using 10 RDX
|
||||||
cartridges as its virtual magazines. The default volume naming scheme used
|
cartridges as its virtual magazines. The default volume naming scheme used
|
||||||
by the CREATEVOLS command will name the first volume file created on the
|
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
|
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
|
"changer1_0000_0000", 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
|
</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 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
|
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
|
cartridge needs to be attached in order to make the requested volume
|
||||||
available.</p>
|
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
|
<p>On most systems, filesystems to be used as magazines may be specified by
|
||||||
filesystem UUID, rather than mountpoint directory. This is useful on
|
filesystem UUID, rather than mountpoint directory. This is useful on
|
||||||
systems where udev, Gnome Nautilus, other dbus-enabled automounters, and
|
systems where udev, Gnome Nautilus, other dbus-enabled automounters, and
|
||||||
etc. are used to automatically mount removable drives whenever they are
|
etc. are used to automatically mount removable drives whenever they are
|
||||||
attached. Since vchanger is not normally running as root, it makes no
|
attached. Since vchanger is not normally running as root, it makes no
|
||||||
attempt to mount those filesystems. It only queries the system to
|
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
|
<p>Note that there is nothing special about the directories and filesystems
|
||||||
being used as magazines. A directory containing volume files created by
|
being used as magazines. A directory containing volume files created by
|
||||||
Bacula's native disk storage handling can be used as a vchanger magazine.
|
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
|
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
|
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>
|
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
|
or <b>Autochanger</b> resource that it will be used with. If existing
|
||||||
a <span style="font-style: italic; font-weight: bold;">Storage</span>
|
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
|
or <b>Autochanger </b>resource that<span style="font-style: italic; font-weight: bold;">
|
||||||
a different <span style="font-style: italic; font-weight: bold;">Media
|
</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>, then it will be necessary to manually update the <span style="font-style: italic; font-weight: bold;">Media
|
||||||
Type</span> for those volumes.</p>
|
Type</span> for those volumes.</p>
|
||||||
<h2><a name="volume_files"></a>4.2. Volume Files</h2>
|
<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
|
<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
|
directories or filesystems. A file cannot be used by Bacula until a Bacula
|
||||||
Bacula volume label has been written to it. Bacula supports bulk labeling
|
volume label has been written to it. Bacula supports bulk labeling of
|
||||||
of volumes using barcodes. Many tape autochangers have barcode reader
|
volumes using barcodes. Many tape autochangers have barcode reader
|
||||||
hardware that can read the name of a tape cartridge from a barcode printed
|
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
|
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
|
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
|
barcodes</span> command acquires this information from the tape
|
||||||
autochanger and writes a Bacula volume label to each unlabeled tape,
|
autochanger and writes a Bacula volume label to each unlabeled tape,
|
||||||
naming it according to the tape's barcode. Vchanger emulates a barcode
|
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
|
<p>While it is recommended to use the default volume naming scheme
|
||||||
implemented by the CREATEVOLS command, it is not required and volume files
|
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
|
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
|
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
|
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
|
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
|
different filename. if renamed, they should also have a new Bacula volume
|
||||||
written to them.</p>
|
label written to them.</p>
|
||||||
<h2><a name="virtual_slots"></a>4.3. Virtual Slots</h2>
|
<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
|
<p>Each time vchanger is invoked it maps the volume files on all currently
|
||||||
magazines to a virtual slot number. State information kept in the
|
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
|
autochanger's work directory is used to keep volume-to-slot mapping as
|
||||||
consistent as possible when removable disk drives are attached and
|
consistent as possible as removable disk drives are attached and detached
|
||||||
detached from the system. Drive state files contain information about the
|
from the system. Drive state files contain information about the volume
|
||||||
volume last loaded into a virtual drive and are named 'drive_state-N',
|
last loaded into a virtual drive and are named 'drive_state-N', where N is
|
||||||
where N is the drive number. Magazine state files contain information
|
the drive number. Magazine state files contain information about the
|
||||||
about the magazines that were attached when vchanger was last invoked and
|
magazines that were attached when vchanger was last invoked and are named
|
||||||
are named 'bay_state-N', where N is the magazine index.</p>
|
'bay_state-N', where N is the magazine index.</p>
|
||||||
<p>Whenever anything happens to change the volume-to-slot mapping, Bacula
|
<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
|
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
|
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
|
number of the range of virtual slots mapped to the magazine's volume
|
||||||
files, and <span style="font-style: italic;">mountpoint </span>is the
|
files, and <span style="font-style: italic;">mountpoint </span>is the
|
||||||
magazine's directory or current filesystem mount point.</p>
|
magazine's directory or current filesystem mount point.</p>
|
||||||
<p>The CREATEVOLS command is used to add new volume files to a magazine and
|
<p>The CREATEVOLS command is used to add new volume files to a magazine and,
|
||||||
cause Bacula to write volume labels to them.</p>
|
optionally, cause Bacula to write volume labels to them.</p>
|
||||||
<p>The REFRESH command causes vchanger to refresh the current state of
|
<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
|
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
|
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
|
<h2><a name="win32_build"></a>5.3.1. Installing the Windows Version from
|
||||||
Source</h2>
|
Source</h2>
|
||||||
<p>The Windows version was developed under <a href="http://www.centos.org/">Centos</a>
|
<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>
|
7.8 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
|
(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>
|
development tools installed, the Windows version can be built as follows:</p>
|
||||||
<p>Unpack the gzip compressed tar archive in your home directory.</p>
|
<p>Unpack the gzip compressed tar archive in your home directory.</p>
|
||||||
<pre>[]$ cd ~
|
<pre>[]$ cd ~
|
||||||
@ -904,11 +931,12 @@ Device {
|
|||||||
vchanger</p>
|
vchanger</p>
|
||||||
<pre>[]$ cd vchanger
|
<pre>[]$ cd vchanger
|
||||||
[]$ ./configure --host=x86_64-w64-mingw32 --build=`./config.guess` --prefix=./win32
|
[]$ ./configure --host=x86_64-w64-mingw32 --build=`./config.guess` --prefix=./win32
|
||||||
[]$ make
|
[]$ make</pre>
|
||||||
[]$ make install-strip</pre>
|
|
||||||
<p style="margin-top: 0.08in">The win32 executable, vchanger.exe, will be in
|
<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/bin and the Windows version documentation in
|
||||||
~/vchanger/win32/share/doc/vchanger.</p>
|
~/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
|
<p>Building the Windows installer for vchanger requires the makensis
|
||||||
ustility from the NSIS project in addition to MinGW-w64. A shell script
|
ustility from the NSIS project in addition to MinGW-w64. A shell script
|
||||||
named win32build in the source distribution will configure and build both
|
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
|
<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
|
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
|
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
|
read/write access to the user:group that the bacula-sd Storage Daemon runs
|
||||||
partition somewhere, then setting the appropriate permissions to give
|
as. This can be done by mounting the new partition somewhere, then setting
|
||||||
read/write access to the user that the Storage Daemon runs as. It may also
|
the appropriate permissions to give read/write access to the user that the
|
||||||
be necessary to configure SELinux or AppArmour to allow the user that the
|
Storage Daemon runs as. It may also be necessary to configure SELinux or
|
||||||
Storage Daemon runs as to read/write the magazine filesystems.</p>
|
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
|
<h2><a name="determining_uuid"></a>6.2. Determining the Magazine's
|
||||||
Filesystem UUID</h2>
|
Filesystem UUID</h2>
|
||||||
<p>On most POSIX systems, the blkid utility can be used to view the UUID of
|
<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
|
but this may not suffice for use with daemons, such as the Bacula Storage
|
||||||
Daemon that will normally invoke vchanger. The block storage device
|
Daemon that will normally invoke vchanger. The block storage device
|
||||||
containing the magazine's filesystem partition must, by some means, be
|
containing the magazine's filesystem partition must, by some means, be
|
||||||
mounted before it can be used by vchanger. Since vchanger will be invoked
|
mounted before it can be used by vchanger or Bacula. Since vchanger will
|
||||||
by the Bacula Storage Daemon, and will not ordinarily run with superuser
|
be invoked by the Bacula Storage Daemon, and will not ordinarily run with
|
||||||
privileges, it does not itself attempt to mount filesystems. </p>
|
superuser privileges, it does not itself attempt to mount filesystems. </p>
|
||||||
<h2><a name="udev"></a>7.1. udev and Hot-swappable Drives</h2>
|
<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>
|
<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
|
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>
|
<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>
|
<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>
|
<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
|
<p>It is also possible, when manually mounting magazine partitions, to use a
|
||||||
the mountpoint path in the <span style="font-style: italic; font-weight: bold;">Magazine
|
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
|
</span>directive, rather than a UUID. When a magazine is specified by
|
||||||
path (rather than by UUID), vchanger assumes the magazine is mounted if
|
path (rather than by UUID), vchanger assumes the magazine is mounted if
|
||||||
that path exists. However, if that directory path exists while the
|
that path exists. However, if that directory path exists while the
|
||||||
magazine's partition is not mounted, then that directory will be part of
|
magazine's partition is not mounted, then that directory will be part of
|
||||||
the underlying filesystem rather than the unmounted magazine partition's
|
the underlying filesystem rather than the unmounted magazine partition's
|
||||||
filesystem. For this reason, specifying directory paths in Magazine
|
filesystem. For this reason, specifying directory paths in Magazine
|
||||||
directives is only recommended for permanently mounted filesystems.
|
directives is only recommended for permanently mounted filesystems. For
|
||||||
Filesystems that are not permanently mounted should be specified by UUID.
|
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>
|
</p>
|
||||||
<h2><a name="udev_mounting"></a>7.3. Using udev To Mount Removable Drive
|
<h2><a name="udev_mounting"></a>7.3. Using udev To Mount Removable Drive
|
||||||
Partitions</h2>
|
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
|
<p>After adding or changing Magazine directives in a vchanger configuration
|
||||||
file, configure automounting through udev by:</p>
|
file, configure automounting through udev by:</p>
|
||||||
<pre>[]# vchanger-genudevrules >/etc/udev/rules.d/96-vchanger.rules<br>[]# udevadm control --reload-rules</pre>
|
<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
|
<h2><a name="autofs"></a>7.4. Using autofs To Mount Removable Drive
|
||||||
Partitions</h2>
|
Partitions</h2>
|
||||||
<p>The <a href="http://www.autofs.org/">autofs</a> daemon provides a way to
|
<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
|
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
|
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
|
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
|
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
|
a mount point folder path to a drive</a>” for instructions on
|
||||||
mountpoints for removable drive partitions. Like with drive letters, it is
|
assigning mountpoints for removable drive partitions. Like with drive
|
||||||
not possible to assign the same mountpoint to more than one drive.</p>
|
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
|
<p>On Windows, magazine partitions should always be specified by UUID
|
||||||
(Volume Serial Number). This ensures that vchanger will be able to find
|
(Volume Serial Number). This ensures that vchanger will be able to find
|
||||||
the partition's mountpoint without prior knowledge of which drive letter
|
the partition's mountpoint without prior knowledge of which drive letter
|
||||||
or mountpoint Windows has currently assigned to the drive.</p>
|
or mountpoint Windows has currently assigned to the drive.</p>
|
||||||
<h1><a name="vchanger_config"></a>8. Configuring vchanger</h1>
|
<h1><a name="vchanger_config"></a>8. Configuring vchanger</h1>
|
||||||
<p>Each vchanger autochanger is defined by a configuration file. Multiple
|
<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
|
autochangers may be defined as long as each is given a unique <i><b>Storage
|
||||||
own unique work directory, and its own unique configuration file. By
|
Resource</b></i> name, its own unique work directory, and its own
|
||||||
default, vchanger configuration files are placed in the /etc/vchanger
|
unique configuration file. By default, vchanger configuration files are
|
||||||
directory. The configuration files <b>must be given permissions</b> that
|
placed in the /etc/vchanger directory. The configuration files <b>must be
|
||||||
allow the user that the Bacula Storage Daemon runs as to have read access.</p>
|
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
|
<p style="font-style: normal">A vchanger configuration file consists of
|
||||||
keyword = value pairs. Comments are defined by a '#' character, and cause
|
keyword = value pairs. Comments are defined by a '#' character, and cause
|
||||||
text from the '#' until the next newline character to be ignored. Values
|
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
|
appearing inside of the quoted value must be escaped by prepending with a
|
||||||
'\' character. The following keywords are defined for an autochanger
|
'\' character. The following keywords are defined for an autochanger
|
||||||
configuration file:</p>
|
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>
|
<colgroup><col width="172"> <col width="492"> </colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
@ -1171,7 +1218,9 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
|||||||
<td width="492">
|
<td width="492">
|
||||||
<p>[Required] The name of the Storage resource, defined in the
|
<p>[Required] The name of the Storage resource, defined in the
|
||||||
Bacula Director configuration file, that is associated with this
|
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>
|
Default: none</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -1238,7 +1287,9 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
|||||||
<td width="492">
|
<td width="492">
|
||||||
<p>The path to the bconsole binary that vchanger will invoke to
|
<p>The path to the bconsole binary that vchanger will invoke to
|
||||||
issue 'update slots' and 'label barcodes' commands to Bacula. 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>
|
Default: /usr/sbin/bconsole</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -1248,7 +1299,9 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
|||||||
</td>
|
</td>
|
||||||
<td width="492">
|
<td width="492">
|
||||||
<p>The path to the configuration file to use when invoking bconsole<span
|
<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>
|
Default: /etc/bacula/bconsole.conf</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -1268,11 +1321,11 @@ style="font-style: normal">9667f83c-6150-44c7-b0d4-57564f174b35</span></pre>
|
|||||||
</td>
|
</td>
|
||||||
<td width="492">
|
<td width="492">
|
||||||
<p>[Required] Defines either the path to a directory or the UUID of
|
<p>[Required] Defines either the path to a directory or the UUID of
|
||||||
a filesystem partition (prepended by the string “UUID:”) that is
|
a filesystem partition (prepended by the string
|
||||||
to be used as a magazine containing volume files . The magazine
|
“UUID:”) that is to be used as a magazine containing
|
||||||
directive assigns a directory or partition to this autochanger.
|
volume files. The Magazine directive assigns a directory or
|
||||||
This directive may appear multiple times to assign multiple
|
partition to this autochanger. This directive may appear multiple
|
||||||
magazines.<br>
|
times to assign multiple magazines.<br>
|
||||||
Default: none</p>
|
Default: none</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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
|
directive to the vchanger configuration file. For removable storage, the <span
|
||||||
style="font-weight: bold; font-style: italic;">Magazine </span>directive
|
style="font-weight: bold; font-style: italic;">Magazine </span>directive
|
||||||
should specify the filesystem UUID (or the mountpoint path if using
|
should specify the filesystem UUID (or the mountpoint path if using
|
||||||
autofs). If a directory on permanently mounted fixed-disk storage is being
|
autofs or manual mounting). If a directory on permanently mounted
|
||||||
used as a magazine, then the <span style="font-weight: bold; font-style: italic;">Magazine
|
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
|
</span>directive should specify the directory path. In either case, the
|
||||||
filesystem or directory must by writable by the user that Bacula Storage
|
filesystem or directory must by writable by the user that Bacula Storage
|
||||||
Daemon runs as. The LISTMAGS vchanger command can be used to determine
|
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>
|
][# 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>
|
][# chmod 750 /mnt/vchanger/5039284a<span style="font-style: normal">-4312-57d1-92c4-354710032c79</span>
|
||||||
</pre>
|
</pre>
|
||||||
<p>The Storage resource that this autochanger is associated with is defined
|
<p>The Autochanger resource that this autochanger is associated with is
|
||||||
in bacula-dir.conf as:</p>
|
defined in bacula-dir.conf as:</p>
|
||||||
<pre># /etc/bacula/bacula-dir.conf<br>...<br># vchanger autochanger vchanger-1
|
<pre># /etc/bacula/bacula-dir.conf<br>...<br># vchanger autochanger vchanger-1
|
||||||
Storage {
|
Autochanger {
|
||||||
Name = vchanger-1
|
Name = vchanger-1
|
||||||
Address = 192.168.1.9
|
Address = 192.168.1.9
|
||||||
SDPort = 9103
|
SDPort = 9103
|
||||||
Password = "password"
|
Password = "password"
|
||||||
Device = usb-vchanger-1
|
Device = usb-vchanger-1
|
||||||
Media Type = File
|
Media Type = File
|
||||||
Autochanger = yes;
|
|
||||||
Maximum Concurrent Jobs = 20
|
Maximum Concurrent Jobs = 20
|
||||||
}
|
}
|
||||||
<span style="font-style: normal">...</span>
|
<span style="font-style: normal">...</span>
|
||||||
@ -1419,8 +1471,8 @@ Device {
|
|||||||
volumes<span style="font-style: italic;"></span>. We can now add some
|
volumes<span style="font-style: italic;"></span>. We can now add some
|
||||||
volumes with:</p>
|
volumes with:</p>
|
||||||
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf createvols 0 2
|
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf createvols 0 2
|
||||||
creating label 'vchanger-1_0_0'
|
creating label 'vchanger-1_0000_0000'
|
||||||
creating label 'vchanger-1_0_1'
|
creating label 'vchanger-1_0000_0001'
|
||||||
Created 2 volume files on magazine 0
|
Created 2 volume files on magazine 0
|
||||||
</pre>
|
</pre>
|
||||||
<p>Now the output from a LISTMAGS<span style="font-weight: bold; font-style: italic;">
|
<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
|
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>
|
volumes the vchanger-1 autochanger has in its virtual slots.</p>
|
||||||
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf list
|
<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
|
<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>
|
bconsole to see what Bacula thinks the autochanger status is.</p>
|
||||||
<pre>[]# echo "status slots storage=vchanger-1 drive=0" | bconsole
|
<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 ...
|
Connecting to Storage daemon vchanger-1 at 192.168.1.9:9103 ...
|
||||||
3306 Issuing autochanger "list" command.
|
3306 Issuing autochanger "list" command.
|
||||||
Slot | Volume Name | Status | Media Type | Pool |
|
Slot | Volume Name | Status | Media Type | Pool |
|
||||||
------+------------------+-----------+----------------------+--------------------|
|
------+------------------------+-----------+----------------------+--------------------|
|
||||||
1 | vchanger-1_0_0 | Append | File | Scratch |
|
1 | vchanger-1_0000_0000 | Append | File | Scratch |
|
||||||
2 | vchanger-1_0_1 | Append | File | Scratch | </pre>
|
2 | vchanger-1_0000_0001 | Append | File | Scratch | </pre>
|
||||||
<p>This shows that the CREATEVOLS<span style="font-style: italic; font-weight: bold;">
|
<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
|
</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
|
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>
|
bconsole.</p>
|
||||||
<p>Now attach the second USB drive and add some volumes to it using:</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
|
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf createvols 1 3
|
||||||
creating label 'vchanger-1_1_0'
|
creating label 'vchanger-1_0001_0000'
|
||||||
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_0001'<br>creating label 'vchanger-1_0001_0002'<br>Created 3 volume files on magazine 1
|
||||||
</pre>
|
</pre>
|
||||||
<p>and confirm that the volumes were added as expected with:</p>
|
<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
|
<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: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
|
Connecting to Director 127.0.0.1:9101
|
||||||
1000 OK: bacula-dir Version: 5.2.13 (19 February 2013)
|
1000 OK: bacula-dir Version: 5.2.13 (19 February 2013)
|
||||||
Enter a period to cancel a command.
|
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 ...
|
Connecting to Storage daemon vchanger-1 at 192.168.1.9:9103 ...
|
||||||
3306 Issuing autochanger "list" command.
|
3306 Issuing autochanger "list" command.
|
||||||
Slot | Volume Name | Status | Media Type | Pool |
|
Slot | Volume Name | Status | Media Type | Pool |
|
||||||
------+------------------+-----------+----------------------+--------------------|
|
------+------------------------+-----------+----------------------+--------------------|
|
||||||
1 | vchanger-1_0_0 | Append | File | Scratch |<br> 2 | vchanger-1_0_1 | Append | File | Scratch |
|
1 | vchanger-1_0000_0000 | Append | File | Scratch |<br> 2 | vchanger-1_0000_0001 | Append | File | Scratch |
|
||||||
3 | vchanger-1_1_0 | Append | File | Scratch |
|
3 | vchanger-1_0001_0000 | Append | File | Scratch |
|
||||||
4 | vchanger-1_1_1 | Append | File | Scratch |
|
4 | vchanger-1_0001_0001 | Append | File | Scratch |
|
||||||
5 | vchanger-1_1_2 | Append | File | Scratch |
|
5 | vchanger-1_0001_0002 | Append | File | Scratch |
|
||||||
</pre>
|
</pre>
|
||||||
<p>If the first USB drive is now unplugged, the script invoked by udev
|
<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
|
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
|
[]# vchanger /etc/vchanger/vchanger-1.conf list
|
||||||
1:
|
1:
|
||||||
2:
|
2:
|
||||||
3:vchanger-1_1_0
|
3:vchanger-1_0001_0000
|
||||||
4:vchanger-1_1_1
|
4:vchanger-1_0001_0001
|
||||||
5:vchanger-1_1_2
|
5:vchanger-1_0001_0002
|
||||||
|
|
||||||
[]# echo "status slots storage=vchanger-1 drive=0" | bconsole
|
[]# echo "status slots storage=vchanger-1 drive=0" | bconsole
|
||||||
Connecting to Director 127.0.0.1:9101
|
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 ...
|
Connecting to Storage daemon vchanger-1 at 192.168.1.9:9103 ...
|
||||||
3306 Issuing autochanger "list" command.
|
3306 Issuing autochanger "list" command.
|
||||||
Slot | Volume Name | Status | Media Type | Pool |
|
Slot | Volume Name | Status | Media Type | Pool |
|
||||||
------+------------------+-----------+----------------------+--------------------|<br> 1*| | ? | ? | ? |<br> 2*| | ? | ? | ? |<br> 3 | vchanger-1_1_0 | Append | File | Scratch |
|
------+------------------------+-----------+----------------------+--------------------|<br> 1*| | ? | ? | ? |<br> 2*| | ? | ? | ? |<br> 3 | vchanger-1_0001_0000 | Append | File | Scratch |
|
||||||
4 | vchanger-1_1_1 | Append | File | Scratch |
|
4 | vchanger-1_0001_0001 | Append | File | Scratch |
|
||||||
5 | vchanger-1_1_2 | Append | File | Scratch |
|
5 | vchanger-1_0001_0002 | Append | File | Scratch |
|
||||||
</pre>
|
</pre>
|
||||||
<p>Let's now examine what happens when a volume file is "loaded" into a
|
<p>Let's now examine what happens when a volume file is "loaded" into a
|
||||||
virtual drive.</p>
|
virtual drive.</p>
|
||||||
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf load 3 /dev/null 0
|
<pre>[]# vchanger /etc/vchanger/vchanger-1.conf load 3 /dev/null 0
|
||||||
[]# ls -l /var/spool/vchanger/vchanger-1
|
[]# 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 21 Mar 1 16:46 bay_state-1
|
||||||
-rw-r----- 1 bacula tape 30 Mar 1 16:46 drive_state-0
|
-rw-r----- 1 bacula tape 30 Mar 1 16:46 drive_state-0
|
||||||
</pre>
|
</pre>
|
||||||
<p>The LOAD command created a symlink named '0' in the autochanger's work
|
<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
|
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
|
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
|
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
|
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
|
symlink for reading or writing, it will actually be opening the volume
|
||||||
file that the symlink points to. </p>
|
file that the symlink points to. </p>
|
||||||
<p>The LOADED command can be used to check the status of a drive.</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
|
<pre># /etc/bacula/bacula-dir.conf
|
||||||
# ...
|
# ...
|
||||||
# Local USB drive virtual autochanger
|
# Local USB drive virtual autochanger
|
||||||
Storage {
|
Autochanger {
|
||||||
Name = vchanger-1 # same as 'Storage Resource' in the vchanger config file
|
Name = vchanger-1 # same as 'Storage Resource' in the vchanger config file
|
||||||
Address = sd-server-address
|
Address = sd-server-address
|
||||||
Password = "secret_password"
|
Password = "secret_password"
|
||||||
Device = usb-changer # name of the Autochanger resource in bacula-sd.conf
|
Device = usb-changer # name of the Autochanger resource in bacula-sd.conf
|
||||||
Media Type = File
|
Media Type = File
|
||||||
Autochanger = yes;
|
|
||||||
}
|
}
|
||||||
# eof</pre>
|
# eof</pre>
|
||||||
<h1><a name="appendixa"></a>Appendix A. vchanger Commands</h1>
|
<h1><a name="appendixa"></a>Appendix A. vchanger Commands</h1>
|
||||||
<h2><a name="command_list"></a>A.1. LIST Command</h2>
|
<h2><a name="command_list"></a>A.1. LIST Command</h2>
|
||||||
<p style="margin-top: 0in; margin-bottom: 0in; font-style: normal">Bacula
|
<p style="margin-top: 0in; margin-bottom: 0in; font-style: normal">Bacula
|
||||||
issues this command to an autochanger to list to stdout the “barcode
|
issues this command to an autochanger to list to stdout the “barcode
|
||||||
labels” of volumes in the autochanger's slots. Many tape autochanger
|
labels” of volumes in the autochanger's slots. Many tape autochanger
|
||||||
robots have barcode readers such that tapes can be affixed with an
|
robots have barcode readers such that tapes can be affixed with an
|
||||||
adhesive barcode label that identifies the tape. This allows Bacula to
|
adhesive barcode label that identifies the tape. This allows Bacula to
|
||||||
automate the process of creating volume labels by utilizing the
|
automate the process of creating volume labels by utilizing the
|
||||||
@ -1640,19 +1691,19 @@ Storage {
|
|||||||
volume file).</p>
|
volume file).</p>
|
||||||
<h2><a name="command_listall"></a>A.2. LISTALL Command</h2>
|
<h2><a name="command_listall"></a>A.2. LISTALL Command</h2>
|
||||||
<p>It is not clear that Bacula currently uses this command internally, and
|
<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
|
Autochanger Interface</a> documentation. Nevertheless, it is implemented
|
||||||
in Bacula's mtx-changer script since version 5.1.0 and is used by some
|
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
|
web-based admin utilities, so has been implemented in vchanger. This
|
||||||
command is similar to the LIST command except that it also lists current
|
command is similar to the LIST command except that it also lists current
|
||||||
drive status in addition to slot status.</p>
|
drive status in addition to slot status.</p>
|
||||||
<h2><a name="command_load"></a>A.3. LOAD Command</h2>
|
<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
|
<p style="font-style: normal">The load command is used to “load”
|
||||||
file from a virtual slot into a virtual drive. A tape autochanger does
|
a volume file from a virtual slot into a virtual drive. A tape autochanger
|
||||||
this by physically moving the tape located in the requested library slot
|
does this by physically moving the tape located in the requested library
|
||||||
into a tape drive. Bacula reads and writes volume data from/to the tape
|
slot into a tape drive. Bacula reads and writes volume data from/to the
|
||||||
drive's device file. With vchanger, a filesystem symlink at a known path
|
tape drive's device file. With vchanger, a filesystem symlink at a known
|
||||||
is used as a virtual drive in place of a tape drive's device file. A
|
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
|
volume file is then loaded by making the target of that symlink point to
|
||||||
the volume file mapped to the requested slot. </p>
|
the volume file mapped to the requested slot. </p>
|
||||||
<p style="font-style: normal">Parameter 3 gives the autochanger slot number
|
<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
|
<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
|
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
|
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
|
stdout. If the drive is not loaded, the string “0” is written
|
||||||
inform Bacula that the drive is not loaded.</p>
|
to stdout to inform Bacula that the drive is not loaded.</p>
|
||||||
<h2><a name="command_slots"></a>A.5. SLOTS Command</h2>
|
<h2><a name="command_slots"></a>A.5. SLOTS Command</h2>
|
||||||
<p style="margin-top: 0in; margin-bottom: 0in; font-style: normal">This
|
<p style="margin-top: 0in; margin-bottom: 0in; font-style: normal">This
|
||||||
command simply prints to stdout the maximum number of volume files that
|
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>
|
this by deleting the virtual drive's symlink.</p>
|
||||||
<h2><a name="command_createvols"></a>A.7. CREATEVOLS Command</h2>
|
<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
|
<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
|
Autochanger
|
||||||
Interface</a></span> <span style="font-weight: normal">API, and is
|
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
|
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>
|
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>
|
<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>
|
<p style="margin-top: 0.08in">where:</p>
|
||||||
<table style="margin-left: 3rem;" border="0" cellpadding="0" cellspacing="0"
|
<table style="margin-left: 3rem;" width="664" cellspacing="0" cellpadding="0"
|
||||||
width="664">
|
border="0">
|
||||||
<colgroup><col width="131"> <col width="533"> </colgroup>
|
<colgroup><col width="131"> <col width="533"> </colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<table style="margin-left: 1rem; width: 50em; margin-bottom: 1rem;" border="0"
|
<table style="margin-left: 1rem; width: 50em; margin-bottom: 1rem;" cellspacing="0"
|
||||||
cellpadding="0" cellspacing="0">
|
cellpadding="0" border="0">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="9em">
|
<td width="9em">
|
||||||
@ -1746,8 +1797,10 @@ Autochanger
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<p>An optional prefix string used in naming the created volume
|
<p>An optional prefix string used in naming the created volume
|
||||||
files. The default prefix string is the autochanger's name
|
files. The filenames created will be the prefix string
|
||||||
concatenated with '_' plus the magazine index number.</p>
|
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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -1769,14 +1822,14 @@ Autochanger
|
|||||||
this reason, vchanger will also issue the <span style="font-weight: bold; font-style: italic;">update
|
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>
|
slots</span> command to Bacula whenever new volume files are added.</p>
|
||||||
<h2><a name="command_listmags"></a>A.8. LISTMAGS Command</h2>
|
<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
|
Autochanger
|
||||||
Interface</a> API, and is used to list status information about the
|
Interface</a> API, and is used to list status information about the
|
||||||
autochanger's assigned magazines. The format of this command is</p>
|
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>
|
<pre style="margin-top: 0.01in; margin-bottom: 0.2in">vchanger config_file listmags</pre>
|
||||||
<p style="margin-top: 0.08in">where:</p>
|
<p style="margin-top: 0.08in">where:</p>
|
||||||
<table style="margin-left: 1em; margin-bottom: 1em;" border="0" cellpadding="0"
|
<table style="margin-left: 1em; margin-bottom: 1em;" width="664" cellspacing="0"
|
||||||
cellspacing="0" width="664">
|
cellpadding="0" border="0">
|
||||||
<colgroup><col width="131"> <col width="533"> </colgroup>
|
<colgroup><col width="131"> <col width="533"> </colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
@ -1793,8 +1846,8 @@ Autochanger
|
|||||||
to stdout, one line per bay. The format of an output line is:</p>
|
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>
|
<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>
|
<p style="margin-top: 0.08in">where:</p>
|
||||||
<table style="margin-left: 1em; margin-bottom: 1em;" border="0" cellpadding="0"
|
<table style="margin-left: 1em; margin-bottom: 1em;" width="664" cellspacing="0"
|
||||||
cellspacing="0" width="664">
|
cellpadding="0" border="0">
|
||||||
<colgroup><col width="131"> <col width="533"> </colgroup>
|
<colgroup><col width="131"> <col width="533"> </colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
#
|
#
|
||||||
Summary: A virtual autochanger for Bacula
|
Summary: A virtual autochanger for Bacula
|
||||||
Name: vchanger
|
Name: vchanger
|
||||||
Version: 1.0.1
|
Version: 1.0.3
|
||||||
Release: 1.el6
|
Release: 1%{dist}
|
||||||
License: GPLv2
|
License: GPLv2
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
Source: http://sourceforge.net/projects/vchanger/files/vchanger/%{version}/vchanger-%{version}.tar.gz
|
Source: http://sourceforge.net/projects/vchanger/files/vchanger/%{version}/vchanger-%{version}.tar.gz
|
||||||
@ -35,6 +35,7 @@ make
|
|||||||
rm -rf $RPM_BUILD_ROOT
|
rm -rf $RPM_BUILD_ROOT
|
||||||
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
||||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig
|
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}%{_sysconfdir}/%{name}
|
||||||
mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir}/%{name}
|
mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir}/%{name}
|
||||||
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man5
|
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}
|
mkdir -m 0755 -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}
|
||||||
make DESTDIR=${RPM_BUILD_ROOT} install-strip
|
make DESTDIR=${RPM_BUILD_ROOT} install-strip
|
||||||
install -m 0644 scripts/vchanger.default ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/vchanger
|
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
|
%clean
|
||||||
rm -rf $RPM_BUILD_ROOT
|
rm -rf $RPM_BUILD_ROOT
|
||||||
@ -52,6 +54,7 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
%{_bindir}/*
|
%{_bindir}/*
|
||||||
%{_libexecdir}/%{name}/*
|
%{_libexecdir}/%{name}/*
|
||||||
|
%{_sysconfdir}/logrotate.d/*
|
||||||
%doc %{_docdir}/%{name}-%{version}/AUTHORS
|
%doc %{_docdir}/%{name}-%{version}/AUTHORS
|
||||||
%doc %{_docdir}/%{name}-%{version}/ChangeLog
|
%doc %{_docdir}/%{name}-%{version}/ChangeLog
|
||||||
%doc %{_docdir}/%{name}-%{version}/COPYING
|
%doc %{_docdir}/%{name}-%{version}/COPYING
|
||||||
@ -85,6 +88,10 @@ if [ $1 -eq 1 ] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
%changelog
|
%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>
|
* Wed Jun 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||||
- Updated to release 1.0.1
|
- Updated to release 1.0.1
|
||||||
* Fri Apr 3 2015 Josh Fisher <jfisher@jaybus.com>
|
* Fri Apr 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
#
|
#
|
||||||
Summary: A virtual autochanger for Bacula
|
Summary: A virtual autochanger for Bacula
|
||||||
Name: vchanger
|
Name: vchanger
|
||||||
Version: 1.0.1
|
Version: 1.0.3
|
||||||
Release: 1.el7
|
Release: 1%{dist}
|
||||||
License: GPLv2
|
License: GPLv2
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
Source: http://sourceforge.net/projects/vchanger/files/vchanger/%{version}/vchanger-%{version}.tar.gz
|
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)
|
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||||
Requires(post): /bin/mkdir, /bin/chown, /usr/bin/getent, /usr/sbin/useradd, /usr/sbin/groupadd
|
Requires(post): /bin/mkdir, /bin/chown, /usr/bin/getent, /usr/sbin/useradd, /usr/sbin/groupadd
|
||||||
|
|
||||||
|
# For libudev support
|
||||||
|
BuildRequires: systemd-devel
|
||||||
|
|
||||||
%description
|
%description
|
||||||
Vchanger implements a virtual autochanger for use with the Bacula open source
|
Vchanger implements a virtual autochanger for use with the Bacula open source
|
||||||
network backup system. Vchanger emulates a magazine-based tape autoloader
|
network backup system. Vchanger emulates a magazine-based tape autoloader
|
||||||
@ -35,6 +38,7 @@ make
|
|||||||
rm -rf $RPM_BUILD_ROOT
|
rm -rf $RPM_BUILD_ROOT
|
||||||
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
||||||
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig
|
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}%{_sysconfdir}/%{name}
|
||||||
mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir}/%{name}
|
mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir}/%{name}
|
||||||
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man5
|
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}
|
mkdir -m 0755 -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}
|
||||||
make DESTDIR=${RPM_BUILD_ROOT} install-strip
|
make DESTDIR=${RPM_BUILD_ROOT} install-strip
|
||||||
install -m 0644 scripts/vchanger.default ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/vchanger
|
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
|
%clean
|
||||||
rm -rf $RPM_BUILD_ROOT
|
rm -rf $RPM_BUILD_ROOT
|
||||||
@ -52,6 +57,7 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
%{_bindir}/*
|
%{_bindir}/*
|
||||||
%{_libexecdir}/%{name}/*
|
%{_libexecdir}/%{name}/*
|
||||||
|
%{_sysconfdir}/logrotate.d/*
|
||||||
%doc %{_docdir}/%{name}-%{version}/AUTHORS
|
%doc %{_docdir}/%{name}-%{version}/AUTHORS
|
||||||
%doc %{_docdir}/%{name}-%{version}/ChangeLog
|
%doc %{_docdir}/%{name}-%{version}/ChangeLog
|
||||||
%doc %{_docdir}/%{name}-%{version}/COPYING
|
%doc %{_docdir}/%{name}-%{version}/COPYING
|
||||||
@ -85,6 +91,10 @@ if [ $1 -eq 1 ] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
%changelog
|
%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>
|
* Wed Jun 3 2015 Josh Fisher <jfisher@jaybus.com>
|
||||||
- Updated to release 1.0.1
|
- Updated to release 1.0.1
|
||||||
* Fri Apr 3 2015 Josh Fisher <jfisher@jaybus.com>
|
* 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
|
#!/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
|
# Search all autochanger configuration files for magazines being defined
|
||||||
# by filesystem UUID and print to stdout the udev rules for launching
|
# by filesystem UUID and print to stdout the udev rules for launching
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
#!/bin/sh
|
#!/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
|
# This script is used to run the vchanger-mount-uuid.sh script as
|
||||||
# another [background] process launched by the at command in order
|
# a detached process and immediately exit. This is to prevent delays
|
||||||
# to prevent delays when invoked by a udev rule.
|
# when invoked by a udev rule.
|
||||||
#
|
#
|
||||||
VCHANGER_MOUNT=/usr/libexec/vchanger/vchanger-mount-uuid.sh
|
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
|
#!/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
|
# This script is used to run the vchanger-umount-uuid.sh script in
|
||||||
# another [background] process launched by the at command in order
|
# another [background] process launched by the at command in order
|
||||||
# to prevent delays when invoked by a udev rule.
|
# to prevent delays when invoked by a udev rule.
|
||||||
#
|
#
|
||||||
VCHANGER_UMOUNT=/usr/libexec/vchanger/vchanger-umount-uuid.sh
|
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
|
#!/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
|
# This script is used to mount the filesystem having the
|
||||||
# UUID specified in parameter 1 at a fixed path. The path
|
# UUID specified in parameter 1 at a fixed path. The path
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/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
|
# This script is used to unmount the filesystem having the
|
||||||
# UUID specified in parameter 1. The mountpoint path
|
# UUID specified in parameter 1. The mountpoint path
|
||||||
|
@ -4,11 +4,10 @@ AM_CXXFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
|
|||||||
AM_LDFLAGS = @WINLDADD@
|
AM_LDFLAGS = @WINLDADD@
|
||||||
bin_PROGRAMS = vchanger
|
bin_PROGRAMS = vchanger
|
||||||
vchanger_SOURCES = compat/getline.c compat/gettimeofday.c \
|
vchanger_SOURCES = compat/getline.c compat/gettimeofday.c \
|
||||||
compat/localtime_r.c \
|
compat/readlink.c compat/semaphore.c \
|
||||||
compat/readlink.c \
|
|
||||||
compat/symlink.c compat/sleep.c compat/syslog.c \
|
compat/symlink.c compat/sleep.c compat/syslog.c \
|
||||||
win32_util.c uuidlookup.c bconsole.cpp \
|
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 \
|
vconf.cpp loghandler.cpp errhandler.cpp \
|
||||||
util.cpp changerstate.cpp diskchanger.cpp \
|
util.cpp changerstate.cpp diskchanger.cpp \
|
||||||
vchanger.cpp
|
vchanger.cpp
|
||||||
|
@ -91,12 +91,12 @@ CONFIG_CLEAN_VPATH_FILES =
|
|||||||
am__installdirs = "$(DESTDIR)$(bindir)"
|
am__installdirs = "$(DESTDIR)$(bindir)"
|
||||||
PROGRAMS = $(bin_PROGRAMS)
|
PROGRAMS = $(bin_PROGRAMS)
|
||||||
am_vchanger_OBJECTS = getline.$(OBJEXT) gettimeofday.$(OBJEXT) \
|
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) \
|
sleep.$(OBJEXT) syslog.$(OBJEXT) win32_util.$(OBJEXT) \
|
||||||
uuidlookup.$(OBJEXT) bconsole.$(OBJEXT) tstring.$(OBJEXT) \
|
uuidlookup.$(OBJEXT) bconsole.$(OBJEXT) tstring.$(OBJEXT) \
|
||||||
inifile.$(OBJEXT) mypopen.$(OBJEXT) vconf.$(OBJEXT) \
|
inifile.$(OBJEXT) mymutex.$(OBJEXT) mypopen.$(OBJEXT) \
|
||||||
loghandler.$(OBJEXT) errhandler.$(OBJEXT) util.$(OBJEXT) \
|
vconf.$(OBJEXT) loghandler.$(OBJEXT) errhandler.$(OBJEXT) \
|
||||||
changerstate.$(OBJEXT) diskchanger.$(OBJEXT) \
|
util.$(OBJEXT) changerstate.$(OBJEXT) diskchanger.$(OBJEXT) \
|
||||||
vchanger.$(OBJEXT)
|
vchanger.$(OBJEXT)
|
||||||
vchanger_OBJECTS = $(am_vchanger_OBJECTS)
|
vchanger_OBJECTS = $(am_vchanger_OBJECTS)
|
||||||
vchanger_LDADD = $(LDADD)
|
vchanger_LDADD = $(LDADD)
|
||||||
@ -269,11 +269,10 @@ AM_CFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
|
|||||||
AM_CXXFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
|
AM_CXXFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
|
||||||
AM_LDFLAGS = @WINLDADD@
|
AM_LDFLAGS = @WINLDADD@
|
||||||
vchanger_SOURCES = compat/getline.c compat/gettimeofday.c \
|
vchanger_SOURCES = compat/getline.c compat/gettimeofday.c \
|
||||||
compat/localtime_r.c \
|
compat/readlink.c compat/semaphore.c \
|
||||||
compat/readlink.c \
|
|
||||||
compat/symlink.c compat/sleep.c compat/syslog.c \
|
compat/symlink.c compat/sleep.c compat/syslog.c \
|
||||||
win32_util.c uuidlookup.c bconsole.cpp \
|
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 \
|
vconf.cpp loghandler.cpp errhandler.cpp \
|
||||||
util.cpp changerstate.cpp diskchanger.cpp \
|
util.cpp changerstate.cpp diskchanger.cpp \
|
||||||
vchanger.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)/getline.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettimeofday.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)/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)/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)/mypopen.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readlink.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)/sleep.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symlink.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@
|
@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@
|
@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`
|
@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
|
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_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
|
@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@
|
@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`
|
@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
|
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_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
|
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/symlink.Tpo $(DEPDIR)/symlink.Po
|
||||||
|
131
src/bconsole.cpp
131
src/bconsole.cpp
@ -1,6 +1,6 @@
|
|||||||
/* bconsole.cpp
|
/* 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
|
* 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
|
* it under the terms of the GNU General Public License, as published by
|
||||||
@ -47,18 +47,22 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "compat_defs.h"
|
||||||
|
#include "util.h"
|
||||||
#include "loghandler.h"
|
#include "loghandler.h"
|
||||||
|
#include "mymutex.h"
|
||||||
#include "mypopen.h"
|
#include "mypopen.h"
|
||||||
#include "vconf.h"
|
#include "vconf.h"
|
||||||
#include "bconsole.h"
|
#include "bconsole.h"
|
||||||
|
|
||||||
|
#ifndef HAVE_WINDOWS_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function to issue command in Bacula console.
|
* Function to issue command in Bacula console.
|
||||||
* Returns zero on success, or errno if there was an error running the command
|
* Returns zero on success, or errno if there was an error running the command
|
||||||
* or a timeout occurred.
|
* 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;
|
int pid, rc, n, len, fno_in = -1, fno_out = -1;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
@ -66,7 +70,6 @@ int issue_bconsole_command(const char *bcmd)
|
|||||||
tString cmd, tmp;
|
tString cmd, tmp;
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
|
||||||
#ifndef HAVE_WINDOWS_H
|
|
||||||
/* Build command line */
|
/* Build command line */
|
||||||
cmd = conf.bconsole;
|
cmd = conf.bconsole;
|
||||||
if (cmd.empty()) return 0;
|
if (cmd.empty()) return 0;
|
||||||
@ -76,11 +79,11 @@ int issue_bconsole_command(const char *bcmd)
|
|||||||
}
|
}
|
||||||
cmd += " -n -u 30";
|
cmd += " -n -u 30";
|
||||||
/* Start bconsole process */
|
/* 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);
|
pid = mypopen_raw(cmd.c_str(), &fno_in, &fno_out, NULL);
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
rc = errno;
|
rc = errno;
|
||||||
log.Error("bconsole: run failed errno=%d", rc);
|
vlog.Error("bconsole run failed errno=%d", rc);
|
||||||
errno = rc;
|
errno = rc;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -91,7 +94,7 @@ int issue_bconsole_command(const char *bcmd)
|
|||||||
FD_SET(fno_in, &rfd);
|
FD_SET(fno_in, &rfd);
|
||||||
rc = select(fno_in + 1, NULL, &rfd, NULL, &tv);
|
rc = select(fno_in + 1, NULL, &rfd, NULL, &tv);
|
||||||
if (rc == 0) {
|
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_in);
|
||||||
close(fno_out);
|
close(fno_out);
|
||||||
errno = ETIMEDOUT;
|
errno = ETIMEDOUT;
|
||||||
@ -99,20 +102,21 @@ int issue_bconsole_command(const char *bcmd)
|
|||||||
}
|
}
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
rc = errno;
|
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_in);
|
||||||
close(fno_out);
|
close(fno_out);
|
||||||
errno = rc;
|
errno = rc;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
/* Send command to bconsole's stdin */
|
/* Send command to bconsole's stdin */
|
||||||
|
vlog.Debug("sending bconsole command '%s'", bcmd);
|
||||||
len = strlen(bcmd);
|
len = strlen(bcmd);
|
||||||
n = 0;
|
n = 0;
|
||||||
while (n < len) {
|
while (n < len) {
|
||||||
rc = write(fno_in, bcmd + n, len - n);
|
rc = write(fno_in, bcmd + n, len - n);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
rc = errno;
|
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_in);
|
||||||
close(fno_out);
|
close(fno_out);
|
||||||
errno = rc;
|
errno = rc;
|
||||||
@ -120,57 +124,90 @@ int issue_bconsole_command(const char *bcmd)
|
|||||||
}
|
}
|
||||||
n += rc;
|
n += rc;
|
||||||
}
|
}
|
||||||
|
if (write(fno_in, "\n", 1) != 1) {
|
||||||
|
rc = errno;
|
||||||
|
vlog.Error("send to bconsole's stdin failed errno=%d", rc);
|
||||||
close(fno_in);
|
close(fno_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);
|
close(fno_out);
|
||||||
errno = rc;
|
errno = rc;
|
||||||
return 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 */
|
/* Wait for bconsole process to finish */
|
||||||
|
close(fno_in);
|
||||||
pid = waitpid(pid, &rc, 0);
|
pid = waitpid(pid, &rc, 0);
|
||||||
if (!WIFEXITED(rc)) {
|
if (!WIFEXITED(rc)) {
|
||||||
log.Error("bconsole: abnormal exit of bconsole process");
|
vlog.Error("abnormal exit of bconsole process");
|
||||||
|
close(fno_out);
|
||||||
return EPIPE;
|
return EPIPE;
|
||||||
}
|
}
|
||||||
if (WEXITSTATUS(rc)) {
|
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);
|
return WEXITSTATUS(rc);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
#else
|
/* Read stdout from bconsole */
|
||||||
return EINVAL;
|
vlog.Debug("bconsole: bconsole terminated normally");
|
||||||
#endif
|
memset(buf, 0, sizeof(buf));
|
||||||
|
tmp.clear();
|
||||||
|
rc = read(fno_out, buf, 4095);
|
||||||
|
while (rc > 0) {
|
||||||
|
buf[rc] = 0;
|
||||||
|
tmp += buf;
|
||||||
|
rc = read(fno_out, buf, 4095);
|
||||||
}
|
}
|
||||||
|
if (rc < 0) {
|
||||||
|
rc = errno;
|
||||||
|
vlog.Error("errno=%d reading bconsole stdout", rc);
|
||||||
|
close(fno_out);
|
||||||
|
errno = rc;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
close(fno_out);
|
||||||
|
vlog.Debug("bconsole output:\n%s", tmp.c_str());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function to fork a new process and issue commands in Bacula console to
|
||||||
|
* perform update slots and/or label new volumes using barcodes.
|
||||||
|
*/
|
||||||
|
void IssueBconsoleCommands(bool update_slots, bool label_barcodes)
|
||||||
|
{
|
||||||
|
tString cmd;
|
||||||
|
|
||||||
|
/* Check if update needed */
|
||||||
|
if (!update_slots && !label_barcodes) return; /* Nothing to do */
|
||||||
|
|
||||||
|
/* Perform update slots command in bconsole */
|
||||||
|
if (update_slots) {
|
||||||
|
tFormat(cmd, "update slots storage=\"%s\" drive=\"0\"", conf.storage_name.c_str());
|
||||||
|
if(issue_bconsole_command(cmd.c_str())) {
|
||||||
|
vlog.Error("WARNING! 'update slots' needed in bconsole");
|
||||||
|
}
|
||||||
|
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.
|
* 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.
|
* vchanger is free software.
|
||||||
* You may redistribute it and/or modify it under the terms of the
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
@ -24,6 +24,6 @@
|
|||||||
#ifndef BCONSOLE_H_
|
#ifndef BCONSOLE_H_
|
||||||
#define BCONSOLE_H_
|
#define BCONSOLE_H_
|
||||||
|
|
||||||
int issue_bconsole_command(const char *bcmd);
|
void IssueBconsoleCommands(bool update_slots, bool label_barcodes);
|
||||||
|
|
||||||
#endif /* BCONSOLE_H_ */
|
#endif /* BCONSOLE_H_ */
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of vchanger by Josh Fisher.
|
* 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.
|
* vchanger is free software.
|
||||||
* You may redistribute it and/or modify it under the terms of the
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
@ -173,7 +173,7 @@ int MagazineState::save()
|
|||||||
|
|
||||||
if (mag_bay < 0) {
|
if (mag_bay < 0) {
|
||||||
verr.SetErrorWithErrno(EINVAL, "cannot save state of invalid magazine %d", mag_bay);
|
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;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
/* Build path to state file */
|
/* Build path to state file */
|
||||||
@ -191,7 +191,7 @@ int MagazineState::save()
|
|||||||
rc = errno;
|
rc = errno;
|
||||||
umask(old_mask);
|
umask(old_mask);
|
||||||
verr.SetErrorWithErrno(rc, "cannot open magazine %d state file for writing", mag_bay);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
/* Save magazine device (directory or UUID), number of volumes, and start of
|
/* Save magazine device (directory or UUID), number of volumes, and start of
|
||||||
@ -203,12 +203,12 @@ int MagazineState::save()
|
|||||||
unlink(sname);
|
unlink(sname);
|
||||||
umask(old_mask);
|
umask(old_mask);
|
||||||
verr.SetErrorWithErrno(rc, "cannot write to magazine %d state file", mag_bay);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
fclose(FS);
|
fclose(FS);
|
||||||
umask(old_mask);
|
umask(old_mask);
|
||||||
log.Notice("saved state of magazine %d", mag_bay);
|
vlog.Notice("saved state of magazine %d", mag_bay);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ int MagazineState::restore()
|
|||||||
|
|
||||||
if (mag_bay < 0) {
|
if (mag_bay < 0) {
|
||||||
verr.SetErrorWithErrno(EINVAL, "cannot restore state of invalid magazine %d", mag_bay);
|
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;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
clear();
|
clear();
|
||||||
@ -250,7 +250,7 @@ int MagazineState::restore()
|
|||||||
/* No read permission? */
|
/* No read permission? */
|
||||||
rc = errno;
|
rc = errno;
|
||||||
verr.SetErrorWithErrno(rc, "cannot open magazine %d state file for reading", mag_bay);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
if (tGetLine(line, FS) == NULL) {
|
if (tGetLine(line, FS) == NULL) {
|
||||||
@ -259,7 +259,7 @@ int MagazineState::restore()
|
|||||||
/* error reading bay state file */
|
/* error reading bay state file */
|
||||||
fclose(FS);
|
fclose(FS);
|
||||||
verr.SetErrorWithErrno(rc, "error reading magazine %d state file", mag_bay);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ int MagazineState::restore()
|
|||||||
p = 0;
|
p = 0;
|
||||||
if (tParseCSV(word, line, p) <= 0) {
|
if (tParseCSV(word, line, p) <= 0) {
|
||||||
/* bay state file should not be empty, assume it didn't exist */
|
/* 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);
|
unlink(sname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -285,7 +285,7 @@ int MagazineState::restore()
|
|||||||
/* Bay state file is corrupt.
|
/* Bay state file is corrupt.
|
||||||
* Treat as if it was not mounted at last invocation */
|
* Treat as if it was not mounted at last invocation */
|
||||||
clear();
|
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);
|
unlink(sname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -293,7 +293,7 @@ int MagazineState::restore()
|
|||||||
/* Corrupt bay state file, assume it doesn't exist */
|
/* Corrupt bay state file, assume it doesn't exist */
|
||||||
clear();
|
clear();
|
||||||
unlink(sname);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
prev_num_slots = (int)strtol(word.c_str(), NULL, 10);
|
prev_num_slots = (int)strtol(word.c_str(), NULL, 10);
|
||||||
@ -302,7 +302,7 @@ int MagazineState::restore()
|
|||||||
clear();
|
clear();
|
||||||
prev_num_slots = 0;
|
prev_num_slots = 0;
|
||||||
unlink(sname);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +312,7 @@ int MagazineState::restore()
|
|||||||
* Treat as if it was not mounted at last invocation */
|
* Treat as if it was not mounted at last invocation */
|
||||||
clear();
|
clear();
|
||||||
prev_num_slots = 0;
|
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);
|
unlink(sname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -321,7 +321,7 @@ int MagazineState::restore()
|
|||||||
clear();
|
clear();
|
||||||
prev_num_slots = 0;
|
prev_num_slots = 0;
|
||||||
unlink(sname);
|
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);
|
mag_bay);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -332,11 +332,11 @@ int MagazineState::restore()
|
|||||||
prev_num_slots = 0;
|
prev_num_slots = 0;
|
||||||
prev_start_slot = 0;
|
prev_start_slot = 0;
|
||||||
unlink(sname);
|
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);
|
mag_bay);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
log.Notice("restored state of magazine %d", mag_bay);
|
vlog.Notice("restored state of magazine %d", mag_bay);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ int MagazineState::UpdateMagazineFormat()
|
|||||||
fs = fopen(lname.c_str(), "r");
|
fs = fopen(lname.c_str(), "r");
|
||||||
if (fs == NULL) {
|
if (fs == NULL) {
|
||||||
verr.SetErrorWithErrno(errno, "failed to find loaded%d file when updating magazine %d", drv, mag_bay);
|
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);
|
de = readdir(dir);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -397,7 +397,7 @@ int MagazineState::UpdateMagazineFormat()
|
|||||||
fclose(fs);
|
fclose(fs);
|
||||||
if (str.empty()) {
|
if (str.empty()) {
|
||||||
verr.SetError(-1, "loaded%d file empty when updating magazine %d", drv, mag_bay);
|
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);
|
de = readdir(dir);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -406,7 +406,7 @@ int MagazineState::UpdateMagazineFormat()
|
|||||||
if (rename(fname.c_str(), vname.c_str())) {
|
if (rename(fname.c_str(), vname.c_str())) {
|
||||||
verr.SetError(EINVAL, "unable to rename 'drive%d' on magazine %d",
|
verr.SetError(EINVAL, "unable to rename 'drive%d' on magazine %d",
|
||||||
drv, mag_bay);
|
drv, mag_bay);
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
de = readdir(dir);
|
de = readdir(dir);
|
||||||
@ -445,7 +445,7 @@ int MagazineState::UpdateMagazineFormat()
|
|||||||
tFormat(fname, "%s%sindex", mountpoint.c_str(), DIR_DELIM);
|
tFormat(fname, "%s%sindex", mountpoint.c_str(), DIR_DELIM);
|
||||||
unlink(fname.c_str());
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +494,7 @@ int MagazineState::Mount()
|
|||||||
}
|
}
|
||||||
if (rc) {
|
if (rc) {
|
||||||
verr.SetError(rc, "system error determining mountpoint from UUID");
|
verr.SetError(rc, "system error determining mountpoint from UUID");
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
mountpoint.clear();
|
mountpoint.clear();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -510,7 +510,7 @@ int MagazineState::Mount()
|
|||||||
/* Ensure access to magazine mountpoint */
|
/* Ensure access to magazine mountpoint */
|
||||||
if (access(mountpoint.c_str(), W_OK) != 0) {
|
if (access(mountpoint.c_str(), W_OK) != 0) {
|
||||||
verr.SetError(rc, "no write access to directory %s", mountpoint.c_str());
|
verr.SetError(rc, "no write access to directory %s", mountpoint.c_str());
|
||||||
log.Error("%s", verr.GetErrorMsg());
|
vlog.Error("%s", verr.GetErrorMsg());
|
||||||
mountpoint.clear();
|
mountpoint.clear();
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
@ -529,7 +529,7 @@ int MagazineState::Mount()
|
|||||||
/* could not open mountpoint dir */
|
/* could not open mountpoint dir */
|
||||||
rc = errno;
|
rc = errno;
|
||||||
verr.SetErrorWithErrno(rc, "cannot open directory '%s'", mountpoint.c_str());
|
verr.SetErrorWithErrno(rc, "cannot open directory '%s'", mountpoint.c_str());
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
mountpoint.clear();
|
mountpoint.clear();
|
||||||
if (rc == ENOTDIR || rc == ENOENT) return -3;
|
if (rc == ENOTDIR || rc == ENOENT) return -3;
|
||||||
if (rc == EACCES) return -5;
|
if (rc == EACCES) return -5;
|
||||||
@ -659,7 +659,7 @@ int MagazineState::CreateVolume(const char *vol_label_in)
|
|||||||
}
|
}
|
||||||
if (rc != ENOENT) {
|
if (rc != ENOENT) {
|
||||||
verr.SetErrorWithErrno(rc, "error %d accessing volumes on magazine %d", rc, mag_bay);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Create new volume file on magazine */
|
/* Create new volume file on magazine */
|
||||||
@ -667,7 +667,7 @@ int MagazineState::CreateVolume(const char *vol_label_in)
|
|||||||
if (!fs) {
|
if (!fs) {
|
||||||
rc = errno;
|
rc = errno;
|
||||||
verr.SetErrorWithErrno(rc, "error %d creating volume on magazine %d", rc, mag_bay);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
fclose(fs);
|
fclose(fs);
|
||||||
@ -676,7 +676,7 @@ int MagazineState::CreateVolume(const char *vol_label_in)
|
|||||||
new_mslot.label = label;
|
new_mslot.label = label;
|
||||||
mslot.push_back(new_mslot);
|
mslot.push_back(new_mslot);
|
||||||
++num_slots;
|
++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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,7 +784,7 @@ void DynamicConfig::save()
|
|||||||
/* Unable to open dynamic.conf file for writing */
|
/* Unable to open dynamic.conf file for writing */
|
||||||
rc = errno;
|
rc = errno;
|
||||||
umask(old_mask);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
/* Save max slot number in use to dynamic configuration */
|
/* Save max slot number in use to dynamic configuration */
|
||||||
@ -794,12 +794,12 @@ void DynamicConfig::save()
|
|||||||
fclose(FS);
|
fclose(FS);
|
||||||
unlink(sname);
|
unlink(sname);
|
||||||
umask(old_mask);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
fclose(FS);
|
fclose(FS);
|
||||||
umask(old_mask);
|
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) {
|
if (!FS) {
|
||||||
/* No read permission? */
|
/* No read permission? */
|
||||||
rc = errno;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (tGetLine(line, FS) == NULL) {
|
if (tGetLine(line, FS) == NULL) {
|
||||||
@ -835,7 +835,7 @@ void DynamicConfig::restore()
|
|||||||
if (!feof(FS)) {
|
if (!feof(FS)) {
|
||||||
/* error reading bay state file */
|
/* error reading bay state file */
|
||||||
fclose(FS);
|
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;
|
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.
|
* 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.
|
* vchanger is free software.
|
||||||
* You may redistribute it and/or modify it under the terms of the
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
@ -65,20 +65,13 @@
|
|||||||
#include "loghandler.h"
|
#include "loghandler.h"
|
||||||
#include "bconsole.h"
|
#include "bconsole.h"
|
||||||
#include "diskchanger.h"
|
#include "diskchanger.h"
|
||||||
|
#include "vconf.h"
|
||||||
|
|
||||||
|
|
||||||
/*=================================================
|
/*=================================================
|
||||||
* Class DiskChanger
|
* Class DiskChanger
|
||||||
*=================================================*/
|
*=================================================*/
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
* destructor
|
|
||||||
*-------------------------------------------------*/
|
|
||||||
DiskChanger::~DiskChanger()
|
|
||||||
{
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
* Protected method to read previous state of magazine bays.
|
* Protected method to read previous state of magazine bays.
|
||||||
@ -148,6 +141,7 @@ void DiskChanger::InitializeVirtSlots()
|
|||||||
|
|
||||||
/* Create all known slots as initially empty */
|
/* Create all known slots as initially empty */
|
||||||
vslot.clear();
|
vslot.clear();
|
||||||
|
vs.clear();
|
||||||
for (s = 0; s <= dconf.max_slot; s++) {
|
for (s = 0; s <= dconf.max_slot; s++) {
|
||||||
vs.vs = s;
|
vs.vs = s;
|
||||||
vslot.push_back(vs);
|
vslot.push_back(vs);
|
||||||
@ -155,7 +149,7 @@ void DiskChanger::InitializeVirtSlots()
|
|||||||
/* Re-create virtual slots that existed previously if possible */
|
/* Re-create virtual slots that existed previously if possible */
|
||||||
for (m = 0; m < (int)magazine.size(); m++) {
|
for (m = 0; m < (int)magazine.size(); m++) {
|
||||||
/* Create slots if needed to match max slot used by previous magazines */
|
/* 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()) {
|
if (last >= (int)vslot.size()) {
|
||||||
vs.clear();
|
vs.clear();
|
||||||
while ((int)vslot.size() <= last) {
|
while ((int)vslot.size() <= last) {
|
||||||
@ -165,11 +159,11 @@ void DiskChanger::InitializeVirtSlots()
|
|||||||
}
|
}
|
||||||
/* Check this magazine's slots */
|
/* Check this magazine's slots */
|
||||||
if (magazine[m].empty()) {
|
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 */
|
/* magazine is not currently mounted, so will have no slots assigned */
|
||||||
if (magazine[m].prev_start_slot) {
|
if (magazine[m].prev_start_slot) {
|
||||||
/* Since it was previously mounted, an 'update slots' is needed */
|
/* 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_num_slots, magazine[m].prev_start_slot,
|
||||||
magazine[m].prev_start_slot + magazine[m].prev_num_slots - 1);
|
magazine[m].prev_start_slot + magazine[m].prev_num_slots - 1);
|
||||||
needs_update = true;
|
needs_update = true;
|
||||||
@ -177,12 +171,12 @@ void DiskChanger::InitializeVirtSlots()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Magazine is currently mounted, so check for change in slot assignment */
|
/* 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());
|
magazine[m].mountpoint.c_str());
|
||||||
if (magazine[m].num_slots != magazine[m].prev_num_slots) {
|
if (magazine[m].num_slots != magazine[m].prev_num_slots) {
|
||||||
/* Number of volumes has changed or magazine was not previously mounted, so
|
/* Number of volumes has changed or magazine was not previously mounted, so
|
||||||
* needs new slot assignment and also 'update slots' will be needed */
|
* 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);
|
magazine[m].num_slots, magazine[m].prev_num_slots);
|
||||||
needs_update = true;
|
needs_update = true;
|
||||||
continue;
|
continue;
|
||||||
@ -194,7 +188,7 @@ void DiskChanger::InitializeVirtSlots()
|
|||||||
/* Magazine is mounted, was previously mounted, and has the same volume count,
|
/* Magazine is mounted, was previously mounted, and has the same volume count,
|
||||||
* so attempt to assign to the same slots previously assigned */
|
* so attempt to assign to the same slots previously assigned */
|
||||||
found = false;
|
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()) {
|
if (!vslot[v].empty()) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
@ -204,7 +198,7 @@ void DiskChanger::InitializeVirtSlots()
|
|||||||
/* Slot used previously has already been assigned to another magazine.
|
/* Slot used previously has already been assigned to another magazine.
|
||||||
* Magazine will need to be assigned a new slot range, so an
|
* Magazine will need to be assigned a new slot range, so an
|
||||||
* 'update slots' will also be needed. */
|
* '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);
|
magazine[m].prev_start_slot, magazine[m].prev_start_slot + magazine[m].prev_num_slots - 1);
|
||||||
needs_update = true;
|
needs_update = true;
|
||||||
continue;
|
continue;
|
||||||
@ -216,7 +210,7 @@ void DiskChanger::InitializeVirtSlots()
|
|||||||
vslot[v].mag_bay = m;
|
vslot[v].mag_bay = m;
|
||||||
vslot[v].mag_slot = s;
|
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);
|
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_bay = m;
|
||||||
vslot[v].mag_slot = s;
|
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);
|
magazine[m].start_slot, magazine[m].start_slot + magazine[m].num_slots - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +257,7 @@ int DiskChanger::InitializeDrives()
|
|||||||
if (!d) {
|
if (!d) {
|
||||||
rc = errno;
|
rc = errno;
|
||||||
verr.SetErrorWithErrno(rc, "error %d accessing work directory", rc);
|
verr.SetErrorWithErrno(rc, "error %d accessing work directory", rc);
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
de = readdir(d);
|
de = readdir(d);
|
||||||
@ -297,7 +291,7 @@ int DiskChanger::InitializeDrives()
|
|||||||
drive.push_back(ds);
|
drive.push_back(ds);
|
||||||
/* Attempt to restore drive's last state */
|
/* Attempt to restore drive's last state */
|
||||||
if (RestoreDriveState(n)) {
|
if (RestoreDriveState(n)) {
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -351,7 +345,7 @@ int DiskChanger::CreateDriveSymlink(int drv)
|
|||||||
lname[rc] = 0;
|
lname[rc] = 0;
|
||||||
if (fname == lname) {
|
if (fname == lname) {
|
||||||
/* symlink already exists */
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Symlink points to wrong mountpoint, so delete and re-create */
|
/* 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);
|
verr.SetErrorWithErrno(rc, "error %d creating symlink for drive %d", rc, drv);
|
||||||
return rc;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +383,7 @@ int DiskChanger::RemoveDriveSymlink(int drv)
|
|||||||
verr.SetErrorWithErrno(errno, "error %d deleting symlink for drive %d: ", rc, drv);
|
verr.SetErrorWithErrno(errno, "error %d deleting symlink for drive %d: ", rc, drv);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
log.Notice("deleted symlink for drive %d", drv);
|
vlog.Notice("deleted symlink for drive %d", drv);
|
||||||
return 0;
|
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);
|
tFormat(sname, "%s%sdrive_state-%d", conf.work_dir.c_str(), DIR_DELIM, drv);
|
||||||
if (drive[drv].empty()) {
|
if (drive[drv].empty()) {
|
||||||
if (access(sname.c_str(), F_OK) == 0) {
|
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());
|
unlink(sname.c_str());
|
||||||
return 0;
|
return 0;
|
||||||
@ -443,7 +437,7 @@ int DiskChanger::SaveDriveState(int drv)
|
|||||||
}
|
}
|
||||||
fclose(FS);
|
fclose(FS);
|
||||||
umask(old_mask);
|
umask(old_mask);
|
||||||
log.Notice("wrote state file for drive %d", drv);
|
vlog.Notice("wrote state file for drive %d", drv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,7 +471,7 @@ int DiskChanger::RestoreDriveState(int drv)
|
|||||||
if (stat(sname.c_str(), &st)) {
|
if (stat(sname.c_str(), &st)) {
|
||||||
/* drive state file not found, so drive is not loaded */
|
/* drive state file not found, so drive is not loaded */
|
||||||
RemoveDriveSymlink(drv);
|
RemoveDriveSymlink(drv);
|
||||||
log.Info("drive %d previously unloaded", drv);
|
vlog.Info("drive %d previously unloaded", drv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Read loaded volume info from state file */
|
/* Read loaded volume info from state file */
|
||||||
@ -526,7 +520,7 @@ int DiskChanger::RestoreDriveState(int drv)
|
|||||||
}
|
}
|
||||||
if (v >= (int)vslot.size()) {
|
if (v >= (int)vslot.size()) {
|
||||||
/* Volume last loaded is no longer available. Change state to unloaded. */
|
/* 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);
|
labl.c_str(), drv);
|
||||||
unlink(sname.c_str());
|
unlink(sname.c_str());
|
||||||
RemoveDriveSymlink(drv);
|
RemoveDriveSymlink(drv);
|
||||||
@ -538,7 +532,7 @@ int DiskChanger::RestoreDriveState(int drv)
|
|||||||
if ((rc = CreateDriveSymlink(drv)) != 0) {
|
if ((rc = CreateDriveSymlink(drv)) != 0) {
|
||||||
/* Unable to create symlink */
|
/* Unable to create symlink */
|
||||||
drive[drv].vs = -1;
|
drive[drv].vs = -1;
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,7 +540,7 @@ int DiskChanger::RestoreDriveState(int drv)
|
|||||||
vslot[v].drv = drv;
|
vslot[v].drv = drv;
|
||||||
m = vslot[v].mag_bay;
|
m = vslot[v].mag_bay;
|
||||||
ms = vslot[v].mag_slot;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,7 +556,6 @@ int DiskChanger::RestoreDriveState(int drv)
|
|||||||
int DiskChanger::Initialize()
|
int DiskChanger::Initialize()
|
||||||
{
|
{
|
||||||
/* Make sure we have a lock on this changer */
|
/* Make sure we have a lock on this changer */
|
||||||
if (Lock()) return verr.GetError();
|
|
||||||
magazine.clear();
|
magazine.clear();
|
||||||
vslot.clear();
|
vslot.clear();
|
||||||
drive.clear();
|
drive.clear();
|
||||||
@ -591,38 +584,38 @@ int DiskChanger::LoadDrive(int drv, int slot)
|
|||||||
{
|
{
|
||||||
int rc, m, ms;
|
int rc, m, ms;
|
||||||
|
|
||||||
if (!changer_lock) {
|
|
||||||
verr.SetError(EINVAL, "changer not initialized");
|
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
if (drv < 0) {
|
if (drv < 0) {
|
||||||
verr.SetError(EINVAL, "invalid drive number %d", drv);
|
verr.SetError(EINVAL, "invalid drive number %d", drv);
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
SetMaxDrive(drv);
|
SetMaxDrive(drv);
|
||||||
if (slot < 1 || slot >= (int)vslot.size()) {
|
if (slot < 1 || slot >= (int)vslot.size()) {
|
||||||
verr.SetError(EINVAL, "cannot load drive %d from invalid slot %d", drv, slot);
|
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;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!drive[drv].empty()) {
|
if (!drive[drv].empty()) {
|
||||||
if (drive[drv].vs == slot) return 0; /* already loaded from this slot */
|
if (drive[drv].vs == slot) return 0; /* already loaded from this slot */
|
||||||
verr.SetError(EBUSY, "drive %d already loaded from slot %d", drv, 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;
|
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()) {
|
if (vslot[slot].empty()) {
|
||||||
verr.SetError(EINVAL, "cannot load drive %d from empty slot %d", drv, slot);
|
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;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
/* Create symlink for drive pointing to volume file */
|
/* Create symlink for drive pointing to volume file */
|
||||||
drive[drv].vs = slot;
|
drive[drv].vs = slot;
|
||||||
if ((rc = CreateDriveSymlink(drv))) {
|
if ((rc = CreateDriveSymlink(drv))) {
|
||||||
drive[drv].vs = -1;
|
drive[drv].vs = -1;
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
/* Save state of newly loaded drive */
|
/* Save state of newly loaded drive */
|
||||||
@ -630,14 +623,14 @@ int DiskChanger::LoadDrive(int drv, int slot)
|
|||||||
/* Error writing drive state file */
|
/* Error writing drive state file */
|
||||||
RemoveDriveSymlink(drv);
|
RemoveDriveSymlink(drv);
|
||||||
drive[drv].vs = -1;
|
drive[drv].vs = -1;
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
/* Assign virtual slot to drive */
|
/* Assign virtual slot to drive */
|
||||||
vslot[slot].drv = drv;
|
vslot[slot].drv = drv;
|
||||||
m = vslot[slot].mag_bay;
|
m = vslot[slot].mag_bay;
|
||||||
ms = vslot[slot].mag_slot;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,14 +645,9 @@ int DiskChanger::UnloadDrive(int drv)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!changer_lock) {
|
|
||||||
verr.SetError(EINVAL, "changer not initialized");
|
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
if (drv < 0) {
|
if (drv < 0) {
|
||||||
verr.SetError(EINVAL, "invalid drive number %d", drv);
|
verr.SetError(EINVAL, "invalid drive number %d", drv);
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
SetMaxDrive(drv);
|
SetMaxDrive(drv);
|
||||||
@ -669,7 +657,7 @@ int DiskChanger::UnloadDrive(int drv)
|
|||||||
}
|
}
|
||||||
/* Remove drive's symlink */
|
/* Remove drive's symlink */
|
||||||
if ((rc = RemoveDriveSymlink(drv)) != 0) {
|
if ((rc = RemoveDriveSymlink(drv)) != 0) {
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
/* Remove virtual slot assignment */
|
/* Remove virtual slot assignment */
|
||||||
@ -677,10 +665,10 @@ int DiskChanger::UnloadDrive(int drv)
|
|||||||
drive[drv].vs = -1;
|
drive[drv].vs = -1;
|
||||||
/* Update drive state file (will delete state file due to negative slot number) */
|
/* Update drive state file (will delete state file due to negative slot number) */
|
||||||
if ((rc = SaveDriveState(drv)) != 0) {
|
if ((rc = SaveDriveState(drv)) != 0) {
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
log.Notice("unloaded drive %d", drv);
|
vlog.Notice("unloaded drive %d", drv);
|
||||||
return 0;
|
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);
|
tString label, label_prefix(label_prefix_in);
|
||||||
int i;
|
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()) {
|
if (bay < 0 || bay >= (int)magazine.size()) {
|
||||||
verr.SetError(EINVAL, "invalid magazine");
|
verr.SetError(EINVAL, "invalid magazine");
|
||||||
log.Error("ERROR! %s", verr.GetErrorMsg());
|
vlog.Error("ERROR! %s", verr.GetErrorMsg());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (count < 1) count = 1;
|
if (count < 1) count = 1;
|
||||||
tStrip(tRemoveEOL(label_prefix));
|
tStrip(tRemoveEOL(label_prefix));
|
||||||
if (label_prefix.empty()) {
|
if (label_prefix.empty()) {
|
||||||
/* Default prefix is storage-name_magazine-number */
|
/* 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) {
|
if (start < 0) {
|
||||||
/* Find highest uniqueness number for this filename prefix */
|
/* Find highest uniqueness number for this filename prefix */
|
||||||
for (i = magazine[bay].num_slots * 5; i > 0; i--) {
|
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;
|
if (magazine[bay].GetVolumeSlot(label) >= 0) break;
|
||||||
}
|
}
|
||||||
start = i;
|
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());
|
fprintf(stdout, "creating label '%s'\n", label.c_str());
|
||||||
if (magazine[bay].CreateVolume(label)) {
|
if (magazine[bay].CreateVolume(label)) {
|
||||||
|
/* On failure, update magazine state if any were created */
|
||||||
if (i) magazine[bay].save();
|
if (i) magazine[bay].save();
|
||||||
return -1;
|
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 */
|
/* New mag state will require 'update slots' and 'label barcodes' in Bacula */
|
||||||
needs_update = true;
|
needs_update = true;
|
||||||
needs_label = true;
|
needs_label = true;
|
||||||
log.Notice("update slots needed. %d volumes added to magazine %d",count , bay);
|
vlog.Notice("%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());
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,7 +739,7 @@ const char* DiskChanger::GetVolumeLabel(int slot)
|
|||||||
{
|
{
|
||||||
if (slot <= 0 || slot >= (int)vslot.size()) {
|
if (slot <= 0 || slot >= (int)vslot.size()) {
|
||||||
verr.SetError(-1, "volume label request from invalid slot %d", slot);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (vslot[slot].empty()) return "";
|
if (vslot[slot].empty()) return "";
|
||||||
@ -825,7 +755,7 @@ const char* DiskChanger::GetVolumePath(tString &path, int slot)
|
|||||||
path.clear();
|
path.clear();
|
||||||
if (slot <= 0 || slot >= (int)vslot.size()) {
|
if (slot <= 0 || slot >= (int)vslot.size()) {
|
||||||
verr.SetError(-1, "volume path request from invalid slot %d", slot);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (vslot[slot].empty()) return path.c_str();
|
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,
|
* Method returns true if magazine is not mounted,
|
||||||
* else returns false.
|
* else returns false.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of vchanger by Josh Fisher.
|
* 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.
|
* vchanger is free software.
|
||||||
* You may redistribute it and/or modify it under the terms of the
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
@ -30,13 +30,12 @@
|
|||||||
class DiskChanger
|
class DiskChanger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DiskChanger() : changer_lock(NULL), needs_update(false), needs_label(false) {}
|
DiskChanger() : needs_update(false), needs_label(false) {}
|
||||||
virtual ~DiskChanger();
|
virtual ~DiskChanger() {};
|
||||||
int Initialize();
|
int Initialize();
|
||||||
int LoadDrive(int drv, int slot);
|
int LoadDrive(int drv, int slot);
|
||||||
int UnloadDrive(int drv);
|
int UnloadDrive(int drv);
|
||||||
int CreateVolumes(int bay, int count, int start = -1, const char *label_prefix = "");
|
int CreateVolumes(int bay, int count, int start = -1, const char *label_prefix = "");
|
||||||
int UpdateBacula();
|
|
||||||
const char* GetVolumeLabel(int slot);
|
const char* GetVolumeLabel(int slot);
|
||||||
const char* GetVolumePath(tString &fname, int slot);
|
const char* GetVolumePath(tString &fname, int slot);
|
||||||
bool MagazineEmpty(int bay) const;
|
bool MagazineEmpty(int bay) const;
|
||||||
@ -54,8 +53,6 @@ public:
|
|||||||
inline const char* GetErrorMsg() const { return verr.GetErrorMsg(); }
|
inline const char* GetErrorMsg() const { return verr.GetErrorMsg(); }
|
||||||
inline bool NeedsUpdate() const { return needs_update; }
|
inline bool NeedsUpdate() const { return needs_update; }
|
||||||
inline bool NeedsLabel() const { return needs_label; }
|
inline bool NeedsLabel() const { return needs_label; }
|
||||||
int Lock(long timeout = 30);
|
|
||||||
void Unlock();
|
|
||||||
protected:
|
protected:
|
||||||
void InitializeMagazines();
|
void InitializeMagazines();
|
||||||
int FindEmptySlotRange(int count);
|
int FindEmptySlotRange(int count);
|
||||||
@ -67,7 +64,6 @@ protected:
|
|||||||
int SaveDriveState(int drv);
|
int SaveDriveState(int drv);
|
||||||
int RestoreDriveState(int drv);
|
int RestoreDriveState(int drv);
|
||||||
protected:
|
protected:
|
||||||
FILE *changer_lock;
|
|
||||||
bool needs_update;
|
bool needs_update;
|
||||||
bool needs_label;
|
bool needs_label;
|
||||||
ErrorHandler verr;
|
ErrorHandler verr;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* loghandler.cpp
|
/* 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
|
* 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
|
* it under the terms of the GNU General Public License, as published by
|
||||||
@ -22,6 +22,9 @@
|
|||||||
#ifdef HAVE_STDIO_H
|
#ifdef HAVE_STDIO_H
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_TIME_H
|
#ifdef HAVE_TIME_H
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#endif
|
#endif
|
||||||
@ -34,13 +37,11 @@
|
|||||||
#ifdef HAVE_STDARG_H
|
#ifdef HAVE_STDARG_H
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#endif
|
#endif
|
||||||
#ifndef HAVE_LOCALTIME_R
|
|
||||||
#include "compat/localtime_r.h"
|
#include "compat/localtime_r.h"
|
||||||
#endif
|
|
||||||
#define LOGHANDLER_SOURCE 1
|
#define LOGHANDLER_SOURCE 1
|
||||||
#include "loghandler.h"
|
#include "loghandler.h"
|
||||||
|
|
||||||
LogHandler log;
|
LogHandler vlog;
|
||||||
|
|
||||||
LogHandler::LogHandler() : use_syslog(false), max_debug_level(LOG_WARNING), errfs(stderr)
|
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;
|
size_t n;
|
||||||
struct tm bt;
|
struct tm bt;
|
||||||
time_t t;
|
time_t t;
|
||||||
char buf[1024];
|
char ftim[128], buf[4096];
|
||||||
Lock();
|
Lock();
|
||||||
if (priority > max_debug_level || priority < LOG_EMERG || !fmt) {
|
if (priority > max_debug_level || priority < LOG_EMERG || !fmt) {
|
||||||
Unlock();
|
Unlock();
|
||||||
@ -187,8 +188,8 @@ void LogHandler::WriteLog(int priority, const char *fmt, va_list vl)
|
|||||||
}
|
}
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
localtime_r(&t, &bt);
|
localtime_r(&t, &bt);
|
||||||
strftime(buf, 100, "%b %d %T: ", &bt);
|
strftime(ftim, 100, "%b %d %T: ", &bt);
|
||||||
strncpy(buf + strlen(buf), fmt, sizeof(buf) - strlen(buf));
|
snprintf(buf, sizeof(buf), "%s [%d]: %s", ftim, getpid(), fmt);
|
||||||
if (use_syslog) vsyslog(priority, buf, vl);
|
if (use_syslog) vsyslog(priority, buf, vl);
|
||||||
else {
|
else {
|
||||||
n = strlen(buf);
|
n = strlen(buf);
|
||||||
@ -204,3 +205,17 @@ void LogHandler::WriteLog(int priority, const char *fmt, va_list vl)
|
|||||||
}
|
}
|
||||||
Unlock();
|
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
|
/* 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
|
* 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
|
* it under the terms of the GNU General Public License, as published by
|
||||||
@ -32,6 +32,15 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void LogHandler_write(int level, const char *format, ...);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
class LogHandler
|
class LogHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -50,6 +59,7 @@ public:
|
|||||||
void Debug(const char *fmt, ... );
|
void Debug(const char *fmt, ... );
|
||||||
void MajorDebug(const char *fmt, ... );
|
void MajorDebug(const char *fmt, ... );
|
||||||
inline bool UsingSyslog() { return use_syslog; }
|
inline bool UsingSyslog() { return use_syslog; }
|
||||||
|
friend void LogHandler_write(int level, const char *format, ...);
|
||||||
protected:
|
protected:
|
||||||
void Lock();
|
void Lock();
|
||||||
void Unlock();
|
void Unlock();
|
||||||
@ -64,7 +74,8 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifndef LOGHANDLER_SOURCE
|
#ifndef LOGHANDLER_SOURCE
|
||||||
extern LogHandler log;
|
extern LogHandler vlog;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _LOGHANDLER_H_ */
|
#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 */
|
/* Build argv array from command line string */
|
||||||
if (mypopen_args(cline, argv, argc, argbuf, sizeof(argbuf))) {
|
if (mypopen_args(cline, argv, argc, argbuf, sizeof(argbuf))) {
|
||||||
/* Invalid args, so terminate child */
|
/* Invalid args, so terminate child */
|
||||||
log.Debug("popen: invalid cmdline args for child");
|
vlog.Debug("popen: invalid cmdline args for child");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -193,7 +193,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
|||||||
/* error creating pipe */
|
/* error creating pipe */
|
||||||
return -1;
|
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) {
|
} else if (*fno_stdin == STDIN_FILENO) {
|
||||||
/* Caller specified stdin so just let child inherit it */
|
/* Caller specified stdin so just let child inherit it */
|
||||||
fno_stdin = NULL;
|
fno_stdin = NULL;
|
||||||
@ -212,7 +212,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
|||||||
errno = rc;
|
errno = rc;
|
||||||
return -1;
|
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 {
|
} else {
|
||||||
if (*fno_stdout == STDOUT_FILENO) fno_stdout = NULL;
|
if (*fno_stdout == STDOUT_FILENO) fno_stdout = NULL;
|
||||||
else fsync(*fno_stdout);
|
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;
|
errno = rc;
|
||||||
return -1;
|
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 {
|
} else {
|
||||||
if (*fno_stderr == STDERR_FILENO) fno_stderr = NULL;
|
if (*fno_stderr == STDERR_FILENO) fno_stderr = NULL;
|
||||||
else fsync(*fno_stderr);
|
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 */
|
/* fork a child process to run the command in */
|
||||||
log.Debug("popen: forking now");
|
vlog.Debug("popen: forking now");
|
||||||
pid = fork();
|
pid = fork();
|
||||||
switch (pid)
|
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 */
|
case 0: /* child is running */
|
||||||
/* close pipe ends always used by parent */
|
/* 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_in[1] >= 0) close(pipe_in[1]);
|
||||||
if (pipe_out[0] >= 0) close(pipe_out[0]);
|
if (pipe_out[0] >= 0) close(pipe_out[0]);
|
||||||
if (pipe_err[0] >= 0) close(pipe_err[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) {
|
||||||
if (*fno_stdin < 0) {
|
if (*fno_stdin < 0) {
|
||||||
/* Read end of pipe will be child's stdin */
|
/* 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);
|
dup2(pipe_in[0], STDIN_FILENO);
|
||||||
close(pipe_in[0]);
|
close(pipe_in[0]);
|
||||||
} else {
|
} 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) {
|
||||||
if (*fno_stdout < 0) {
|
if (*fno_stdout < 0) {
|
||||||
/* Write end of pipe will be child's stdout */
|
/* 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);
|
dup2(pipe_out[1], STDOUT_FILENO);
|
||||||
close(pipe_out[1]);
|
close(pipe_out[1]);
|
||||||
} else {
|
} 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) {
|
||||||
if (*fno_stderr < 0) {
|
if (*fno_stderr < 0) {
|
||||||
/* Write end of pipe will be child's stderr */
|
/* 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);
|
dup2(pipe_err[1], STDERR_FILENO);
|
||||||
close(pipe_err[1]);
|
close(pipe_err[1]);
|
||||||
} else {
|
} else {
|
||||||
@ -295,7 +295,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* now run the command */
|
/* now run the command */
|
||||||
log.Debug("popen: child executing '%s'", argv[0]);
|
vlog.Debug("popen: child executing '%s'", argv[0]);
|
||||||
execvp(argv[0], argv);
|
execvp(argv[0], argv);
|
||||||
/* only gets here if execvp fails */
|
/* only gets here if execvp fails */
|
||||||
return -1;
|
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 */
|
/* parent is running this */
|
||||||
|
|
||||||
/* close pipe ends always used by child */
|
/* 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_in[0] >= 0) close(pipe_in[0]);
|
||||||
if (pipe_out[1] >= 0) close(pipe_out[1]);
|
if (pipe_out[1] >= 0) close(pipe_out[1]);
|
||||||
if (pipe_err[1] >= 0) close(pipe_err[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) {
|
if (*fno_stdin < 0) {
|
||||||
/* Caller will be writing to child's stdin through pipe */
|
/* Caller will be writing to child's stdin through pipe */
|
||||||
*fno_stdin = pipe_in[1];
|
*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) {
|
||||||
if (*fno_stdout < 0) {
|
if (*fno_stdout < 0) {
|
||||||
/* Caller will be reading from child's stdout through pipe */
|
/* Caller will be reading from child's stdout through pipe */
|
||||||
*fno_stdout = pipe_out[0];
|
*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) {
|
||||||
if (*fno_stderr < 0) {
|
if (*fno_stderr < 0) {
|
||||||
/* Caller will be reading from child's stderr through pipe */
|
/* Caller will be reading from child's stderr through pipe */
|
||||||
*fno_stderr = pipe_err[0];
|
*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);
|
//sleep(2);
|
||||||
log.Debug("popen: parent returning pid=%d of child", pid);
|
vlog.Debug("popen: parent returning pid=%d of child", pid);
|
||||||
return 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 */
|
/* Build argv array from command line string */
|
||||||
if (mypopen_args(cline, argv, argc, argbuf, sizeof(argbuf))) {
|
if (mypopen_args(cline, argv, argc, argbuf, sizeof(argbuf))) {
|
||||||
/* Invalid args, so terminate child */
|
/* Invalid args, so terminate child */
|
||||||
log.Debug("popen: invalid cmdline args for child");
|
vlog.Debug("popen: invalid cmdline args for child");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -375,7 +375,7 @@ static int do_mypopen_raw(const char *cline, int *fno_stdin, int *fno_stdout, in
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
child_in = pipe_in[0];
|
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 {
|
} else {
|
||||||
if (*fno_stdin != STDIN_FILENO) {
|
if (*fno_stdin != STDIN_FILENO) {
|
||||||
/* Caller supplied an open file to use as child's stdin */
|
/* 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;
|
return -1;
|
||||||
}
|
}
|
||||||
child_out = pipe_out[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 {
|
} else {
|
||||||
if (*fno_stdout != STDOUT_FILENO) {
|
if (*fno_stdout != STDOUT_FILENO) {
|
||||||
/* Caller supplied open file to use as child's stdout */
|
/* 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;
|
return -1;
|
||||||
}
|
}
|
||||||
child_err = pipe_err[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 {
|
} else {
|
||||||
if (*fno_stderr != STDERR_FILENO) {
|
if (*fno_stderr != STDERR_FILENO) {
|
||||||
/* Caller supplied an open file to use as child's stderr */
|
/* 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_out[0] >= 0) *fno_stdout = pipe_out[0];
|
||||||
if (pipe_err[0] >= 0) *fno_stderr = pipe_err[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;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of vchanger by Josh Fisher.
|
* 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.
|
* vchanger is free software.
|
||||||
* You may redistribute it and/or modify it under the terms of the
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
@ -41,6 +41,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "uuidlookup.h"
|
#include "uuidlookup.h"
|
||||||
|
#include "loghandler.h"
|
||||||
|
|
||||||
#ifdef HAVE_WINDOWS_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)
|
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;
|
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_list_entry *devices, *dev_list_entry;
|
||||||
struct udev_device *dev;
|
struct udev_device *dev;
|
||||||
int rc = -3;
|
int rc = -3;
|
||||||
const char *dev_name, *path, *uuid;
|
const char *dev_name, *dev_links, *path, *uuid;
|
||||||
size_t n, pos, dev_name_len;
|
size_t n, pos, dev_links_len;
|
||||||
char devlink[4096];
|
char devlink[4096];
|
||||||
|
|
||||||
if (!mountp || !mountp_sz) return -2;
|
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");
|
dev_name = udev_device_get_property_value(dev, "DEVNAME");
|
||||||
if (dev_name == NULL) {
|
if (dev_name == NULL) {
|
||||||
/* Failed to get kernel device node */
|
/* Failed to get kernel device node */
|
||||||
|
LogHandler_write(LOG_DEBUG, "filesystem %s has no udev assigned device node",
|
||||||
|
uuid_str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
LogHandler_write(LOG_DEBUG, "filesystem %s has udev assigned device %s",
|
||||||
|
uuid_str, dev_name);
|
||||||
/* Lookup mountpoint of the kernel device node */
|
/* Lookup mountpoint of the kernel device node */
|
||||||
rc = GetDevMountpoint(mountp, mountp_sz, dev_name);
|
rc = GetDevMountpoint(mountp, mountp_sz, dev_name);
|
||||||
if (rc == 0) break;
|
if (rc == 0) {
|
||||||
/* If not mounted as the DEVNAME, also check if mounted as
|
/* Found mountpoint */
|
||||||
* a device alias name from DEVLINKS */
|
LogHandler_write(LOG_DEBUG, "filesystem %s (device %s) mounted at %s", uuid_str, dev_name, mountp);
|
||||||
dev_name = udev_device_get_property_value(dev, "DEVLINKS");
|
|
||||||
if (dev_name == NULL) {
|
|
||||||
/* Failed to get device alias links */
|
|
||||||
break;
|
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;
|
pos = 0;
|
||||||
while (rc == -4 && pos < dev_name_len) {
|
while (rc == -4 && pos < dev_links_len) {
|
||||||
for (n = pos; n < dev_name_len && !isblank(dev_name[n]); n++) ;
|
for (n = pos; n < dev_links_len && !isblank(dev_links[n]); n++) ;
|
||||||
n -= pos;
|
n -= pos;
|
||||||
memmove(devlink, dev_name + pos, n);
|
memmove(devlink, dev_links + pos, n);
|
||||||
devlink[n] = 0;
|
devlink[n] = 0;
|
||||||
rc = GetDevMountpoint(mountp, mountp_sz, devlink);
|
rc = GetDevMountpoint(mountp, mountp_sz, devlink);
|
||||||
pos += n;
|
if (rc == 0) {
|
||||||
while (pos < dev_name_len && isblank(dev_name[pos])) ++pos;
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,7 +363,11 @@ int GetMountpointFromUUID(char *mountp, size_t mountp_sz, const char *uuid_str)
|
|||||||
#else
|
#else
|
||||||
dev_name = blkid_get_devname(NULL, "UUID", uuid_str);
|
dev_name = blkid_get_devname(NULL, "UUID", uuid_str);
|
||||||
#endif
|
#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 */
|
/* find mount point for device */
|
||||||
rc = GetDevMountpoint(mountp, mountp_sz, dev_name);
|
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)
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
171
src/vchanger.cpp
171
src/vchanger.cpp
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of the vchanger package
|
* 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.
|
* vchanger is free software.
|
||||||
* You may redistribute it and/or modify it under the terms of the
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
@ -31,6 +31,9 @@
|
|||||||
#ifdef HAVE_STDINT_H
|
#ifdef HAVE_STDINT_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_ERRNO_H
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
@ -53,7 +56,10 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "compat_defs.h"
|
#include "compat_defs.h"
|
||||||
#include "loghandler.h"
|
#include "loghandler.h"
|
||||||
|
#include "errhandler.h"
|
||||||
#include "diskchanger.h"
|
#include "diskchanger.h"
|
||||||
|
#include "mymutex.h"
|
||||||
|
#include "bconsole.h"
|
||||||
|
|
||||||
DiskChanger changer;
|
DiskChanger changer;
|
||||||
|
|
||||||
@ -80,6 +86,7 @@ typedef struct _cmdparams_s
|
|||||||
{
|
{
|
||||||
bool print_version;
|
bool print_version;
|
||||||
bool print_help;
|
bool print_help;
|
||||||
|
bool force;
|
||||||
int command;
|
int command;
|
||||||
int slot;
|
int slot;
|
||||||
int drive;
|
int drive;
|
||||||
@ -115,12 +122,15 @@ static void print_help(void)
|
|||||||
" changer defined by vchanger configuration file\n"
|
" changer defined by vchanger configuration file\n"
|
||||||
" 'config_file' using 'slot', 'device', and 'drive'\n"
|
" 'config_file' using 'slot', 'device', and 'drive'\n"
|
||||||
" vchanger [options] config_file LISTMAGS\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 [options] config_file CREATEVOLS mag_ndx count [start] [CREATEVOLS options]\n"
|
||||||
" vchanger extension to create 'count' empty volume files on the magazine at\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 when\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"
|
" appending integers to the label prefix when generating volume names.\n"
|
||||||
" vchanger [options] config_file REFRESH\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"
|
" vchanger --version\n"
|
||||||
" print version info\n"
|
" print version info\n"
|
||||||
" vchanger --help\n"
|
" vchanger --help\n"
|
||||||
@ -131,13 +141,13 @@ static void print_help(void)
|
|||||||
"\nCREATEVOLS command options:\n"
|
"\nCREATEVOLS command options:\n"
|
||||||
" -l, --label=string string to use as a prefix for determining the\n"
|
" -l, --label=string string to use as a prefix for determining the\n"
|
||||||
" barcode label of the volume files created. Labels\n"
|
" barcode label of the volume files created. Labels\n"
|
||||||
" will be of the form 'string'_N, where N is an\n"
|
" will be of the form 'string'N, where N is a\n"
|
||||||
" integer. By default the prefix will be generated\n"
|
" 4 digit integer with leading zeros. The magazine\n"
|
||||||
" using the changer name and the position of the\n"
|
" name is used as the prefix string by default.\n"
|
||||||
" magazine's declaration in the configuration file.\n"
|
" --pool=string Overrides the default pool that new volumes should\n"
|
||||||
" --pool=string Overrides the default pool, defined in the vchanger\n"
|
" be placed into when labeling newly created volumes.\n"
|
||||||
" config file, that new volumes should be placed into\n"
|
"\nREFRESH command options:\n"
|
||||||
" when labeling newly created volumes.\n"
|
" --force Force a bconsole update slots command to be invoked\n"
|
||||||
"\nReport bugs to %s.\n", PACKAGE_BUGREPORT);
|
"\nReport bugs to %s.\n", PACKAGE_BUGREPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +157,7 @@ static void print_help(void)
|
|||||||
#define LONGONLYOPT_VERSION 0
|
#define LONGONLYOPT_VERSION 0
|
||||||
#define LONGONLYOPT_HELP 1
|
#define LONGONLYOPT_HELP 1
|
||||||
#define LONGONLYOPT_POOL 2
|
#define LONGONLYOPT_POOL 2
|
||||||
|
#define LONGONLYOPT_FORCE 3
|
||||||
|
|
||||||
static int parse_cmdline(int argc, char *argv[])
|
static int parse_cmdline(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -158,10 +169,12 @@ static int parse_cmdline(int argc, char *argv[])
|
|||||||
{ "group", 1, 0, 'g' },
|
{ "group", 1, 0, 'g' },
|
||||||
{ "label", 1, 0, 'l' },
|
{ "label", 1, 0, 'l' },
|
||||||
{ "pool", 1, 0, LONGONLYOPT_POOL },
|
{ "pool", 1, 0, LONGONLYOPT_POOL },
|
||||||
|
{ "force", 0, 0, LONGONLYOPT_FORCE },
|
||||||
{ 0, 0, 0, 0 } };
|
{ 0, 0, 0, 0 } };
|
||||||
|
|
||||||
cmdl.print_version = false;
|
cmdl.print_version = false;
|
||||||
cmdl.print_help = false;
|
cmdl.print_help = false;
|
||||||
|
cmdl.force = false;
|
||||||
cmdl.command = 0;
|
cmdl.command = 0;
|
||||||
cmdl.slot = 0;
|
cmdl.slot = 0;
|
||||||
cmdl.drive = 0;
|
cmdl.drive = 0;
|
||||||
@ -198,6 +211,9 @@ static int parse_cmdline(int argc, char *argv[])
|
|||||||
case LONGONLYOPT_POOL:
|
case LONGONLYOPT_POOL:
|
||||||
cmdl.pool = optarg;
|
cmdl.pool = optarg;
|
||||||
break;
|
break;
|
||||||
|
case LONGONLYOPT_FORCE:
|
||||||
|
cmdl.force = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "unknown option %s\n", optarg);
|
fprintf(stderr, "unknown option %s\n", optarg);
|
||||||
return -1;
|
return -1;
|
||||||
@ -237,6 +253,11 @@ static int parse_cmdline(int argc, char *argv[])
|
|||||||
fprintf(stderr, "flag --pool not valid for this command\n");
|
fprintf(stderr, "flag --pool not valid for this command\n");
|
||||||
return -1;
|
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 */
|
/* Check param 3 exists */
|
||||||
++ndx;
|
++ndx;
|
||||||
if (ndx >= argc) {
|
if (ndx >= argc) {
|
||||||
@ -378,7 +399,7 @@ static int do_list_cmd()
|
|||||||
fprintf(stdout, "%d:%s\n", slot, changer.GetVolumeLabel(slot));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +411,7 @@ static int do_list_cmd()
|
|||||||
static int do_slots_cmd()
|
static int do_slots_cmd()
|
||||||
{
|
{
|
||||||
fprintf(stdout, "%d\n", changer.NumSlots());
|
fprintf(stdout, "%d\n", changer.NumSlots());
|
||||||
log.Info(" SUCCESS reporting %d slots", changer.NumSlots());
|
vlog.Info(" SUCCESS reporting %d slots", changer.NumSlots());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,10 +424,10 @@ static int do_load_cmd()
|
|||||||
{
|
{
|
||||||
if (changer.LoadDrive(cmdl.drive, cmdl.slot)) {
|
if (changer.LoadDrive(cmdl.drive, cmdl.slot)) {
|
||||||
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,10 +440,10 @@ static int do_unload_cmd()
|
|||||||
{
|
{
|
||||||
if (changer.UnloadDrive(cmdl.drive)) {
|
if (changer.UnloadDrive(cmdl.drive)) {
|
||||||
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,10 +458,11 @@ static int do_loaded_cmd()
|
|||||||
int slot = changer.GetDriveSlot(cmdl.drive);
|
int slot = changer.GetDriveSlot(cmdl.drive);
|
||||||
if (slot < 0) slot = 0;
|
if (slot < 0) slot = 0;
|
||||||
fprintf(stdout, "%d\n", slot);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
* LISTALL Command
|
* LISTALL Command
|
||||||
* Prints state of drives (loaded or empty), followed by state
|
* 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);
|
fprintf(stdout, "S:%d:E\n", n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Info(" SUCCESS sent listall to stdout");
|
vlog.Info(" SUCCESS sent listall to stdout");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,7 +509,7 @@ static int do_list_magazines()
|
|||||||
|
|
||||||
if (changer.NumMagazines() == 0) {
|
if (changer.NumMagazines() == 0) {
|
||||||
fprintf(stdout, "No magazines are defined\n");
|
fprintf(stdout, "No magazines are defined\n");
|
||||||
log.Info(" SUCCESS no magazines are defined");
|
vlog.Info(" SUCCESS no magazines are defined");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for (n = 0; n < changer.NumMagazines(); n++) {
|
for (n = 0; n < changer.NumMagazines(); n++) {
|
||||||
@ -498,10 +520,11 @@ static int do_list_magazines()
|
|||||||
changer.GetMagazineStartSlot(n), changer.GetMagazineMountpoint(n));
|
changer.GetMagazineStartSlot(n), changer.GetMagazineMountpoint(n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Info(" SUCCESS listing magazine info to stdout");
|
vlog.Info(" SUCCESS listing magazine info to stdout");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
* CREATEVOLS (Create Volumes) Command
|
* CREATEVOLS (Create Volumes) Command
|
||||||
* Creates volume files on the specified magazine
|
* Creates volume files on the specified magazine
|
||||||
@ -511,12 +534,12 @@ static int do_create_vols()
|
|||||||
/* Create new volume files on magazine */
|
/* Create new volume files on magazine */
|
||||||
if (changer.CreateVolumes(cmdl.mag_bay, cmdl.count, cmdl.slot, cmdl.label_prefix.c_str())) {
|
if (changer.CreateVolumes(cmdl.mag_bay, cmdl.count, cmdl.slot, cmdl.label_prefix.c_str())) {
|
||||||
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
||||||
log.Error(" ERROR");
|
vlog.Error(" ERROR: %s", changer.GetErrorMsg());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fprintf(stdout, "Created %d volume files on magazine %d\n",
|
fprintf(stdout, "Created %d volume files on magazine %d\n",
|
||||||
cmdl.count, cmdl.mag_bay);
|
cmdl.count, cmdl.mag_bay);
|
||||||
log.Info(" SUCCESS");
|
vlog.Info(" SUCCESS");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,13 +552,14 @@ int main(int argc, char *argv[])
|
|||||||
int rc;
|
int rc;
|
||||||
FILE *fs = NULL;
|
FILE *fs = NULL;
|
||||||
int32_t error_code;
|
int32_t error_code;
|
||||||
|
void *command_mux = NULL, *bconsole_mux = NULL;
|
||||||
|
|
||||||
#ifdef HAVE_LOCALE_H
|
#ifdef HAVE_LOCALE_H
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Log initially to stderr */
|
/* Log initially to stderr */
|
||||||
log.OpenLog(stderr, LOG_ERR);
|
vlog.OpenLog(stderr, LOG_ERR);
|
||||||
/* parse the command line */
|
/* parse the command line */
|
||||||
if ((error_code = parse_cmdline(argc, argv)) != 0) {
|
if ((error_code = parse_cmdline(argc, argv)) != 0) {
|
||||||
print_help();
|
print_help();
|
||||||
@ -551,6 +575,7 @@ int main(int argc, char *argv[])
|
|||||||
print_help();
|
print_help();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read vchanger config file */
|
/* Read vchanger config file */
|
||||||
if (!conf.Read(cmdl.config_file)) {
|
if (!conf.Read(cmdl.config_file)) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -573,89 +598,137 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stderr, "Error opening opening log file\n");
|
fprintf(stderr, "Error opening opening log file\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
log.OpenLog(fs, conf.log_level);
|
vlog.OpenLog(fs, conf.log_level);
|
||||||
}
|
}
|
||||||
/* Validate and commit configuration parameters */
|
/* Validate and commit configuration parameters */
|
||||||
if (!conf.Validate()) {
|
if (!conf.Validate()) {
|
||||||
|
fprintf(stderr, "ERROR! configuration file error\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#ifndef HAVE_WINDOWS_H
|
#ifndef HAVE_WINDOWS_H
|
||||||
/* Ignore SIGPIPE signals */
|
/* Ignore SIGPIPE signals */
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
#endif
|
#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
|
* to the changer. As a result, changer initialization may block
|
||||||
* for up to 30 seconds, and may fail if a timeout is reached */
|
* for up to 30 seconds, and may fail if a timeout is reached */
|
||||||
if (changer.Initialize()) {
|
if (changer.Initialize()) {
|
||||||
|
vlog.Error("%s", changer.GetErrorMsg());
|
||||||
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
fprintf(stderr, "%s\n", changer.GetErrorMsg());
|
||||||
|
mymutex_destroy("vchanger-command", command_mux);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform command */
|
/* Perform command */
|
||||||
switch (cmdl.command) {
|
switch (cmdl.command) {
|
||||||
case CMD_LIST:
|
case CMD_LIST:
|
||||||
log.Debug("==== preforming LIST command pid=%d", getpid());
|
vlog.Debug("==== preforming LIST command");
|
||||||
error_code = do_list_cmd();
|
error_code = do_list_cmd();
|
||||||
break;
|
break;
|
||||||
case CMD_SLOTS:
|
case CMD_SLOTS:
|
||||||
log.Debug("==== preforming SLOTS command pid=%d", getpid());
|
vlog.Debug("==== preforming SLOTS command");
|
||||||
error_code = do_slots_cmd();
|
error_code = do_slots_cmd();
|
||||||
break;
|
break;
|
||||||
case CMD_LOAD:
|
case CMD_LOAD:
|
||||||
log.Debug("==== preforming LOAD command pid=%d", getpid());
|
vlog.Debug("==== preforming LOAD command");
|
||||||
error_code = do_load_cmd();
|
error_code = do_load_cmd();
|
||||||
break;
|
break;
|
||||||
case CMD_UNLOAD:
|
case CMD_UNLOAD:
|
||||||
log.Debug("==== preforming UNLOAD command pid=%d", getpid());
|
vlog.Debug("==== preforming UNLOAD command");
|
||||||
error_code = do_unload_cmd();
|
error_code = do_unload_cmd();
|
||||||
break;
|
break;
|
||||||
case CMD_LOADED:
|
case CMD_LOADED:
|
||||||
log.Debug("==== preforming LOADED command pid=%d", getpid());
|
vlog.Debug("==== preforming LOADED command");
|
||||||
error_code = do_loaded_cmd();
|
error_code = do_loaded_cmd();
|
||||||
break;
|
break;
|
||||||
case CMD_LISTALL:
|
case CMD_LISTALL:
|
||||||
log.Debug("==== preforming LISTALL command pid=%d", getpid());
|
vlog.Debug("==== preforming LISTALL command");
|
||||||
error_code = do_list_all();
|
error_code = do_list_all();
|
||||||
break;
|
break;
|
||||||
case CMD_LISTMAGS:
|
case CMD_LISTMAGS:
|
||||||
log.Debug("==== preforming LISTMAGS command pid=%d", getpid());
|
vlog.Debug("==== preforming LISTMAGS command");
|
||||||
error_code = do_list_magazines();
|
error_code = do_list_magazines();
|
||||||
break;
|
break;
|
||||||
case CMD_CREATEVOLS:
|
case CMD_CREATEVOLS:
|
||||||
log.Debug("==== preforming CREATEVOLS command pid=%d", getpid());
|
vlog.Debug("==== preforming CREATEVOLS command");
|
||||||
error_code = do_create_vols();
|
error_code = do_create_vols();
|
||||||
break;
|
break;
|
||||||
case CMD_REFRESH:
|
case CMD_REFRESH:
|
||||||
log.Debug("==== preforming REFRESH command pid=%d", getpid());
|
vlog.Debug("==== preforming REFRESH command");
|
||||||
error_code = 0;
|
error_code = 0;
|
||||||
log.Info(" SUCCESS pid=%d", getpid());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
changer.Unlock();
|
|
||||||
|
|
||||||
/* If there was an error, then exit */
|
/* 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 */
|
/* If not updating Bacula, then exit */
|
||||||
|
#ifdef HAVE_WINDOWS_H
|
||||||
|
conf.bconsole = ""; /* Issuing bconsole commands not implemented on Windows */
|
||||||
|
#endif
|
||||||
if (conf.bconsole.empty()) {
|
if (conf.bconsole.empty()) {
|
||||||
/* Bacula interaction via bconsole is disabled, so log warnings */
|
/* Bacula interaction via bconsole is disabled, so log warnings */
|
||||||
if (changer.NeedsUpdate())
|
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())
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update Bacula via bconsole */
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of vchanger by Josh Fisher.
|
* 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.
|
* vchanger is free software.
|
||||||
* You may redistribute it and/or modify it under the terms of the
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
@ -45,26 +45,21 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_WINDOWS_H
|
#ifdef HAVE_WINDOWS_H
|
||||||
#include "targetver.h"
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SHLOBJ_H
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_DIRECT_H
|
||||||
#include <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
|
#endif
|
||||||
|
|
||||||
|
#include "compat_defs.h"
|
||||||
#include "loghandler.h"
|
#include "loghandler.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#define __VCONF_SOURCE 1
|
#define __VCONF_SOURCE 1
|
||||||
#include "vconf.h"
|
#include "vconf.h"
|
||||||
|
|
||||||
/* Global configuration object */
|
|
||||||
VchangerConfig conf;
|
|
||||||
|
|
||||||
/*-------------------------------------------
|
/*-------------------------------------------
|
||||||
* Config file keywords and defaults
|
* Config file keywords and defaults
|
||||||
@ -145,19 +140,19 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
|
|
||||||
tmp_ini.ClearKeywordValues();
|
tmp_ini.ClearKeywordValues();
|
||||||
if (!cfile || !cfile[0]) {
|
if (!cfile || !cfile[0]) {
|
||||||
log.Error("config file not specified");
|
vlog.Error("config file not specified");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Does config file exist */
|
/* Does config file exist */
|
||||||
if (access(cfile, R_OK)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
/* Read config file values */
|
/* Read config file values */
|
||||||
rc = tmp_ini.Read(cfile);
|
rc = tmp_ini.Read(cfile);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
if (rc > 0) log.Error("Parse error in %s at line %d", cfile, rc);
|
if (rc > 0) vlog.Error("Parse error in %s at line %d", cfile, rc);
|
||||||
else log.Error("could not open config file %s", cfile);
|
else vlog.Error("could not open config file %s", cfile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Update keyword values */
|
/* Update keyword values */
|
||||||
@ -168,7 +163,7 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
storage_name = (const char*)keyword[VK_STORAGE_NAME];
|
storage_name = (const char*)keyword[VK_STORAGE_NAME];
|
||||||
tStrip(storage_name);
|
tStrip(storage_name);
|
||||||
if (storage_name.empty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
/* Update defaults for this changer name */
|
/* Update defaults for this changer name */
|
||||||
@ -181,7 +176,7 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
work_dir = (const char*)keyword[VK_WORK_DIR];
|
work_dir = (const char*)keyword[VK_WORK_DIR];
|
||||||
tStrip(work_dir);
|
tStrip(work_dir);
|
||||||
if (work_dir.empty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,7 +186,7 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
logfile = (const char*)keyword[VK_LOGFILE];
|
logfile = (const char*)keyword[VK_LOGFILE];
|
||||||
tStrip(logfile);
|
tStrip(logfile);
|
||||||
if (logfile.empty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,7 +195,7 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
if (keyword[VK_LOG_LEVEL].IsSet()) {
|
if (keyword[VK_LOG_LEVEL].IsSet()) {
|
||||||
log_level = (int)keyword[VK_LOG_LEVEL];
|
log_level = (int)keyword[VK_LOG_LEVEL];
|
||||||
if (log_level < 0 || log_level > 7) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,7 +205,7 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
user = (const char*)keyword[VK_USER];
|
user = (const char*)keyword[VK_USER];
|
||||||
tStrip(user);
|
tStrip(user);
|
||||||
if (user.empty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +215,7 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
group = (const char*)keyword[VK_GROUP];
|
group = (const char*)keyword[VK_GROUP];
|
||||||
tStrip(group);
|
tStrip(group);
|
||||||
if (group.empty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,7 +237,7 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
def_pool = (const char*)keyword[VK_DEF_POOL];
|
def_pool = (const char*)keyword[VK_DEF_POOL];
|
||||||
tStrip(def_pool);
|
tStrip(def_pool);
|
||||||
if (def_pool.empty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,13 +247,13 @@ bool VchangerConfig::Read(const char *cfile)
|
|||||||
magazine = keyword[VK_MAGAZINE];
|
magazine = keyword[VK_MAGAZINE];
|
||||||
}
|
}
|
||||||
if (magazine.empty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
for (n = 0; n < (int)magazine.size(); n++) {
|
for (n = 0; n < (int)magazine.size(); n++) {
|
||||||
tStrip(magazine[n]);
|
tStrip(magazine[n]);
|
||||||
if (magazine[n].empty()) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,13 +278,13 @@ bool VchangerConfig::Validate()
|
|||||||
#else
|
#else
|
||||||
if (_mkdir(work_dir.c_str())) {
|
if (_mkdir(work_dir.c_str())) {
|
||||||
#endif
|
#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);
|
umask(old_mask);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
umask(old_mask);
|
umask(old_mask);
|
||||||
} else {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,7 +294,7 @@ bool VchangerConfig::Validate()
|
|||||||
if (!bconsole_config.empty()) {
|
if (!bconsole_config.empty()) {
|
||||||
if (access(bconsole_config.c_str(), R_OK)) {
|
if (access(bconsole_config.c_str(), R_OK)) {
|
||||||
/* If bconsole config doesn't exist or is not readable, disable use of bconsole */
|
/* 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.clear();
|
||||||
bconsole_config.clear();
|
bconsole_config.clear();
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of vchanger by Josh Fisher.
|
* 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.
|
* vchanger is free software.
|
||||||
* You may redistribute it and/or modify it under the terms of the
|
* You may redistribute it and/or modify it under the terms of the
|
||||||
@ -65,6 +65,7 @@ extern char DEFAULT_STATEDIR[4096];
|
|||||||
#else
|
#else
|
||||||
char DEFAULT_LOGDIR[4096];
|
char DEFAULT_LOGDIR[4096];
|
||||||
char DEFAULT_STATEDIR[4096];
|
char DEFAULT_STATEDIR[4096];
|
||||||
|
VchangerConfig conf;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _VCONF_H_ */
|
#endif /* _VCONF_H_ */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#................-
|
#................-
|
||||||
#. Date of creation: 2015-06-01
|
#. Date of creation: 2020-05-06
|
||||||
#. Name: installer.nsi
|
#. Name: installer.nsi
|
||||||
#................-
|
#................-
|
||||||
#..- Package parameters ...
|
#..- Package parameters ...
|
||||||
@ -9,7 +9,15 @@ SetCompressor lzma
|
|||||||
!include MUI2.nsh
|
!include MUI2.nsh
|
||||||
!include WinMessages.nsh
|
!include WinMessages.nsh
|
||||||
!include x64.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 ..
|
#... Installation Windows Parameters ..
|
||||||
!define APPNAME "vchanger"
|
!define APPNAME "vchanger"
|
||||||
!define COMPANYNAME "Josh Fisher"
|
!define COMPANYNAME "Josh Fisher"
|
||||||
@ -17,20 +25,20 @@ SetCompressor lzma
|
|||||||
# These three must be integers
|
# These three must be integers
|
||||||
!define VERSIONMAJOR 1
|
!define VERSIONMAJOR 1
|
||||||
!define VERSIONMINOR 0
|
!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"
|
# 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
|
!define HELPURL "http://sourceforge.net/projects/vchanger/" # "Support Information" link
|
||||||
Name "vchanger 1.0.1"
|
Name "vchanger 1.0.3"
|
||||||
VIProductVersion "1.0.1.0"
|
VIProductVersion "1.0.3.0"
|
||||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "vchanger Installer"
|
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} "FileDescription" "vchanger Windows Installer"
|
||||||
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "1.0.1"
|
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "1.0.3"
|
||||||
ShowInstDetails nevershow
|
ShowInstDetails nevershow
|
||||||
SilentInstall normal
|
SilentInstall normal
|
||||||
RequestExecutionLevel admin
|
RequestExecutionLevel admin
|
||||||
AutoCloseWindow True
|
AutoCloseWindow True
|
||||||
OutFile "vchanger-1.0.1.exe"
|
OutFile "vchanger-1.0.3.exe"
|
||||||
|
|
||||||
PageEx license
|
PageEx license
|
||||||
LicenseData "license.txt"
|
LicenseData "license.txt"
|
||||||
@ -121,13 +129,13 @@ Function .onInit
|
|||||||
SetShellVarContext all
|
SetShellVarContext all
|
||||||
#Determine the bitness of the OS and enable the correct section
|
#Determine the bitness of the OS and enable the correct section
|
||||||
${If} ${RunningX64}
|
${If} ${RunningX64}
|
||||||
SectionSetFlags SEC0001 ${SECTION_OFF}
|
SectionSetFlags ${SEC0001} ${SECTION_OFF}
|
||||||
SectionSetFlags SEC0002 ${SF_SELECTED}
|
SectionSetFlags ${SEC0002} ${SF_SELECTED}
|
||||||
StrCpy $INSTDIR "$PROGRAMFILES64\vchanger"
|
StrCpy $INSTDIR "$PROGRAMFILES64\vchanger"
|
||||||
SetRegView 64
|
SetRegView 64
|
||||||
${Else}
|
${Else}
|
||||||
SectionSetFlags SEC0002 ${SECTION_OFF}
|
SectionSetFlags ${SEC0002} ${SECTION_OFF}
|
||||||
SectionSetFlags SEC0001 ${SF_SELECTED}
|
SectionSetFlags ${SEC0001} ${SF_SELECTED}
|
||||||
StrCpy $INSTDIR "$PROGRAMFILES32\vchanger"
|
StrCpy $INSTDIR "$PROGRAMFILES32\vchanger"
|
||||||
SetRegView 32
|
SetRegView 32
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#
|
#
|
||||||
# Build for 32-bit and 64-bit Windows binary and create NSIS installer
|
# 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-$VERS.exe
|
||||||
rm -f ./win32/vchanger.exe
|
rm -f ./win32/vchanger.exe
|
||||||
rm -f ./win32/vchanger64.exe
|
rm -f ./win32/vchanger64.exe
|
||||||
|
Loading…
x
Reference in New Issue
Block a user