/* Copyright (c) 2008-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 prqd.c The prqd daemon. */ #include "prqd.h" $(trace-include) /** Program name. */ static char appname[] = { "prqd" }; /** Texts for responses to jobstart requests. */ static char *response_keywords[]= { /* 0 */ "ACCEPT\n", /* 1 */ "FAIL\n", /* 2 */ "HOLD\n", /* 3 */ "REMOVE\n" }; /** Log messages for syslog logging. */ static char *logmsgs[] = { "prqd-acct job u=%s c=%s pr=%s pa=%ld h=%s j=%s", "prqd-acct summary u=%s c=%s pa=%ld l=%s", "prqd-acct summary u=%s c=%s ac=%s", "prqd-acct balance-account u=%s c=%s", "prqd-acct limit-reached u=%s c=%s", }; /** Texts in user information files. */ static char *uift[] = { /* 0 */ "Date: ", /* 1 */ "Printed pages / General limit: ", /* 2 */ "Additional pages in personal account:", /* 3 */ "Allowed to print: ", /* 4 */ "yes", /* 5 */ "no", /* 6 */ "unlimited", NULL }; /** Database entry format for current job. */ static char current_job_format[] = { "%s:%s" }; /** Database key pattern for current job on a printer. */ static char key_current_job_format[] = { "j:%s" }; /** Database key pattern for pages printed by users. */ static char key_user_pages[] = { "p:%s:%s" }; /** Database key pattern for print accounts. */ static char key_user_account[]= { "a:%s:%s" }; /** Empty string. */ static char empty_string[] = { "" }; /** Replace NULL string pointers by pointer to empty string. */ #define XSTR(s) ((s) ? (s) : empty_string) /** Flag: SIGHUP received. */ static #if DK_HAVE_VOLATILE volatile #endif int sighup_r = 0; /** SIGHUP handler. @param signo Signal number (SIGHUP). */ dk_signal_ret_t sighup_handler DK_P1(int, signo) { dksignal_refresh(signo,sighup_handler); sighup_r = 1; dksignal_return(0); } /** Flag: SIGINT received. */ static #if DK_HAVE_VOLATILE volatile #endif int sigint_r = 0; /** SIGINT handler. @param signo Signal number (SIGINT). */ dk_signal_ret_t sigint_handler DK_P1(int, signo) { dksignal_refresh(signo,sigint_handler); sigint_r = 1; dksignal_return(0); } /** Flag: SIGPIPE received. */ static #if DK_HAVE_VOLATILE volatile #endif int sigpipe_r = 0; /** SIGPIPE handler. @param signo Signal number (SIGPIPE). */ dk_signal_ret_t sigpipe_handler DK_P1(int, signo) { dksignal_refresh(signo,sigpipe_handler); sigpipe_r = 1; dksignal_return(0); } /** Flag: SIGTERM was received. */ static #if DK_HAVE_VOLATILE volatile #endif int sigterm_r = 0; /** SIGTERM handler. @param signo Signal number (SIGTERM). */ dk_signal_ret_t sigterm_handler DK_P1(int, signo) { dksignal_refresh(signo,sigterm_handler); sigterm_r = 1; dksignal_return(0); } /** Exit outer loop (main program) only on SIGTERM, SIGINT or serious error. @param pj Pointer to prqd job structure. @return 1 if we can continue, 0 if we have to leave the loop. */ int prqd_cc1 DK_P1(PJ *,pj) { int back = 1; $? "+ prqd_cc1" if(sigterm_r) back = 0; if(sigint_r) back = 0; if(pj->e1) back = 0; if(!back) { prqdlog(pj, PRQD_PRIO_INFO, prqd_get_kw(55)); } $? "- prqd_cc1 %d", back return back; } /** Exit inner loop on SIGTERM, SIGINT, serious errors or reconfiguration. @param pj Pointer to prqd job structure. @return 1 if we can continue, 0 if we have to leave the loop. */ int prqd_cc2 DK_P1(PJ *,pj) { int back = 0; $? "+ prqd_cc2" back = prqd_cc1(pj); if(back) { if(sighup_r) back = 0; /* reconfiguration */ if(pj->e2) back = 0; } if(!back) { prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(54)); } $? "- prqd_cc2 %d", back return back; } /** Check inner ``can continue'' condition. @param pj Pointer to prqd job structure. @return 1 if we can continue, 0 if we need to leave the loop. */ int prqd_cc3 DK_P1(PJ *,pj) { int back = 0; $? "+ prqd_cc3" back = prqd_cc1(pj); if(back) { if(sigpipe_r) back = 0; /* broken pipe, exit session */ /* on sighup reconfigure _after_ the session */ if(pj->e2) back = 0; /* but on errors exit loop */ if(pj->e3) back = 0; } if(!back) { prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(53)); } $? "- prqd_cc3" return back; } /** Change the UID and GID of the process. To minimize the risk of abuse the prqd process should not run in the root account. Use ``run as user ='' and ``run as group ='' in the prqd.conf file to choose a user account and group. @param pj Pointer to prqd job structure. */ static void change_user_and_group DK_P1(PJ *,pj) { struct passwd *ppwd = NULL; struct group *pgrp = NULL; uid_t tuid; gid_t tgid; $? "+ change_user_and_group" tuid = geteuid(); tgid = getegid(); if((pj->prqdc)->rag) { $? ". run as group" pgrp = getgrnam((pj->prqdc)->rag); if(pgrp) { /* gr_gid */ tgid = pgrp->gr_gid; $? ". group found" } else { pj->e1 = 1; $? "! group name %s not found", (pj->prqdc)->rag prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(47), (pj->prqdc)->rag); } } else { $? ". no run-as-group entry" prqdlog(pj, PRQD_PRIO_WARNING, prqd_get_kw(49)); } if((pj->prqdc)->rau) { $? ". run as user" ppwd = getpwnam((pj->prqdc)->rau); if(ppwd) { /* pw_uid */ tuid = ppwd->pw_uid; $? ". user found" } else { pj->e1 = 1; $? "! user name %s not found", (pj->prqdc)->rau prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(48), (pj->prqdc)->rau); } } else { $? ". no run-as-user entry" prqdlog(pj, PRQD_PRIO_WARNING, prqd_get_kw(50)); } (void)chown((pj->prqdc)->sockname, tuid, tgid); (void)chown(prqdconf_get_logfile(), tuid, tgid); prqdbe_change_ownership(pj, tuid, tgid); if(pgrp) { $? ". changing group" setgid(tgid); prqdlog(pj, PRQD_PRIO_INFO, prqd_get_kw(52), (pj->prqdc)->rag); } if(ppwd) { $? ". changing user" setuid(tuid); prqdlog(pj, PRQD_PRIO_INFO, prqd_get_kw(51), (pj->prqdc)->rau); } $? "- change_user_and_group" } /** For each printer retrieve information about the currently open job from the database. @param pj Pointer to prqd job structure. */ static void initialize_open_jobs DK_P1(PJ *,pj) { PR *pr; $? "+ initialize_open_jobs" dksto_it_reset((pj->prqdc)->pri); while((pr = (PR *)dksto_it_next((pj->prqdc)->pri)) != NULL) { if(!(pr->alt)) { $? ". getting open job for printer \"%s\"", pr->n (pr->cj)[0] = '\0'; if((2 + strlen(pr->n)) < pj->sz_dbkey) { $? ". string length ok" sprintf(pj->dbkey, "j:%s", pr->n); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { $? " prqdbe_fetch ok" if(strlen(pj->dbval) < (pr->sz_cj)) { strcpy(pr->cj, pj->dbval); $? ". value \"%s\"", pj->dbval } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(46), pj->dbval); } } else { prqdbe_store(pj, pj->dbkey, pr->cj); } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(36), pr->n); } } } $? "- initialize_open_jobs" } /** Read a request from standard input to buffer. @param pj Pointer to prqd job structure. @return 1 on success, 0 on error. */ static int read_request DK_P1(PJ *,pj) { int back = 0; size_t sz = 0; fd_set rfds; struct timeval tv; $? "+ read_request" if(((pj->prqdc)->to_seconds > 0L) ||((pj->prqdc)->to_microseconds > 0L)) { prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(17)); FD_ZERO(&rfds); FD_SET(pj->ss, &rfds); tv.tv_sec = (pj->prqdc)->to_seconds; tv.tv_usec = (pj->prqdc)->to_microseconds; if(select((1 + pj->ss), &rfds, NULL, NULL, &tv) > 0) { if(FD_ISSET(pj->ss,&rfds)) { sz = recv(pj->ss, pj->b1, pj->sz_b1, 0); } } } else { prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(18)); sz = recv(pj->ss, pj->b1, pj->sz_b1, 0); } if(sz > 0) { prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(19), (unsigned long)sz); if(sz >= pj->sz_b1) { (pj->b1)[(pj->sz_b1) - 1] = '\0'; } else { (pj->b1)[sz] = '\0'; } back = 1; } else { prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(20)); } $? "- read_request %d", back return back; } /** Write user information file for a user on a printer class. @param pj Pointer to prqd job structure. @param uname User name. @param pclass Printer class name. */ void prqd_write_userinfo_file DK_P3(PJ *,pj, char *,uname, char *,pclass) { PC *pc; LE *le; long uap = 0L; long upp = 0L; long l; char keybuffer[PRQD_DBENTRY_SIZE], valbuffer[PRQD_DBENTRY_SIZE], pagebuffer[32]; int limit_value; unsigned long limit_pages; int is_bigger = 0, apply_limit = 0, is_allowed = 0; struct group *gr; struct passwd *pw; uid_t uid_uname; gid_t gid_uname; char *fn, *p1, **lfdptr; time_t timer; struct tm *tm; FILE *fipo; size_t sz; int do_print = 0; $? "+ prqd_write_userinfo_file" if((pj) && (uname) && (pclass)) { $? ". arguments ok" if((pj->prqdc)->userinfdir) { if((3 + strlen(uname) + strlen(pclass)) < sizeof(keybuffer)) { /* find printed pages */ sprintf(keybuffer, "p:%s:%s", pclass, uname); if(prqdbe_fetch(pj, keybuffer, valbuffer, sizeof(valbuffer))) { if(sscanf(valbuffer, "%ld", &l) == 1) { upp = l; } } /* find pages in personal account */ sprintf(keybuffer, "a:%s:%s", pclass, uname); if(prqdbe_fetch(pj, keybuffer, valbuffer, sizeof(valbuffer))) { if(sscanf(valbuffer, "%ld", &l) == 1) { uap = l; } } /* find limit */ limit_value = LIMIT_VALUE_DENIED; limit_pages = 0UL; is_allowed = 0; pc = (PC *)dksto_it_find_like((pj->prqdc)->cli, pclass, 1); if(pc) { if(pc->wi) { do_print = 1; uid_uname = 0; gid_uname = 0; pw = getpwnam(uname); if(pw) { uid_uname = pw->pw_uid; gid_uname = pw->pw_gid; } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(45), uname); } dksto_it_reset(pc->li); while((le = dksto_it_next(pc->li)) != NULL) { is_bigger = 0; if(le->val > limit_value) { is_bigger = 1; } else { if((le->val == LIMIT_VALUE_PAGES) && (limit_value == LIMIT_VALUE_PAGES)) { if(le->p > limit_pages) { is_bigger = 1; } } } if(is_bigger) { apply_limit = 0; switch(le->tp) { case LIMIT_ENTRY_TYPE_DEFAULT: { apply_limit = 1; } break; case LIMIT_ENTRY_TYPE_GROUP: { if(le->who) { gr = getgrnam(le->who); if(gr) { if(pw) { if(gid_uname == gr->gr_gid) { apply_limit = 1; } } if(!apply_limit) { lfdptr = gr->gr_mem; while((*lfdptr) && (apply_limit == 0)) { if(strcmp(*lfdptr, uname) == 0) { apply_limit = 1; } lfdptr++; } } } } } break; case LIMIT_ENTRY_TYPE_USER: { if(le->who) { if(strcmp(le->who, uname) == 0) { apply_limit = 1; } } } break; } if(apply_limit) { limit_value = le->val; limit_pages = le->p; } } } } } else { $? "! printer class not found" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(44), pclass); } /* decide */ switch(limit_value) { case LIMIT_VALUE_PAGES: { if(limit_pages > upp) { is_allowed = 1; } else { if(uap > 0L) { is_allowed = 1; } } } break; case LIMIT_VALUE_UNLIMITED: { is_allowed = 1; } break; } /* write output */ if(do_print) { sz = 7 + strlen((pj->prqdc)->userinfdir) + strlen(uname) + strlen(pclass); fn = dk_new(char,sz); if(fn) { $? ". fn ok" time(&timer); tm = localtime(&timer); sprintf(fn, "%s/%s-%s.txt", (pj->prqdc)->userinfdir, pclass, uname); $? ". fn = \"%s\"", fn fipo = dksf_fopen(fn, "w"); if(fipo) { $? ". file opened" fchmod(fileno(fipo), (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)); fprintf(fipo, "%s %04d-%02d-%02d %02d:%02d:%02d\r\n", uift[0], (1900 + tm->tm_year), (1 + tm->tm_mon), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec ); switch(limit_value) { case LIMIT_VALUE_UNLIMITED: { p1 = uift[6]; } break; case LIMIT_VALUE_PAGES: { sprintf(pagebuffer, "%lu", limit_pages); p1 = pagebuffer; } break; default: { sprintf(pagebuffer, "%lu", 0UL); p1 = pagebuffer; } break; } fprintf(fipo, "%s %ld / %s\r\n", uift[1], upp, p1); fprintf(fipo, "%s %ld\r\n", uift[2], uap); fprintf(fipo, "%s %s\r\n", uift[3], uift[is_allowed ? 4 : 5]); fclose(fipo); fipo = NULL; } else { $? "! failed to open file" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(43), fn); } chmod(fn, 0644); dk_delete(fn); } else { $? "! memory" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); } } } else { $? "! key too large" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(41), uname, pclass); } } } else { $? "! wrong arguments" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(40)); } $? "- prqd_write_userinfo_file" } /** Process jobstart request. Check whether the user is allowed to print. @param pj Pointer to prqd job structure. @return 1 on success, 0 on error. */ static int jobstart_request DK_P1(PJ *,pj) { int back = 0; long upp = 0L, uap = 0L; $? "+ jobstart_request" prqd_pj_get_names(pj); prqd_pj_find_limit(pj); if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { if(sscanf(pj->dbval, "%ld", &upp) != 1) { upp = 0L; back = 0; $? "! failed to convert db entry to number \"%s\"", pj->dbval prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(37), pj->dbval); } } } else { $? "! db key too long" back = 0; } if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_account, pj->cname, pj->uname); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { if(sscanf(pj->dbval, "%ld", &uap) != 1) { uap = 0L; back = 0; $? "! failed to convert db entry to number \"%s\"", pj->dbval prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(38), pj->dbval); } } } else { $? "! db key too long" back = 0; } $? ". pages printed %ld, account %ld", upp, uap $? ". limit %d %lu", pj->limit_type, pj->limit_pages switch(pj->limit_type) { case LIMIT_VALUE_UNLIMITED: { $? ". unlimited printing granted" strcpy(pj->b2, response_keywords[0]); back = 1; } break; case LIMIT_VALUE_PAGES: { $? ". printing limited by page number" if((unsigned long)upp < pj->limit_pages) { $? ". page limit not yet reached" strcpy(pj->b2, response_keywords[0]); back = 1; } else { if(uap > 0L) { $? ". free pages in personal account" strcpy(pj->b2, response_keywords[0]); back = 1; } else { $? "! limit exceeded" } } } break; default: { $? "! printing denied" } break; } prqdlog(pj, PRQD_PRIO_INFO, prqd_get_kw(39), back); $? "- jobstart_request %d pj->b2=\"%s\"", back, pj->b2 return back; } /** Seed pseudo random number generator for faked limits. For users which do not exist we return a faked entry indicating ``over limit'' to prevent prqd for being abused to guess user names. */ static void set_random_for_name DK_P1(char *,uname) { char *p1, *p2; size_t szrs, i; unsigned rs; rs = (unsigned)getpid; p1 = (char *)(&rs); szrs = sizeof(unsigned); p2 = uname; i = 0; while(*p2) { p1[i] = p1[i] ^ (*p2); p2++; i++; if(i >= szrs) { i = 0; } } srand(rs); } /** Process info request. @param pj Pointer to prqd job structure. @param p Additional arguments for the request. @return 1 on success, 0 on error. */ static int info_request DK_P2(PJ *,pj, char *,p) { int back = 1; char *p1, *p2; long upp = 0L, uap = 0L, page_limit = 0L; struct passwd *pw; /* uppt: bereits gedruckte Seiten uapt: Seiten in persoenlichem Account lt: Limit (Seitenzahl) ft: Flag (0 oder 1) */ char uppt[32], uapt[32], lt[32], ft[32]; $? "+ info_request" sprintf(uppt, "%ld", 0L); sprintf(uapt, "%ld", 0L); sprintf(lt, "%ld", 0L); sprintf(ft, "%ld", 0L); if(p) { $? ". args ok" p1 = dkstr_start(p, NULL); if(p1) { $? ". p1 ok" p2 = dkstr_next(p1, NULL); if(p2) { $? ". p2 ok" pw = getpwnam(p2); if(pw) { prqd_pj_set_arg(pj, 'n', p2); prqd_pj_set_arg(pj, 'P', p1); prqd_pj_get_names(pj); prqd_pj_find_limit(pj); if(pj->cname) { if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { if(sscanf(pj->dbval, "%ld", &upp) != 1) { upp = 0L; back = 0; $? "! failed to convert db entry to number \"%s\"", pj->dbval prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(37), pj->dbval); } else { sprintf(uppt, "%ld", upp); } } } else { $? "! db key too long" back = 0; } if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_account, pj->cname, pj->uname); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { if(sscanf(pj->dbval, "%ld", &uap) != 1) { uap = 0L; back = 0; $? "! failed to convert db entry to number \"%s\"", pj->dbval prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(38), pj->dbval); } else { sprintf(uapt, "%ld", uap); } } } else { $? "! db key too long" back = 0; } $? ". pages printed %ld, account %ld", upp, uap $? ". limit %d %lu", pj->limit_type, pj->limit_pages switch(pj->limit_type) { case LIMIT_VALUE_UNLIMITED: { $? ". unlimited printing granted" /* strcpy(pj->b2, response_keywords[0]); */ sprintf(ft, "%ld", 1L); sprintf(lt, "%ld", -1L); back = 1; } break; case LIMIT_VALUE_PAGES: { $? ". printing limited by page number" sprintf(lt, "%ld", pj->limit_pages); if((unsigned long)upp < pj->limit_pages) { $? ". page limit not yet reached" /* strcpy(pj->b2, response_keywords[0]); */ sprintf(ft, "%ld", 1L); back = 1; } else { if(uap > 0L) { $? ". free pages in personal account" /* strcpy(pj->b2, response_keywords[0]); */ sprintf(ft, "%ld", 1L); back = 1; } else { $? "! limit exceeded" } } } break; default: { $? "! printing denied" } break; } } else { /* ##### ERROR: Missing class name */ $? "! missing class name" } } else { /* ##### Invalid user name. Provide faked data */ prqd_pj_set_arg(pj, 'n', p2); prqd_pj_set_arg(pj, 'P', p1); prqd_pj_get_names(pj); prqd_pj_find_limit(pj); if(pj->cname) { page_limit = 200L; set_random_for_name(pj->uname); upp = page_limit + (rand() % page_limit); uap = 0 - (rand() % (2 * page_limit)); sprintf(uppt, "%ld", upp); sprintf(uapt, "%ld", uap); sprintf(lt, "%ld", page_limit); } else { /* ##### ERROR: Missing class name */ } } } else { /* ##### ERROR: Missing user name */ $? "! missing user name" } } else { /* ##### ERROR: Missing printer name */ $? "! missing printer name" } } sprintf(pj->b2, "%s %s %s %s\n", lt, uppt, uapt, ft); $? "- info_request %d", back return back; } /** Process file start request. Keep track of the current print user and the old pagecount value of a printer. @param pj Pointer to prqd job structure. @return 1 on success, 0 on error. */ static int filestart_request DK_P1(PJ *,pj) { int back = 1; PR *pr; $? "+ filestart_request" #if OLD_VERSION if((pj->uname) && (pj->pname) && (pj->pages)) { $? ". u=\"%s\" p=\"%s\" pages=\"%s\"", pj->uname, pj->pname, pj->pages pc = NULL; pr = NULL; pr = dksto_it_find_like((pj->prqdc)->pri, pj->pname, 1); if(pr) { $? ". printer found" while(pr->alt) { pr = pr->alt; } if(pr->pc) { $? ". printer class found" pc = pr->pc; if((1 + strlen(pj->pages) + strlen(pj->uname)) < pr->sz_cj) { $? ". length 1 ok" sprintf(pr->cj, "%s:%s", pj->pages, pj->uname); if((2 + strlen(pr->n)) < pj->sz_dbkey) { $? ". length 2 ok" sprintf(pj->dbkey, "j:%s", pr->n); prqdbe_store(pj, pj->dbkey, pr->cj); } } else { } } else { $? "! no printer class" } } else { $? "! printer not found" } } #else prqd_pj_get_names(pj); if((pj->uname) && (pj->pname) && (pj->pages) && (pj->rname) && (pj->cname)) { $? ". u=\"%s\" p=\"%s\" pages=\"%s\"", pj->uname, pj->pname, pj->pages pr = dksto_it_find_like((pj->prqdc)->pri, pj->rname, 1); if(pr) { $? ". printer found" if((1 + strlen(pj->pages) + strlen(pj->uname)) < pr->sz_cj) { sprintf(pr->cj, current_job_format, pj->pages, pj->uname); if((2 + strlen(pr->n)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_current_job_format, pr->n); if(!prqdbe_store(pj, pj->dbkey, pr->cj)) { back = 0; $? "! failed to store" } } else { $? "! key too long" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(36), pr->n); back = 0; } } else { $? "! value too long" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(36), pj->uname); back = 0; } } else { $? "! printer not found" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(26), pj->rname); back = 0; } } else { $? "! missing arguments" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(25)); } #endif $? "- filestart_request" return back; } /** Buffer for print limit text. */ static char limit_buffer[32]; /** Keywords used in limitations. */ static char *limit_keywords[] = { "denied", "unlimited" }; /** Convert limit value back to text form. @param pj Pointer to prqd job structure. @return Pointer to text form of limit. */ static char *limit_str DK_P1(PJ *,pj) { char *back; back = limit_keywords[0]; switch(pj->limit_type) { case LIMIT_VALUE_UNLIMITED: { back = limit_keywords[1]; } break; default: { sprintf(limit_buffer, "%lu", pj->limit_pages); back = limit_buffer; } break; } return back; } /** Handle fileend request. Calculate number of pages in the job and process and change database entries. @param pj Pointer to print job data. @return 1 on success, 0 on error. */ #if VERSION_BEFORE_2010_10_26 static int fileend_request DK_P1(PJ *,pj) { int back = 1; PR *pr; unsigned long job_start_pages, job_end_pages; long job_pages; long upp; /* user pages printed */ long uap; /* user account of pages */ char *ou; /* old user name (start of job) */ int must_balance; $? "+ fileend_request" #if OLD_VERSION if((pj->uname) && (pj->pname) && (pj->pages)) { prqd_pj_find_limit(pj); $? ". u=\"%s\" p=\"%s\" pages=\"%s\"", pj->uname, pj->pname, pj->pages pc = NULL; pr = NULL; pr = dksto_it_find_like((pj->prqdc)->pri, pj->pname, 1); if(pr) { while(pr->alt) { pr = pr->alt; } if(pr->pc) { pc = pr->pc; if(pc) { } } } } #else job_start_pages = job_end_pages = 0UL; job_pages = 0L; upp = uap = 0L; ou = NULL; prqd_pj_get_names(pj); prqd_pj_find_limit(pj); if((pj->uname) && (pj->pname) && (pj->pages) && (pj->rname) && (pj->cname)) { $? ". all needed names found" pr = dksto_it_find_like((pj->prqdc)->pri, pj->rname, 1); if(pr) { $? ". printer found" ou = dkstr_chr(pr->cj, ':'); if(ou) { $? ". user name for current job found" *(ou++) = '\0'; if(strcmp(ou, pj->uname) == 0) { $? ". user names match" if(sscanf(pr->cj, "%lu", &job_start_pages) == 1) { if(sscanf(pj->pages, "%lu", &job_end_pages) == 1) { if(job_end_pages > job_start_pages) { job_pages = (long)(job_end_pages - job_start_pages); if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { if(sscanf(pj->dbval, "%ld", &upp) != 1) { upp = 0L; back = 0; $? "! not a number \"%s\"", pj->dbval } } } else { $? "! key name too long" back = 0; } if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_account, pj->cname, pj->uname); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { if(sscanf(pj->dbval, "%ld", &uap) != 1) { uap = 0L; back = 0; $? "! not a number \"%s\"", pj->dbval } } } else { $? "! key name too long" back = 0; } $? ". pages printed so far default=%ld account=%ld", upp, uap upp = upp + job_pages; if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); sprintf(pj->dbval, "%ld", upp); if(!prqdbe_store(pj, pj->dbkey, pj->dbval)) { back = 0; $? "! failed to store" } } /* ##### LOG job summary */ prqdlog(pj,PRQD_PRIO_INFO,logmsgs[0],pj->uname,pj->cname,pj->pname,job_pages,XSTR(pj->hname),XSTR(pj->tname)); prqdlog(pj,PRQD_PRIO_INFO,logmsgs[1],pj->uname,pj->cname,upp,limit_str(pj)); must_balance = 0; if(pj->limit_type == LIMIT_VALUE_PAGES) { if(upp > pj->limit_pages) { must_balance = 1; } } if(must_balance) { $? ". balance" uap = uap + (long)(pj->limit_pages) - upp; upp = pj->limit_pages; if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); sprintf(pj->dbval, "%ld", upp); if(!prqdbe_store(pj, pj->dbkey, pj->dbval)) { back = 0; $? "! failed to store" } } if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_account, pj->cname, pj->uname); sprintf(pj->dbval, "%ld", uap); if(!prqdbe_store(pj, pj->dbkey, pj->dbval)) { back = 0; $? "! failed to store" } } prqdlog(pj, PRQD_PRIO_INFO, logmsgs[3],pj->uname,pj->cname); prqdlog(pj,PRQD_PRIO_INFO,logmsgs[1],pj->uname,pj->cname,upp,limit_str(pj)); prqdlog(pj,PRQD_PRIO_INFO,logmsgs[2],pj->uname,pj->cname,pj->dbval); } } else { $? "! page number at end of job must be larger" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(34)); back = 0; } } else { $? "! failed to sscanf page number (end of job)" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(33), pj->pages); back = 0; } } else { $? "! failed to sscanf page number (start of job) \"%s\"", pr->cj prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(32), pr->cj); back = 0; } } else { $? "! user names do not match" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(31), ou, pj->uname); } } else { $? "! no user name for current job" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(30)); } (pr->cj)[0] = '\0'; if((2 + strlen(pr->n)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_current_job_format, pr->n); prqdbe_store(pj, pj->dbkey, pr->cj); } } else { $? "! printer not found" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(26), pj->rname); back = 0; } prqd_write_userinfo_file(pj, pj->uname, pj->cname); } else { $? "! name missing" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(25)); back = 0; } #endif $? "- fileend_request %d", back return back; } #else static int fileend_request DK_P1(PJ *,pj) { int back = 1; PR *pr; unsigned long job_start_pages, job_end_pages; long job_pages; long upp; /* user pages printed */ long uap; /* user account of pages */ char *ou; /* old user name (start of job) */ int must_balance; int have_account; $? "+ fileend_request" #if OLD_VERSION if((pj->uname) && (pj->pname) && (pj->pages)) { prqd_pj_find_limit(pj); $? ". u=\"%s\" p=\"%s\" pages=\"%s\"", pj->uname, pj->pname, pj->pages pc = NULL; pr = NULL; pr = dksto_it_find_like((pj->prqdc)->pri, pj->pname, 1); if(pr) { while(pr->alt) { pr = pr->alt; } if(pr->pc) { pc = pr->pc; if(pc) { } } } } #else job_start_pages = job_end_pages = 0UL; job_pages = 0L; upp = uap = 0L; ou = NULL; have_account = 0; prqd_pj_get_names(pj); prqd_pj_find_limit(pj); if((pj->uname) && (pj->pname) && (pj->pages) && (pj->rname) && (pj->cname)) { $? ". all needed names found" pr = dksto_it_find_like((pj->prqdc)->pri, pj->rname, 1); if(pr) { $? ". printer found" ou = dkstr_chr(pr->cj, ':'); if(ou) { $? ". user name for current job found" *(ou++) = '\0'; if(strcmp(ou, pj->uname) == 0) { $? ". user names match" if(sscanf(pr->cj, "%lu", &job_start_pages) == 1) { if(sscanf(pj->pages, "%lu", &job_end_pages) == 1) { if(job_end_pages > job_start_pages) { job_pages = (long)(job_end_pages - job_start_pages); if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { if(sscanf(pj->dbval, "%ld", &upp) != 1) { upp = 0L; back = 0; $? "! not a number \"%s\"", pj->dbval } } } else { $? "! key name too long" back = 0; } if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_account, pj->cname, pj->uname); if(prqdbe_fetch(pj, pj->dbkey, pj->dbval, pj->sz_dbval)) { have_account = 1; if(sscanf(pj->dbval, "%ld", &uap) != 1) { uap = 0L; back = 0; $? "! not a number \"%s\"", pj->dbval have_account = 0; } } } else { $? "! key name too long" back = 0; } $? ". pages printed so far default=%ld account=%ld", upp, uap upp = upp + job_pages; /* ##### LOG job summary */ prqdlog(pj,PRQD_PRIO_INFO,logmsgs[0],pj->uname,pj->cname,pj->pname,job_pages,XSTR(pj->hname),XSTR(pj->tname)); prqdlog(pj,PRQD_PRIO_INFO,logmsgs[1],pj->uname,pj->cname,upp,limit_str(pj)); must_balance = 0; if(pj->limit_type == LIMIT_VALUE_PAGES) { if(upp > pj->limit_pages) { must_balance = 1; } } if(must_balance) { $? ". balance" if(have_account || (pj->prqdc)->do_balance) { uap = uap + (long)(pj->limit_pages) - upp; upp = pj->limit_pages; if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); sprintf(pj->dbval, "%ld", upp); if(!prqdbe_store(pj, pj->dbkey, pj->dbval)) { back = 0; $? "! failed to store" } } if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_account, pj->cname, pj->uname); sprintf(pj->dbval, "%ld", uap); if(!prqdbe_store(pj, pj->dbkey, pj->dbval)) { back = 0; $? "! failed to store" } } prqdlog(pj, PRQD_PRIO_INFO, logmsgs[3],pj->uname,pj->cname); prqdlog(pj,PRQD_PRIO_INFO,logmsgs[1],pj->uname,pj->cname,upp,limit_str(pj)); prqdlog(pj,PRQD_PRIO_INFO,logmsgs[2],pj->uname,pj->cname,pj->dbval); } else { upp = pj->limit_pages; if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); sprintf(pj->dbval, "%ld", upp); if(!prqdbe_store(pj, pj->dbkey, pj->dbval)) { back = 0; $? "! failed to store" } } prqdlog(pj, PRQD_PRIO_INFO, logmsgs[4],pj->uname,pj->cname); prqdlog(pj,PRQD_PRIO_INFO,logmsgs[1],pj->uname,pj->cname,upp,limit_str(pj)); } } else { $? ". no need to balance" if((3 + strlen(pj->cname) + strlen(pj->uname)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_user_pages, pj->cname, pj->uname); sprintf(pj->dbval, "%ld", upp); if(!prqdbe_store(pj, pj->dbkey, pj->dbval)) { back = 0; $? "! failed to store" } } } } else { $? "! page number at end of job must be larger" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(34)); back = 0; } } else { $? "! failed to sscanf page number (end of job)" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(33), pj->pages); back = 0; } } else { $? "! failed to sscanf page number (start of job) \"%s\"", pr->cj prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(32), pr->cj); back = 0; } } else { $? "! user names do not match" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(31), ou, pj->uname); } } else { $? "! no user name for current job" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(30)); } (pr->cj)[0] = '\0'; if((2 + strlen(pr->n)) < pj->sz_dbkey) { sprintf(pj->dbkey, key_current_job_format, pr->n); prqdbe_store(pj, pj->dbkey, pr->cj); } } else { $? "! printer not found" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(26), pj->rname); back = 0; } prqd_write_userinfo_file(pj, pj->uname, pj->cname); } else { $? "! name missing" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(25)); back = 0; } #endif $? "- fileend_request %d", back return back; } #endif /** Handle jobend request. No action necessary. @param pj Pointer to prqd job structure. @return 1 on success, 0 on error. */ static int jobend_request DK_P1(PJ *,pj) { int back = 1; return back; } /** Find request type and start dedicated handler function. @param pj Pointer to print job data. @return 1 on success, 0 on error. */ static int process_request DK_P1(PJ *,pj) { int back = 0; $? "+ process_request" char *p1, *p2; pj->rqtstr = p1 = dkstr_start(pj->b1, NULL); if(p1) { dkstr_chomp(p1, NULL); $? ". request=\"%s\"", p1 prqdlog(pj,PRQD_PRIO_INFO,"%s",p1); p2 = dkstr_next(p1, NULL); prqd_pj_get_rq_type(pj, p1); pj->uname = NULL; pj->pname = NULL; pj->tname = NULL; pj->pages = NULL; pj->cname = NULL; pj->rname = NULL; pj->hname = NULL; switch(pj->rqt) { case PRQD_RQ_T_JOBSTART: { pj->must_respond = 0x01; prqd_pj_set_all_args(pj, p2); if(!jobstart_request(pj)) { prqd_pj_use_deny_action(pj); } back = 1; } break; case PRQD_RQ_T_FILESTART: case PRQD_RQ_T_START: { pj->must_respond = 0x00; prqd_pj_set_all_args(pj, p2); back = filestart_request(pj); } break; case PRQD_RQ_T_END: case PRQD_RQ_T_FILEEND: { pj->must_respond = 0x00; prqd_pj_set_all_args(pj, p2); back = fileend_request(pj); } break; case PRQD_RQ_T_JOBEND: { pj->must_respond = 0x00; prqd_pj_set_all_args(pj, p2); back = jobend_request(pj); } break; case PRQD_RQ_T_CONTROL: { back = prqdctrl_request(pj, p2); } break; case PRQD_RQ_T_INFO: { pj->must_respond = 0x01; back = info_request(pj, p2); } break; default: { } break; } } else { } $? "- process_request %d", back return back; } /** Send response text to peer if necessary. @param pj Pointer to print job data. @return 1 on success, 0 on error. */ static int write_response DK_P1(PJ *,pj) { int back = 0; size_t sz, osz; char logbuffer[64]; fd_set wfds; struct timeval tv; $? "+ write_response" if(pj->must_respond) { $? ". must write response" if(strlen(pj->b2) < sizeof(logbuffer)) { $? ". size ok for logbuffer" strcpy(logbuffer, pj->b2); dkstr_chomp(logbuffer, NULL); prqdlog(pj,PRQD_PRIO_INFO,"Response: %s",logbuffer); } sz = 1 + strlen(pj->b2); if(((pj->prqdc)->to_seconds > 0L) ||((pj->prqdc)->to_microseconds > 0L)) { FD_ZERO(&wfds); FD_SET(pj->ss,&wfds); tv.tv_sec = (pj->prqdc)->to_seconds; tv.tv_usec = (pj->prqdc)->to_microseconds; if(select((1 + pj->ss), NULL, &wfds, NULL, &tv) > 0) { if(FD_ISSET(pj->ss,&wfds)) { osz = send(pj->ss, pj->b2, sz, 0); if(osz >= sz) { back = 1; } } } } else { osz = send(pj->ss, pj->b2, sz, 0); if(osz >= sz) { back = 1; } } } else { $? ". no response to write" back = 1; } $? "- write_response %d", back return back; } /** Run a service session. As long as the peer sends request data process the requests and send the response. @param pj Pointer to print job data. */ static void run_session DK_P1(PJ *,pj) { int cc; $? "+ run_session" cc = 1; sigpipe_r = 0; pj->e3 = 0; while((cc) && prqd_cc3(pj)) { /* (pj->b2)[0] = '\0'; */ strcpy(pj->b2, response_keywords[3]); pj->must_respond = 0x00; prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(15)); if(read_request(pj)) { prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(16)); if(!process_request(pj)) { cc = 0; } prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(21)); write_response(pj); } else { cc = 0; } } $? "- run_session" } /** Accept connection requests and start a session as long as we can continue. @param pj Pointer to print job structure. */ static void inner_loop DK_P1(PJ *,pj) { sighup_r = 0; pj->e2 = 0; while(prqd_cc2(pj)) { prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(10)); pj->ss = accept(pj->sock, NULL, 0); if(pj->ss > -1) { $? ". socket ok" prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(11)); run_session(pj); prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(12)); close(pj->ss); pj->ss = -1; prqdlog(pj, PRQD_PRIO_DEBUG, prqd_get_kw(13)); } else { $? "! accept failed" if(errno != EINTR) { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(14)); pj->e1 = 1; } } } } /** Create and set up socket and run service loop. @param pj Pointer to print job structure. */ static void outer_loop DK_P1(PJ *,pj) { static int first_run = 1; struct sockaddr_un soun; char *sn; $? "+ outer_loop" sn = (pj->prqdc)->sockname; $? ". sn = \"%s\"", sn unlink(sn); pj->sock = socket(PF_UNIX, SOCK_STREAM, 0); if(pj->sock > -1) { soun.sun_family = AF_UNIX; if(strlen(sn) < 108) { strcpy(soun.sun_path, sn); if(bind(pj->sock, (struct sockaddr *)(&soun), SZSOUN) == 0) { if(listen(pj->sock, pj->backlog) == 0) { chmod(sn, 0660); if(first_run) { first_run = 0; change_user_and_group(pj); } prqdlog(pj, PRQD_PRIO_PROGRESS, prqd_get_kw(8)); initialize_open_jobs(pj); prqdlog(pj, PRQD_PRIO_PROGRESS, prqd_get_kw(9)); inner_loop(pj); } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(7), sn); pj->e1 = 1; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(6), sn); pj->e1 = 1; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(5), sn); pj->e1 = 1; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(4)); pj->e1 = 1; } $? "- outer_loop" } /** Run the service in a loop as long as we can continue (no SIGTERM received or fatal error occured). On SIGHUP reload the configuration file. @param pj Pointer to print job structure. */ static void run_the_service DK_P1(PJ *,pj) { $(trace-init /var/log/prqd/prqd.deb) $? "+ run_the_service" while(prqd_cc1(pj)) { $? ". start of loop" sighup_r = 0; pj->e2 = 0; pj->prqdc = prqdconf_new_prqdc(pj, prqdconf_get_cfgfile()); if(pj->prqdc) { $? ". configuration was read" if(prqdbe_open(pj)) { $? ". database is open" if((pj->prqdc)->sockname) { outer_loop(pj); } else { prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(24)); pj->e1 = 1; } prqdbe_close(pj); } else { $? "! failed to open database" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(23)); pj->e1 = 1; } prqdconf_delete_prqdc(pj->prqdc); pj->prqdc = NULL; } else { $? "! failed to read configuration" prqdlog(pj,PRQD_PRIO_ERROR,prqd_get_kw(22)); pj->e1 = 1; } } $? "- run_the_service" $(trace-end) } /** Run processing. Change to root directory, set file creation mask, close all files and detach from terminals before running the service in background. @param pj Pointer to print job structure. */ static void run DK_P1(PJ *,pj) { int maxfiles, i; pid_t pid; dk_signal_disp_t disp_hup; dk_signal_disp_t disp_int; dk_signal_disp_t disp_term; dk_signal_disp_t disp_pipe; disp_hup = disp_int = disp_term = disp_pipe = NULL; (void)chdir("/"); umask(077); maxfiles = (int)dksf_get_maxfiles(); for(i = 0; i < maxfiles; i++) { (void)close(i); } pid = fork(); if(pid == 0) { #if DK_HAVE_SETSID setsid(); #else #if DK_HAVE_SETPGRP setpgrp(); #endif #endif disp_hup = dksignal_set(SIGHUP, sighup_handler); pid = fork(); if(pid == 0) { dksf_write_pid_file(appname, 1); disp_int = dksignal_set(SIGINT,sigint_handler); disp_term = dksignal_set(SIGTERM,sigterm_handler); disp_pipe = dksignal_set(SIGPIPE,sigpipe_handler); #if DK_HAVE_SYSLOG_H openlog(prqdconf_get_progname(),(LOG_CONS|LOG_NDELAY|LOG_PID),LOG_LPR); #endif prqdlog(pj, PRQD_PRIO_INFO, "%s", prqd_get_kw(1)); prqdlog(pj, PRQD_PRIO_INFO, "%s", prqd_get_kw(3)); run_the_service(pj); prqdlog(pj, PRQD_PRIO_INFO, "%s", prqd_get_kw(2)); #if DK_HAVE_SYSLOG_H closelog(); #endif if(disp_pipe) { dksignal_set(SIGPIPE,disp_pipe); } if(disp_term) { dksignal_set(SIGTERM,disp_term); } if(disp_int) { dksignal_set(SIGINT,disp_int); } dksf_write_pid_file(appname, 0); } else { if(pid == ((pid_t)-1)) { pj->ec = 1; } } dksignal_set(SIGHUP, disp_hup); } else { if(pid == ((pid_t)-1)) { pj->ec = 1; } } } /** Buffer to read input line. */ static char inbuffer[PRQD_BUFFER_SIZE]; /** Buffer to create a response. */ static char outbuffer[PRQD_BUFFER_SIZE]; /** Buffer for use as b1 in static PJ. */ static char dbkey[PRQD_DBENTRY_SIZE]; /** Buffer for use as b2 in static PJ. */ static char dbval[PRQD_DBENTRY_SIZE]; /** Buffer for use as b3 in static PJ. */ static char pgnamebuffer[PRQD_DBENTRY_SIZE]; /** Array of argument pointers for use in static PJ. */ static char *args[53]; /** Main function. This function initializes a static PJ structure, and sets up buffers before running further processing. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, positive values on error. */ #if DK_HAVE_PROTOTYPES int main(int argc, char *argv[]) #else int main(argc, argv) int argc; char *argv[]; #endif { PJ pj; prqd_pj_init(&pj); pj.b1 = inbuffer; pj.sz_b1 = sizeof(inbuffer); pj.b2 = outbuffer; pj.sz_b2 = sizeof(outbuffer); pj.b3 = pgnamebuffer; pj.sz_b3 = sizeof(pgnamebuffer); pj.args = args; pj.dbkey = dbkey; pj.sz_dbkey = sizeof(dbkey); pj.dbval = dbval; pj.sz_dbval = sizeof(dbval); pj.allow_file_logging = 1; run(&pj); exit(pj.ec); return(pj.ec); }