12264Sjacobs /* 22264Sjacobs * CDDL HEADER START 32264Sjacobs * 42264Sjacobs * The contents of this file are subject to the terms of the 52264Sjacobs * Common Development and Distribution License (the "License"). 62264Sjacobs * You may not use this file except in compliance with the License. 72264Sjacobs * 82264Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92264Sjacobs * or http://www.opensolaris.org/os/licensing. 102264Sjacobs * See the License for the specific language governing permissions 112264Sjacobs * and limitations under the License. 122264Sjacobs * 132264Sjacobs * When distributing Covered Code, include this CDDL HEADER in each 142264Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152264Sjacobs * If applicable, add the following below this CDDL HEADER, with the 162264Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying 172264Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner] 182264Sjacobs * 192264Sjacobs * CDDL HEADER END 202264Sjacobs */ 212264Sjacobs 222264Sjacobs /* 233758Sjacobs * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 242264Sjacobs * Use is subject to license terms. 252264Sjacobs * 262264Sjacobs */ 272264Sjacobs 282264Sjacobs /* $Id: lpd-query.c 155 2006-04-26 02:34:54Z ktou $ */ 292264Sjacobs 302264Sjacobs #pragma ident "%Z%%M% %I% %E% SMI" 312264Sjacobs 322264Sjacobs #include <stdio.h> 332264Sjacobs #include <stdlib.h> 342264Sjacobs #include <unistd.h> 352264Sjacobs #include <sys/types.h> 362264Sjacobs #include <sys/stat.h> 372264Sjacobs #include <sys/fcntl.h> 382264Sjacobs #include <time.h> 392264Sjacobs #include <ctype.h> 402264Sjacobs #include <string.h> 412264Sjacobs #include <stdarg.h> 423758Sjacobs #include <regex.h> 432264Sjacobs 442264Sjacobs #include <papi_impl.h> 452264Sjacobs 463758Sjacobs /* The string is modified by this call */ 473758Sjacobs static char * 483758Sjacobs regvalue(regmatch_t match, char *string) 492264Sjacobs { 503758Sjacobs char *result = NULL; 513758Sjacobs 523758Sjacobs if (match.rm_so != match.rm_eo) { 533758Sjacobs result = string + match.rm_so; 543758Sjacobs *(result + (match.rm_eo - match.rm_so)) = '\0'; 553758Sjacobs } 563758Sjacobs 573758Sjacobs return (result); 583758Sjacobs } 593758Sjacobs 603758Sjacobs /* 613758Sjacobs * Print job entries start with: 623758Sjacobs * (user): (rank) [job (number) (...)] 633758Sjacobs * (user) is the job-owner's user name 643758Sjacobs * (rank) is the rank in queue. (active, 1st, 2nd, ...) 653758Sjacobs * (number) is the job number 663758Sjacobs * (...) is an optional hostname 673758Sjacobs * some servers will use whitespace a little differently than is displayed 683758Sjacobs * above. The regular expression below makes whitespace optional in some 693758Sjacobs * places. 703758Sjacobs */ 713758Sjacobs static char *job_expr = "^(.*[[:alnum:]]):[[:space:]]+([[:alnum:]]+)[[:space:]]+[[][[:space:]]*job[[:space:]]*([[:digit:]]+)[[:space:]]*(.*)]"; 723758Sjacobs static regex_t job_re; 733758Sjacobs 743758Sjacobs /* 753758Sjacobs * status line(s) for "processing" printers will contain one of the following: 763758Sjacobs * ready and printing 773758Sjacobs * Printing 783758Sjacobs */ 793758Sjacobs static char *proc_expr = "(ready and printing|printing)"; 803758Sjacobs static regex_t proc_re; 813758Sjacobs 823758Sjacobs /* 833758Sjacobs * status line(s) for "idle" printers will contain one of the following: 843758Sjacobs * no entries 853758Sjacobs * (printer) is ready 863758Sjacobs * idle 873758Sjacobs */ 883758Sjacobs static char *idle_expr = "(no entries|is ready| idle)"; 893758Sjacobs static regex_t idle_re; 903758Sjacobs 913758Sjacobs /* 923758Sjacobs * document line(s) 933758Sjacobs * (copies) copies of (name) (size) bytes 943758Sjacobs * (name) (size) bytes 953758Sjacobs * document lines can be in either format above. 963758Sjacobs * (copies) is the number of copies of the document to print 973758Sjacobs * (name) is the name of the document: /etc/motd, ... 983758Sjacobs * (size) is the number of bytes in the document data 993758Sjacobs */ 1003758Sjacobs static char *doc1_expr = "[[:space:]]+(([[:digit:]]+) copies of )([^[:space:]]+)[[:space:]]*([[:digit:]]+) bytes"; 1013758Sjacobs static char *doc2_expr = "[[:space:]]+()([^[:space:]]+)[[:space:]]*([[:digit:]]+) bytes"; 1023758Sjacobs static regex_t doc1_re; 1033758Sjacobs static regex_t doc2_re; 1043758Sjacobs 1053758Sjacobs static void 1063758Sjacobs parse_lpd_job(service_t *svc, job_t **job, int fd, char *line, int len) 1073758Sjacobs { 1082264Sjacobs papi_attribute_t **attributes = NULL; 1093758Sjacobs regmatch_t matches[5]; 1103758Sjacobs char *s; 1112264Sjacobs int octets = 0; 1122264Sjacobs 1133758Sjacobs /* job_re was compiled in the calling function */ 1143758Sjacobs if (regexec(&job_re, line, (size_t)5, matches, 0) == REG_NOMATCH) 1152264Sjacobs return; 1163758Sjacobs 1173758Sjacobs if ((s = regvalue(matches[1], line)) == NULL) 1183758Sjacobs s = "nobody"; 1192264Sjacobs papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE, 1203758Sjacobs "job-originating-user-name", s); 1212264Sjacobs 1223758Sjacobs if ((s = regvalue(matches[2], line)) == NULL) 1233758Sjacobs s = "0"; 1242264Sjacobs papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE, 1253758Sjacobs "number-of-intervening-jobs", atoi(s) - 1); 1263758Sjacobs 1273758Sjacobs if ((s = regvalue(matches[3], line)) == NULL) 1283758Sjacobs s = "0"; 1292264Sjacobs papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE, 1303758Sjacobs "job-id", atoi(s)); 1313758Sjacobs 1323758Sjacobs if ((s = regvalue(matches[4], line)) == NULL) 1333758Sjacobs s = svc->uri->host; 1342264Sjacobs papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE, 1353758Sjacobs "job-originating-host-name", s); 1362264Sjacobs 1373758Sjacobs while ((fdgets(line, len, fd) != NULL) && 1383758Sjacobs (regexec(&job_re, line, (size_t)0, NULL, 0) == REG_NOMATCH)) { 1393758Sjacobs int size = 0, copies = 1; 1403758Sjacobs /* process copies/documents */ 1412264Sjacobs 1423758Sjacobs /* doc1_re and doc2_re were compiled in the calling function */ 1433758Sjacobs if ((regexec(&doc1_re, line, (size_t)4, matches, 0) != 0) && 1443758Sjacobs (regexec(&doc2_re, line, (size_t)4, matches, 0) != 0)) 1453758Sjacobs continue; 1462264Sjacobs 1473758Sjacobs if ((s = regvalue(matches[1], line)) == NULL) 1483758Sjacobs s = "1"; 1493758Sjacobs if ((copies = atoi(s)) < 1) 1503758Sjacobs copies = 1; 1512264Sjacobs 1523758Sjacobs if ((s = regvalue(matches[2], line)) == NULL) 1533758Sjacobs s = "unknown"; 1543758Sjacobs papiAttributeListAddString(&attributes, 1553758Sjacobs PAPI_ATTR_APPEND, "job-name", s); 1563758Sjacobs papiAttributeListAddString(&attributes, 1573758Sjacobs PAPI_ATTR_APPEND, "job-file-names", s); 1582264Sjacobs 1593758Sjacobs if ((s = regvalue(matches[3], line)) == NULL) 1603758Sjacobs s = "0"; 1613758Sjacobs size = atoi(s); 1623758Sjacobs papiAttributeListAddInteger(&attributes, 1632264Sjacobs PAPI_ATTR_APPEND, "job-file-sizes", size); 1642264Sjacobs 1653758Sjacobs octets += (size * copies); 1662264Sjacobs } 1672264Sjacobs 1682264Sjacobs papiAttributeListAddInteger(&attributes, PAPI_ATTR_APPEND, 1692264Sjacobs "job-k-octets", octets/1024); 1702264Sjacobs papiAttributeListAddInteger(&attributes, PAPI_ATTR_APPEND, 1712264Sjacobs "job-octets", octets); 1722264Sjacobs papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND, 1732264Sjacobs "printer-name", queue_name_from_uri(svc->uri)); 1742264Sjacobs 1752264Sjacobs if ((*job = (job_t *)calloc(1, sizeof (**job))) != NULL) 1762264Sjacobs (*job)->attributes = attributes; 1772264Sjacobs } 1782264Sjacobs 1792264Sjacobs void 1802264Sjacobs parse_lpd_query(service_t *svc, int fd) 1812264Sjacobs { 1822264Sjacobs papi_attribute_t **attributes = NULL; 1832264Sjacobs cache_t *cache = NULL; 1842264Sjacobs int state = 0x03; /* idle */ 1852264Sjacobs char line[128]; 1863758Sjacobs char status[1024]; 1873758Sjacobs char *s; 1882264Sjacobs 1892264Sjacobs papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND, 1902264Sjacobs "printer-name", queue_name_from_uri(svc->uri)); 1912264Sjacobs 1923758Sjacobs if (uri_to_string(svc->uri, status, sizeof (status)) == 0) 1932264Sjacobs papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND, 1943758Sjacobs "printer-uri-supported", status); 1953758Sjacobs 1963758Sjacobs /* 1973758Sjacobs * on most systems, status is a single line, but some appear to 1983758Sjacobs * return multi-line status messages. To get the "best" possible 1993758Sjacobs * printer-state-reason, we accumulate the text until we hit the 2003758Sjacobs * first print job entry. 2013758Sjacobs * 2023758Sjacobs * Print job entries start with: 2033758Sjacobs * user: rank [job number ...] 2043758Sjacobs */ 2053758Sjacobs (void) regcomp(&job_re, job_expr, REG_EXTENDED|REG_ICASE); 2063758Sjacobs 2073758Sjacobs status[0] = '\0'; 2083758Sjacobs while ((fdgets(line, sizeof (line), fd) != NULL) && 2093758Sjacobs (regexec(&job_re, line, (size_t)0, NULL, 0) == REG_NOMATCH)) { 2103758Sjacobs strlcat(status, line, sizeof (status)); 2113758Sjacobs } 2123758Sjacobs /* chop off trailing whitespace */ 2133758Sjacobs s = status + strlen(status) - 1; 2143758Sjacobs while ((s > status) && (isspace(*s) != 0)) 2153758Sjacobs *s-- = '\0'; 2162264Sjacobs 2172264Sjacobs papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE, 2183758Sjacobs "printer-state-reasons", status); 2192264Sjacobs 2203758Sjacobs (void) regcomp(&proc_re, proc_expr, REG_EXTENDED|REG_ICASE); 2213758Sjacobs (void) regcomp(&idle_re, idle_expr, REG_EXTENDED|REG_ICASE); 2223758Sjacobs if (regexec(&proc_re, status, (size_t)0, NULL, 0) == 0) 2232264Sjacobs state = 0x04; /* processing */ 2243758Sjacobs else if (regexec(&idle_re, status, (size_t)0, NULL, 0) == 0) 2252264Sjacobs state = 0x03; /* idle */ 2262264Sjacobs else 2272264Sjacobs state = 0x05; /* stopped */ 2282264Sjacobs 2292264Sjacobs papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE, 2302264Sjacobs "printer-state", state); 2312264Sjacobs 2322264Sjacobs if ((cache = (cache_t *)calloc(1, sizeof (*cache))) == NULL) 2332264Sjacobs return; 2342264Sjacobs 2352264Sjacobs if ((cache->printer = (printer_t *)calloc(1, sizeof (*cache->printer))) 2362264Sjacobs == NULL) 2372264Sjacobs return; 2382264Sjacobs 2392264Sjacobs cache->printer->attributes = attributes; 2402264Sjacobs svc->cache = cache; 2412264Sjacobs 2423758Sjacobs (void) regcomp(&doc1_re, doc1_expr, REG_EXTENDED|REG_ICASE); 2433758Sjacobs (void) regcomp(&doc2_re, doc2_expr, REG_EXTENDED|REG_ICASE); 2443758Sjacobs /* process job related entries */ 2453758Sjacobs while (line[0] != '\0') { 2463758Sjacobs job_t *job = NULL; 2473758Sjacobs 2483758Sjacobs parse_lpd_job(svc, &job, fd, line, sizeof (line)); 2493758Sjacobs if (job == NULL) 2503758Sjacobs break; 2513758Sjacobs list_append(&cache->jobs, job); 2522264Sjacobs } 2532264Sjacobs 2542264Sjacobs time(&cache->timestamp); 2552264Sjacobs } 2562264Sjacobs 2572264Sjacobs void 2582264Sjacobs cache_update(service_t *svc) 2592264Sjacobs { 2602264Sjacobs int fd; 2612264Sjacobs 2622264Sjacobs if (svc->cache != NULL) /* this should be time based */ 2632264Sjacobs return; 2642264Sjacobs 2652264Sjacobs if (svc == NULL) 2662264Sjacobs return; 2672264Sjacobs 268*3915Sceastha if ((fd = lpd_open(svc, 'q', NULL, 15)) < 0) 2692264Sjacobs return; 2702264Sjacobs 2712264Sjacobs parse_lpd_query(svc, fd); 2722264Sjacobs 2732264Sjacobs close(fd); 2742264Sjacobs } 2752264Sjacobs 2762264Sjacobs papi_status_t 2772264Sjacobs lpd_find_printer_info(service_t *svc, printer_t **printer) 2782264Sjacobs { 2792264Sjacobs papi_status_t result = PAPI_BAD_ARGUMENT; 2802264Sjacobs 2812264Sjacobs if ((svc == NULL) || (printer == NULL)) 2822264Sjacobs return (PAPI_BAD_ARGUMENT); 2832264Sjacobs 2842264Sjacobs cache_update(svc); 2852264Sjacobs 2862264Sjacobs if (svc->cache != NULL) { 2872264Sjacobs *printer = svc->cache->printer; 2882264Sjacobs result = PAPI_OK; 2892264Sjacobs } else 2902264Sjacobs result = PAPI_NOT_FOUND; 2912264Sjacobs 2922264Sjacobs return (result); 2932264Sjacobs } 2942264Sjacobs 2952264Sjacobs papi_status_t 2962264Sjacobs lpd_find_jobs_info(service_t *svc, job_t ***jobs) 2972264Sjacobs { 2982264Sjacobs papi_status_t result = PAPI_BAD_ARGUMENT; 2992264Sjacobs 3002264Sjacobs if (svc != NULL) { 3012264Sjacobs cache_update(svc); 3022264Sjacobs 3032264Sjacobs if (svc->cache != NULL) { 3042264Sjacobs *jobs = svc->cache->jobs; 3052264Sjacobs result = PAPI_OK; 3062264Sjacobs } 3072264Sjacobs } 3082264Sjacobs 3092264Sjacobs return (result); 3102264Sjacobs } 3112264Sjacobs 3122264Sjacobs papi_status_t 3132264Sjacobs lpd_find_job_info(service_t *svc, int job_id, job_t **job) 3142264Sjacobs { 3152264Sjacobs papi_status_t result = PAPI_BAD_ARGUMENT; 3162264Sjacobs job_t **jobs; 3172264Sjacobs 3182264Sjacobs if (lpd_find_jobs_info(svc, &jobs) != PAPI_OK) { 3192264Sjacobs int i; 3202264Sjacobs 3212264Sjacobs *job = NULL; 3222264Sjacobs for (i = 0; ((*job == NULL) && (jobs[i] != NULL)); i++) { 3232264Sjacobs int id = -1; 3242264Sjacobs 3252264Sjacobs papiAttributeListGetInteger(jobs[i]->attributes, NULL, 3262264Sjacobs "job-id", &id); 3272264Sjacobs if (id == job_id) 3282264Sjacobs *job = jobs[i]; 3292264Sjacobs } 3302264Sjacobs 3312264Sjacobs if (*job != NULL) 3322264Sjacobs result = PAPI_OK; 3332264Sjacobs } 3342264Sjacobs 3352264Sjacobs return (result); 3362264Sjacobs } 3372264Sjacobs 3382264Sjacobs void 3392264Sjacobs cache_free(cache_t *item) 3402264Sjacobs { 3412264Sjacobs if (item != NULL) { 3422264Sjacobs if (item->printer != NULL) 3432264Sjacobs papiPrinterFree((papi_printer_t *)item->printer); 3442264Sjacobs if (item->jobs != NULL) 3452264Sjacobs papiJobListFree((papi_job_t *)item->jobs); 3462264Sjacobs free(item); 3472264Sjacobs } 3482264Sjacobs } 349