xref: /illumos-gate/usr/src/cmd/lp/lib/msgs/mconnect.c (revision 7c478bd9)
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