%% options copyright owner = Dirk Krause copyright year = 2016-xxxx license = bsd %% module /** @file lprngcl.c Lprng Cleanup. */ #include "dk4conf.h" #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_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_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_SIGNAL_H #ifndef SIGNAL_H_INCLUDED #include #define SIGNAL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_MATH_H #ifndef MATH_H_INCLUDED #include #define MATH_H_INCLUDED 1 #endif #endif #include "dk4types.h" #include "dk4const.h" #include "dk4vers.h" #include "dk4str8.h" #include "dk4strd.h" #include "dk4app.h" #include "dk4aopt.h" #include "dk4enc.h" #include "dk4fput.h" #include "dk4mem.h" #include "dk4mema.h" #include "dk4fput.h" #include "dk4tspdk.h" #include "dk4sock.h" #include "dk4socka.h" #include "dk4user.h" #include "dk4rec.h" $!trace-include /** Buffer for request and response data. */ static char buf[4096]; /** Current queue complete name. */ static dkChar curqueue[1024]; /** Current user name. */ static dkChar username[1024]; /** Queue name in 8 bit characters. */ static char queue8[1024]; /** User name in 8 bit characters. */ static char user8[1024]; /** Default help text, used if help text file is not found. */ static const dkChar * const lprngcl_help_text[] = { $!text macro=dkT,preprocessor Clean up LPRng queues lprngcl [-t seconds] [-a] ... lprngcl [--help] [--version] [--license] [--manual] Specify queues in name@host notation. -t seconds --timeout=seconds Timeout for network operations. -a --ascii Server uses ASCII, not UTF-8. --help Show this short help text. --version Show version information. --license Show license information. --manual *** SHOW FULL MANUAL *** $!end }; /** License conditions. */ static const dkChar * const lprngcl_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 }; /** Options used by the program. */ static const dk4_option_specification_t lprngcl_options[] = { /* Timeout for connection attempts and other network operations. */ { dkT('t'), dkT("timeout"), DK4_OPT_ARG_DOUBLE }, /* Remote host uses ASCII encoding, not UTF-8. */ { dkT('a'), dkT("ascii"), DK4_OPT_ARG_NONE }, /* Verbose output. */ { dkT('v'), dkT("verbose"), DK4_OPT_ARG_NONE } }; /** Constant texts used by the program, not localized. */ static const dkChar * const lprngcl_kwnl[] = { $!string-table macro=dkT # # 0 1 2 Group, help text file, string table file # dktools lprngcl.txt lprngcl.str $!end }; /** Defaults for keywords, replaced by localized version if found. */ static const dkChar * const lprngcl_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: Failed to set up text stream processor! # Failed to set up text stream processor! # # 3 ERROR: Failed to construct request! # Failed to construct request!\nQueue or user name too long! # # 4 ERROR: Failed to convert queue name to 8 bit text! # Failed to convert queue name to 8 bit text! # # 5 ERROR: No host name specified in queue! # No host name specified in queue! # # 6 ERROR: Queue name too long! # Queue name too long! # # 7 ERROR: Failed to obtain command line argument (bug)! # Failed to obtain command line argument (bug)! # # 8 ERROR: Failed to convert user name to 8 bit text! # Failed to convert user name to 8 bit text! # # 9 ERROR: Failed to find current user name! # Failed to find current user name! # # 10 ERROR: Queue name(s) required! # Queue name(s) required! # # 11 ERROR: Failed to write to standard output! # Failed to write to standard output! # # 12 13 # Request:\n" ". $!end }; static const char * const lprngcl_c8_kw[] = { $!string-table # # 0 Space # # # 1 Newline # \n # # 2 all print jobs # all $!end }; /** Application object. */ static dk4_app_t *app = NULL; /** Message texts, changed to localized texts if possible. */ static const dkChar * const *msg = lprngcl_kw_def; /** Size of lprngcl_options array. */ static const size_t lprngcl_sz_options = sizeof(lprngcl_options)/sizeof(dk4_option_specification_t); /** Size of lprngcl_kw_def array. */ static size_t sz_msg = (sizeof(lprngcl_kw_def)/sizeof(DK4_PDKCHAR) - 1); /** Size of buffer for current queue. */ static const size_t szcurqueue = DK4_SIZEOF(curqueue,dkChar); /** Size of buffer. */ static size_t szbuf = sizeof(buf); /** Timeout (seconds) for network operations. */ static long to_secs = 0L; /** Timeout (microseconds) for network operations. */ static long to_usecs = 0L; /** Exit status code. */ static int exval = EXIT_FAILURE; /** Flag: Errors while writing to stdout. */ static int wrerror = 0; /** Flag: Remote host uses UTF-8 encoding. */ static int isUtf8 = 1; /** Flag: Produce verbose output. */ static int isVerbose = 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; } /** Use timeout value specified as double. @param to Timeout for network operations. */ static void use_timeout(double to) { $? "+ use_timeout %lg", to if (0.0 > to) { to = -1.0 * to; } to_secs = (long)floor(to); to = to - floor(to); to = to * 1000000.0; to_usecs = (long)floor(to); $? "- use_timeout secs=%ld usecs=%ld", to_secs, to_usecs } /** Process command line options. @return 1 on success, 0 on error. */ static int process_options(void) { double to = 0.0; int back = 1; $? "+ process_options" if (0 != dk4app_opt_is_set_short(app, dkT('t'), NULL)) { if (0 != dk4app_opt_get_double_short(&to, app, dkT('t'), NULL)) { $? ". timeout" use_timeout(to); } } else { } if (0 != dk4app_opt_is_set_short(app, dkT('a'), NULL)) { $? ". ASCII" isUtf8 = 0; } if (0 != dk4app_opt_is_set_short(app, dkT('v'), NULL)) { $? ". verbose" isVerbose = 1; } $? "- process_options %d", back return back; } /** Character handler for text stream processing. */ static int lprngcl_char_handler( void *obj, dkChar c, dk4_text_stream_position_t *pos, dk4_er_t *erp ) { int back = DK4_TSP_RES_OK; if (0 == dk4fputc(c, stdout, NULL)) { exval = EXIT_FAILURE; wrerror = 1; } return back; } /** Process one request to delete print jobs. @param hptr Host name pointer. @param fullqueue Full queue name. */ static void process_one_delete_request(const dkChar *hptr, const dkChar *fullqueue) { dk4_tspdk_t tspdk; size_t rql; size_t wrb; int cc; int tspok; int res; dk4_socket_t sock; $? "+ process_one_delete_request" rql = dk4str8_len(buf); sock = dk4socket_tcp_client_for_host_port_app( hptr, 515, 0, to_secs, to_usecs, app ); if (INVALID_SOCKET != sock) { $? ". socket" wrb = rql; if (0 != isVerbose) { $? ". verbose" if (0 == dk4fputs(fullqueue, stdout, NULL)) { wrerror = 1; $? "! fputs" exval = EXIT_FAILURE; } if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { wrerror = 1; $? "! fputc" exval = EXIT_FAILURE; } } $? ". attempt send" res = dk4socket_send_attempt_app( sock, buf, &wrb, 0, to_secs, to_usecs, app, 1 ); $? ". attempt send done" switch (res) { case DK4_SOCKET_RESULT_SUCCESS : case DK4_SOCKET_RESULT_IN_PROGRESS : { $? ". send ok" if ((0 != isVerbose) && (DK4_SOCKET_RESULT_SUCCESS == res)) { $? ". verbose" res = dk4socket_shutdown_app(sock, DK4_SOCKET_SHUT_WRITE, app); if (DK4_SOCKET_RESULT_SUCCESS == res) { $? ". shutdown" tspok = dk4tspdk_setup_char( &tspdk, NULL, lprngcl_char_handler, dk4app_get_stdout_encoding(app), ( (0 != isUtf8) ? (DK4_FILE_ENCODING_UTF8) : (DK4_FILE_ENCODING_ASCII) ), NULL ); if (0 == tspok) { $? "! text processing" /* ERROR: Failed to set up text stream processor */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 2); exval = EXIT_FAILURE; } cc = 1; do { if (0 != sig_can_continue(0)) { $? ". loop pass" wrb = sizeof(buf); res = dk4socket_recv_app( sock, buf, &wrb, 0, to_secs, to_usecs, app ); if (DK4_SOCKET_RESULT_SUCCESS == res) { $? ". recv" if (0 == wrb) { $? ". 0 bytes" cc = 0; } else { $? ". data found" if (0 != tspok) { $? ". text processing" res = dk4tspdk_add_bytes(&tspdk,(unsigned char *)buf,wrb); if (DK4_TSP_RES_OK != res) { $? "! text processing" exval = EXIT_FAILURE; tspok = 0; } } } } else { $? "! recv" cc = 0; } } else { $? ". signal" cc = -1; } } while(1 == cc); if ((0 == cc) && (0 != tspok)) { $? ". regular loop end" res = dk4tspdk_finish(&tspdk); if (DK4_TSP_RES_OK != res) { $? "! text processing" exval = EXIT_FAILURE; } } } else { $? "! shutdown" exval = EXIT_FAILURE; } } else { $? ". not verbose" res = dk4socket_shutdown_app(sock, DK4_SOCKET_SHUT_WRITE, app); if (DK4_SOCKET_RESULT_SUCCESS == res) { $? ". shutdown" cc = 1; do { if (0 != sig_can_continue(0)) { $? ". loop pass" wrb = sizeof(buf); res = dk4socket_recv_app( sock, buf, &wrb, 0, to_secs, to_usecs, app ); if (DK4_SOCKET_RESULT_SUCCESS == res) { $? ". recv" if (0 == wrb) { $? ". 0 bytes" cc = 0; } } else { $? "! recv" cc = 0; } } else { $? "! signal" cc = -1; } } while(1 == cc); } else { $? "! shutdown" exval = EXIT_FAILURE; } } } break; #if TRACE_DEBUG default : { $? "! send failed" } break; #endif } res = dk4socket_close_app(sock, app); if (DK4_SOCKET_RESULT_SUCCESS != res) { $? "! close" exval = EXIT_FAILURE; } } else { $? "! socket" exval = EXIT_FAILURE; } $? "- process_one_delete_request" } /** Send requests to delete the users print jobs. @param xargc Number of queue names. */ static void send_delete_requests(int xargc) { const dkChar *xargv = NULL; /* Current cmd line argument */ dkChar *hptr = NULL; /* Start of host name */ int res = 0; /* Text conversion result */ int i = 0; /* Current cmd line arg index */ $? "+ send_delete_requests %d", xargc if (0 != dk4user_get_logname(username, DK4_SIZEOF(username,dkChar),0, NULL)) { $? ". logname = \"%!ds\"", username if (0 != isUtf8) { $? ". UTF-8" res = dk4recode_dk_to_any( user8, sizeof(user8), DK4_ENCODING_UTF8, username, dk4app_get_encoding(app), NULL ); } else { $? ". ASCII" res = dk4recode_dk_to_any( user8, sizeof(user8), DK4_ENCODING_ASCII, username, dk4app_get_encoding(app), NULL ); } if (0 != res) { $? ". conversion to 8 bit text" exval = EXIT_SUCCESS; for (i = 0; ((i < xargc) && (sig_can_continue(0))); i++) { $? ". pass %d", i xargv = dk4app_get_argv(app, i); if (NULL != xargv) { $? ". argv = \"%!ds\"", xargv if (0 != dk4str_cpy_s(curqueue, szcurqueue, xargv, NULL)) { $? ". copied" hptr = dk4str_chr(curqueue, dkT('@')); if (NULL != hptr) { *(hptr++) = dkT('\0'); hptr = dk4str_start(hptr, NULL); if (NULL != hptr) { $? ". host = \"%!ds\"", hptr if (0 != isUtf8) { $? ". UTF-8" res = dk4recode_dk_to_any( queue8, sizeof(queue8), DK4_ENCODING_UTF8, curqueue, dk4app_get_encoding(app), NULL ); } else { $? ". ASCII" res = dk4recode_dk_to_any( queue8, sizeof(queue8), DK4_ENCODING_ASCII, curqueue, dk4app_get_encoding(app), NULL ); } if (0 != res) { $? ". conversion to 8 bit text" res = 1; if (0 == dk4str8_cpy_s(buf, szbuf, lprngcl_c8_kw[0], NULL)) { res = 0; $? "! request construction" buf[0] = '\0'; } if (0 == dk4str8_cat_s(buf, szbuf, queue8, NULL)) { res = 0; $? "! request construction" } if (0 == dk4str8_cat_s(buf, szbuf, lprngcl_c8_kw[0], NULL)) { res = 0; $? "! request construction" } if (0 == dk4str8_cat_s(buf, szbuf, user8, NULL)) { res = 0; $? "! request construction" } if (0 == dk4str8_cat_s(buf, szbuf, lprngcl_c8_kw[0], NULL)) { res = 0; $? "! request construction" } if (0 == dk4str8_cat_s(buf, szbuf, user8, NULL)) { res = 0; $? "! request construction" } if (0 != res) { $? ". request=\"%!8s\"", buf /* LOG Print removal request */ #if DK4_CHAR_SIZE == 1 dk4app_log_3(app, msg, sz_msg, DK4_LL_INFO, 12, 13, buf); #endif } if (0 == dk4str8_cat_s(buf, szbuf, lprngcl_c8_kw[1], NULL)) { res = 0; $? "! request construction" } buf[0] = 0x05; if (0 != res) { $? ". process rq" process_one_delete_request(hptr, xargv); } else { $? "! failed to construct rq" /* ERROR: Failed to construct request */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 3); } } else { $? "! conversion to 8 bit text" exval = EXIT_FAILURE; /* ERROR: Failed to convert queue name to 8 bit text */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 4); } } else { $? "! no host name in queue" exval = EXIT_FAILURE; /* ERROR: No host name in queue */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 5); } } else { $? "! no host name in queue" exval = EXIT_FAILURE; /* ERROR: No host name in queue */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 5); } } else { $? "! buffer too small" exval = EXIT_FAILURE; /* ERROR: Queue name too long */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 6); } } else { $? "! bug, no argv" exval = EXIT_FAILURE; /* ERROR: Failed to obtain command line argument */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 7); } } } else { $? "! conversion to 8 bit text" /* ERROR: Failed to recode user name to 8 bit characters */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 8); } } else { $? "! user name" /* ERROR: Failed to find current user name */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 9); } $? "- send_delete_requests" } /** The real work. */ static void run_the_functions(void) { int xargc = 0; $? "+ run_the_functions" if (0 != process_options()) { $? ". option processing ok" xargc = dk4app_get_argc(app); if (0 < xargc) { $? ". cmd line arguments" if (0 != dk4socket_up_app(app)) { $? ". socket subsys up" send_delete_requests(xargc); dk4socket_down_app(app); } else { $? "! socket subsys" exval = EXIT_FAILURE; } } else { $? "! no cmd line arguments" /* ERROR: No queues specified */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 10); } } #if TRACE_DEBUG else { $? "! option processing failed" } #endif $? "- run_the_functions" } #if DK4_HAVE_SIGACTION /** Set signal handlers and run. */ static void run_with_signals(void) { #ifdef SIGPIPE struct sigaction opipe; #endif struct sigaction oint; struct sigaction oterm; #ifdef SIGPIPE struct sigaction npipe; #endif struct sigaction nint; struct sigaction nterm; int success = 0; $? "+ run_with_signals DK4_HAVE_SIGACTION" #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)) { $? "! pipe sigemtpyset" /* ERROR: Failed to set up masked signal set for SIGPIPE */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 0); goto finished; } if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { $? "! pipe sigaddset" /* ERROR: Failed to set up masked signal set for SIGPIPE */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 0); goto finished; } if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { $? "! pipe sigaction" /* ERROR: Failed to set up signal handler for SIGPIPE */ dk4app_log_1(app, msg, 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)) { $? "! int sigemptyset" /* ERROR: Failed to set up masked signal set for SIGINT */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 0); goto restore_old_pipe; } if (0 != sigaddset(&nint.sa_mask, SIGINT)) { $? "! int sigaddset" /* ERROR: Failed to set up masked signal set for SIGINT */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 0); goto restore_old_pipe; } if (0 != sigaction(SIGINT, &nint, &oint)) { $? "! int sigaction" /* ERROR: Failed to set up signal handler for SIGINT */ dk4app_log_1(app, msg, 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)) { $? "! term sigemptyset" /* ERROR: Failed to set up masked signal set for SIGTERM */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { $? "! term sigaddset" /* ERROR: Failed to set up masked signal set for SIGTERM */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } if (0 != sigaction(SIGTERM, &nterm, &oterm)) { $? "! term sigaction" /* ERROR: Failed to set up signal handler for SIGTERM */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } success = 1; $? ". signals ok" run_the_functions(); /* Restore signal handling for SIGTERM. */ if (0 != sigaction(SIGTERM, &oterm, NULL)) { $? "! term sigaction" /* ERROR: Failed to restore old SIGTERM settings */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 1); success = 0; } /* Restore signal handling for SIGINT. */ restore_old_int: if (0 != sigaction(SIGINT, &oint, NULL)) { $? "! int sigaction" /* ERROR: Failed to restore old SIGPIPE settings */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 1); success = 0; } #ifdef SIGPIPE /* Restore signal handling for SIGPIPE. */ restore_old_pipe: if (0 != sigaction(SIGPIPE, &opipe, NULL)) { $? "! pipe sigaction" /* ERROR: Failed to restore old SIGPIPE settings */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 1); success = 0; } #endif /* Set exit status code if error occured. */ finished: if (0 == success) { $? "! errors occured" exval = EXIT_FAILURE; } $? "- run_with_signals DK4_HAVE_SIGACTION" } #else #if DK4_HAVE_SIGSET /** Set signal handlers and run. */ static void run_with_signals(void) { #ifdef SIGPIPE dk4_sig_handler_t *oldpipe = NULL; #endif dk4_sig_handler_t *oldint = NULL; dk4_sig_handler_t *oldterm = NULL; $? "+ run_with_signals DK4_HAVE_SIGSET" #ifdef SIGPIPE oldpipe = sigset(SIGPIPE, sig_handler_pipe); #endif oldint = sigset(SIGINT, sig_handler_int); oldterm = sigset(SIGTERM, sig_handler_term); run_the_functions(); sigset(SIGTERM, oldterm); sigset(SIGINT, oldint); #ifdef SIGPIPE sigset(SIGPIPE, oldpipe); #endif $? "- run_with_signals DK4_HAVE_SIGSET" } #else #if DK4_HAVE_SIGNAL /** Set signal handlers and run. */ static void run_with_signals(void) { #ifdef SIGPIPE dk4_sig_handler_t *oldpipe = NULL; #endif dk4_sig_handler_t *oldint = NULL; dk4_sig_handler_t *oldterm = NULL; $? "+ run_with_signals DK4_HAVE_SIGNAL" #ifdef SIGPIPE oldpipe = signal(SIGPIPE, sig_handler_pipe); #endif oldint = signal(SIGINT, sig_handler_int); oldterm = signal(SIGTERM, sig_handler_term); run_the_functions(); signal(SIGTERM, oldterm); signal(SIGINT, oldint); #ifdef SIGPIPE signal(SIGPIPE, oldpipe); #endif $? "- run_with_signals DK4_HAVE_SIGNAL" } #else /** Set signal handlers and run. */ static void run_with_signals(void) { $? "+ run_with_signals NO SIGNALS" run_the_functions(); $? "- run_with_signals NO SIGNALS" } #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 { $!trace-init lprngcl.deb $? "+ main" dk4fput_initialize_stdout(); dk4fput_initialize_stderr(); app = dk4app_open_cmd( argc, argv, lprngcl_options, lprngcl_sz_options, lprngcl_kwnl[0], DKT_VERSION_DK, lprngcl_kwnl[1], lprngcl_help_text, lprngcl_license_text ); if (NULL != app) { $? ". app" sz_msg = dk4app_string_table_size(lprngcl_kw_def); msg = dk4app_string_table(app, lprngcl_kwnl[2], lprngcl_kw_def); if (0 != dk4app_can_run_normally(app)) { $? ". run normally" run_with_signals(); } else { $? ". help, version, license" if (0 != dk4app_help_version_license(app)) { exval = EXIT_SUCCESS; } } if (0 != wrerror) { $? "! stdout write error" /* ERROR: Failed to write to standard output */ dk4app_log_1(app, msg, sz_msg, DK4_LL_ERROR, 11); } dk4app_close(app); } #if TRACE_DEBUG else { $? "! app" } #endif fflush(stdout); fflush(stderr); dk4fput_cleanup_stderr(); dk4fput_cleanup_stdout(); $? "- main %d", exval $!trace-end exit(exval); return exval; }