1 /* $OpenBSD: lp_displayq.c,v 1.1.1.1 2018/04/27 16:14:36 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Eric Faurot <eric@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <limits.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <unistd.h> 23 24 #include "lp.h" 25 26 #include "log.h" 27 28 static void dolong(int, struct lp_printer *, struct lp_jobfilter *, int, 29 const char *, int); 30 static void doshort(int, struct lp_printer *, struct lp_jobfilter *, int, 31 const char *, int); 32 33 void 34 lp_displayq(int ofd, struct lp_printer *lp, int lng, struct lp_jobfilter *jf) 35 { 36 struct lp_queue q; 37 pid_t currpid; 38 char status[256], currjob[PATH_MAX]; 39 int i, active, qstate; 40 41 /* Warn about the queue state if needed. */ 42 if (lp_getqueuestate(lp, 0, &qstate) == -1) 43 log_warnx("cannot get queue state"); 44 else { 45 if (qstate & LPQ_PRINTER_DOWN) { 46 if (lp->lp_type == PRN_LPR) 47 dprintf(ofd, "%s: ", lpd_hostname); 48 dprintf(ofd, "Warning: %s is down\n", lp->lp_name); 49 } 50 if (qstate & LPQ_QUEUE_OFF) { 51 if (lp->lp_type == PRN_LPR) 52 dprintf(ofd, "%s: ", lpd_hostname); 53 dprintf(ofd, "Warning: %s queue is turned off\n", 54 lp->lp_name); 55 } 56 } 57 58 /* Read queue content. */ 59 if ((lp_readqueue(lp, &q)) == -1) { 60 log_warnx("cannot read queue"); 61 if (lp->lp_type == PRN_LPR) 62 dprintf(ofd, "%s: ", lpd_hostname); 63 dprintf(ofd, "Warning: cannot read queue\n"); 64 } 65 66 /* Display current printer status. */ 67 if (lp_getcurrtask(lp, &currpid, currjob, sizeof(currjob)) == -1) 68 log_warnx("cannot get current task"); 69 70 if (currpid) { 71 if (lp->lp_type == PRN_LPR) 72 dprintf(ofd, "%s: ", lpd_hostname); 73 if (lp_getstatus(lp, status, sizeof(status)) == -1) { 74 log_warnx("cannot read printer status"); 75 dprintf(ofd, "Warning: cannot read status file\n"); 76 } 77 else 78 dprintf(ofd, "%s\n", status); 79 } 80 81 /* Display queue content. */ 82 if (q.count == 0) { 83 if (lp->lp_type != PRN_LPR) 84 dprintf(ofd, "no entries\n"); 85 } 86 else { 87 if (currpid == 0) { 88 if (lp->lp_type == PRN_LPR) 89 dprintf(ofd, "%s: ", lpd_hostname); 90 dprintf(ofd, "Warning: no daemon present\n"); 91 } 92 if (!lng) { 93 dprintf(ofd, "Rank Owner Job Files"); 94 dprintf(ofd, "%43s\n", "Total Size"); 95 } 96 for (i = 0; i < q.count; i++) { 97 active = !strcmp(q.cfname[i], currjob); 98 if (lng) 99 dolong(ofd, lp, jf, i+1, q.cfname[i], active); 100 else 101 doshort(ofd, lp, jf, i+1, q.cfname[i], active); 102 } 103 } 104 105 lp_clearqueue(&q); 106 } 107 108 static int 109 checklists(const char *cfname, struct lp_jobfilter *jf, const char *person) 110 { 111 int i; 112 113 if (jf->nuser == 0 && jf->njob == 0) 114 return 1; 115 116 /* Check if user is in user list. */ 117 for (i = 0; i < jf->nuser; i++) 118 if (!strcmp(jf->users[i], person)) 119 return 1; 120 121 /* Skip if hostnames don't match. */ 122 if (strcmp(LP_JOBHOST(cfname), jf->hostfrom)) 123 return 0; 124 125 /* Check for matching jobnum. */ 126 for (i = 0; i < jf->njob; i++) 127 if (jf->jobs[i] == LP_JOBNUM(cfname)) 128 return 1; 129 130 return 0; 131 } 132 133 static const char * 134 rankstr(int rank, int active) 135 { 136 static char buf[16]; 137 const char *sfx; 138 139 if (active) 140 return "active"; 141 142 sfx = "th"; 143 switch (rank % 10) { 144 case 1: 145 if ((rank / 10) % 10 != 1) 146 sfx = "st"; 147 break; 148 case 2: 149 sfx = "nd"; 150 break; 151 case 3: 152 sfx = "rd"; 153 154 } 155 156 snprintf(buf, sizeof(buf), "%d%s", rank, sfx); 157 return buf; 158 } 159 160 static void 161 doshort(int ofd, struct lp_printer *lp, struct lp_jobfilter *jf, int rank, 162 const char *cfname, int active) 163 { 164 struct stat st; 165 FILE *fp; 166 const char *fname; 167 char dfname[PATH_MAX], names[80], *line = NULL; 168 ssize_t len; 169 size_t linesz = 0, totalsz = 0; 170 int copies = 0; 171 172 fp = lp_fopen(lp, cfname); 173 if (fp == NULL) { 174 log_warn("cannot open %s", cfname); 175 return; 176 } 177 178 names[0] = '\0'; 179 180 while ((len = getline(&line, &linesz, fp)) != -1) { 181 if (line[len-1] == '\n') 182 line[len - 1] = '\0'; 183 switch (line[0]) { 184 case 'P': 185 if (!checklists(cfname, jf, line + 1)) 186 goto end; 187 188 dprintf(ofd, "%-7s%-11s%-4i ", rankstr(rank, active), 189 line + 1, LP_JOBNUM(cfname)); 190 break; 191 192 case 'N': 193 fname = line + 1; 194 if (!strcmp(fname, " ")) 195 fname = "(standard input)"; 196 197 if (names[0]) 198 (void)strlcat(names, ", ", sizeof(names)); 199 (void)strlcat(names, fname, sizeof(names)); 200 if (lp_stat(lp, dfname, &st) == -1) 201 log_warn("cannot stat %s", dfname); 202 else 203 totalsz += copies * st.st_size; 204 copies = 0; 205 break; 206 207 default: 208 if (line[0] < 'a' || line[0] > 'z') 209 continue; 210 if (copies++ == 0) 211 (void)strlcpy(dfname, line+1, sizeof(dfname)); 212 break; 213 } 214 } 215 216 dprintf(ofd, "%-37s %lld bytes\n", names, (long long)totalsz); 217 218 end: 219 free(line); 220 } 221 222 static void 223 dolong(int ofd, struct lp_printer *lp, struct lp_jobfilter *jf, int rank, 224 const char *cfname, int active) 225 { 226 struct stat st; 227 FILE *fp; 228 const char *fname; 229 char dfname[PATH_MAX], names[80], buf[64], *line = NULL; 230 ssize_t len; 231 size_t linesz = 0; 232 int copies = 0; 233 234 fp = lp_fopen(lp, cfname); 235 if (fp == NULL) { 236 log_warn("cannot open %s", cfname); 237 return; 238 } 239 240 names[0] = '\0'; 241 242 while ((len = getline(&line, &linesz, fp)) != -1) { 243 if (line[len-1] == '\n') 244 line[len - 1] = '\0'; 245 switch (line[0]) { 246 case 'P': 247 if (!checklists(cfname, jf, line + 1)) 248 goto end; 249 250 snprintf(buf, sizeof(buf), "%s: %s", line+1, 251 rankstr(rank, active)); 252 dprintf(ofd, "\n%-41s[job %s]\n", buf, cfname + 3); 253 break; 254 255 case 'N': 256 fname = line + 1; 257 if (!strcmp(fname, " ")) 258 fname = "(standard input)"; 259 260 if (copies > 1) 261 dprintf(ofd, "\t%-2d copies of %-19s", copies, 262 fname); 263 else 264 dprintf(ofd, "\t%-32s", fname); 265 266 if (lp_stat(lp, dfname, &st) == -1) { 267 log_warn("cannot stat %s", dfname); 268 dprintf(ofd, " ??? bytes\n"); 269 } 270 else 271 dprintf(ofd, " %lld bytes\n", 272 (long long)st.st_size); 273 copies = 0; 274 break; 275 276 default: 277 if (line[0] < 'a' || line[0] > 'z') 278 continue; 279 if (copies++ == 0) 280 (void)strlcpy(dfname, line+1, sizeof(dfname)); 281 break; 282 } 283 } 284 285 end: 286 free(line); 287 } 288