/* Copyright (C) 2012-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). 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: printqda.ctr */ /** @file printqda.c The printqda module. */ #line 29 "printqda.ctr" #include "printqd.h" #include "printqda.h" #line 36 "printqda.ctr" /** If this is defined to 1, each original request / daemon request pair is reported to stdout. */ #define PRINTQDA_DEBUG 0 #if DK3_CHAR_SIZE == 1 #if DK3_HAVE_STRUCT_SOCKADDR_UN /** Configuration file name relative to sysconf directory. */ static char const pqda_conffile[] = { PQD_CONFFILE }; /** Constant non-localized keywords used by the module. */ static char const * const pqda_c8_kw[] = { /* 0 */ "printqda", /* 1 */ "dktools", /* 2 */ " ", /* 3 */ "acct-check", /* 4 */ "acct-start", /* 5 */ "acct-end", /* 6 */ "printqdc", NULL #line 85 "printqda.ctr" }; /** Localized message texts used by the program. */ static char const * const pqda_loc[] = { /* 0 */ "printqda.str", /* 1 */ "Option was already set: \"", /* 2 */ "\"!", /* 3 */ "Option not started by a character: \"", /* 4 */ "\"!", /* 5 */ "Empty option: \"", /* 6 */ "\"!", /* 7 */ "Syntax error in request!", /* 8 */ "Syntax error, string not finalized!", /* 9 */ "Request contents too long!", /* 10 */ "Incomplete request! Missing one from:\nuser name, printer name, page count, job name, or job title!", /* 11 */ "Too few arguments in request!", /* 12 */ "Incomplete request, missing either user or printer name!", /* 13 */ "Illegal control sub-request: \"", /* 14 */ "\"!", /* 15 */ "Connection failed, skipping all remaining input!", /* 16 */ "Name of system configuration directory too long:\n\"", /* 17 */ "\"!", /* 18 */ "Failed to find system configuration directory!", /* 19 */ "Only printqda can process control requests, not printqdc!", NULL #line 159 "printqda.ctr" }; /** Request types (first word in request line). */ static char const * const pqda_request_types[] = { /* 0 */ "info", /* 1 */ "acct-check", /* 2 */ "acct-start", /* 3 */ "acct-end", /* 4 */ "jobstart", /* 5 */ "filestart", /* 6 */ "fileend", /* 7 */ "jobend", /* 8 */ "control", NULL #line 177 "printqda.ctr" }; /** Possible responses to LPRng jobstart requests. */ static char const * const pqda_decisions[] = { /* 0 */ "ACCEPT", /* 1 */ "REMOVE", /* 2 */ "HOLD", NULL #line 189 "printqda.ctr" }; /** Subrequests of control request. */ static char const * const pqda_control_sub_requests[] = { /* 0 */ "r$eset", /* 1 */ "a$dd", /* 2 */ "d$atabase-cleanup", NULL #line 201 "printqda.ctr" }; /** Initialize job structure. @param job Job structure to initialize. */ static void pqda_job_init(pqda_job_t *job) { #line 214 "printqda.ctr" dk3mem_res((void *)job, sizeof(pqda_job_t)); job->app = NULL; job->lmsg = NULL; job->cmsg = NULL; job->exval = 3; #line 219 "printqda.ctr" job->fadm = 0; #line 220 "printqda.ctr" job->fcerr = 0; job->up = NULL; job->lo = NULL; #line 224 "printqda.ctr" } /** Clean up job structure before exiting program. @param job Job structure to clean up. */ static void pqda_job_cleanup(pqda_job_t *job) { #line 236 "printqda.ctr" if(job->app) { dk3app_close(job->app); job->app = NULL; } #line 239 "printqda.ctr" } /** Check whether the program is run as administration program printqda or as multiplexor printqdc. The result is stored in fadm. @param job Job structure. @param exename Name of the executable file running. */ static void pqda_check_admin(pqda_job_t *job, char const *exename) { char bu[DK3_MAX_PATH]; /* Buffer for modification. */ char *p1; /* Start of program name. */ char *p2; /* File name suffix. */ #line 257 "printqda.ctr" if(exename) { if(strlen(exename) < sizeof(bu)) { strcpy(bu, exename); p1 = dk3str_rchr(bu, '/'); if(p1) { p1++; } else { p1 = bu; } p2 = dk3str_rchr(p1, '.'); if(p2) { *p2 = '\0'; } #line 268 "printqda.ctr" if(0 == strcmp(p1, pqda_c8_kw[0])) { job->fadm = 1; #line 270 "printqda.ctr" } } } #line 273 "printqda.ctr" } /** Store an LPRng option. @param job Job structure. @param kc Key character. @param v Value to store. @return 1 on success, 0 on error. */ static int pqda_lprng_set_option(pqda_job_t *job, char kc, char *v) { int back = 0; #line 289 "printqda.ctr" if(('a' <= kc) && ('z' >= kc)) { if((job->lo)[kc - 'a']) { if(job->fadm) { /* WARNING: Option set twice! */ dk3app_log_3(job->app, DK3_LL_WARNING, job->lmsg, 1, 2, v); } } (job->lo)[kc - 'a'] = v; back = 1; } else { if(('A' <= kc) && ('Z' >= kc)) { if((job->up)[kc - 'A']) { if(job->fadm) { /* WARNING: Option set twice! */ dk3app_log_3(job->app, DK3_LL_WARNING, job->lmsg, 1, 2, v); } } (job->up)[kc - 'A'] = v; back = 1; } } #line 310 "printqda.ctr" return back; } /** Retrieve one LPRng option. @param job Job structure. @param kc Key character. @return Pointer to option value if defined, NULL otherwise. */ static char * pqda_lprng_get_option(pqda_job_t *job, char kc) { char *back = NULL; #line 326 "printqda.ctr" if(('a' <= kc) && ('z' >= kc)) { back = (job->lo)[kc - 'a']; } else { if(('A' <= kc) && ('Z' >= kc)) { back = (job->up)[kc - 'A']; } } #line 333 "printqda.ctr" return back; } /** Retrieve LPRng specific options. @param job Job structure. @param p2 String containing the options. @return 1 on success, 0 on error. */ static int pqda_lprng_options(pqda_job_t *job, char *p2) { char *ptr; /* Current character to process. */ char *ps; /* Start of current string. */ int back = 1; int i; /* Traverse all up and lo pointers. */ int st; /* Current reader state. */ #line 354 "printqda.ctr" for(i = 0; i < 26; i++) { (job->up)[i] = NULL; (job->lo)[i] = NULL; } st = 0; ptr = p2; ps = NULL; while(*ptr) { #line 359 "printqda.ctr" switch(st) { case 0: { /* in space before a string. */ if('\'' == *ptr) { st = 1; ps = ptr; } } break; case 1: { /* in string. */ switch(*ptr) { case '\'': { #line 369 "printqda.ctr" *ptr = '\0'; st = 0; if(ps) { #line 372 "printqda.ctr" ps++; if('-' == ps[0]) { if('\0' != ps[1]) { if(!pqda_lprng_set_option(job, ps[1], &(ps[2]))) { back = 0; #line 377 "printqda.ctr" if(job->fadm) { /* ERROR: Not a character */ dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 3, 4, ps); } } } else { #line 383 "printqda.ctr" back = 0; if(job->fadm) { /* ERROR in string, empty option */ dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 5, 6, ps); } } } } else { #line 391 "printqda.ctr" back = 0; if(job->fadm) { /* ERROR in input! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 7); } } } break; case '\\': { #line 399 "printqda.ctr" st = 2; } break; } } break; case 2: { /* in string, backslash found. */ st = 1; } break; } ptr++; } if(0 != st) { #line 410 "printqda.ctr" back = 0; if(job->fadm) { /* ERROR: Incorrect input! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 8); } } #line 416 "printqda.ctr" return back; } /** Convert a filestart/fileend request. @param job Job structure. @param rq First request word. @param ib3 Input buffer 3 to use for response. @return 1 on success, 0 on error. */ static int pqda_file_startend(pqda_job_t *job, char const *rq, char *ib3) { char *pn; /* Printer name. */ char *un; /* User name. */ char *pc; /* Pagecount value as text. */ char *jn; /* Print job name. */ char *jt; /* Print job title. */ size_t sz; /* Size of converted request. */ int back = 0; #line 439 "printqda.ctr" un = NULL; pn = NULL; pc = NULL; jn = NULL; jt = NULL; un = pqda_lprng_get_option(job, 'n'); pn = pqda_lprng_get_option(job, 'P'); pc = pqda_lprng_get_option(job, 'p'); jt = pqda_lprng_get_option(job, 'J'); jn = pqda_lprng_get_option(job, 'A'); if(!(jn)) { jn = pqda_lprng_get_option(job, 'D'); } if(!(jn)) { jn = pn; } if(!(jt)) { jt = jn; } if((un) && (pn) && (pc) && (jt) && (jn)) { sz = 5 * strlen(pqda_c8_kw[2]); sz += strlen(rq); sz += strlen(un); sz += strlen(pn); sz += strlen(pc); sz += strlen(jt); sz += strlen(jn); if(PQD_INPUT_BUFFER_SIZE > sz) { strcpy(ib3, rq); strcat(ib3, pqda_c8_kw[2]); strcat(ib3, pn); strcat(ib3, pqda_c8_kw[2]); strcat(ib3, un); strcat(ib3, pqda_c8_kw[2]); strcat(ib3, pc); strcat(ib3, pqda_c8_kw[2]); strcat(ib3, jn); strcat(ib3, pqda_c8_kw[2]); strcat(ib3, jt); back = 1; } else { if(job->fadm) { /* ERROR: Request contents too long! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 9); } } } else { if(job->fadm) { /* ERROR: Incomplete jobstart/jobend request! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 10); } } #line 481 "printqda.ctr" return back; } /** Prepare input for printqd. @param job Job structure. @param ib1 Original request, unmodified. @param ib3 Input buffer for printqd, our destination. @param p2 Arguments to original request, writable copy. @param act Request type. */ static int pqda_daemon_input( pqda_job_t *job, char *ib1, char *ib3, char *p2, int act ) { char *parts[16]; /* Splitted request string. */ char *un; /* User name. */ char *pn; /* Printer name. */ size_t na; /* Number of elements in nparts. */ size_t sz; /* String length of result string. */ int res; /* Operation result. */ int back = 0; #line 511 "printqda.ctr" if((act < 8) || (job->fadm)) { /* control requests only printqda. */ un = NULL; pn = NULL; switch(act) { case 0: { /* info */ na = dk3str_c8_explode(parts, 15, p2, NULL); if(2 <= na) { back = 1; } else { if(job->fadm) { /* ERROR: Too few arguments in request! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11); } } } break; case 1: { /* acct-check */ na = dk3str_c8_explode(parts, 15, p2, NULL); if(2 <= na) { back = 1; } else { if(job->fadm) { /* ERROR: Too few arguments in request! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11); } } } break; case 2: { /* acct-start */ na = dk3str_c8_explode(parts, 15, p2, NULL); if(5 <= na) { back = 1; } else { if(job->fadm) { /* ERROR: Too few arguments in request! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11); } } } break; case 3: { /* acct-end */ na = dk3str_c8_explode(parts, 15, p2, NULL); if(5 <= na) { back = 1; } else { if(job->fadm) { /* ERROR: Too few arguments in request */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11); } } } break; case 4: { /* jobstart */ if(pqda_lprng_options(job, p2)) { un = pqda_lprng_get_option(job, 'n'); pn = pqda_lprng_get_option(job, 'P'); if((un) && (pn)) { sz = strlen(pqda_c8_kw[3]); sz += 2 * strlen(pqda_c8_kw[2]); sz += strlen(un); sz += strlen(pn); if(sz < PQD_INPUT_BUFFER_SIZE) { strcpy(ib3, pqda_c8_kw[3]); strcat(ib3, pqda_c8_kw[2]); strcat(ib3, pn); strcat(ib3, pqda_c8_kw[2]); strcat(ib3, un); back = 1; } else { if(job->fadm) { /* ERROR: Request data too long! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 9); } } } else { if(job->fadm) { /* ERROR: Incomplete information in request! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 12); } } } } break; case 5: { /* filestart */ if(pqda_lprng_options(job, p2)) { back = pqda_file_startend(job, pqda_c8_kw[4], ib3); } } break; case 6: { /* fileend */ if(pqda_lprng_options(job, p2)) { back = pqda_file_startend(job, pqda_c8_kw[5], ib3); } } break; case 7: { /* jobend */ /* Nothing to do, we ignore this request. */ } break; case 8: { /* control */ na = dk3str_c8_explode(parts, 15, p2, NULL); if(na > 0) { res = dk3str_array_abbr(pqda_control_sub_requests, parts[0], '$', 0); if(-1 < res) { back = 1; } else { if(job->fadm) { /* ERROR: Too few arguments in request! */ dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 13, 14, parts[0]); } } } else { if(job->fadm) { dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 11); } } } break; } } else { if((8 == act) && (!(job->fadm))) { job->exval = 1; #line 624 "printqda.ctr" dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 19); #if DK3_HAVE_SYSLOG openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR); syslog(LOG_ERR, "Attempt to send control request to printqdc!"); closelog(); #endif } } #if PRINTQDA_DEBUG if(back) { printf("%s\n%s\n", ib1, ib3); } else { if(7 != act) { printf("!!! FAILED %s\n", ib1); } } #endif #line 642 "printqda.ctr" return back; } /** Convert daemon response to this programs response. @param job Job structure. @param ib3 Destination buffer. @param ib2 Daemon response. @param act Request type. @return 1 if we must write output to standard output, 0 otherwise. */ static int pqda_daemon_output(pqda_job_t *job, char *ib3, char *ib2, int act) { int back = 0; #line 661 "printqda.ctr" ib3[0] = '\0'; switch(act) { case 0: { #line 664 "printqda.ctr" back = 1; } break; case 1: { #line 667 "printqda.ctr" back = 1; } break; case 4: { #line 670 "printqda.ctr" back = 1; } break; } if(back) { strcpy(ib3, ib2); dk3str_c8_delnl(ib3); if(!(strlen(ib3) > 0)) { back = 0; } } #line 681 "printqda.ctr" return back; } /** Process all input lines found on standard input. @param job Job structure */ static void pqda_process_input(pqda_job_t *job) { char ib1[PQD_INPUT_BUFFER_SIZE]; /* Original input. */ char ib2[PQD_INPUT_BUFFER_SIZE]; /* Copy for test. */ char ib3[PQD_INPUT_BUFFER_SIZE]; /* Daemon input. */ char *p1; /* Request keyword. */ char *p2; /* Request arguments. */ dk3_socket_t sock; /* Socket to daemon. */ size_t sz; /* Request size. */ int act; /* Action to take. */ int bw; /* Bytes written. */ int first; /* Flag: First resp. */ int res; /* Shutdown result. */ #line 705 "printqda.ctr" while(fgets(ib1, sizeof(ib1), stdin)) { if(!(job->fcerr)) { dk3str_c8_delnl(ib1); strcpy(ib2, ib1); p1 = dk3str_c8_start(ib2, NULL); if(p1) { if(*p1 != '#') { p2 = dk3str_c8_next(p1, NULL); act = dk3str_c8_array_index(pqda_request_types, p1, 0); strcpy(ib3, ib1); if(pqda_daemon_input(job, ib1, ib3, p2, act)) { sz = strlen(ib3); sock = dk3socket_un_stream_client( (job->cfg).usn, 0L, 0L, NULL, job->app ); if(INVALID_SOCKET != sock) { bw = dk3socket_send(sock, ib3, sz, 0L, 0L, NULL, job->app); if(bw >= 0) { res = dk3socket_shutdown( sock, DK3_TCPIP_SHUTDOWN_WRITE, NULL, job->app ); if(res) { first = 1; ib2[0] = '\0'; do { bw = dk3socket_recv( sock, ib3, (sizeof(ib3) - 1), 0L, 0L, NULL, job->app ); if(bw > 0) { if(first) { first = 0; ib3[((size_t)bw < sizeof(ib3)) ? bw : (sizeof(ib3) - 1)] = '\0'; strcpy(ib2, ib3); } } } while(bw > 0); if(!(first)) { if(pqda_daemon_output(job, ib3, ib2, act)) { fputs(ib3, stdout); fputc('\n', stdout); fflush(stdout); if(!(job->fadm)) { #line 748 "printqda.ctr" switch(dk3str_c8_array_index(pqda_decisions, ib3, 0)) { case 1: { job->exval = 3; #line 751 "printqda.ctr" } break; case 2: { job->exval = 6; #line 754 "printqda.ctr" } break; } } else { #line 757 "printqda.ctr" } } } } } dk3socket_close(sock, NULL, NULL); #if VERSION_BEFORE_20150821 sock = INVALID_SOCKET; #endif } else { job->fcerr = 1; job->exval = 1; #line 769 "printqda.ctr" /* FATAL: Connection failed, skipping all remaining input */ if(job->fadm) { dk3app_log_1(job->app, DK3_LL_FATAL, job->lmsg, 15); } else { #if DK3_HAVE_SYSLOG openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR); syslog(LOG_ERR, "Failed to connect to printqd! Skipping all input!"); closelog(); #endif } } } else { #line 781 "printqda.ctr" } } } } } #line 787 "printqda.ctr" } /** Process configuration file and run. @param job Job structure. @param cfgfilename Name of configuration file. */ static void pqda_run_with_config_filename(pqda_job_t *job, char const *cfgfilename) { int res; #line 801 "printqda.ctr" res = pqdconf_read( &(job->cfg), cfgfilename, ((job->fadm) ? PQD_PROGRAM_TYPE_ADMIN : PQD_PROGRAM_TYPE_MULTIPLEXOR), job->app, job->cmsg ); if(res) { #line 808 "printqda.ctr" res = pqdconf_check( &(job->cfg), ((job->fadm) ? PQD_PROGRAM_TYPE_ADMIN : PQD_PROGRAM_TYPE_MULTIPLEXOR), job->app, job->cmsg ); if(res) { #line 814 "printqda.ctr" #line 815 "printqda.ctr" job->exval = 0; #line 816 "printqda.ctr" pqda_process_input(job); } else { #line 818 "printqda.ctr" /* ERROR: Check failed! */ } } else { #line 821 "printqda.ctr" /* ERROR: Failed to read configuration! */ } pqdconf_cleanup(&(job->cfg)); #line 825 "printqda.ctr" } /** Find configuration file name and run with it. @param job Job structure. */ static void pqda_search_for_config_filename(pqda_job_t *job) { char bu[DK3_MAX_PATH]; /* Buffer to construct file name. */ char const *scd; /* System configuration directory. */ #line 839 "printqda.ctr" scd = dk3inst_get_directory(1); if(scd) { if(strlen(scd) < sizeof(bu)) { strcpy(bu, scd); if((strlen(bu) + strlen(pqda_conffile)) < sizeof(bu)) { strcat(bu, pqda_conffile); pqda_run_with_config_filename(job, bu); } else { /* ERROR: sysconfdir name too long! */ if(job->fadm) { dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 16, 17, scd); } else { #if DK3_HAVE_SYSLOG openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR); syslog(LOG_ERR, "File name of sysconfdir too long!"); closelog(); #endif } } } else { /* ERROR: sysconfdir too long! */ if(job->fadm) { dk3app_log_3(job->app, DK3_LL_ERROR, job->lmsg, 16, 17, scd); } else { #if DK3_HAVE_SYSLOG openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR); syslog(LOG_ERR, "File name of sysconfdir too long!"); closelog(); #endif } } } else { /* ERROR: Failed to obtain sysconfdir! */ if(job->fadm) { dk3app_log_1(job->app, DK3_LL_ERROR, job->lmsg, 18); } else { #if DK3_HAVE_SYSLOG openlog(pqda_c8_kw[6], LOG_PID, LOG_LPR); syslog(LOG_ERR, "Failed to find sysconfdir!"); closelog(); #endif } } #line 882 "printqda.ctr" } /** Run after allocating an application structure. @param job Job structure. */ static void pqda_run_with_app(pqda_job_t *job) { char const * const *xargv; /* Command line arguments array. */ int xargc; /* Number of command line arguments. */ #line 896 "printqda.ctr" job->lmsg = dk3app_messages(job->app, pqda_loc[0], pqda_loc); job->cmsg = pqdconf_get_messages(job->app); xargc = dk3app_get_argc(job->app); xargv = dk3app_get_argv(job->app); if((xargc > 1) && (job->fadm)) { pqda_run_with_config_filename(job, xargv[1]); } else { pqda_search_for_config_filename(job); } #line 906 "printqda.ctr" } /** For printqdc we use a silent application now instead of a daemon application. Multiple instance of printqdc may run at the same time, so we should not let them write all to the same log file. */ #if VERSION_BEFORE_20120526 /** When running as daemon (no output to stderr) we need the current directory. @param job Job structure. @param argc Number of command line arguments. @param argv Command line arguments array. */ static void pqda_run_for_daemon(pqda_job_t *job, int argc, char *argv[]) { char bu[DK3_MAX_PATH]; /* Buffer for current working dir. */ #line 928 "printqda.ctr" if(dk3sf_c8_getcwd_app(bu, sizeof(bu), NULL)) { job->app = dk3app_open_daemon( bu, argc, (dkChar const * const *)argv, pqda_c8_kw[1] ); if(job->app) { pqda_run_with_app(job); } } else { /* ERROR: Failed to find current directory! */ } #line 938 "printqda.ctr" } #endif /** Entry point of the program. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, any other value indicates an error. */ int main(int argc, char *argv[]) { pqda_job_t job; /* Job structure. */ char *up[26]; /* Upper case option arguments. */ char *lo[26]; /* Lower case option arguments. */ int exval; /* Exit status code. */ #line 956 "printqda.ctr" #line 957 "printqda.ctr" pqda_job_init(&job); pqda_check_admin(&job, argv[0]); job.up = up; job.lo = lo; #if VERSION_BEFORE_20120526 if(job.fadm) { job.app = dk3app_open_command( argc, (dkChar const * const *)argv, pqda_c8_kw[1] ); if(job.app) { pqda_run_with_app(&job); } else { fputs("printqda: ERROR: Not enough memory (RAM/swap)!\n", stderr); fflush(stderr); } } else { pqda_run_for_daemon(&job, argc, argv); } #endif if(job.fadm) { job.app = dk3app_open_command( argc, (dkChar const * const *)argv, pqda_c8_kw[1] ); } else { job.app = dk3app_open_silent( argc, (dkChar const * const *)argv, pqda_c8_kw[1] ); } if(job.app) { pqda_run_with_app(&job); } else { if(job.fadm) { fputs("printqda: ERROR: Not enough memory (RAM/swap)!\n", stderr); fflush(stderr); } } exval = job.exval; #if 0 /* NO, EXIT CODE MUST INDICATE ACTION TOO! */ if(!(job.fadm)) { exval = 0; } #endif pqda_job_cleanup(&job); #line 1001 "printqda.ctr" #line 1002 "printqda.ctr" fflush(stdout); exit(exval); return exval; } #else /** Program entry point. @param argc @param argv @return 0 on success, any other value indicates an error. */ int main(int argc, char *argv[]) { fprintf(stderr, "printqd: ERROR: No UNIX domain sockets available!\n"); fflush(stderr); exit(1); } #endif #else /** Program entry point. @param argc @param argv @return 0 on success, any other value indicates an error. */ int main(int argc, char *argv[]) { fprintf( stderr, "printqd: ERROR: This program does not support wide characters (%d)!\n", DK3_CHAR_SIZE ); fflush(stderr); exit(1); } #endif