1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 /* LINTLIBRARY */ 33 34 # include <unistd.h> 35 # include <fcntl.h> 36 # include <errno.h> 37 # include <sys/utsname.h> 38 # include <stdlib.h> 39 # include <sys/types.h> 40 # include <sys/stat.h> 41 42 #include "lp.h" 43 #include "msgs.h" 44 45 #define TURN_OFF(X,F) (void)Fcntl(X, F_SETFL, (Fcntl(X, F_GETFL, 0) & ~(F))) 46 47 #if defined(__STDC__) 48 static MESG * connect3_2 ( void ); 49 static int checklock ( void ); 50 #else 51 static MESG * connect3_2(); 52 static int checklock(); 53 #endif 54 55 /* 56 ** mconnect() - OPEN A MESSAGE PATH 57 */ 58 59 #if defined(__STDC__) 60 MESG * mconnect ( char * path, int id1, int id2 ) 61 #else 62 MESG * mconnect () 63 char *path; 64 int id1; 65 int id2; 66 #endif 67 { 68 int fd; 69 int wronly = 0; 70 int count = 0; 71 MESG *md; 72 struct stat stbuf; 73 74 /* 75 ** invoked as mconnect(path, 0, 0) 76 ** 77 ** Open <path>, if isastream() is true for the returned file 78 ** descriptor, then we're done. If not, proceed with the 3.2 79 ** handshaking. 80 */ 81 82 if (path) 83 { 84 /* 85 ** Verify that the spooler is running and that the 86 ** <path> identifies a pipe. 87 ** This prevents us from getting hung in the open 88 ** and from thinking the <path> is a non-streams pipe. 89 */ 90 if (checklock() == -1) 91 return(NULL); 92 Again: if (stat(path, &stbuf) == -1) 93 return(NULL); 94 if ((stbuf.st_mode & S_IFMT) != S_IFIFO) { 95 if (count++ > 20) 96 return (NULL); 97 sleep(1); 98 goto Again; 99 } 100 101 if ((fd = Open(path, O_RDWR, 0)) == -1) 102 if ((fd = Open(path, O_WRONLY, 0)) == -1) 103 return(NULL); 104 else 105 wronly = 1; 106 107 if (isastream(fd) && !wronly) 108 { 109 #if defined(NOCONNLD) 110 int fds[2]; 111 112 if (pipe(fds) != 0) 113 return(NULL); 114 115 if (ioctl(fd, I_SENDFD, fds[1]) != 0) 116 return(NULL); 117 118 (void)_Close(fd); 119 120 fd = fds[0]; 121 (void)_Close(fds[1]); 122 #endif 123 124 if ((md = (MESG *)Malloc(MDSIZE)) == NULL) 125 { 126 errno = ENOMEM; 127 return(NULL); 128 } 129 130 memset(md, 0, sizeof (MESG)); 131 md->gid = getgid(); 132 md->on_discon = NULL; 133 md->readfd = fd; 134 md->state = MDS_IDLE; 135 md->type = MD_STREAM; 136 md->uid = getuid(); 137 md->writefd = fd; 138 139 ResetFifoBuffer (md->readfd); 140 return(md); 141 } 142 143 return(connect3_2()); 144 } 145 146 if (id1 > 0 && id2 > 0) 147 { 148 if ((md = (MESG *)Malloc(MDSIZE)) == NULL) 149 { 150 errno = ENOMEM; 151 return(NULL); 152 } 153 154 memset(md, 0, sizeof (MESG)); 155 md->gid = getgid(); 156 md->on_discon = NULL; 157 md->readfd = id1; 158 md->state = MDS_IDLE; 159 md->type = MD_BOUND; 160 md->uid = getuid(); 161 md->writefd = id2; 162 163 ResetFifoBuffer (md->readfd); 164 165 return(md); 166 } 167 168 errno = EINVAL; 169 return(NULL); 170 } 171 172 #if defined(__STDC__) 173 static MESG * connect3_2 ( void ) 174 #else 175 static MESG * connect3_2() 176 #endif 177 { 178 char *msgbuf = 0, 179 *fifo_name = "UUUUUUUUNNNNN"; 180 int tmp_fd = -1, 181 size; 182 short status; 183 struct utsname ubuf; 184 MESG *md; 185 186 if ((md = (MESG *)Malloc(MDSIZE)) == NULL) 187 return(NULL); 188 189 memset(md, 0, sizeof (MESG)); 190 md->gid = getgid(); 191 md->state = MDS_IDLE; 192 md->type = MD_USR_FIFO; 193 md->uid = getuid(); 194 195 if ((md->writefd = Open(Lp_FIFO, O_WRONLY, 0222)) == -1) 196 { 197 errno = ENOENT; 198 return (NULL); 199 } 200 201 /* 202 ** Combine the machine node-name with the process ID to 203 ** get a name that will be unique across the network. 204 ** The 99999 is just a safety precaution against over-running 205 ** the buffer. 206 */ 207 208 (void)uname (&ubuf); 209 210 sprintf (fifo_name, "%.8s%u", ubuf.nodename, (getpid() & 99999)); 211 212 if (!(md->file = makepath(Lp_Public_FIFOs, fifo_name, (char *)0))) 213 { 214 errno = ENOMEM; 215 goto Error; 216 } 217 218 (void) Unlink(md->file); 219 220 if (Mknod(md->file, S_IFIFO | S_IRUSR, 0) == -1) 221 goto Error; 222 223 if ((md->readfd = Open(md->file, O_RDONLY|O_NDELAY, S_IRUSR)) == -1) 224 goto Error; 225 226 TURN_OFF (md->readfd, O_NDELAY); 227 228 size = putmessage((char *)0, S_NEW_QUEUE, 0, fifo_name, ubuf.nodename); 229 if (!(msgbuf = Malloc((unsigned)size))) 230 { 231 errno = ENOMEM; 232 goto Error; 233 } 234 (void) putmessage(msgbuf, S_NEW_QUEUE, 0, fifo_name, ubuf.nodename); 235 236 if ( 237 mwrite(md, msgbuf) == -1 238 || mread(md, msgbuf, size) == -1 239 || getmessage(msgbuf, R_NEW_QUEUE, &status) != R_NEW_QUEUE 240 ) 241 { 242 Free (msgbuf); 243 goto Error; 244 } 245 else 246 if (status != MOK) 247 { 248 Free(msgbuf); 249 errno = ENOSPC; 250 goto Error; 251 } 252 253 Free (msgbuf); 254 255 /* 256 * Prepare to use the fifo the Spooler created. This new FIFO can be 257 * read ONLY by who we said we are, so if we lied, tough luck for us! 258 */ 259 260 (void)Unlink (md->file); /* must exist to get here */ 261 tmp_fd = md->readfd; /* save the old fd */ 262 263 Free(md->file); 264 265 if (!(md->file = makepath(Lp_Private_FIFOs, fifo_name, (char *)0))) 266 { 267 errno = ENOMEM; 268 goto Error; 269 } 270 271 if ((md->readfd = Open(md->file, O_RDONLY|O_NDELAY, S_IRUSR)) == -1) 272 goto Error; 273 274 TURN_OFF (md->readfd, O_NDELAY); 275 276 size = putmessage((char *)0, S_NEW_QUEUE, 1, fifo_name, ubuf.nodename); 277 if (!(msgbuf = Malloc((unsigned)size))) 278 { 279 errno = ENOMEM; 280 goto Error; 281 } 282 (void) putmessage(msgbuf, S_NEW_QUEUE, 1, fifo_name, ubuf.nodename); 283 284 if ( 285 mwrite(md, msgbuf) == -1 286 || mread(md, msgbuf, size) == -1 287 || getmessage(msgbuf, R_NEW_QUEUE, &status) != R_NEW_QUEUE 288 ) 289 { 290 Free (msgbuf); 291 goto Error; 292 } 293 else 294 if (status != MOK) 295 { 296 Free(msgbuf); 297 errno = ENOSPC; 298 goto Error; 299 } 300 301 Free (msgbuf); 302 (void) Close(tmp_fd); 303 return (md); 304 305 Error: 306 if (md->writefd != -1) 307 (void) Close (md->writefd); 308 if (md->writefd != -1) 309 (void) Close (md->readfd); 310 if (md->file) 311 { 312 (void) Unlink (md->file); 313 Free (md->file); 314 } 315 if (tmp_fd != -1) 316 (void) Close(tmp_fd); 317 318 Free(md); 319 320 return(NULL); 321 } 322 323 324 #if defined(__STDC__) 325 static int checklock ( void ) 326 #else 327 static int checklock() 328 #endif 329 { 330 int fd; 331 struct flock lock; 332 333 if ((fd = Open(Lp_Schedlock, O_RDONLY, 0666)) == -1) 334 return (-1); 335 336 /* 337 * Now, we try to read-lock the lock file. This can only succeed if 338 * the Spooler (lpsched) is down. 339 */ 340 341 lock.l_type = F_RDLCK; 342 lock.l_whence = 0; 343 lock.l_start = 0; 344 lock.l_len = 0; /* till end of file */ 345 346 if (Fcntl(fd, F_SETLK, &lock) != -1 || errno != EAGAIN) 347 { 348 (void)Close (fd); 349 return (-1); 350 } 351 352 /* 353 * We can get here only when fcntl() == -1 && errno == EAGAIN, 354 * i.e., spooler (lpsched) is running. 355 */ 356 357 (void)Close (fd); 358 359 return(0); 360 } 361