/* 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 prqdconf.c The prqd configuration module. */ /** Inside the prqdconf module. */ #define PRQDCONF_C 1 #include "prqd.h" #include "dktools-version.h" $(trace-include) /** The keywords to print to the log file. */ char *prqd_kw[] = { /* 0 */ "", /* 1 */ "prqd (dktools-" VERSNUMB ") starting", /* 2 */ "prqd exiting.", /* 3 */ " For accounting we use abbreviations as follows:\n" /* 3 */ " u ... user job data about one job printed\n" /* 3 */ " c ... printer class summary accumulated values\n" /* 3 */ " pr ... printer balance-account default page limit exceeded,\n" /* 3 */ " pa ... page number switching to pages from\n" /* 3 */ " l ... page limit (default) personal account\n" /* 3 */ " ac ... pages in personal account", /* 4 */ "Failed to create socket!", /* 5 */ "Socket name \"%s\" is too long!", /* 6 */ "Failed to bind to UNIX socket \"%s\"!", /* 7 */ "Failed to listen on socket \"%s\"!", /* 8 */ "Retrieving open jobs from database.", /* 9 */ "Finished retrieving open jobs from database.", /* 10 */ "Accepting incoming connection request to start session.", /* 11 */ "Connection established.", /* 12 */ "Closing session.", /* 13 */ "Session closed.", /* 14 */ "Failed to accept incoming connection request!", /* 15 */ "Reading request.", /* 16 */ "Processing request.", /* 17 */ "Timeout specified.", /* 18 */ "No timeout specified.", /* 19 */ "Successfully read %lu bytes.", /* 20 */ "No data received!", /* 21 */ "Writing response if necessary.", /* 22 */ "Failed to read configuration!", /* 23 */ "Failed to open database!", /* 24 */ "No socket name specified!", /* 25 */ "Incomplete set of arguments for request!", /* 26 */ "No data found for printer \"%s\"", /* 27 */ "DB BE: store \"%s\"=\"%s\"", /* 28 */ "DB BE: fetched \"%s\"=\"%s\"", /* 29 */ "DB BE: Failed to fetch \"%s\"!", /* 30 */ "No user name for current job!", /* 31 */ "Stored job user name \"%s\" does not match current user name \"%s\"!", /* 32 */ "Failed to retrieve page number at start of job from \"%s\"!", /* 33 */ "Failed to retrieve page number at end of job from \"%s\"!", /* 34 */ "Page number at end of job must be larger than at start of job!", /* 35 */ "DB BE: Failed to store \"%s\"=\"%s\"!", /* 36 */ "Printer name \"%s\" is too long!", /* 37 */ "Failed to retrieve number of printed pages from \"%s\"!", /* 38 */ "Failed to retrieve number of pages in personal account from \"%s\"!", /* 39 */ "Printing allowed (1=yes, 0=no): %d", /* 40 */ "Insufficient arguments to write user information file!", /* 41 */ "User name \"%s\" and/or printer class name \"%s\" too long!", /* 42 */ "Not enough memory (RAM/swap space)!", /* 43 */ "Failed to open user information file \"%s\" for writing!", /* 44 */ "Printer class \"%s\" not found!", /* 45 */ "User \"%s\" not found!", /* 46 */ "Database entry \"%s\" too long to be stored as current job!", /* 47 */ "Cannot change group, failed to find group \"%s\"!", /* 48 */ "Cannot change user, failed to find user \"%s\"!", /* 49 */ "Potential security problem: No \"run as group\" option used.", /* 50 */ "Potential security problem: No \"run as user\" option used.", /* 51 */ "Switching user to \"%s\".", /* 52 */ "Switching group to \"%s\".", /* 53 */ "Finishing session (errors or reconfiguration or broken pipe).", /* 54 */ "Restarting service (errors or reconfiguration).", /* 55 */ "Finishing service (errors/reconfiguration/broken pipe/termination)!", /* 56 */ "Error(s) while reading configuration file!", /* 57 */ "No printer class definition found for printer \"%s\"!", /* 58 */ "Failed to open configuration file \"%s\" for reading!", /* 59 */ "%s:%lu: Syntax error!", /* 60 */ "%s:%lu: Printer class \"%s\" undefined!", /* 61 */ "%s:%lu: Printer class \"%s\" already defined!", /* 62 */ "%s:%lu: Multiple definitions for user information directory!", /* 63 */ "Illegal or unknown request type \"%s\"!", /* 64 */ "Insufficient data to construct a request!", /* 65 */ "Failed to connect to prqd!", /* 66 */ "Error while sending data!", /* 67 */ "DB BE: Failed to delete entry \"%s\"!", /* 68 */ "DB BE: Request for unsupported backend type!", /* 69 */ "DB BE: Failed to create database!", /* 70 */ "DB BE: Failed to open database \"%s\"!", /* 71 */ "DB BE: No database specified!", /* 72 */ "DB BE: Database is not a type:name pair!", /* 73 */ "DB BE: Empty database name!", /* 74 */ "DB BE: Invalid database type \"%s\", must be \"bdb\", \"ndbm\" or \"gdbm\"!", /* 75 */ "DB BE: Failed to change file ownership for \"%s\" to %lu:%lu!", /* 76 */ "DB BE: Failed to change permissions of \"%s\" to 0660!", /* 77 */ "DB BE: Error processing \"%s\"=\"%s\" (can continue iteration)!", /* 78 */ "DB BE: Error processing \"%s\"=\"%s\" (can not continue iteration)!", /* 79 */ "Missing control request type!", /* 80 */ "Unknown control request type \"%s\"!", /* 81 */ "Missing user name!", /* 82 */ "Missing printer class name!", /* 83 */ "Wildcard not allowed here!", /* 84 */ "DB BE: delete \"%s\"", /* 85 */ "Cleanup: Remove db entry \"%s\"=\"%s\"", NULL }; /** Type definition for pointer to characters. */ typedef char *PCHR; /** Get an entry from the prqd_kw array. @param s index of the entry to get. @return The string selected by the index. */ char * prqd_get_kw DK_P1(size_t,s) { char *back = NULL; $? "+ prqd_get_kw %lu", (unsigned long)s if(s < (sizeof(prqd_kw)/sizeof(PCHR))) { back = prqd_kw[s]; } else { back = prqd_kw[0]; } $? "- prqd_get_kw %s", TR_STR(back) return back; } /** Scopes for limits. */ static char *le_scope_texts[] = { "u$ser", "g$roup", "d$efault", NULL }; /** Patterns to choose a default deny action. */ static char *da_texts[] = { "r$emove", "h$old", NULL }; /** Configuration file section headers. */ static char *conf_section_headers[] = { "o$ptions", "c$lass", "p$rinter", NULL }; /** Keyword unlimited. */ static char key_unlimited[] = { "unlimited" }; /** Database configuration line in options section. */ static char *kw01_00[] = { "d$atabase", NULL }; /** Socket configuration line in options section. */ static char *kw01_01[] = { "s$ocket", NULL }; /** Run as user configuration line in options section. */ static char *kw01_02[] = { "r$un", "a$s", "u$ser", NULL }; /** Run as group configuration line in options section. */ static char *kw01_03[] = { "r$un", "a$s", "g$roup", NULL }; /** Socket timeout configuration line in options section. */ static char *kw01_04[] = { "s$ocket", "t$imeout", NULL }; /** User information directory configuration line in options section. */ static char *kw01_05[] = { "u$ser", "i$nformation", "d$irectory", NULL }; static char *kw01_06[] = { "cr$eate", "a$ccounts", "a$utomatically", NULL }; /** Configuration lines in options section. */ static char **kw01[] = { kw01_00, kw01_01, kw01_02, kw01_03, kw01_04, kw01_05, kw01_06, NULL }; /** Limit configuration line in printer class definition. */ static char *kw02_00[] = { "l$imit", NULL }; /** Deny action configuration line in printer class definition. */ static char *kw02_01[] = { "d$eny", "a$ction", NULL }; /** Write user information files configuration line in printer class. */ static char *kw02_02[] = { "w$rite", "u$ser", "i$nformation", NULL }; /** Configuration lines used in printer class definition. */ static char **kw02[] = { kw02_00, kw02_01, kw02_02, NULL }; /** Alias configuration line in printer definition. */ static char *kw03_00[] = { "a$lias", NULL }; /** Class configuration line in printer definition. */ static char *kw03_01[] = { "c$lass", NULL }; /** Configuration lines used in printer definitions. */ static char **kw03[] = { kw03_00, kw03_01, NULL }; /** Program name, used in log messages. */ static char progname[] = { "prqd" }; /** Compare two limit structures. @param l Pointer to left structure. @param r Pointer to right structure. @param cr Comparison criteria (unused). @return 1 for l>r, 0 for l=r or -1 for ltp > pr->tp) { back = 1; } else { if(pl->tp < pr->tp) { back = -1; } else { if(pl->tp != LIMIT_ENTRY_TYPE_DEFAULT) { back = strcmp(pl->who, pr->who); } } } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Destroy a limit entry and release the memory. @param le Pointer to limit entry structure to destroy. */ static void le_delete DK_P1(LE *,le) { $? "+ le_delete %d %s %d %lu", le->tp, TR_STR(le->who), le->val, le->p if(le->who) { char *x; x = le->who; dk_delete(x); } le->who = NULL; le->tp = 0; le->val = 0; le->p = 0UL; dk_delete(le); $? "- le_delete" } /** Set limit in limit structure. @param le Limit entry structure. @param s Limit value in textual form. */ static void add_limit_value DK_P2(LE *,le, char *,s) { le->val = LIMIT_VALUE_DENIED; le->p = 0UL; if(strcmp(key_unlimited, s) == 0) { le->val = LIMIT_VALUE_UNLIMITED; } else { unsigned long ul; if(sscanf(s, "%lu", &ul) == 1) { le->val = LIMIT_VALUE_PAGES; le->p = ul; } } } /** Create limit entry structure. The structure is created in dynamically allocated memory and must be release using le_delete(). @param pj Pointer to prqd job structure. @param s String containing the limit in textual form. @param fn Configuration file name. @param lineno The line number in the configuration file. */ static LE * le_new DK_P4(PJ *,pj, char *,s, char *,fn, unsigned long,lineno) { LE *back = NULL; char buffer[256], *p1, *p2, *p3; int i; $? "+ le_new %s", TR_STR(s) if(strlen(s) < sizeof(buffer)) { $? ". args ok" strcpy(buffer, s); p1 = dkstr_start(buffer, NULL); if(p1) { $? ". text ok" p2 = dkstr_chr(p1, ':'); if(p2) { $? ". first colon found" *(p2++) = '\0'; p3 = dkstr_chr(p2, ':'); if(p3) { $? ". second colon found" *(p3++) = '\0'; } switch((i = dkstr_array_abbr(le_scope_texts, p1, '$', 0))) { case 0: case 1: { $? ". user or group \"%s\"", TR_STR(p2) if(p3) { back = dk_new(LE,1); if(back) { $? ". allocation ok" back->tp = 0; back->who = NULL; back->val = 0; back->p = 0UL; if(i) { $? ". group" back->tp = LIMIT_ENTRY_TYPE_GROUP; } else { $? ". user" back->tp = LIMIT_ENTRY_TYPE_USER; } back->who = dkstr_dup(p2); if(back->who) { $? ". copy of name created" add_limit_value(back,p3); } else { $? ". memory allocation failed for name" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); dk_delete(back); back = NULL; } } else { $? "! memory allocation failed" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); } } else { $? "! syntax error" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); } } break; case 2: { $? ". default for all" back = dk_new(LE,1); if(back) { $? ". allocation ok" back->tp = 0; back->who = NULL; back->val = 0; back->p = 0UL; back->tp = LIMIT_ENTRY_TYPE_DEFAULT; add_limit_value(back,p2); } else { $? "! memory allocation failed" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); } } break; default: { $? "! syntax error" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); } break; } } else { $? "! first colon not found" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); } } else { $? "! no start of text" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); } } $? "- le_new %s", TR_PTR(back) return back; } /** Compare two printer class structures. @param l Pointer to left structure. @param r Pointer to right structure. @param cr Comparison criteria (unused). @return 1 for l>r, 0 for l=r, -1 for ln) { back = strcmp(pl->n, (char *)r); } else { back = -1; } } break; default: { if(pl->n) { if(pr->n) { back = strcmp(pl->n, pr->n); } else { back = 1; } } else { if(pr->n) { back = -1; } } } break; } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Destory printer class structure and release the memory. @param pc Pointer to printer class structure. */ static void pc_delete DK_P1(PC *,pc) { LE *ple; $? "+ pc_delete %s", TR_STR(pc->n) if(pc->n) { char *x; x = pc->n; dk_delete(x); } pc->n = NULL; if(pc->l) { if(pc->li) { dksto_it_reset(pc->li); while((ple = (LE *)dksto_it_next(pc->li)) != NULL) { le_delete(ple); } dksto_it_close(pc->li); } dksto_close(pc->l); } pc->l = NULL; pc->li = NULL; dk_delete(pc); $? "- pc_delete" } /** Create new printer class structure. The printer class structure is created in dynamically allocated memory and must be released using pc_delete(). @param pj Pointer to prqd job structure. @param prqdc Pointer to configuration structure. @param n Printer class name. @return Pointer to new printer class structure on success, 0 on error. */ static PC * pc_new DK_P3(PJ *,pj, PRQDC *,prqdc, char *,n) { PC *back = NULL; $? "+ pc_new %s", TR_STR(n) back = dk_new(PC,1); if(back) { back->n = NULL; back->l = NULL; back->li = NULL; back->n = dkstr_dup(n); back->l = dksto_open(0); back->da = DENY_ACTION_REMOVE; back->wi = 0; if(back->l) { dksto_set_comp(back->l, le_compare, 0); back->li = dksto_it_open(back->l); } if((back->n) && (back->l) && (back->li)) { if(!dksto_add(prqdc->cl, (void *)back)) { pc_delete(back); back = NULL; } } else { pc_delete(back); back = NULL; } } $? "- pc_new %s", TR_PTR(back) return back; } /** Compare two printer structures. @param l Pointer to left structure. @param r Pointer to right printer structure. @param cr Comparison criteria (unused), @return 1 for l>r, 0 for l=r or -1 for ln) { back = strcmp(pl->n, (char *)r); } else { back = -1; } } break; default: { if(pl->n) { if(pr->n) { back = strcmp(pl->n, pr->n); } else { back = 1; } } else { if(pr->n) { back = -1; } } } break; } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Destroy a printer structure created by pr_new() and release the memory. @param pr Pointer to printer structure to release. */ static void pr_delete DK_P1(PR *,pr) { $? "+ pr_delete %s", TR_STR(pr->n) if(pr->alt) { $? ". printer was an alias" } if(pr->pc) { $? ". printer in class %s", TR_STR((pr->pc)->n) } if(pr->n) { char *x; x = pr->n; dk_delete(x); } if(pr->cj) { char *x; x = pr->cj; dk_delete(x); } pr->n = NULL; pr->cj = NULL; pr->pc = NULL; pr->alt = NULL; dk_delete(pr); $? "- pr_delete" } /** Create new printer structure. the structure is created in dynamically allocated memory and must be released using the pr_delete() function. @param pj Pointer to prqd job structure. @param prqdc Pointer to configuration structure. @param n Printer name. @return Pointer to new printer structure. */ static PR * pr_new DK_P3(PJ *,pj, PRQDC *,prqdc, char *,n) { PR *back = NULL; $? "+ pr_new %s", TR_STR(n) if(n) { back = dk_new(PR,1); if(back) { back->pc = NULL; back->alt = NULL; back->n = dkstr_dup(n); back->cj = dk_new(char,64); if((back->n) && (back->cj)) { back->sz_cj = 64; if(!dksto_add(prqdc->pr, (void *)back)) { pr_delete(back); back = NULL; } } else { pr_delete(back); back = NULL; } } } $? "- pr_new %s", TR_PTR(back) return back; } /** Initialize elements in configuration structure to 0. @param prqdc Pointer to configuration structure. */ static void init_empty_prqdc DK_P1(PRQDC *,prqdc) { $? "+ init_empty_prqdc" prqdc->cl = NULL; prqdc->cli = NULL; prqdc->pr = NULL; prqdc->pri = NULL; prqdc->dbname = NULL; prqdc->sockname = NULL; prqdc->rau = NULL; prqdc->rag = NULL; prqdc->to_seconds = 0UL; prqdc->to_microseconds = 0UL; prqdc->userinfdir = NULL; prqdc->do_balance = 0; $? "- init_empty_prqdc" } /** Initialize configuration structure elements after allocating the structure. @param pj Pointer to prqd job structure. @param prqdc Pointer to configuration structure. @return 1 on success, 0 on error. */ static int init_components_in_prqdc DK_P2(PJ *,pj, PRQDC *,prqdc) { int back = 0; $? "+ init_components_in_prqdc" prqdc->cl = dksto_open(0); prqdc->pr = dksto_open(0); if(prqdc->cl) { dksto_set_comp(prqdc->cl, pc_compare, 0); prqdc->cli = dksto_it_open(prqdc->cl); } if(prqdc->pr) { dksto_set_comp(prqdc->pr, pr_compare, 0); prqdc->pri = dksto_it_open(prqdc->pr); } if((prqdc->pr) && (prqdc->cl) && (prqdc->pri) && (prqdc->cli)) { back = 1; } $? "- init_components_in_prqdc %d", back return back; } /** Destroy configuration structure after usage and release memory. @param p Pointer to configuration structure. */ void prqdconf_delete_prqdc DK_P1(PRQDC *,p) { PR *ppr; PC *pcl; $? "+ prqdconf_delete_prqdc" if(p) { if(p->dbname) { char *x; $? ". release database name %s", TR_STR(p->dbname) x = p->dbname; dk_delete(x); } p->dbname = NULL; if(p->sockname) { char *x; $? ". release socket name %s", TR_STR(p->sockname) x = p->sockname; dk_delete(x); } p->sockname = NULL; if(p->rau) { char *x; $? ". release run as user name %s", TR_STR(p->rau) x = p->rau; dk_delete(x); } p->rau = NULL; if(p->rag) { char *x; $? ". release run as group name %s", TR_STR(p->rag) x = p->rag; dk_delete(x); } p->rag = NULL; if(p->pr) { if(p->pri) { dksto_it_reset(p->pri); while((ppr = (PR *)dksto_it_next(p->pri)) != NULL) { pr_delete(ppr); } dksto_it_close(p->pri); } dksto_close(p->pr); } p->pr = NULL; p->pri = NULL; if(p->cl) { if(p->cli) { dksto_it_reset(p->cli); while((pcl = (PC *)dksto_it_next(p->cli)) != NULL) { pc_delete(pcl); } dksto_it_close(p->cli); } } p->cl = NULL; p->cli = NULL; if(p->userinfdir) { char *x; $? ". release userinfdir %s", p->userinfdir x = p->userinfdir; dk_delete(x); } p->userinfdir = NULL; dk_delete(p); } $? "- prqdconf_delete_prqdc" } /** Read configuration file into configuration structure. @param pj Pointer to prqd job structure. @param prqdc Pointer to configuration structure. @param fn Configuration file name. @return 1 on success, 0 on error. */ static int read_configuration_file DK_P3(PJ *,pj, PRQDC *,prqdc, char *,fn) { int back = 0, cc = 0, i = 0; char buffer[512], *parts[16], *p1, *p2, *newvalue; FILE *f; unsigned long lineno; PR *cpr, *alt; PC *cpc; size_t u_parts; int st; /* 0=unknown, 1=options, 2=class, 3=printer */ $? "+ read_configuration_file %s %s %s", TR_PTR(pj), TR_PTR(prqdc), TR_STR(fn) f = dksf_fopen(fn, "r"); if(f) { back = 1; cc = 1; lineno = 0UL; cpr = NULL; cpc = NULL; st = 0; while((cc) && (back)) { if(fgets(buffer, sizeof(buffer), f)) { lineno++; dkstr_delcomm(buffer, '#'); p1 = dkstr_start(buffer, NULL); if(p1) { if(*p1 == '[') { st = 0; cpr = NULL; cpc = NULL; p1++; p1 = dkstr_start(p1, NULL); if(p1) { p2 = dkstr_chr(p1, ']'); if(p2) { *p2 = '\0'; p2 = dkstr_next(p1, NULL); if(p2) { dkstr_chomp(p2, NULL); } st = dkstr_array_abbr(conf_section_headers, p1, '$', 0); if(st > -1) { st += 1; switch(st) { case 2: { if(p2) { cpc = dksto_it_find_like(prqdc->cli, p2, 1); if(!cpc) { cpc = pc_new(pj, prqdc, p2); if(!cpc) { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(61), fn, lineno, p2); back = cc = 0; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } } break; case 3: { if(p2) { cpr = dksto_it_find_like(prqdc->pri, p2, 1); if(!cpr) { cpr = pr_new(pj, prqdc, p2); if(!cpr) { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(61), fn, lineno, p2); back = cc = 0; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } } break; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } } else { back = cc = 0; prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); } } else { p1 = dkstr_start(buffer, NULL); if(p1) { p2 = dkstr_chr(p1, '='); if(p2) { *(p2++) = '\0'; dkstr_chomp(p1, NULL); p2 = dkstr_start(p2, NULL); if(p2) { dkstr_chomp(p2, NULL); u_parts = dkstr_explode(parts, 16, p1, NULL); if(u_parts > 0) { switch(st) { case 1: { i = dkstr_find_multi_part_abbr(parts, kw01, '$', 0); switch(i) { case 0: { $? ". database" newvalue = dkstr_dup(p2); if(newvalue) { if(prqdc->dbname) { char *x; x = prqdc->dbname; dk_delete(x); } prqdc->dbname = newvalue; } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } break; case 1: { $? ". socket" newvalue = dkstr_dup(p2); if(newvalue) { if(prqdc->sockname) { char *x; x = prqdc->sockname; dk_delete(x); } prqdc->sockname = newvalue; } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } break; case 2: { $? ". run as user" newvalue = dkstr_dup(p2); if(newvalue) { if(prqdc->rau) { char *x; x = prqdc->rau; dk_delete(x); } prqdc->rau = newvalue; } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } break; case 3: { $? ". run as group" newvalue = dkstr_dup(p2); if(newvalue) { if(prqdc->rag) { char *x; x = prqdc->rag; dk_delete(x); } prqdc->rag = newvalue; } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } break; case 4: { $? ". socket timeout" { int ec = 0; unsigned long s1, s2; double d, d1; if(sscanf(p2, "%lf", &d) == 1) { $? ". sscanf ok %lg", d d1 = floor(d); $? ". d1 = %lg", d1 d = d - d1; $? ". d = %lg", d s1 = dkma_double_to_ul_ok(d1, &ec); $? ". s1 = %lu", s1 d = dkma_mul_double_ok(1000000.0, d, &ec); $? ". d = %lg", d s2 = dkma_double_to_ul_ok(d, &ec); $? ". s2 = %lu", s2 if(ec == 0) { $? " to: sec=%lu usec=%lu", s1, s2 prqdc->to_seconds = ((long)s1); prqdc->to_microseconds = ((long)s2); } } } } break; case 5: { $? ". user information directory = \"%s\"", p2 if(p2) { newvalue = dkstr_dup(p2); if(newvalue) { if(prqdc->userinfdir) { char *x; x = prqdc->userinfdir; dk_delete(x); prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(62), fn, lineno); } prqdc->userinfdir = newvalue; } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } } break; case 6: { if(p2) { if(dkstr_is_bool(p2)) { if(dkstr_is_on(p2)) { prqdc->do_balance = 1; } else { prqdc->do_balance = 0; } } } } break; default: { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } break; } } break; case 2: { if(cpc) { i = dkstr_find_multi_part_abbr(parts, kw02, '$', 0); switch(i) { case 0: { $? ". limit" LE *le; le = le_new(pj, p2, fn, lineno); if(le) { if(!dksto_add(cpc->l, (void *)le)) { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } break; case 1: { $? ". deny action" cpc->da = dkstr_array_abbr(da_texts, p2, '$', 0); if(cpc->da < 0) { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } } break; case 2: { cpc->wi = 0; if(p2) { if(dkstr_is_bool(p2)) { if(dkstr_is_on(p2)) { cpc->wi = 1; } else { cpc->wi = 0; } } } } break; default: { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } break; } } } break; case 3: { if(cpr) { i = dkstr_find_multi_part_abbr(parts, kw03, '$', 0); switch(i) { case 0: { $? ". alias" alt = pr_new(pj, prqdc, p2); if(alt) { alt->alt = cpr; } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); back = cc = 0; } } break; case 1: { $? ". class" cpc = dksto_it_find_like(prqdc->cli, p2, 1); if(cpc) { cpr->pc = cpc; cpc = NULL; } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(60), fn, lineno, p2); back = cc = 0; } } break; default: { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } break; } } } break; } } } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(59), fn, lineno); back = cc = 0; } } } } } else { cc = 0; $? ". end of file" } if(!back) { $? "! back==0 after processing line %lu", lineno } } fclose(f); f = NULL; } else { $? "! failed to open file" prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(58), fn); } $? "- read_configuration_file %d", back return back; } /** Check configuration. Each printer which is not an alias must have a class assigned. @param pj Pointer to prqd job structure. @param prqdc Pointer to configuration structure. @return 1 if the configuration is ok, 0 on error. */ static int check_prqdc DK_P2(PJ *,pj, PRQDC *,prqdc) { PR *pr; int back = 1; $? "+ check_prqdc" dksto_it_reset(prqdc->pri); while((pr = (PR *)dksto_it_next(prqdc->pri)) != NULL) { if(!(pr->alt)) { if(!(pr->pc)) { $? "! No class for printer \"%s\"", TR_STR(pr->n) back = 0; prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(57), (pr->n ? pr->n : "(NONE)")); } } } $? "- check_prqdc %d", back return back; } /** Create new prqd configuration structure. The structure is created in dynamically allocated memory. Use prqdconf_delete_prqdc() to release the memory after usage. @param pj Pointer to prqd job structure. @param fn File name. @return Pointer to the new configuration structure on success, NULL on error. */ PRQDC * prqdconf_new_prqdc DK_P2(PJ *,pj, char *,fn) { PRQDC *back = NULL; $? "+ prqdconf_new_prqdc %s %s", TR_PTR(pj), TR_STR(fn) back = dk_new(PRQDC,1); if(back) { init_empty_prqdc(back); if(init_components_in_prqdc(pj,back)) { if(read_configuration_file(pj, back, fn)) { if(!check_prqdc(pj, back)) { prqdconf_delete_prqdc(back); back = NULL; prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(56)); } } else { prqdconf_delete_prqdc(back); back = NULL; prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(56)); } } else { $? "! failed to init components" prqdconf_delete_prqdc(back); back = NULL; prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); } } else { prqdlog(pj, PRQD_PRIO_ERROR, prqd_get_kw(42)); } $? "- prqdconf_new_prqdc %s", TR_PTR(back) return back; } /** Return the program name. @return The program name. */ char * prqdconf_get_progname DK_P0() { return progname; } /** Retrieve debug level. @param pj Pointer to prqd job structure. @return The log level in the pj. */ int prqdconf_get_debug DK_P1(PJ *,pj) { return pj->deb; } /** Default configuration file name. */ char prqd_conf_cfgfile[] = { DK_SYSCONFDIR "/prqd/prqd.conf" }; /** Default log file name. */ char prqd_conf_logfile[] = { DK_LOCALSTATEDIR "/log/prqd/prqd.log" }; /** Return log file name. @return The log file name. */ char * prqdconf_get_logfile DK_P0() { return prqd_conf_logfile; } /** Return configuration file name. @return The configuration file name. */ char * prqdconf_get_cfgfile DK_P0() { return prqd_conf_cfgfile; } #if PRQDCONF_TEST int main(int argc, char *argv[]) { PJ pj; PRQDC *prqdc; $(trace-init prqdconf-test.deb) $? "+ main" pj.prqdc = prqdconf_new_prqdc(&pj, "prqd.conf"); if(pj.prqdc) { $? ". success" prqdconf_delete_prqdc(pj.prqdc); pj.prqdc = NULL; } else { $? "! error" } $? "- main" $(trace-end) exit(0); return 0; } #endif