/* WARNING: This file was generated by dkct. Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: printqdc.ctr */ /* Copyright (C) 2016-2017, Dirk Krause 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 opyright 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 author 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. */ /** @file printqdc.c The printqdc module. */ #line 10 "printqdc.ctr" #include "dk4conf.h" #include "dk4types.h" #include #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_PROCESS_H #ifndef PROCESS_H_INCLUDED #include #define PROCESS_H_INCLUDED 1 #endif #endif /** Requirements to build this program: * Use 8 bit characters, so we can use the directories from dk4inst.c. * Signal handling mechanism. */ #if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) #if DK4_HAVE_MATH_H #ifndef MATH_H_INCLUDED #include #define MATH_H_INCLUDED 1 #endif #endif #if DK4_HAVE_ERRNO_H #ifndef ERRNO_H_INCLUDED #include #define ERRNO_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_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_STRING_H #ifndef STRING_H_INCLUDED #include #define STRING_H_INCLUDED 1 #endif #endif #include "dk4inst.h" #include "dk4mpl.h" #include "dk4mem.h" #include "dk4mai8ddu.h" #include "dk4mai8dus.h" #include "dk4str8.h" #include "dk4lprng.h" #include "dk4opt.h" #include "dk4sock.h" #include "dk4vers.h" #line 103 "printqdc.ctr" /** Information from one LPRng accounting line. */ typedef struct { char *username; char *queuename; char *jobtitle; char *pagecount; } lprng_info_t; /** Command line options for program. */ static dk4_option_t options[] = { { { dkT('i'), dkT("interactive"), DK4_OPT_ARG_NONE }, { NULL }, 0}, { { dkT('s'), dkT("socket"), DK4_OPT_ARG_STRING }, { NULL }, 0}, { { dkT('h'), dkT("host"), DK4_OPT_ARG_STRING }, { NULL }, 0}, { { dkT('p'), dkT("port"), DK4_OPT_ARG_UNSIGNED }, { NULL }, 0}, { { dkT('\0'),dkT("help"), DK4_OPT_ARG_NONE}, { NULL }, 0}, { { dkT('\0'),dkT("version"), DK4_OPT_ARG_NONE}, { NULL }, 0}, { { dkT('\0'),dkT("license"), DK4_OPT_ARG_NONE}, { NULL }, 0} }; /** Help text. */ static const char * const help_text[] = { "", "Print quota daemon client", "", "printqdc [-i] [-s path] | [-h host -p port]", "", "-i\t\t\tInteractive mode instead of default pipe mode.", "--interactive", "", "-s path\t\t\tPath name for local UNIX domain socket.", "--socket=path", "", "-h host\t\t\tHost name of remote host.", "--host=host", "", "-p port\t\t\tPort number at remote host.", "--port=port", "", "--help\t\t\tShow this help text.", "--version\t\tShow version number.", "--license\t\tShow license information.", "", NULL #line 158 "printqdc.ctr" }; /** License conditions text. */ static const char * const license_text[] = { "", "This software uses code from the following projects, either directly or as", "a library:", "", "dktools\t\tDirk Krause's tools and libraries.", "\t\tSee http://dktools.sourceforge.net/ for more information.", "", "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.", "", NULL #line 204 "printqdc.ctr" }; /** Version information. */ static const char version_text[] = { DKT_VERSION_C8 }; /** Constant text keywords used by the module. */ static const char * const pqdc_kw[] = { /* 0 */ "\n", /* 1 */ " ", /* 2 */ "x@x+1", /* 3 */ "Print job", /* 4 */ "-> ", /* 5 */ "<- \"", /* 6 */ "\"\n", /* 7 */ "printqdc: ", /* 8 */ "ERROR: Port number too large!\n", /* 9 */ "ERROR: Port number required!\n", /* 10 */ "ERROR: Host name required!\n", /* 11 */ "ERROR: Failed to shut down socket!\n", /* 12 */ "ERROR: Failed to send data!\n", /* 13 */ "ERROR: Failed to open connection to accounting system!\n", /* 14 */ "ERROR: Failed to construct request (would be too long)!\n", /* 15 */ "ERROR: Incomplete information to construct request!\n", /* 16 */ "ERROR: Pagecounter not numeric!\n", /* 17 */ "ERROR: Too few arguments for request!\n", /* 18 */ "ERROR: Unknown command keyword!\n", /* 19 */ "ERROR: Missing arguments!\n", /* 20 */ "ERROR: Interrupted by signal!\n", /* 21 */ "ERROR: Failed to install signal handlers!\n", /* 22 */ "ERROR: Failed to restore signal handlers!\n", /* 23 */ "ERROR: Failed to initialize socket subsystem!\n", NULL #line 276 "printqdc.ctr" }; /** Default socket name. */ static const char def_sock_name[] = { DK4_INST_DIR_VAR "/run/printqd/printqd.sock" }; /** Protocol keywords at start of accounting line. */ static const char * const command_names[] = { /* 0 */ "jobstart", /* 1 */ "jobend", /* 2 */ "start", /* 3 */ "end", /* 4 */ "filestart", /* 5 */ "fileend", /* 6 */ "info", /* 7 */ "acct-check", /* 8 */ "acct-start", /* 9 */ "acct-end", /* 10 */ "acct-charge", /* 11 */ "control", NULL #line 311 "printqdc.ctr" }; /** Responses from printqd */ static const char * const responses[] = { /* 0 */ "ACCEPT", /* 1 */ "HOLD", /* 2 */ "REMOVE", NULL #line 322 "printqdc.ctr" }; /** Data exchange buffer. */ static char inbuf[4096]; /** Copy for inspection. */ static char cpbuf[sizeof(inbuf)]; /** Host name for network connection. */ static char *host_name = NULL; /** Socket file name for local connection. */ static char *sock_name = NULL; /** Number of options. */ static size_t szoptions = sizeof(options)/sizeof(dk4_option_t); /** Normal exit value (when run as pipe). */ static int exval = LPRNG_EXIT_SUCCESS; /** Help (1), version (2), license (4). */ static int hvl = 0; /** Exit value for interactive mode. */ static int iexval = EXIT_FAILURE; /** Flag: Interactive mode (-i option). */ static int intera = 0; /** Flag: EOF was found. */ static int eof_found = 0; /** Flag: Response already found and processed. */ static int found_response = 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; /** Port number for network connection. */ static unsigned short portno = 0U; /** Pass pointer through. Use of this function is recommended by CERT C coding standard to avoid optimizing out. @param ptr Pointer to pass through. @return The ptr argument. */ 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 must abort due to signal. @param dopipe Flag: Check for SIGPIPE too. @return 1 if we can continue, 0 otherwise. */ static int can_continue(void) { int back = 1; if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } if (0 != sig_read_atomic(&sig_had_int)) { back = 0; } return back; } /** Log one-component message to stderr. @param kwind Index of text in printqdc_kw array. */ static void log_1(size_t kwind) { if (0 != intera) { fputs(pqdc_kw[7], stderr); fputs(pqdc_kw[kwind], stderr); fflush(stderr); } } /** Eat up input to avoid broken pipe in feeder. */ static void eatup_input(void) { size_t rdb; int cc = 1; do { if (0 != can_continue()) { rdb = fread(inbuf, 1, sizeof(inbuf), stdin); if (0 == rdb) { cc = 0; } } else { cc = -1; } } while(1 == cc); } /** Process command line arguments. @param argc Number of command line arguments. @param argv Command line arguments array. @return 1 on success, 0 on error. */ static int cmd_line_args(int argc, char *argv[]) { dkChar *filenames[32]; size_t szfilenames = DK4_SIZEOF(filenames,DK4_PDKCHAR); int back; back = dk4opt_process_argv( options, szoptions, argc, argv, filenames, &szfilenames, 1, 0, NULL ); if (1 == back) { if (0 != options[4].found) { hvl |= 1; } if (0 != options[5].found) { hvl |= 2; } if (0 != options[6].found) { hvl |= 4; } if (0 != options[0].found) { intera = 1; } if (0 != options[1].found) { sock_name = options[1].val.t; } if (0 != options[2].found) { host_name = options[2].val.t; } if (0 != options[3].found) { if ((dk4_um_t)0x0000FFFFUL >= options[3].val.u) { portno = (unsigned short)(options[3].val.u); } else { back = 0; /* ERROR: Port number to large! */ log_1(8); } } if ((NULL != host_name) && (0 == portno)) { back = 0; /* ERROR: Port number required */ log_1(9); } if ((NULL == host_name) && (0 != portno)) { back = 0; /* ERROR: Host name required */ log_1(10); } } else { if (0 != options[0].found) { (void)dk4opt_process_argv( options, szoptions, argc, argv, filenames, &szfilenames, 1, 1, NULL ); } } return back; } /** Data exchange with accounting system. @param pres Flag: Process response, 0=no, 1=acct-check, 2=info. */ static void process_data(int pres) { const char *ep; /* End pointer for text to number conversions */ char *ptr; /* Traverse data line */ dk4_um_t um; /* Number obtained from text */ size_t sl; /* Input buffer string length */ size_t wrb; /* Bytes we still have to write */ dk4_socket_t sock; /* Connection to accounting/quota daemon */ int res; /* Operation result */ int cc; /* Flag: Can continue */ #line 611 "printqdc.ctr" wrb = sl = strlen(inbuf); /* LOG/SHOW: Request */ if (0 != intera) { #line 614 "printqdc.ctr" fputs(pqdc_kw[4], stdout); if (0 < sl) { fputs(inbuf, stdout); if (0 < sl) { if ('\n' != inbuf[sl - 1]) { fputc('\n', stdout); } } else { fputc('\n', stdout); } } fflush(stdout); } if ((0 < sl) && (0 != can_continue())) { #line 628 "printqdc.ctr" if ((NULL != host_name) && (0 < portno)) { #line 629 "printqdc.ctr" sock = dk4socket_c8_tcp_client_host_port( host_name, portno, 0, 0L, 0L, NULL ); } else { #line 633 "printqdc.ctr" sock = dk4socket_c8_unix_client( ((NULL != sock_name) ? sock_name : def_sock_name), NULL ); } if (INVALID_SOCKET != sock) { #line 638 "printqdc.ctr" if (0 != can_continue()) { #line 639 "printqdc.ctr" res = dk4socket_send(sock, inbuf, &wrb, 0, 0L, 0L, NULL); if ((DK4_SOCKET_RESULT_SUCCESS == res) && (wrb == sl)) { #line 641 "printqdc.ctr" if (0 != can_continue()) { #line 642 "printqdc.ctr" res = dk4socket_shutdown(sock, DK4_SOCKET_SHUT_WRITE, NULL); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 644 "printqdc.ctr" cc = 1; do { if (0 != can_continue()) { #line 647 "printqdc.ctr" wrb = sizeof(inbuf); res = dk4socket_recv(sock, inbuf, &wrb, 0, 0L, 0L, NULL); if ((DK4_SOCKET_RESULT_SUCCESS==res)&&(0 != can_continue())) { if (0 < wrb) { #line 651 "printqdc.ctr" if (0 != pres) { #line 652 "printqdc.ctr" if (sizeof(inbuf) > wrb) { inbuf[wrb] = '\0'; } else { iexval = EXIT_FAILURE; inbuf[sizeof(inbuf)-1] = '\0'; } dk4str8_normalize(inbuf, NULL); /* LOG/SHOW: Response */ if (0 != intera) { fputs(pqdc_kw[5], stdout); fputs(inbuf, stdout); fputs(pqdc_kw[6], stdout); fflush(stdout); } switch (pres) { case 1: { if (0 == found_response) { switch (dk4str8_array_index(responses,inbuf,0)) { case 1: { exval = LPRNG_EXIT_HOLD; } break; case 2: { exval = LPRNG_EXIT_REMOVE; } break; } } found_response = 1; } break; case 2: { if (0 == found_response) { um = (dk4_um_t)0UL; ep = NULL; ptr = dk4str8_start(inbuf, NULL); if (NULL != ptr) { ptr = dk4str8_next(ptr, NULL); if (NULL != ptr) { ptr = dk4str8_next(ptr, NULL); if (NULL != ptr) { ptr = dk4str8_next(ptr, NULL); if (NULL != ptr) { res = dk4ma_input_c8_dec_dk4_um_t( &um, ptr, &ep, 1, NULL ); if (0 == res) { um = (dk4_um_t)0UL; } } } } } if ((dk4_um_t)0UL == um) { exval = LPRNG_EXIT_REMOVE; } } found_response = 1; } break; } } else { #line 710 "printqdc.ctr" } } else { #line 712 "printqdc.ctr" cc = 0; } } else { #line 715 "printqdc.ctr" iexval = EXIT_FAILURE; cc = -1; } } else { #line 719 "printqdc.ctr" cc = -1; } } while (1 == cc); } else { #line 723 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Failed to shut down socket */ log_1(11); } } else { #line 728 "printqdc.ctr" } } else { #line 730 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Sending data failed */ log_1(12); } } else { #line 735 "printqdc.ctr" } dk4socket_close(sock, NULL); } else { #line 738 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Failed to open socket */ log_1(13); } } else { #line 743 "printqdc.ctr" } #line 745 "printqdc.ctr" } /** Find final quote for current word. @param str String to find quote in. @param quote Quote character. @return Pointer to found quote on success, NULL on error. */ static char * lprng_final_quote(char *str, char quote) { char *back = NULL; #line 760 "printqdc.ctr" while (('\0' != *str) && (NULL == back)) { if (quote == *str) { *str = '\0'; back = str; back++; back = dk4str8_start(back, NULL); } else { if ('\\' == *str) { if ('\0' != str[1]) { dk4str8_cpy_to_left(str, &(str[1])); str++; } else { *str = '\0'; } } else { str++; } } } #line 780 "printqdc.ctr" return back; } /** Find start of next text word in LPRng accounting line. @param str Current word (remaining text) in accounting line. @return Pointer to next word if found, NULL on error. */ static char * lprng_next_word(char *str) { char *back = NULL; #line 794 "printqdc.ctr" switch (*str) { case '\'' : { back = lprng_final_quote(&(str[1]), '\''); } break; case '"' : { back = lprng_final_quote(&(str[1]), '"'); } break; default : { back = dk4str8_next(str, NULL); } break; } #line 805 "printqdc.ctr" return back; } /** Fill data structure from LPRng accounting line. @param liptr Structure to fill. @param textline The text line to use. @return 1 on success, 0 on error. */ static int lprng_info_from_line(lprng_info_t *liptr, char *textline) { char *next; int back = 1; #line 822 "printqdc.ctr" DK4_MEMRES(liptr, sizeof(lprng_info_t)); liptr->username = NULL; liptr->queuename = NULL; liptr->jobtitle = NULL; liptr->pagecount = NULL; while (NULL != textline) { next = lprng_next_word(textline); if (('\'' == *textline) || ('"' == *textline)) { textline++; } if ('-' == *textline) { textline++; switch (*textline) { case 'n': { liptr->username = ++textline; } break; case 'P': { liptr->queuename = ++textline; } break; case 'J': { liptr->jobtitle = ++textline; } break; case 'p': { liptr->pagecount = ++textline; } break; } } else { #line 847 "printqdc.ctr" #if 0 /* 2016-02-15 Simply ignore non-option text. */ back = 0; /* ERROR: No minus sign */ #endif } textline = next; } #line 857 "printqdc.ctr" return back; } /** Process one line received from LPRng. @param cmd Index in command names array. @param args Further arguments in line. */ static void lprng_line(int cmd, char *args) { lprng_info_t li; /* All relevant components of line */ const char *ep = NULL; /* End pointer for numeric conversion */ const char *jt; /* Job title */ dk4_um_t um; /* Text to number conversion result */ int res; /* Operation result */ int ok = 0; /* Flag: Can process line */ #line 877 "printqdc.ctr" if (0 != lprng_info_from_line(&li, args)) { switch (cmd) { case 0: { if ((NULL != li.username) && (NULL != li.queuename)) { if (0 != dk4str8_cpy_s(inbuf,sizeof(inbuf),command_names[7], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.queuename, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.username, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[0], NULL)) { ok = 1; #line 888 "printqdc.ctr" } } } } } } if (0 != ok) { process_data(1); } else { #line 897 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Failed to construct request */ log_1(14); } } else { #line 902 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Incomplete information */ log_1(15); } } break; default: { if ((NULL != li.username) && (NULL != li.queuename)) { if (NULL != li.pagecount) { res = dk4ma_input_c8_dec_dk4_um_t(&um, li.pagecount, &ep, 1, NULL); if (0 != res) { cmd += 4; if(0 !=dk4str8_cpy_s(inbuf,sizeof(inbuf),command_names[cmd],NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.queuename, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.username, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.pagecount, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[2], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { jt = li.jobtitle; if (NULL == jt) { jt = pqdc_kw[3]; } if (0 != dk4str8_cat_s(inbuf, sizeof(inbuf), jt, NULL)) { if (0 != dk4str8_cat_s(inbuf, sizeof(inbuf), pqdc_kw[0], NULL)) { ok = 1; } } } } } } } } } } } } if (0 != ok) { #line 942 "printqdc.ctr" process_data(0); } else { #line 944 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Failed to construct request */ log_1(14); } } else { #line 949 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Pagecounter not numeric */ log_1(16); } } else { #line 954 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Incomplete information */ log_1(15); } } else { #line 959 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Incomplete information */ log_1(15); } } break; } } else { iexval = EXIT_FAILURE; } #line 969 "printqdc.ctr" } /** Process one line containing printqd style data. @param args Arguments text. @param minargs Minimum required number of arguments. @param num3 Flag: Argument 3 must be unsigned number. @param pres Flag: Process response. */ static void printqd_line(char *args, size_t minargs, int num3, int pres) { const char *ep = NULL; /* End of usable data */ char *next; /* Start of arguments */ dk4_um_t um = (dk4_um_t)0UL; /* Numeric conversion result */ size_t i; /* Current argument index */ int res; /* Operation result */ int errnum = 0; /* Flag: Numeric error */ #line 990 "printqdc.ctr" dk4str8_normalize(args, NULL); i = 0; #line 992 "printqdc.ctr" while(args) { i++; next = dk4str8_next(args, NULL); if ((3 == i) && (0 != num3)) { #line 996 "printqdc.ctr" res = dk4ma_input_c8_dec_dk4_um_t(&um, args, &ep, 1, NULL); if (0 == res) { errnum = 1; } } args = next; } #line 1001 "printqdc.ctr" if ((i >= minargs) && (0 == errnum)) { process_data(pres); } else { if (i < minargs) { /* ERROR: Too few arguments */ log_1(17); } if (0 != errnum) { /* ERROR: Page counter not numeric */ log_1(16); } iexval = EXIT_FAILURE; } #line 1015 "printqdc.ctr" } /** Process input from stdin. */ static void process_input(void) { char *args; /* Start of arguments after command */ int cc; /* Flag: Can continue */ int res; /* Operation result for numeric conversions */ #line 1029 "printqdc.ctr" cc = 1; do { if (0 != can_continue()) { #line 1032 "printqdc.ctr" if (fgets(inbuf, sizeof(inbuf), stdin)) { #line 1033 "printqdc.ctr" dk4str8_cpy_s(cpbuf, sizeof(cpbuf), inbuf, NULL); dk4str8_delnl(cpbuf); if (NULL != dk4str8_start(cpbuf, NULL)) { if (0 != intera) { #line 1037 "printqdc.ctr" fputs(cpbuf, stdout); fputc('\n', stdout); fflush(stdout); } args = dk4str8_next(cpbuf, NULL); if (NULL != args) { #line 1043 "printqdc.ctr" res = dk4str8_array_index(command_names, cpbuf, 0); if (0 != can_continue()) { switch (res) { case 0: { lprng_line(res, args); } break; case 1: { } break; case 2: { } break; case 3: { } break; case 4: { lprng_line(res, args); } break; case 5: { lprng_line(res, args); } break; case 6: { printqd_line(args, 2, 0, 2); } break; case 7: { printqd_line(args, 2, 0, 1); } break; case 8: { printqd_line(args, 4, 1, 0); } break; case 9: { printqd_line(args, 4, 1, 0); } break; case 10: { printqd_line(args, 3, 1, 0); } break; case 11: { printqd_line(args, 1, 0, 0); } break; default: { iexval = EXIT_FAILURE; /* ERROR: Unknown keyword */ log_1(18); } break; } } else { cc = -1; } } else { #line 1089 "printqdc.ctr" /* ERROR: No arguments */ log_1(19); iexval = EXIT_FAILURE; } } else { #line 1094 "printqdc.ctr" } } else { #line 1096 "printqdc.ctr" eof_found = 1; cc = 0; } } else { #line 1100 "printqdc.ctr" cc = -1; } } while (1 == cc); #line 1104 "printqdc.ctr" } /** Show a text paragraph on standard output. @param txt Text to show. */ static void show_text(const char * const *txt) { if (NULL != txt) { while (NULL != *txt) { fputs(*(txt++), stdout); fputc('\n', stdout); } fflush(stdout); } } /** Handle --help, --version, --license options. */ static void run_hvl(void) { if (0 != (1 & hvl)) { show_text(help_text); } if (0 != (2 & hvl)) { fputs(version_text, stdout); fputc('\n', stdout); fflush(stdout); } if (0 != (4 & hvl)) { show_text(license_text); } } /** Main program. @param argc Number of command line arguments. @param argv Command line arguments array. @return Exit status code. */ int main(int argc, char *argv[]) { #ifdef DK4_HAVE_SIGACTION #ifdef SIGPIPE struct sigaction opipe; struct sigaction npipe; #endif struct sigaction oint; struct sigaction nint; struct sigaction oterm; struct sigaction nterm; #else #ifdef SIGPIPE dk4_sig_handler_t *opipe = NULL; #endif dk4_sig_handler_t *oterm = NULL; dk4_sig_handler_t *oint = NULL; #endif #ifdef DK4_HAVE_SIGACTION #ifdef SIGPIPE int spipe = 0; #endif int sint = 0; int sterm = 0; int s_f_i = 0; int s_f_r = 0; #endif int socki = 0; /* Set signal handlers */ #if DK4_HAVE_SIGACTION #ifdef SIGPIPE DK4_MEMRES(&npipe, sizeof(npipe)); npipe.sa_handler = sig_handler_pipe; npipe.sa_flags = 0; if (0 != sigemptyset(&npipe.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { s_f_i = 1; goto finished; } spipe = 1; #endif DK4_MEMRES(&nterm, sizeof(nterm)); nterm.sa_handler = sig_handler_term; nterm.sa_flags = 0; if (0 != sigemptyset(&nterm.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGTERM, &nterm, &oterm)) { s_f_i = 1; goto finished; } sterm = 1; DK4_MEMRES(&nint, sizeof(nint)); nint.sa_handler = sig_handler_int; nint.sa_flags = 0; if (0 != sigemptyset(&nint.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nint.sa_mask, SIGINT)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGINT, &nint, &oint)) { s_f_i = 1; goto finished; } sint = 1; #else #ifdef SIGPIPE opipe = sigset(SIGPIPE, sig_handler_pipe); #endif oint = sigset(SIGINT, sig_handler_int); oterm = sigset(SIGTERM, sig_handler_term); #endif /* Start tracing */ #line 1246 "printqdc.ctr" #line 1247 "printqdc.ctr" /* Process command line arguments */ if (0 == cmd_line_args(argc, argv)) { goto finished; } /* Help, version, license. */ if (0 != hvl) { run_hvl(); goto finished; } /* Bring socket subsystem up. */ if (DK4_SOCKET_RESULT_SUCCESS != dk4socket_up(NULL)) { /* ERROR: Failed to initialize socket subsystem */ log_1(23); goto finished; } socki = 1; iexval = EXIT_SUCCESS; #line 1270 "printqdc.ctr" process_input(); finished: /* Eat up remaining input, if any. */ if ((0 == hvl) && (0 == eof_found)) { eatup_input(); } /* Log notification about abort by signal. */ if (0 == can_continue()) { /* LOG: Interrupted by signal */ log_1(20); iexval = EXIT_FAILURE; } /* Release socket subsystem. */ if (0 != socki) { (void)dk4socket_down(NULL); } /* Restore signal handlers */ #if DK4_HAVE_SIGACTION if (0 != s_f_i) { /* ERROR: Failed to install signal handlers */ log_1(21); iexval = EXIT_FAILURE; } if (0 != sint) { if (0 != sigaction(SIGINT, &oint, NULL)) { s_f_r = 1; } } if (0 != sterm) { if (0 != sigaction(SIGTERM, &oterm, NULL)) { s_f_r = 1; } } #ifdef SIGPIPE if (0 != spipe) { if (0 != sigaction(SIGPIPE, &opipe, NULL)) { s_f_r = 1; } } #endif if (0 != s_f_r) { /* ERROR: Failed to restore signal handlers */ log_1(22); iexval = EXIT_FAILURE; } #else if (NULL != oterm) { sigset(SIGTERM, oterm); } if (NULL != oint ) { sigset(SIGINT, oint ); } #ifdef SIGPIPE if (NULL != opipe) { sigset(SIGPIPE, opipe); } #endif #endif /* Set exit status code depending on interactive mode */ if (0 != intera) { exval = iexval; } /* Finish tracing */ #line 1335 "printqdc.ctr" #line 1336 "printqdc.ctr" /* Exit */ exit(exval); return exval; } #else /* if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */ /** Main program. @param argc Number of command line arguments. @param argv Command line arguments array. @return Exit status code. */ int main(int argc, char *argv[]) { fputs("printqdc: ERROR: Program can not be used on this system!\n", stderr); fflush(stderr); exit(EXIT_FAILURE); return EXIT_FAILURE; } #endif /* if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */