%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% module #include "dk4conf.h" #include #if DK4_ON_WINDOWS #ifndef WINDOWS_H_INCLUDED #include #define WINDOWS_H_INCLUDED 1 #endif #endif #if DK4_HAVE_STDLIB_H #ifndef STDLIB_H_INCLUDED #include #define STDLIB_H_INCLUDED 1 #endif #endif #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SIGNAL_H #ifndef SIGNAL_H_INCLUDED #include #define SIGNAL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_PROCESS_H #ifndef PROCESS_H_INCLUDED #include #define PROCESS_H_INCLUDED 1 #endif #endif #if DK4_HAVE_IO_H #ifndef IO_H_INCLUDED #include #define IO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_FCNTL_H #ifndef FCNTL_H_INCLUDED #include #define FCNTL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_ERRNO_H #ifndef ERRNO_H_INCLUDED #include #define ERRNO_H_INCLUDED 1 #endif #endif #if DK4_TIME_WITH_SYS_TIME #ifndef SYS_TIME_H_INCLUDED #include #define SYS_TIME_H_INCLUDED 1 #endif #ifndef TIME_H_INCLUDED #include #define TIME_H_INCLUDED 1 #endif #else #if DK4_HAVE_TIME_H #ifndef TIME_H_INCLUDED #include #define TIME_H_INCLUDED 1 #endif #else #if DK4_HAVE_SYS_TIME_H #ifndef SYS_TIME_H_INCLUDED #include #define SYS_TIME_H_INCLUDED 1 #endif #endif #endif #endif #include "dk4types.h" #include "dk4const.h" #include "dk4mem.h" #include "dk4app.h" #include "dk4vers.h" #include "dk4fput.h" #include "dk4str8.h" #include "dk4strd.h" #include "dk4enc.h" #include "dk4tsp08.h" #include "dk4tspdk.h" #include "dk4mai8dus.h" #include "dk4mai8ddu.h" #include "dk4maidddu.h" #include "dk4mao8d.h" #include "dk4maodd.h" #include "dk4fopda.h" #include "dk4isadm.h" #include "dk4timec.h" #include "dk4time08.h" #include "dk4aopt.h" #include "dk4mpl.h" #include "dk4pathd.h" $!trace-include /** Information about one media. */ typedef struct { unsigned short year; /**< Year of last backup. */ unsigned short month; /**< Month of last backup. */ unsigned short day; /**< Day within month of last backup. */ unsigned short hour; /**< Hour of last backup. */ unsigned short minute; /**< Minute of last backup. */ unsigned short second; /**< Second of last backup. */ unsigned short times; /**< How many times was the media used. */ } dk_bmm_media_t; /** Line handler object. */ typedef struct { int *backptr; /**< Address of result variable. */ } dk_bmm_lh_obj_t; /** Help text shown if no help text file found. */ static const dkChar * const dk_bmm_help_text[] = { $!text macro=dkT Backup media management dk-bmm [] [] Options: -s --set Use media sets instead of media. -c --confirm Confirm success for backup. -r --report Create tape usage report. --help Show this short help text. --manual *** SHOW FULL MANUAL. *** --version Show version information. --license Show version information. Typical operations: dk-bmm -s Find name of current backup set. dk-bmm Find number of current media in set. dk-bmm -c Confirm successful backup to current media. dk-bmm -c -s Confirm successful backup for current set. http://dktools.sourceforge.net $!end }; /** License conditions. */ static const dkChar * const dk_bmm_license_text[] = { $!text macro=dkT,preprocessor This software uses code from the following projects, either directly or as a library: dktools Dirk Krause's tools and libraries. See http://dktools.sourceforge.net/ for more information. #if DK4_HAVE_ZLIB_H zlib Data compression library. See http://www.zlib.net/ for more information. #endif #if DK4_HAVE_BZLIB_H bzip2 Data compression program and library. See http://www.bzip.org/ for more information. #endif All the licenses below apply to the program. Licenses for used libraries are shown as found on my Scientific Linux 6.x computer in the /usr/share/doc directory on 2015-04-01. Check the project homepages of the used libraries for additional information and/or updated license terms. DK tools and libraries license ============================== Copyright (c) 2015-2016, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if DK4_HAVE_ZLIB_H Zlib license ============ (C) 1995-2004 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu #endif #if DK4_HAVE_BZLIB_H Bzip2 and libbzip2 library license ================================== This program, "bzip2", the associated library "libbzip2", and all documentation, are copyright (C) 1996-2007 Julian R Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Julian Seward, jseward@bzip.org bzip2/libbzip2 version 1.0.5 of 10 December 2007 #endif $!end }; /** Buffer to save set names line. */ static dkChar dk_bmm_set_line[1024]; /** Buffer for reading the line. */ static dkChar dk_bmm_set_buffer[1024]; /** Pointers to all the set names. */ static dkChar *dk_bmm_set_names[512]; /** Constant text keywords used by the program, not localized. */ static const dkChar * const dk_bmm_kwnl[] = { $!string-table macro=dkT # # 0 Program group name # dktools # # 1 Help text file name # dk-bmm.txt # # 2 String table file name # dk-bmm.str # # 3 Path separator for Windows # \\ # # 4 File open mode: Read binary. # rb # # 5 File open mode: Write # w $!end }; /** Constant text keywords used by the program, localized. */ static const dkChar * const dk_bmm_kw_def[] = { $!string-table macro=dkT # # 0 Error: Failed to set up signal handlers! # Failed to set up signal handlers! # # 1 Error: Failed to restore signal handlers! # Failed to restore signal handlers! # # 2 Error: Write attempt to standard output failed! # Write attempt to standard output failed! # # 3 Error: SIGPIPE signal received! # SIGPIPE signal received! # # 4 Error: Aborted by SIGINT signal! # Aborted by SIGINT signal! # # 5 Error: Aborted by SIGTERM signal! # Aborted by SIGTERM signal! # # 6 Hint: Tape was not used in this cycle yet. # (previous cycle) # # 7 Text: Media number for next backup # Media number for next backup: # # 8 ERROR: Option -r is not available for a set names file. # Option -r is not available for a set names file. # # 9 ERROR: Failed to read file, probably not a dk-bmm file! # Failed to read file, probably not a dk-bmm file! # # 10 ERROR: Exactly one file name allowed! # Exactly one file name allowed! # # 11 Info: Cycle completed, please renew media set! # Cycle completed, please renew media set! # # 12 # Failed to write new set file! # # 13 # Not a set names file! $!end }; /** Options understood by the program. */ static const dk4_option_specification_t dk_bmm_options[] = { /* Process media sets, not media. */ { dkT('s'), dkT("set"), DK4_OPT_ARG_NONE }, /* Confirm previously requested media set or media. */ { dkT('c'), dkT("confirm"), DK4_OPT_ARG_NONE }, /* Report media. */ { dkT('r'), dkT("report"), DK4_OPT_ARG_NONE }, }; /** Media numbers in order of usage. This implements the 10 tape rotation scheme. At every time we will have backups of different ages. During 200 backups each of the 10 media is used 20 times. */ static const unsigned char dk_bmm_media_numbers[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4, 6, 1, 2, 3, 4, 7, 1, 2, 3, 4, 8, 2, 3, 4, 5, 6, 2, 3, 4, 5, 7, 2, 3, 4, 5, 8, 2, 3, 4, 5, 9, 3, 4, 5, 6, 7, 3, 4, 5, 6, 8, 3, 4, 5, 6, 9, 3, 4, 5, 6, 10, 4, 5, 6, 7, 8, 4, 5, 6, 7, 9, 4, 5, 6, 7, 10, 4, 5, 6, 7, 1, 5, 6, 7, 8, 9, 5, 6, 7, 8, 10, 5, 6, 7, 8, 1, 5, 6, 7, 8, 2, 6, 7, 8, 9, 10, 6, 7, 8, 9, 1, 6, 7, 8, 9, 2, 6, 7, 8, 9, 3, 7, 8, 9, 10, 1, 7, 8, 9, 10, 2, 7, 8, 9, 10, 3, 7, 8, 9, 10, 4, 8, 9, 10, 1, 2, 8, 9, 10, 1, 3, 8, 9, 10, 1, 4, 8, 9, 10, 1, 5, 9, 10, 1, 2, 3, 9, 10, 1, 2, 4, 9, 10, 1, 2, 5, 9, 10, 1, 2, 6, 10, 1, 2, 3, 4, 10, 1, 2, 3, 5, 10, 1, 2, 3, 6, 10, 1, 2, 3, 7 }; /** Information for the 10 media in the backup scheme. */ static dk_bmm_media_t media_info[10]; /** Flag: Media found for recoding. */ static unsigned short media_found[10]; /** Pointer to either localized messages or default texts. */ static const dkChar * const *dk_bmm_msg = dk_bmm_kw_def; /** Application structure for diagnostics. */ static dk4_app_t *app = NULL; /** Number of used names in dk_bmm_set_names. */ static size_t dk_bmm_n_set_names = 0; /** Number of elements in the dk_bmm_options array. */ static const size_t dk_bmm_sz_options = sizeof(dk_bmm_options)/sizeof(dk4_option_specification_t); /** Number of elements in the dk_bmm_msg array. */ static size_t dk_bmm_sz_msg = sizeof(dk_bmm_kw_def)/sizeof(DK4_PCDKCHAR) - 1; /** Exit status code of the program. */ static int exval = EXIT_FAILURE; /** Flag: Dealing with media set. */ static int dk_bmm_handle_set = 0; /** Flag: Confirm previous media or set. */ static int dk_bmm_do_confirm = 0; /** Flag: Write report. */ static int dk_bmm_do_report = 0; /** Flag: Output mode for stdout was changed. */ static int dk_bmm_mod_stdout = 0; /** Number of recent day within backup cycle. */ static int dk_bmm_day_in_cycle = 0; /** Flag: Cycle was completed. */ static int dk_bmm_cycle_completed = 0; /** Flag: Write attempt to stdout failed. */ static int output_error = 0; #ifdef SIGPIPE /** Indicator: SIGPIPE signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_pipe = 0; #endif /** Indicator: SIGINT signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_int = 0; /** Indicator: SIGTERM signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_term = 0; static DK4_VOLATILE dk4_sig_atomic_t * sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr) { return ptr; } #ifdef SIGPIPE /** Handler for SIGPIPE signal. @param signo Signal number (always SIGPIPE, ignored). */ static void sig_handler_pipe(int signo) { *sig_pass_pointer(&sig_had_pipe) = 1; } #endif /** Handler for SIGINT signal. @param signo Signal number (always SIGINT, ignored). */ static void sig_handler_int(int signo) { *sig_pass_pointer(&sig_had_int) = 1; } /** Handler for SIGTERM signal. @param signo Signal number (always SIGTERM, ignored). */ static void sig_handler_term(int signo) { *sig_pass_pointer(&sig_had_term) = 1; } /** Read value from volatile atomic type. This function is necessary as some compilers mis-optimize direct access to volatile variables (at least if you believe one of the coding standards). @param ap Pointer to volatile atomic variable. @return Contents of the variable. */ static dk4_sig_atomic_t sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap) { return (*ap); } /** Check whether we can continue or if a signal was received. @param check_pipe Flag: Check for occured SIGPIPE signal too. @return 1 if the program can continue, 0 if a signal was received. */ static int sig_can_continue(int check_pipe) { int back = 1; #ifdef SIGPIPE if (0 != check_pipe) { if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; } } #endif if (0 != sig_read_atomic(&sig_had_int )) { back = 0; } if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } return back; } /** Check whether we can continue. @return 1 for yes, 0 for no. */ static int dk_bmm_can_continue(void) { int back = 1; if (0 == sig_can_continue(1)) { back = 0; } return back; } /** Handler function for text lines. @param obj Object to modify while processing the character. @param line Text line to process. @param lineno Current line number. @param erp Error report, may be NULL. @return DK4_TSP_RES_OK if the character was processed successfully, DK4_TSP_RES_ERROR if there was an error but we can continue, DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ static int dk_bmm_sets_line_handler( void *obj, dkChar *line, dk4_um_t lineno, dk4_er_t *erp ) { dk_bmm_lh_obj_t *lhoptr; dkChar *p1; const dkChar *pe; dk4_um_t um; size_t i; size_t al; int res; int back = DK4_TSP_RES_FATAL; $? "+ dk_bmm_sets_line_handler %lu", (unsigned long)lineno lhoptr = (dk_bmm_lh_obj_t *)obj; if ((dk4_um_t)1UL == lineno) { $? ". first line" dk4str_delnl(line); res = dk4str_cpy_s( dk_bmm_set_line, DK4_SIZEOF(dk_bmm_set_line,dkChar), line, NULL ); if (0 != res) { al = sizeof(dk_bmm_set_names)/sizeof(DK4_PDKCHAR); for (i = 0; i < al; i++) { dk_bmm_set_names[i] = NULL; } i = dk4str_tokenize(dk_bmm_set_names, al, dk_bmm_set_line, NULL, NULL); if (0 < i) { dk_bmm_n_set_names = i; back = DK4_TSP_RES_OK; } } } else { if ((dk4_um_t)2UL == lineno) { $? ". second line" dk4str_delnl(line); p1 = dk4str_start(line, NULL); if (NULL != p1) { pe = NULL; um = (dk4_um_t)0UL; res = dk4ma_input_dk_dec_dk4_um_t( &um, p1, &pe, 1, NULL ); if (0 != res) { if ((dk4_um_t)INT_MAX >= um) { dk_bmm_day_in_cycle = (int)um; if ((dk4_um_t)dk_bmm_n_set_names > dk_bmm_day_in_cycle) { back = DK4_TSP_RES_OK; } } } } else { back = DK4_TSP_RES_OK; } } else { $? "! other line" } } if ((DK4_TSP_RES_FATAL == back) || (DK4_TSP_RES_ERROR == back)) { *(lhoptr->backptr) = 0; } $? "- dk_bmm_sets_line_handler %d", back return back; } /** Read sets file. @param filename Name of file to read. @return 1 on success, 0 on error. */ static int dk_bmm_read_sets_file(const dkChar *filename) { dk4_er_t er; dk4_tspdk_t tspdk; dk_bmm_lh_obj_t lhoptr; FILE *fipo; int res; int c; int cc = 1; int back = 0; $? "+ dk_bmm_read_sets_file \"%!ds\"", filename fipo = dk4fopen_app(filename, dk_bmm_kwnl[4], DK4_FOPEN_SC_IS_REGULAR, app); if (NULL != fipo) { lhoptr.backptr = &back; dk4error_init(&er); res = dk4tspdk_setup_line( &tspdk, &lhoptr, dk_bmm_sets_line_handler, dk_bmm_set_buffer, DK4_SIZEOF(dk_bmm_set_buffer,dkChar), dk4app_get_encoding(app), dk4app_get_file_in_encoding(app), &er ); if (0 != res) { back = 1; while (1 == cc) { if (0 != dk_bmm_can_continue()) { c = fgetc(fipo); if (EOF != c) { if (0 != feof(fipo)) { cc = 0; } res = dk4tspdk_add_one_byte(&tspdk, (unsigned char)c); switch (res) { case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: { cc = -1; } break; } } else { cc = 0; } } else { cc = -1; } } if (0 == cc) { res = dk4tspdk_finish(&tspdk); switch (res) { case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: { back = 0; } break; } } else { back = 0; } } else { /* ERROR: Failed to set up line processing, bug */ } fclose(fipo); } $? "- dk_bmm_read_sets_file %d", back return back; } /** Initialize the media_info structures. */ static void dk_bmm_initialize_media_info(void) { size_t i; for (i = 0; i < 10; i++) { media_info[i].year = media_info[i].month = media_info[i].day = media_info[i].hour = media_info[i].minute = media_info[i].second = media_info[i].times = 0U; } } static int dk_bmm_data_line(dk_bmm_media_t *mptr, char *line) { const char *ep; int back = 0; $? "+ dk_bmm_data_line \"%!8s\"", line if (21 > dk4str8_len(line)) { $? "! line too short" goto finished; } if ('-' != line[4]) { $? "! separator year month" goto finished; } line[4] = '\0'; if ('-' != line[7]) { $? "! separator month day" goto finished; } line[7] = '\0'; if (' ' != line[10]) { $? "! separator day hour" goto finished; } line[10] = '\0'; if (':' != line[13]) { $? "! separator hour minute" goto finished; } line[13] = '\0'; if (':' != line[16]) { $? "! separator minute second" goto finished; } line[16] = '\0'; if (' ' != line[19]) { $? "! separator second times" goto finished; } line[19] = '\0'; ep = NULL; if (0 == dk4ma_input_c8_dec_ushort(&(mptr->year), line, &ep, 0, NULL)) { $? "! year" goto finished; } if (0 == dk4ma_input_c8_dec_ushort(&(mptr->month),&(line[5]),&ep,0,NULL)) { $? "! month" goto finished; } if (0 == dk4ma_input_c8_dec_ushort(&(mptr->day),&(line[8]),&ep,0,NULL)) { $? "! day" goto finished; } if (0 == dk4ma_input_c8_dec_ushort(&(mptr->hour),&(line[11]),&ep,0,NULL)) { $? "! hour" goto finished; } if (0 == dk4ma_input_c8_dec_ushort(&(mptr->minute),&(line[14]),&ep,0,NULL)) { $? "! minute" goto finished; } if (0 == dk4ma_input_c8_dec_ushort(&(mptr->second),&(line[17]),&ep,0,NULL)) { $? "! second" goto finished; } if (0 == dk4ma_input_c8_dec_ushort(&(mptr->times),(&line[20]),&ep,0,NULL)) { $? "! times" goto finished; } back = 1; finished: $? "- dk_bmm_data_line %d", back return back; } /** Handler function for text lines. @param obj Object to modify while processing the character. @param line Text line to process. @param lineno Current line number. @param erp Error report, may be NULL. @return DK4_TSP_RES_OK if the character was processed successfully, DK4_TSP_RES_ERROR if there was an error but we can continue, DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ static int dk_bmm_media_line_handler( void *obj, char *line, dk4_um_t lineno, dk4_er_t *erp ) { dk4_er_t er; dk_bmm_lh_obj_t *lhoptr; const char *endptr = NULL; dk4_um_t um; int res; int back = DK4_TSP_RES_FATAL; $? "+ dk_bmm_media_line_handler %lu \"%!8s\"", (unsigned long)lineno, line lhoptr = (dk_bmm_lh_obj_t *)obj; dk4str8_delnl(line); if ((dk4_um_t)1UL == lineno) { $? ". first line" /* Process first line */ dk4error_init(&er); res = dk4ma_input_c8_dec_dk4_um_t(&um, line, &endptr, 1, &er); if (0 != res) { if ((dk4_um_t)200UL > um) { dk_bmm_day_in_cycle = (int)um; back = DK4_TSP_RES_OK; } else { /* ERROR: Out of range */ } } else { /* ERROR: Failed to read number */ } } else { if (((dk4_um_t)2UL <= lineno) && ((dk4_um_t)11UL >= lineno)) { /* Process data line */ lineno -= (dk4_um_t)2UL; $? ". media line" if (0 != dk_bmm_data_line(&(media_info[(size_t)lineno]), line)) { back = DK4_TSP_RES_OK; } else { /* ERROR: Syntax */ } } else { $? ". too many lines" /* ERROR: Syntax, too many lines */ } } if (DK4_TSP_RES_OK != back) { *(lhoptr->backptr) = 0; } $? "- dk_bmm_media_line_handler %d", back return back; } /** Read media file. @param filename Name of media file to read. @return 1 on success, 0 on error. */ static int dk_bmm_read_media_file(const dkChar *filename) { char inb[256]; dk4_tsp08_t tsp08; dk4_er_t er; dk_bmm_lh_obj_t obj; FILE *fipo = NULL; int c; int res; int cc = 1; int back = 0; $? "+ dk_bmm_read_media_file \"%!ds\"", filename obj.backptr = &back; fipo = dk4fopen_app(filename, dk_bmm_kwnl[4], DK4_FOPEN_SC_IS_REGULAR, app); if (NULL != fipo) { dk4error_init(&er); res = dk4tsp08_setup_line( &tsp08, &obj, dk_bmm_media_line_handler, inb, sizeof(inb), DK4_ENCODING_ASCII, dk4app_get_file_in_encoding(app), &er ); if (0 != res) { back = 1; while (1 == cc) { if (0 != dk_bmm_can_continue()) { c = fgetc(fipo); if (EOF != c) { if (0 != feof(fipo)) { cc = 0; } res = dk4tsp08_add_one_byte(&tsp08, (unsigned char)c); switch (res) { case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: { cc = -1; /* ERROR: Processing one byte failed */ } break; } } else { cc = 0; } } else { cc = -1; } } if (0 == cc) { res = dk4tsp08_finish(&tsp08); switch (res) { case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: { back = 0; /* ERROR: Completing failed */ } break; } } else { back = 0; } } else { /* ERROR: Failed to set up line processing */ } fclose(fipo); } else { back = 1; } $? "- dk_bmm_read_media_file %d", back return back; } static void dk_bmm_show_current_media_number(void) { char buf[16*sizeof(dk4_um_t)]; int res; unsigned char uc; uc = dk_bmm_media_numbers[dk_bmm_day_in_cycle]; res = dk4ma_write_c8_decimal_unsigned( buf, sizeof(buf), (dk4_um_t)uc, 0, NULL ); if (0 != res) { if (EOF == fputs(buf, stdout)) { output_error = 1; } if (EOF == fputc('\n', stdout)) { output_error = 1; } fflush(stdout); } else { /* ERROR: Failed to convert number, bug as buffer size is large enough. */ exval = EXIT_FAILURE; } } static void dk_bmm_update_media_info(dk_bmm_media_t *mptr) { #if DK4_ON_WINDOWS SYSTEMTIME st; GetLocalTime(&st); mptr->year = st.wYear; mptr->month = st.wMonth; mptr->day = st.wDay; mptr->hour = st.wHour; mptr->minute = st.wMinute; mptr->second = st.wSecond; #else time_t timer; struct tm *tm; time(&timer); tm = localtime(&timer); if (NULL != tm) { mptr->year = 1900 + tm->tm_year; mptr->month = 1 + tm->tm_mon; mptr->day = tm->tm_mday; mptr->hour = tm->tm_hour; mptr->minute = tm->tm_min; mptr->second = tm->tm_sec; } #endif mptr->times += 1; } static int dk_bmm_switch_to_next(const dkChar *filename) { char buf[128]; FILE *fipo; size_t mediano; int tests; int res; int back = 0; $? "+ dk_bmm_switch_to_next" mediano = (size_t)(dk_bmm_media_numbers[dk_bmm_day_in_cycle]); $? ". mediano = %lu", (unsigned long)mediano dk_bmm_update_media_info(&(media_info[mediano - 1])); if (++dk_bmm_day_in_cycle >= 200) { $? ". cycle completed" dk_bmm_day_in_cycle = 0; dk_bmm_cycle_completed = 1; for (mediano = 0; mediano < 10; mediano++) { media_info[mediano].times = 0; } } tests = DK4_FOPEN_SC_USER; if (1 == dk4isadmin()) { tests = DK4_FOPEN_SC_PRIVILEGED; } fipo = dk4fopen_app(filename, dk_bmm_kwnl[5], tests, app); if (NULL != fipo) { $? ". file opened" back = 1; res = dk4ma_write_c8_decimal_signed( buf, sizeof(buf), (dk4_im_t)dk_bmm_day_in_cycle, 0, NULL ); if (0 != res) { $? ". day in cycle: %!8s", buf if (EOF == fputs(buf, fipo)) { back = 0; } if (EOF == fputc('\n', fipo)) { back = 0; } } else { back = 0; } for (mediano = 0; mediano < 10; mediano++) { res = dk4time_to_text_c8( buf, sizeof(buf), DK4_TIMEFORMAT_DATE_TIME, media_info[mediano].year, media_info[mediano].month, media_info[mediano].day, media_info[mediano].hour, media_info[mediano].minute, media_info[mediano].second, NULL ); if (0 != res) { $? ". media %u text %!8s", (unsigned)mediano,buf if (EOF == fputs(buf, fipo)) { back = 0; } if (EOF == fputc(' ', fipo)) { back = 0; } res = dk4ma_write_c8_decimal_unsigned( buf, sizeof(buf), (dk4_um_t)(media_info[mediano].times), 0, NULL ); if (0 != res) { if (EOF == fputs(buf, fipo)) { back = 0; } } else { back = 0; } if (EOF == fputc('\n', fipo)) { back = 0; } } else { back = 0; } } if (0 != fclose(fipo)) { back = 0; } if (0 == back) { exval = EXIT_FAILURE; } } else { $? "! fopen failed" exval = EXIT_FAILURE; } $? "- dk_bmm_switch_to_next %d", back return back; } /** Write a report of used media. */ static void dk_bmm_report_media(void) { dkChar b1[16*sizeof(dk4_um_t)]; dkChar b3[16*sizeof(dk4_um_t)]; char b2[128]; char *ptr; size_t i; size_t j; size_t mediano; int res; unsigned short nextlevel = 1; for (i = 0; i < 10; i++) { media_found[i] = 0; } if (0 < dk_bmm_day_in_cycle) { for (i = 0; i < (size_t)dk_bmm_day_in_cycle; i++) { j = (size_t)dk_bmm_day_in_cycle - 1 - i; mediano = (size_t)(dk_bmm_media_numbers[j]); if (0 == media_found[mediano - 1]) { media_found[mediano - 1] = nextlevel++; $? ". mediano %u level %u", (unsigned)mediano, (unsigned)nextlevel } } } for (i = (size_t)dk_bmm_day_in_cycle; i < 200; i++) { j = 199 - i; mediano = (size_t)(dk_bmm_media_numbers[j]); if (0 == media_found[mediano - 1]) { media_found[mediano - 1] = nextlevel++; $? ". mediano %u level %u", (unsigned)mediano, (unsigned)nextlevel } } dk_bmm_mod_stdout = 1; $? ". mod stdout" dk4fput_initialize_stdout(); res = dk4ma_write_decimal_unsigned( b1, DK4_SIZEOF(b1,dkChar), (dk4_um_t)(dk_bmm_media_numbers[dk_bmm_day_in_cycle]), 0, NULL ); if (0 != res) { if (0 == dk4fputs(dk_bmm_kw_def[7], stdout, NULL)) { output_error = 1; } if (0 == dk4fputs(b1, stdout, NULL)) { output_error = 1; } if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { output_error = 1; } } else { /* ERROR: Number conversion failed, bug as buffer is large enough. */ exval = EXIT_FAILURE; } for (i = 1; i < 11; i++) { for (mediano = 1; mediano < 11; mediano++) { if (media_found[mediano - 1] == i) { res = dk4ma_write_decimal_unsigned( b1, DK4_SIZEOF(b1,dkChar), (dk4_um_t)mediano, 2, NULL ); if (0 != res) { res = dk4time_to_text_c8( b2, sizeof(b2), DK4_TIMEFORMAT_DATE_TIME, media_info[mediano - 1].year, media_info[mediano - 1].month, media_info[mediano - 1].day, media_info[mediano - 1].hour, media_info[mediano - 1].minute, media_info[mediano - 1].second, NULL ); if (0 != res) { res = dk4ma_write_decimal_unsigned( b3, DK4_SIZEOF(b3,dkChar), (dk4_um_t)(media_info[mediano - 1].times), 2, NULL ); if (0 != res) { if (0 == dk4fputs(b1, stdout, NULL)) { output_error = 1; } for (j = 0; j < 3; j++) { if (0 == dk4fputc(dkT(' '), stdout, NULL)) { output_error = 1; } } ptr = b2; while ('\0' != *ptr) { if (0 == dk4fputc((dkChar)(*(ptr++)), stdout, NULL)) { output_error = 1; } } for (j = 0; j < 3; j++) { if (0 == dk4fputc(dkT(' '), stdout, NULL)) { output_error = 1; } } if (0 == dk4fputs(b3, stdout, NULL)) { output_error = 1; } if (0 == media_info[mediano - 1].times) { if (0 == dk4fputs(dk_bmm_kw_def[6], stdout, NULL)) { output_error = 1; } } if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { output_error = 1; } } else { /* ERROR: Number conversion failed, bug. */ exval = EXIT_FAILURE; } } else { /* ERROR: Date and time conversion failed, bug. */ exval = EXIT_FAILURE; } } else { /* ERROR: Number conversion failed, bug. */ exval = EXIT_FAILURE; } } } } } static void dk4_bmm_write_set_file(const dkChar *filename) { dkChar buf[16*sizeof(dk4_um_t)]; const dkChar *oldsourcefile; FILE *fipo = NULL; dk4_um_t oldsourceline; size_t i; int res; int we = 0; int tests = DK4_FOPEN_SC_USER; $? "+ dk4_bmm_write_set_file \"%!ds\"", filename if (1 == dk4isadmin()) { tests = DK4_FOPEN_SC_PRIVILEGED; } fipo = dk4fopen_app(filename, dk_bmm_kwnl[5], tests, app); if (NULL != fipo) { $? ". file opened" dk4fput_initialize_file(fipo); for (i = 0; i < dk_bmm_n_set_names; i++) { if (0 != i) { if (0 == dk4fputc(dkT(' '), fipo, NULL)) { we = 1; $? "! write error" } } if (0 == dk4fputs(dk_bmm_set_names[i], fipo, NULL)) { we = 1; $? "! write error" } } if (0 == dk4fputc(dkT('\n'), fipo, NULL)) { $? "! write error" we = 1; } res = dk4ma_write_decimal_unsigned( buf, DK4_SIZEOF(buf,dkChar), (dk4_um_t)dk_bmm_day_in_cycle, 0, NULL ); if (0 != res) { if (0 == dk4fputs(buf, fipo, NULL)) { $? "! write error" we = 1; } if (0 == dk4fputc(dkT('\n'), fipo, NULL)) { $? "! write error" we = 1; } } else { $? "! conversion" /* ERROR: Number conversion failed, bug */ exval = EXIT_FAILURE; } if (0 != fclose(fipo)) { $? "! write error" we = 1; } if (0 != we) { /* ERROR: Writing to file failed */ oldsourcefile = dk4app_get_log_source_file(app); oldsourceline = dk4app_get_log_source_line(app); dk4app_set_log_source_file(app, filename); dk4app_set_log_source_line(app, (dk4_um_t)0UL); dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 12); dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); exval = EXIT_FAILURE; } } else { exval = EXIT_FAILURE; } $? "- dk4_bmm_write_set_file" } #if DK4_CHAR_SIZE > 1 /** Check whether a string can be written using 8 bit character width. @param str String to test. @return 1 on success, 0 on error. */ static int dk_bmm_can_write_8bit(const dkChar *str) { #if DK4_CHAR_SIZE > 1 #if DK4_CHAR_SIZE > 2 int back = 1; $? "+ dk_bmm_can_write_8bit 4" while ((dkT('\0') != *str) && (1 == back)) { if (dkC32(0xFF) < *str) { back = 0; } str++; } $? "- dk_bmm_can_write_8bit %d", back return back; #else dk4_utf16_decoder_t dec; dk4_c32_t c32; int back = 1; $? "+ dk_bmm_can_write_8bit 2" dk4utf16_init(&dec); while((dkT('\0') != *str) && (1 == back)) { switch (dk4utf16_add(&dec, *str)) { case DK4_EDSTM_FINISHED: { c32 = dk4utf16_get(&dec); if (dkC32(0x7F) < c32) { back = 0; } } break; case DK4_EDSTM_ERROR: { back = 0; } break; } str++; } if (1 == back) { if (0 == dk4utf16_is_empty(&dec)) { back = 0; } } $? "- dk_bmm_can_write_8bit %d", back return back; #endif #else $? "= dk_bmm_can_write_8bit 1 1" return 1; #endif } /** Write string using 8 bit character functions. @param str String to write. */ static void dk_bmm_write_8bit(const dkChar *str) { #if DK4_CHAR_SIZE > 2 $? "+ dk_bmm_write_8bit 4" while (dkT('\0') != *str) { if (EOF == fputc((char)((unsigned char)(*(str++))), stdout)) { output_error = 1; } } $$? "- dk_bmm_write_8bit" #else dk4_utf16_decoder_t dec; dk4_c32_t c32; int back = 1; $? "+ dk_bmm_write_8bit 2" dk4utf16_init(&dec); while((dkT('\0') != *str) && (1 == back)) { switch (dk4utf16_add(&dec, *str)) { case DK4_EDSTM_FINISHED: { c32 = dk4utf16_get(&dec); if (dkC32(0xF0) > c32) { if (EOF == fputc((char)((unsigned char)c32), stdout)) { output_error = 1; back = 0; } } } break; case DK4_EDSTM_ERROR: { back = 0; } break; } str++; } $? "- dk_bmm_write_8bit" #endif } #endif /** Write current media set name to stdout. */ static void dk_bmm_write_set_name(void) { const dkChar *sn = NULL; $? "+ dk_bmm_write_set_name" if ((dk4_um_t)dk_bmm_day_in_cycle < (dk4_um_t)dk_bmm_n_set_names) { sn = dk_bmm_set_names[(size_t)dk_bmm_day_in_cycle]; } if (NULL != sn) { #if DK4_CHAR_SIZE > 1 $? ". wide characters dk_bmm_mod_stdout=%d", dk_bmm_mod_stdout if (0 != dk_bmm_can_write_8bit(sn)) { $? ". use 8 bits" dk_bmm_write_8bit(sn); if (EOF == fputc('\n', stdout)) { output_error = 1; } } else { $? ". use wide strings" dk_bmm_mod_stdout = 1; $? ". mod stdout" dk4fput_initialize_stdout(); if (0 == dk4fputs(sn, stdout, NULL)) { output_error = 1; } if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { output_error = 1; } } #else $? ". 8 bit characters" if (EOF == fputs(sn, stdout)) { output_error = 1; } if (EOF == fputc('\n', stdout)) { output_error = 1; } #endif fflush(stdout); } $? "- dk_bmm_write_set_name" } /** Process the specified file. @param filename Name of file to process. */ static void dk_bmm_run_for_file(const dkChar *filename) { const dkChar *oldsourcefile; dk4_um_t oldsourceline; $? "+ dk_bmm_run_for_file \"%!ds\"", filename if (0 != dk_bmm_handle_set) { if (0 != dk_bmm_do_report) { /* ERROR: Option -r not available for sets */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 8); } else { if (0 != dk_bmm_read_sets_file(filename)) { if (0 != dk_bmm_do_confirm) { /* TODO: Confirm current media set */ exval = EXIT_SUCCESS; dk_bmm_day_in_cycle++; if (0 > dk_bmm_day_in_cycle) { dk_bmm_day_in_cycle = 0; } if ((dk4_um_t)dk_bmm_day_in_cycle >= (dk4_um_t)dk_bmm_n_set_names) { dk_bmm_day_in_cycle = 0; } dk4_bmm_write_set_file(filename); dk_bmm_write_set_name(); } else { exval = EXIT_SUCCESS; dk_bmm_write_set_name(); } } else { /* ERROR: Not a set file name */ oldsourcefile = dk4app_get_log_source_file(app); oldsourceline = dk4app_get_log_source_line(app); dk4app_set_log_source_file(app, filename); dk4app_set_log_source_line(app, (dk4_um_t)0UL); dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 13); dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); } } } else { dk_bmm_initialize_media_info(); if (dk_bmm_read_media_file(filename)) { if (0 != dk_bmm_do_report) { exval = EXIT_SUCCESS; dk_bmm_report_media(); } else { if (0 != dk_bmm_do_confirm) { exval = EXIT_SUCCESS; dk_bmm_switch_to_next(filename); dk_bmm_show_current_media_number(); } else { exval = EXIT_SUCCESS; dk_bmm_show_current_media_number(); } } } else { /* ERROR: Failed to read file, probably not a dk-bmm file. */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 9); } } $? "- dk_bmm_run_for_file" } #if DK4_ON_WINDOWS static int dk_bmm_expand_pattern(const dkChar *pattern) { dkChar buf[DK4_MAX_PATH]; dk4_dir_t *fne; const dkChar *shf; const dkChar *pth; int back = 0; $? "+ dk_bmm_expand_pattern" fne = dk4app_fne_open(pattern, app); if (NULL != fne) { shf = dk4dir_next_file(fne); if (NULL != shf) { if (NULL == dk4dir_next_file(fne)) { pth = dk4dir_get_path(fne); if (NULL != pth) { if (0 != dk4str_cpy_s(buf, DK4_SIZEOF(buf,dkChar), pth, NULL)) { if(0!=dk4str_cat_s(buf,DK4_SIZEOF(buf,dkChar),dk_bmm_kwnl[3],NULL)) { if(0 != dk4str_cat_s(buf, DK4_SIZEOF(buf,dkChar), shf, NULL)) { dk_bmm_run_for_file(buf); } else { /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { dk_bmm_run_for_file(shf); } } else { /* ERROR: Multiple files */ dk4app_log_base3(app, DK4_LL_ERROR, 100, 106, pattern); } } else { /* ERROR: No file found */ dk4app_log_base3(app, DK4_LL_ERROR, 100, 107, pattern); } dk4dir_close(fne); } $? "- dk_bmm_expand_pattern %d", back return back; } #endif /** Run after installing signal handlers. */ static void dk_bmm_normal_run(void) { const dkChar *xargv; $? "+ dk_bmm_normal_run" if (0 != dk4app_opt_is_set_short(app, dkT('c'), NULL)) { dk_bmm_do_confirm = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('r'), NULL)) { dk_bmm_do_report = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('s'), NULL)) { dk_bmm_handle_set = 1; } if (dk4app_get_argc(app) == 1) { xargv = dk4app_get_argv(app, 0); if (NULL != xargv) { #if DK4_ON_WINDOWS if (0 != dk4path_must_expand(xargv)) { dk_bmm_expand_pattern(xargv); } else { #endif dk_bmm_run_for_file(xargv); #if DK4_ON_WINDOWS } #endif } else { /* ERROR: Exactly one file allowed! */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 10); } } else { /* ERROR: Exactly one file allowed! */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 10); } $? "- dk_bmm_normal_run" } #if DK4_HAVE_SIGACTION /** Set signal handlers and run. */ static void dk_bmm_run_with_signal_handlers(void) { #ifdef SIGPIPE struct sigaction opipe; #endif struct sigaction oint; #ifdef SIGPIPE struct sigaction npipe; #endif struct sigaction nint; struct sigaction oterm; struct sigaction nterm; int success = 0; #ifdef SIGPIPE /* Set up signal handling for SIGPIPE. */ DK4_MEMRES(&npipe, sizeof(npipe)); npipe.sa_handler = sig_handler_pipe; npipe.sa_flags = 0; if (0 != sigemptyset(&npipe.sa_mask)) { /* ERROR: Failed to set up masked signal set for SIGPIPE */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto finished; } if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { /* ERROR: Failed to set up masked signal set for SIGPIPE */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto finished; } if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { /* ERROR: Failed to set up signal handler for SIGPIPE */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto finished; } #endif /* Set up signal handling for SIGINT. */ DK4_MEMRES(&nint, sizeof(nint)); nint.sa_handler = sig_handler_int; nint.sa_flags = 0; if (0 != sigemptyset(&nint.sa_mask)) { /* ERROR: Failed to set up masked signal set for SIGINT */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto restore_old_pipe; } if (0 != sigaddset(&nint.sa_mask, SIGINT)) { /* ERROR: Failed to set up masked signal set for SIGINT */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto restore_old_pipe; } if (0 != sigaction(SIGINT, &nint, &oint)) { /* ERROR: Failed to set up signal handler for SIGINT */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto restore_old_pipe; } /* Set up signal handling for SIGTERM */ DK4_MEMRES(&nterm, sizeof(nterm)); nterm.sa_handler = sig_handler_term; nterm.sa_flags = 0; if (0 != sigemptyset(&nterm.sa_mask)) { /* ERROR: Failed to set up masked signal set for SIGTERM */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { /* ERROR: Failed to set up masked signal set for SIGTERM */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } if (0 != sigaction(SIGTERM, &nterm, &oterm)) { /* ERROR: Failed to set up signal handler for SIGTERM */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } success = 1; dk_bmm_normal_run(); /* Restore signal handling for SIGTERM. */ if (0 != sigaction(SIGTERM, &oterm, NULL)) { /* ERROR: Failed to restore old SIGTERM settings */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 1); success = 0; } /* Restore signal handling for SIGINT. */ restore_old_int: if (0 != sigaction(SIGINT, &oint, NULL)) { /* ERROR: Failed to restore old SIGPIPE settings */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 1); success = 0; } #ifdef SIGPIPE /* Restore signal handling for SIGPIPE. */ restore_old_pipe: if (0 != sigaction(SIGPIPE, &opipe, NULL)) { /* ERROR: Failed to restore old SIGPIPE settings */ dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 1); success = 0; } #endif /* Set exit status code if error occured. */ finished: if (0 == success) { exval = EXIT_FAILURE; } } #else #if DK4_HAVE_SIGSET /** Set signal handlers and run. */ static void dk_bmm_run_with_signal_handlers(void) { #ifdef SIGPIPE dk4_sig_handler_t *oldpipe = NULL; #endif dk4_sig_handler_t *oldint = NULL; dk4_sig_handler_t *oldterm = NULL; #ifdef SIGPIPE oldpipe = sigset(SIGPIPE, sig_handler_pipe); #endif oldint = sigset(SIGINT, sig_handler_int); oldterm = sigset(SIGTERM, sig_handler_term); dk_bmm_normal_run(); sigset(SIGTERM, oldterm); sigset(SIGINT, oldint); #ifdef SIGPIPE sigset(SIGPIPE, oldpipe); #endif } #else #if DK4_HAVE_SIGNAL /** Set signal handlers and run. */ static void dk_bmm_run_with_signal_handlers(void) { #ifdef SIGPIPE dk4_sig_handler_t *oldpipe = NULL; #endif dk4_sig_handler_t *oldint = NULL; dk4_sig_handler_t *oldterm = NULL; #ifdef SIGPIPE oldpipe = signal(SIGPIPE, sig_handler_pipe); #endif oldint = signal(SIGINT, sig_handler_int); oldterm = signal(SIGTERM, sig_handler_term); dk_bmm_normal_run(); signal(SIGTERM, oldterm); signal(SIGINT, oldint); #ifdef SIGPIPE signal(SIGPIPE, oldpipe); #endif } #else /** Set signal handlers and run. */ static void dk_bmm_run_with_signal_handlers(void) { dk_bmm_normal_run(); } #endif #endif #endif /** Main function. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, all other values indicate errors. */ #if DK4_CHAR_SIZE > 1 int wmain(int argc, wchar_t *argv[]) #else int main(int argc, char *argv[]) #endif { int oldstdlevel; int oldfilelevel; $!trace-init dk-bmm.deb $? "+ main" dk4fput_initialize_stderr(); app = dk4app_open_cmd( argc, argv, dk_bmm_options, dk_bmm_sz_options, dk_bmm_kwnl[0], DKT_VERSION_DK, dk_bmm_kwnl[1], dk_bmm_help_text, dk_bmm_license_text ); if (NULL != app) { dk_bmm_sz_msg = dk4app_string_table_size(dk_bmm_kw_def); dk_bmm_msg = dk4app_string_table(app, dk_bmm_kwnl[2], dk_bmm_kw_def); if (0 != dk4app_can_run_normally(app)) { dk_bmm_run_with_signal_handlers(); if (0 != dk_bmm_cycle_completed) { /* INFO: Cycle completed, change media set */ oldstdlevel = app->ll_stderr; oldfilelevel = app->ll_file; app->ll_file = DK4_LL_INFO; app->ll_stderr = DK4_LL_INFO; dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_INFO, 11); app->ll_file = oldfilelevel; app->ll_stderr = oldstdlevel; } if (0 != output_error) { dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 2); exval = EXIT_FAILURE; } #ifdef SIGPIPE if (0 != sig_read_atomic(&sig_had_pipe)) { dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 3); exval = EXIT_FAILURE; } #endif if (0 != sig_read_atomic(&sig_had_term)) { dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 5); exval = EXIT_FAILURE; } if (0 != sig_read_atomic(&sig_had_int)) { dk4app_log_1(app, dk_bmm_msg, dk_bmm_sz_msg, DK4_LL_ERROR, 4); exval = EXIT_FAILURE; } } else { dk4fput_initialize_stdout(); dk_bmm_mod_stdout = 1; $? ". mod stdout" if (0 != dk4app_help_version_license(app)) { exval = EXIT_SUCCESS; } } dk4app_close(app); app = NULL; } fflush(stdout); fflush(stderr); dk4fput_cleanup_stderr(); if (0 != dk_bmm_mod_stdout) { dk4fput_cleanup_stdout(); } $? "- main %d", exval $!trace-end exit(exval); return exval; }