/* Copyright (c) 2010, 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 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 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. */ /** @file fsnmpm.c The fsnmpm module in the fsnmp program. */ /** Inside the fsnmpm.c module. */ #define FSNMPM_C 1 #include "fsnmp.h" #include "dktools-version.h" $(trace-include) /** Static strings used by the program. */ char *fsnmp_kw[] = { /* 0 */ "Processing finished, exit code %d indicates: %s.", /* 1 */ "Response from printer:\n", /* 2 */ "Starting of filter", /* 3 */ "Starting filter", /* 4 */ "An error occured while initializing fsnmp. No filtering!", /* 5 */ "Checking configuration file \"%s\" for configuration \"%s\".", /* 6 */ "Failed to read configuration file!", /* 7 */ "No printer name specified!", /* 8 */ "Syntax problem in \"%s:%lu\"!", /* 9 */ "Standard output is already connected to network socket.", /* 10 */ "Creating file name for temporary file.", /* 11 */ "Failed to create name for temporary file!", /* 12 */ "Temporary file name \"%s\" was created.", /* 13 */ "Retrieving pagecount %s.", /* 14 */ "before data transfer", /* 15 */ "after data transfer", /* 16 */ "No SNMP community specified! Please correct the configuration file!", /* 17 */ "Failed to create SNMP session!", /* 18 */ "Failed to retrieve pagecount!", /* 19 */ "Pagecount retrieved: %lu", /* 20 */ "Printer not responding (offline).\nPRINTER REQUIRES MANUAL INTERVENTION!", /* 21 */ "Error in SNMP response packet.", /* 22 */ "Printer busy.", /* 23 */ "Printer ready.", /* 24 */ "Error while inspecting response packet!", /* 25 */ "SNMP status responses: device = %s (%d), printer = %s (%d).", /* 26 */ "unknown", /* 27 */ "running", /* 28 */ "warning", /* 29 */ "testing", /* 30 */ "down", /* 31 */ "other", /* 32 */ "unknown", /* 33 */ "idle", /* 34 */ "printing", /* 35 */ "warmup", /* 36 */ "PRINTER REQUIRES MANUAL INTERVENTION!", /* 37 */ "Waiting for printer to start processing.", /* 38 */ "Connecting to printer.", /* 39 */ "Printer connection established, transferring data.", /* 40 */ "Transferring data.", /* 41 */ "Data transfer finished.", /* 42 */ "Shutting down printer connection.", /* 43 */ "Waiting for shutdown acknowledge.", /* 44 */ "Printer connection closed.", /* 45 */ "The of filter suspends itself.", /* 46 */ "The of filter woke up.", /* 47 */ "Error while writing to temporary file!", /* 48 */ "Failed to write temporary file!", /* 49 */ "Failed to create PDU for SNMP request!", /* 50 */ "Error while transferring data to printer!", /* 51 */ "Failed to read temporary file!", /* 52 */ "Not enough memory (RAM/swap space)!", /* 53 */ "A mathematical overflow occured!", /* 54 */ "Host \"%s\" not found!", /* 55 */ "No host name specified!", /* 56 */ "Invalid port number \"%s\"!", /* 57 */ "Missing port number!", /* 58 */ "Missing host name and port number specification!", /* 59 */ "No accounting destination specified!", /* 60 */ "Empty accounting destination!", /* 61 */ "Sending accounting data to \"%s\".", /* 62 */ "Accounting data was sent successfully.", /* 63 */ "Problem while sending accounting data!", /* 64 */ "Failed to write accounting file!", /* 65 */ "Failed to run accounting pipe command!", /* 66 */ "Accounting host name \"%s\" not found!", /* 67 */ "Accounting port number \"%s\" not found!", /* 68 */ "Failed to open a socket for accounting!", /* 69 */ "Failed to connect to accounting server \"%s\"!", /* 70 */ "Failed to send accounting data!", /* 71 */ "Problem while shutting down accounting network socket!", /* 72 */ "Shutting down accounting network socket.", /* 73 */ "Waiting for shutdown acknowledge from accounting server.", /* 74 */ "Closing accounting network socket.", /* 75 */ "Command line argument '-%c%s'.", /* 76 */ "Successfully bound to local port %u.", /* 77 */ "Failed to bind to local port range %u...%u!", /* 78 */ "Failed to connect to printer!", /* 79 */ "Failed to open a socket for data transfer!", /* 80 */ "Problem while shutting down data transfer socket!", /* 81 */ "Failed to mark local address for reuse.", /* 82 */ VERSNUMB , /* 83 */ "This is fsnmp-%s.", /* 84 */ "Accounting information was written to program \"%s\"", /* 85 */ "Accounting information will be written to program \"%s\"", NULL }; /** Descriptions for the exit codes in LPRng. */ char *exit_code_meaning[] = { /* 0 */ "Success", "Processing failed (retry later)", "Processing aborted (do not retry)", "Remove job", "Unknown result", "Unknown result", "Hold job", "No spooling to this queue", "No printing to this queue", "Processing aborted by signal", /* 10 */ "Processing failed (do not retry)", NULL }; /** Flag: At least one signal occured. */ static #if DK_HAVE_VOLATILE volatile #endif int signal_received = 0; /** SIGPIPE handler. @param i Signal number (SIGPIPE). */ static dk_signal_ret_t sigpipe_handler DK_P1(int, i) { dksignal_refresh(i, sigpipe_handler); signal_received = 1; } /** SIGTERM handler. @param i Signal number (SIGTERM). */ static dk_signal_ret_t sigterm_handler DK_P1(int, i) { dksignal_refresh(i, sigterm_handler); signal_received = 1; } /** SIGINT handler. @param i Signal number (SIGINT). */ static dk_signal_ret_t sigint_handler DK_P1(int, i) { dksignal_refresh(i, sigint_handler); signal_received = 1; } /** Check whether or not we can continue. @param fc Fsnmp job. @return 1=can continue, 0=stop. */ int fsnmp_cc DK_P1(FC *,fc) { int back = 1; if(signal_received) back = 0; if(fc->exit_code != EXIT_SUCCESS) back = 0; return back; } /** Input buffer. */ static char buffer_in[FSNMP_BUFFER_SIZE]; /** Output buffer. */ static char buffer_out[FSNMP_BUFFER_SIZE]; /** Clean up fsnmp job. @param fc Fsnmp job to clean up. */ static void cleanup DK_P1(FC *,fc) { char *x; $? "+ cleanup" // remove temporary file dksf_remove_file(fc->temp_file); if(fc->a_hostport) { x = fc->a_hostport; dk_delete(x); fc->a_hostport = NULL; } if(fc->a_acctdest) { x = fc->a_acctdest; dk_delete(x); fc->a_acctdest = NULL; } if(fc->a_community) { x = fc->a_community; dk_delete(x); fc->a_community = NULL; } $? "- cleanup" } /** Report one command line argument to log file. @param fc Fsnmp job. @param k Option key to report. */ static void report_one_argument DK_P2(FC *,fc, char,k) { char *v; v = fsnmpcmd_get_argv(fc, k); if(v) { fsnmplog(fc, PRIO_INFO, fsnmp_kw[75], k, v); } } /** Report command line arguments. @param fc Fsnmp job. */ static void report_command_line_arguments DK_P1(FC *,fc) { char c; for(c = 'a'; c <= 'z'; c++) { report_one_argument(fc, c); } for(c = 'A'; c <= 'Z'; c++) { report_one_argument(fc, c); } } /** Default file name for log file. */ static char default_snmp_logfile_name[] = { "netsnmp.log" }; /** Run the program. @param fc Fsnmp job. */ static void run DK_P1(FC *,fc) { // variables to store original signal handlers dk_signal_disp_t disp_term = NULL; dk_signal_disp_t disp_pipe = NULL; dk_signal_disp_t disp_int = NULL; #if DK_HAVE_NETSNMP_ENABLE_FILELOG netsnmp_log_handler *logh = NULL; #endif $? "+ run" // set signal handlers disp_term = dksignal_set(SIGTERM, sigterm_handler); disp_pipe = dksignal_set(SIGPIPE, sigpipe_handler); disp_int = dksignal_set(SIGINT, sigint_handler); #if DK_HAVE_NETSNMP_ENABLE_FILELOG logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_FILE, 5); if(logh) { logh->pri_max = 5; logh->token = strdup(default_snmp_logfile_name); if(logh->token) { netsnmp_enable_filelog(logh, 0); } } #endif // Check, whether or not to use stdout fsnmp_check_peer(fc); // read configuration file fsnmpcmd_read_config_file(fc); // create name for temporary file fsnmpcmd_create_temp_file_name(fc); // run filter or of if(fsnmp_cc(fc)) { fsnmplog(fc, PRIO_PROGRESS, fsnmp_kw[83], fsnmp_kw[82]); if((fc->flags) & FSNMP_FLAG_OF) { fsnmplog(fc, PRIO_PROGRESS, fsnmp_kw[2]); report_command_line_arguments(fc); fsnmp_of(fc); } else { fsnmplog(fc, PRIO_PROGRESS, fsnmp_kw[3]); report_command_line_arguments(fc); fsnmp_filter(fc); } } else { fsnmplog(fc, PRIO_ERROR, fsnmp_kw[4]); } #if DK_HAVE_NETSNMP_ENABLE_FILELOG if(logh) { snmp_disable_filelog(); netsnmp_remove_loghandler(logh); if(logh->token) { SNMP_FREE((logh->token)); logh->token = NULL; } free(logh); } #endif // restore original signal handlers dksignal_set(SIGINT, disp_int); dksignal_set(SIGPIPE, disp_pipe); dksignal_set(SIGTERM, disp_term); // cleanup cleanup(fc); $? "- run" } /** The main function of the fsnmp program. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, any other value indicates an error. */ #if DK_HAVE_PROTOTYPES int main(int argc, char *argv[]) #else int main(argc, argv) int argc; char *argv[]; #endif { FC fc; char *command_line_arguments[52]; // 2 * 26 = a-z,A-Z char temp_file_name_buffer[128]; oid oid_ds[MAX_OID_LEN]; oid oid_ps[MAX_OID_LEN]; oid oid_pc[MAX_OID_LEN]; $(trace-init fsnmp.deb) $? "+ main" // initialize fc fsnmpcmd_init(&fc); fc.argv = command_line_arguments; fc.buffer_in = buffer_in; fc.sz_buffer_in = sizeof(buffer_in); fc.buffer_out = buffer_out; fc.sz_buffer_out = sizeof(buffer_out); fc.temp_file = temp_file_name_buffer; fc.sz_temp_file = sizeof(temp_file_name_buffer); { int i; for(i = 0; i < 52; i++) command_line_arguments[i] = NULL; } fc.oid_ds = oid_ds; fc.oid_ps = oid_ps; fc.oid_pc = oid_pc; fc.sz_oid_ds = fc.sz_oid_ps = fc.sz_oid_pc = MAX_OID_LEN; // process command line arguments fsnmpcmd_apply_argv(&fc, argc, argv); // run the program run(&fc); fsnmplog( &fc, PRIO_INFO, fsnmp_kw[0], fc.exit_code, exit_code_meaning[((fc.exit_code >= 0) && (fc.exit_code <= 10)) ? fc.exit_code : 3] ); $? "- main %d", fc.exit_code $(trace-end) exit(fc.exit_code); return fc.exit_code; }