1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 1997 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.11 */ 32*0Sstevel@tonic-gate /* LINTLIBRARY */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate # include <errno.h> 36*0Sstevel@tonic-gate # include <string.h> 37*0Sstevel@tonic-gate #include <syslog.h> 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate # include "lp.h" 40*0Sstevel@tonic-gate # include "msgs.h" 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate extern char Resync[]; 43*0Sstevel@tonic-gate extern char Endsync[]; 44*0Sstevel@tonic-gate static int Had_Full_Buffer = 1; 45*0Sstevel@tonic-gate int Garbage_Bytes = 0; 46*0Sstevel@tonic-gate int Garbage_Messages= 0; 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate /* 49*0Sstevel@tonic-gate ** A real message is written in one piece, and the write 50*0Sstevel@tonic-gate ** is atomic. Thus, even if the O_NDELAY flag is set, 51*0Sstevel@tonic-gate ** if we read part of the real message, we can continue 52*0Sstevel@tonic-gate ** to read the rest of it in as many steps as we want 53*0Sstevel@tonic-gate ** (up to the size of the message, of course!) without 54*0Sstevel@tonic-gate ** UNIX returning 0 because no data is available. 55*0Sstevel@tonic-gate ** So, a real message doesn't have to be read in one piece, 56*0Sstevel@tonic-gate ** which is good since we don't know how much to read! 57*0Sstevel@tonic-gate ** 58*0Sstevel@tonic-gate ** Fake messages, or improperly written messages, don't 59*0Sstevel@tonic-gate ** have this nice property. 60*0Sstevel@tonic-gate ** 61*0Sstevel@tonic-gate ** INTERRUPTED READS: 62*0Sstevel@tonic-gate ** 63*0Sstevel@tonic-gate ** If a signal occurs during an attempted read, we can exit. 64*0Sstevel@tonic-gate ** The caller can retry the read and we will correctly restart 65*0Sstevel@tonic-gate ** it. The correctness of this assertion can be seen by noticing 66*0Sstevel@tonic-gate ** that at the beginning of each READ below, we can go back 67*0Sstevel@tonic-gate ** to the first statement executed (the first READ below) 68*0Sstevel@tonic-gate ** and correctly reexecute the code. 69*0Sstevel@tonic-gate ** 70*0Sstevel@tonic-gate ** If the last writer closed the fifo, we'll read 0 bytes 71*0Sstevel@tonic-gate ** (at least on the subsequent read). If we were in the 72*0Sstevel@tonic-gate ** middle of reading a message, we were reading a bogus 73*0Sstevel@tonic-gate ** message (but see below). 74*0Sstevel@tonic-gate ** 75*0Sstevel@tonic-gate ** If we read less than we expect, it's because we were 76*0Sstevel@tonic-gate ** reading a fake message (but see below). 77*0Sstevel@tonic-gate ** 78*0Sstevel@tonic-gate ** HOWEVER: In the last two cases, we may have ONE OR MORE 79*0Sstevel@tonic-gate ** REAL MESSAGES snuggled in amongst the trash! 80*0Sstevel@tonic-gate ** 81*0Sstevel@tonic-gate ** All this verbal rambling is preface to let you understand why we 82*0Sstevel@tonic-gate ** buffer the data (which is a shame, but necessary). 83*0Sstevel@tonic-gate */ 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate /* 86*0Sstevel@tonic-gate ** As long as we get real messages, we can avoid needless function calls. 87*0Sstevel@tonic-gate ** The SYNC argument in this macro should be set if the resynch. bytes 88*0Sstevel@tonic-gate ** have been read--i.e. if the rest of the message is trying to be read. 89*0Sstevel@tonic-gate ** In this case, if we had not read a full buffer last time, then we 90*0Sstevel@tonic-gate ** must be in the middle of a bogus message. 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate #define UNSYNCHED_READ(N) \ 94*0Sstevel@tonic-gate if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \ 95*0Sstevel@tonic-gate { \ 96*0Sstevel@tonic-gate switch (_buffer(fifo)) \ 97*0Sstevel@tonic-gate { \ 98*0Sstevel@tonic-gate case -1: \ 99*0Sstevel@tonic-gate return (-1); \ 100*0Sstevel@tonic-gate case 0: \ 101*0Sstevel@tonic-gate if (fbp->psave_end > fbp->psave) \ 102*0Sstevel@tonic-gate goto SyncUp; \ 103*0Sstevel@tonic-gate return (0); \ 104*0Sstevel@tonic-gate } \ 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate #define SYNCHED_READ(N) \ 108*0Sstevel@tonic-gate if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \ 109*0Sstevel@tonic-gate { \ 110*0Sstevel@tonic-gate switch (_buffer(fifo)) \ 111*0Sstevel@tonic-gate { \ 112*0Sstevel@tonic-gate case -1: \ 113*0Sstevel@tonic-gate return (-1); \ 114*0Sstevel@tonic-gate case 0: \ 115*0Sstevel@tonic-gate if (fbp->psave_end > fbp->psave) \ 116*0Sstevel@tonic-gate goto SyncUp; \ 117*0Sstevel@tonic-gate return (0); \ 118*0Sstevel@tonic-gate } \ 119*0Sstevel@tonic-gate if (!Had_Full_Buffer) \ 120*0Sstevel@tonic-gate goto SyncUp; \ 121*0Sstevel@tonic-gate } 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate /* 124*0Sstevel@tonic-gate ** read_fifo() - READ A BUFFER WITH HEADER AND CHECKSUM 125*0Sstevel@tonic-gate */ 126*0Sstevel@tonic-gate int 127*0Sstevel@tonic-gate read_fifo (fifo, buf, size) 128*0Sstevel@tonic-gate int fifo; 129*0Sstevel@tonic-gate char *buf; 130*0Sstevel@tonic-gate unsigned int size; 131*0Sstevel@tonic-gate { 132*0Sstevel@tonic-gate register fifobuffer_t *fbp; 133*0Sstevel@tonic-gate register unsigned int real_chksum, 134*0Sstevel@tonic-gate chksum, 135*0Sstevel@tonic-gate real_size; 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate /* 138*0Sstevel@tonic-gate ** Make sure we start on a message boundary. The first 139*0Sstevel@tonic-gate ** line of defense is to look for the resync. bytes. 140*0Sstevel@tonic-gate ** 141*0Sstevel@tonic-gate ** The "SyncUp" label is global to this routine (below this point) 142*0Sstevel@tonic-gate ** and is called whenever we determine that we're out 143*0Sstevel@tonic-gate ** of sync. with the incoming bytes. 144*0Sstevel@tonic-gate */ 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate if (!(fbp=GetFifoBuffer (fifo))) 147*0Sstevel@tonic-gate return -1; 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate UNSYNCHED_READ (HEAD_RESYNC_LEN); 150*0Sstevel@tonic-gate while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1]) 151*0Sstevel@tonic-gate { 152*0Sstevel@tonic-gate SyncUp: 153*0Sstevel@tonic-gate #if defined(TRACE_MESSAGES) 154*0Sstevel@tonic-gate if (trace_messages) 155*0Sstevel@tonic-gate syslog(LOG_DEBUG, "DISCARD %c\n", *fbp->psave); 156*0Sstevel@tonic-gate #endif 157*0Sstevel@tonic-gate fbp->psave++; 158*0Sstevel@tonic-gate Garbage_Bytes++; 159*0Sstevel@tonic-gate UNSYNCHED_READ (HEAD_RESYNC_LEN); 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate /* 164*0Sstevel@tonic-gate ** We're sync'd, so read the full header. 165*0Sstevel@tonic-gate */ 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate SYNCHED_READ (HEAD_LEN); 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate /* 171*0Sstevel@tonic-gate ** If the header size is smaller than the minimum size for a header, 172*0Sstevel@tonic-gate ** or larger than allowed, we must assume that we really aren't 173*0Sstevel@tonic-gate ** synchronized. 174*0Sstevel@tonic-gate */ 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate real_size = stoh(fbp->psave + HEAD_SIZE); 177*0Sstevel@tonic-gate if (real_size < CONTROL_LEN || MSGMAX < real_size) 178*0Sstevel@tonic-gate { 179*0Sstevel@tonic-gate #if defined(TRACE_MESSAGES) 180*0Sstevel@tonic-gate if (trace_messages) 181*0Sstevel@tonic-gate syslog(LOG_DEBUG, "BAD SIZE\n"); 182*0Sstevel@tonic-gate #endif 183*0Sstevel@tonic-gate goto SyncUp; 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate /* 187*0Sstevel@tonic-gate ** We have the header. Now we can finally read the rest of the 188*0Sstevel@tonic-gate ** message... 189*0Sstevel@tonic-gate */ 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate SYNCHED_READ (real_size); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate ** ...but did we read a real message?... 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate if 199*0Sstevel@tonic-gate ( 200*0Sstevel@tonic-gate *(fbp->psave + TAIL_ENDSYNC(real_size)) != Endsync[0] 201*0Sstevel@tonic-gate || *(fbp->psave + TAIL_ENDSYNC(real_size) + 1) != Endsync[1] 202*0Sstevel@tonic-gate ) 203*0Sstevel@tonic-gate { 204*0Sstevel@tonic-gate #if defined(TRACE_MESSAGES) 205*0Sstevel@tonic-gate if (trace_messages) 206*0Sstevel@tonic-gate syslog(LOG_DEBUG, "BAD ENDSYNC\n"); 207*0Sstevel@tonic-gate #endif 208*0Sstevel@tonic-gate Garbage_Messages++; 209*0Sstevel@tonic-gate goto SyncUp; 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate chksum = stoh(fbp->psave + TAIL_CHKSUM(real_size)); 213*0Sstevel@tonic-gate CALC_CHKSUM (fbp->psave, real_size, real_chksum); 214*0Sstevel@tonic-gate if (real_chksum != chksum) 215*0Sstevel@tonic-gate { 216*0Sstevel@tonic-gate #if defined(TRACE_MESSAGES) 217*0Sstevel@tonic-gate if (trace_messages) 218*0Sstevel@tonic-gate syslog(LOG_DEBUG, "BAD CHKSUM\n"); 219*0Sstevel@tonic-gate #endif 220*0Sstevel@tonic-gate Garbage_Messages++; 221*0Sstevel@tonic-gate goto SyncUp; 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate ** ...yes!...but can the caller handle the message? 226*0Sstevel@tonic-gate */ 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if (size < real_size) 229*0Sstevel@tonic-gate { 230*0Sstevel@tonic-gate errno = E2BIG; 231*0Sstevel@tonic-gate return (-1); 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /* 236*0Sstevel@tonic-gate ** Yes!! We can finally copy the message into the caller's buffer 237*0Sstevel@tonic-gate ** and remove it from our buffer. That wasn't so bad, was it? 238*0Sstevel@tonic-gate */ 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate #if defined(TRACE_MESSAGES) 241*0Sstevel@tonic-gate if (trace_messages) 242*0Sstevel@tonic-gate syslog(LOG_DEBUG, "MESSAGE: %-.*s", real_size, fbp->psave); 243*0Sstevel@tonic-gate #endif 244*0Sstevel@tonic-gate (void)memcpy (buf, fbp->psave, real_size); 245*0Sstevel@tonic-gate fbp->psave += real_size; 246*0Sstevel@tonic-gate return (real_size); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate int 250*0Sstevel@tonic-gate peek3_2 (fifo) 251*0Sstevel@tonic-gate int fifo; 252*0Sstevel@tonic-gate { 253*0Sstevel@tonic-gate register fifobuffer_t *fbp; 254*0Sstevel@tonic-gate register unsigned int real_size; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate /* 257*0Sstevel@tonic-gate ** Make sure we start on a message boundary. The first 258*0Sstevel@tonic-gate ** line of defense is to look for the resync. bytes. 259*0Sstevel@tonic-gate ** 260*0Sstevel@tonic-gate ** The "SyncUp" label is global to this routine (below this point) 261*0Sstevel@tonic-gate ** and is called whenever we determine that we're out 262*0Sstevel@tonic-gate ** of sync. with the incoming bytes. 263*0Sstevel@tonic-gate */ 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate if (!(fbp=GetFifoBuffer (fifo))) 266*0Sstevel@tonic-gate return -1; 267*0Sstevel@tonic-gate UNSYNCHED_READ (HEAD_RESYNC_LEN); 268*0Sstevel@tonic-gate while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1]) 269*0Sstevel@tonic-gate { 270*0Sstevel@tonic-gate SyncUp: 271*0Sstevel@tonic-gate fbp->psave++; 272*0Sstevel@tonic-gate Garbage_Bytes++; 273*0Sstevel@tonic-gate UNSYNCHED_READ (HEAD_RESYNC_LEN); 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate ** We're sync'd, so read the full header. 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate SYNCHED_READ (HEAD_LEN); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate /* 285*0Sstevel@tonic-gate ** If the header size is smaller than the minimum size for a header, 286*0Sstevel@tonic-gate ** or larger than allowed, we must assume that we really aren't 287*0Sstevel@tonic-gate ** synchronized. 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate real_size = stoh(fbp->psave + HEAD_SIZE); 291*0Sstevel@tonic-gate if (real_size < CONTROL_LEN || MSGMAX < real_size) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate goto SyncUp; 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate return(real_size); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate static int 300*0Sstevel@tonic-gate _buffer (fifo) 301*0Sstevel@tonic-gate int fifo; 302*0Sstevel@tonic-gate { 303*0Sstevel@tonic-gate int n, nbytes, count = 0; 304*0Sstevel@tonic-gate register fifobuffer_t *fbp; 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate /* 307*0Sstevel@tonic-gate ** As long as we get real messages, and if we chose 308*0Sstevel@tonic-gate ** SAVE_SIZE well, we shouldn't have to move the data 309*0Sstevel@tonic-gate ** in the "else" branch below: Each time we call "read" 310*0Sstevel@tonic-gate ** we aren't likely to get as many bytes as we ask for, 311*0Sstevel@tonic-gate ** just as many as are in the fifo, AND THIS SHOULD 312*0Sstevel@tonic-gate ** REPRESENT AN INTEGRAL NUMBER OF MESSAGES. Since 313*0Sstevel@tonic-gate ** the "read_fifo" routine reads complete messages, 314*0Sstevel@tonic-gate ** it will end its read at the end of the message, 315*0Sstevel@tonic-gate ** which (eventually) will make "psave_end" == "psave". 316*0Sstevel@tonic-gate */ 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate /* 319*0Sstevel@tonic-gate ** If the buffer is empty, there's nothing to move. 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate if (!(fbp = GetFifoBuffer (fifo))) 322*0Sstevel@tonic-gate return -1; 323*0Sstevel@tonic-gate if (fbp->psave_end == fbp->psave) 324*0Sstevel@tonic-gate fbp->psave = fbp->psave_end = fbp->save; /* sane pointers! */ 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* 327*0Sstevel@tonic-gate ** If the buffer has data at the high end, move it down. 328*0Sstevel@tonic-gate */ 329*0Sstevel@tonic-gate else 330*0Sstevel@tonic-gate if (fbp->psave != fbp->save) /* sane pointers! */ 331*0Sstevel@tonic-gate { 332*0Sstevel@tonic-gate /* 333*0Sstevel@tonic-gate ** Move the data still left in the buffer to the 334*0Sstevel@tonic-gate ** front, so we can read as much as possible into 335*0Sstevel@tonic-gate ** buffer after it. 336*0Sstevel@tonic-gate */ 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate memmove(fbp->save, fbp->psave, fbp->psave_end - fbp->psave); 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate fbp->psave_end = fbp->save + (fbp->psave_end - fbp->psave); 341*0Sstevel@tonic-gate fbp->psave = fbp->save; /* sane pointers! */ 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate /* 345*0Sstevel@tonic-gate ** The "fbp->psave" and "fbp->psave_end" pointers must be in a sane 346*0Sstevel@tonic-gate ** state when we get here, in case the "read()" gets interrupted. 347*0Sstevel@tonic-gate ** When that happens, we return to the caller who may try 348*0Sstevel@tonic-gate ** to restart us! Sane: fbp->psave == fbp->save (HERE!) 349*0Sstevel@tonic-gate */ 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate nbytes = MSGMAX - (fbp->psave_end - fbp->save); 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate while ((n = read(fifo, fbp->psave_end, nbytes)) == 0 && count < 60) 354*0Sstevel@tonic-gate { 355*0Sstevel@tonic-gate (void) sleep ((unsigned) 1); 356*0Sstevel@tonic-gate count++; 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if (n > 0) 360*0Sstevel@tonic-gate fbp->psave_end += n; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate Had_Full_Buffer = fbp->full; 363*0Sstevel@tonic-gate fbp->full = (nbytes == n); 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate return (n); 366*0Sstevel@tonic-gate } 367