1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/***************************************************************************
18 * LPRng - An Extended Print Spooler System
19 *
20 * Copyright 1988-2003, Patrick Powell, San Diego, CA
21 *     papowell@lprng.com
22 * See LICENSE for conditions of use.
23 *
24 ***************************************************************************/
25
26 static char *const _id =
27"$Id: utilities.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $";
28
29#include "lp.h"
30
31#include "utilities.h"
32#include "getopt.h"
33#include "errorcodes.h"
34
35/**** ENDINCLUDE ****/
36
37/*
38 * Time_str: return "cleaned up" ctime() string...
39 *
40 * in YY/MO/DY/hr:mn:sc
41 * Thu Aug 4 12:34:17 BST 1994 -> 12:34:17
42 */
43
44char *Time_str(int shortform, time_t t)
45{
46    static char buffer[99];
47	struct tm *tmptr;
48	struct timeval tv;
49
50	tv.tv_usec = 0;
51	if( t == 0 ){
52		if( gettimeofday( &tv, 0 ) == -1 ){
53			Errorcode = JFAIL;
54			LOGERR_DIE(LOG_ERR)"Time_str: gettimeofday failed");
55		}
56		t = tv.tv_sec;
57	}
58	tmptr = localtime( &t );
59	if( shortform && Full_time_DYN == 0 ){
60		SNPRINTF( buffer, sizeof(buffer))
61			"%02d:%02d:%02d.%03d",
62			tmptr->tm_hour, tmptr->tm_min, tmptr->tm_sec,
63			(int)(tv.tv_usec/1000) );
64	} else {
65		SNPRINTF( buffer, sizeof(buffer))
66			"%d-%02d-%02d-%02d:%02d:%02d.%03d",
67			tmptr->tm_year+1900, tmptr->tm_mon+1, tmptr->tm_mday,
68			tmptr->tm_hour, tmptr->tm_min, tmptr->tm_sec,
69			(int)(tv.tv_usec/1000) );
70	}
71	/* now format the time */
72	if( Ms_time_resolution_DYN == 0 ){
73		char *s;
74		if( ( s = safestrrchr( buffer, '.' )) ){
75			*s = 0;
76		}
77	}
78	return( buffer );
79}
80
81
82/*
83 * Pretty_time: return "cleaned up" ctime() string...
84 *
85 * in YY/MO/DY/hr:mn:sc
86 * Thu Aug 4 12:34:17 BST 1994 -> 12:34:17
87 */
88
89char *Pretty_time( time_t t )
90{
91    static char buffer[99];
92	struct tm *tmptr;
93	struct timeval tv;
94
95	tv.tv_usec = 0;
96	if( t == 0 ){
97		if( gettimeofday( &tv, 0 ) == -1 ){
98			Errorcode = JFAIL;
99			LOGERR_DIE(LOG_ERR)"Time_str: gettimeofday failed");
100		}
101		t = tv.tv_sec;
102	}
103	tmptr = localtime( &t );
104	strftime( buffer, sizeof(buffer), "%b %d %R %Y", tmptr );
105
106	return( buffer );
107}
108
109time_t Convert_to_time_t( char *str )
110{
111	time_t t = 0;
112	if(str) t = strtol(str,0,0);
113	DEBUG5("Convert_to_time_t: %s = %ld", str, (long)t );
114	return(t);
115}
116
117/***************************************************************************
118 * Print the usage message list or any list of strings
119 *  Use for copyright printing as well
120 ***************************************************************************/
121
122void Printlist( char **m, int fd )
123{
124	char msg[SMALLBUFFER];
125	if( m ){
126		if( *m ){
127			SNPRINTF( msg,sizeof(msg)) _(*m), Name );
128			Write_fd_str(fd, msg);
129			Write_fd_str(fd,"\n");
130			++m;
131		}
132		for( ; *m; ++m ){
133			SNPRINTF( msg,sizeof(msg)) "%s\n", _(*m) );
134			Write_fd_str(fd, msg);
135		}
136	}
137}
138
139
140/***************************************************************************
141 * Utility functions: write a string to a fd (bombproof)
142 *   write a char array to a fd (fairly bombproof)
143 * Note that there is a race condition here that is unavoidable;
144 * The problem is that there is no portable way to disable signals;
145 *  post an alarm;  <enable signals and do a read simultaneously>
146 * There is a solution that involves forking a subprocess, but this
147 *  is so painful as to be not worth it.  Most of the timeouts
148 *  in the LPR stuff are in the order of minutes, so this is not a problem.
149 *
150 * Note: we do the write first and then check for timeout.
151 ***************************************************************************/
152
153/*
154 * Write_fd_len( fd, msg, len )
155 * returns:
156 *  0  - success
157 *  <0 - failure
158 */
159
160int Write_fd_len( int fd, const char *msg, int len )
161{
162	int i;
163	int busy_index = 0;//JY1110: add sock
164
165	i = len;
166	while( len > 0 && (i = write( fd, msg, len ) ) >= 0 ){
167		len -= i, msg += i;
168		if(i == 0)
169			busy_index++;//JY1110: add sock
170		else
171			busy_index=0;
172
173		if(busy_index > 3){//JY1110: add sock
174			check_prn_status("BUSY or ERROR", clientaddr);
175		}
176		else{
177			check_prn_status("Printing", clientaddr);
178		}
179	}
180	return( (i < 0) ? -1 : 0 );
181}
182
183/*
184 * Write_fd_len_timeout( timeout, fd, msg, len )
185 * returns:
186 *  0  - success
187 *  <0 - failure
188 */
189
190int Write_fd_len_timeout( int timeout, int fd, const char *msg, int len )
191{
192	int i;
193	if( timeout > 0 ){
194		if( Set_timeout() ){
195			Set_timeout_alarm( timeout  );
196			i = Write_fd_len( fd, msg, len );
197		} else {
198			i = -1;
199		}
200		Clear_timeout();
201	} else {
202		i = Write_fd_len( fd, msg, len );
203	}
204	return( i < 0 ? -1 : 0 );
205}
206
207/*
208 * Write_fd_str_timeout( fd, msg )
209 * returns:
210 *  0  - success
211 *  <0 - failure
212 */
213
214int Write_fd_str( int fd, const char *msg )
215{
216	if( msg && *msg ){
217		return( Write_fd_len( fd, msg, safestrlen(msg) ));
218	}
219	return( 0 );
220}
221
222
223/*
224 * Write_fd_str_timeout( timeout, fd, msg )
225 * returns:
226 *  0  - success
227 *  <0 - failure
228 */
229
230int Write_fd_str_timeout( int timeout, int fd, const char *msg )
231{
232	if( msg && *msg ){
233		return( Write_fd_len_timeout( timeout, fd, msg, safestrlen(msg) ) );
234	}
235	return( 0 );
236}
237
238
239/*
240 * Read_fd_len_timeout( timeout, fd, msg, len )
241 * returns:
242 *  n>0 - read n
243 *  0  - EOF
244 *  <0 - failure
245 */
246
247int Read_fd_len_timeout( int timeout, int fd, char *msg, int len )
248{
249	int i;
250	if( timeout > 0 ){
251		if( Set_timeout() ){
252			Set_timeout_alarm( timeout  );
253			i = read( fd, msg, len );
254		} else {
255			i = -1;
256		}
257		Clear_timeout();
258	} else {
259		i = read( fd, msg, len );
260	}
261	return( i );
262}
263
264
265/**************************************************************
266 *
267 * signal handling:
268 * SIGALRM should be the only signal that terminates system calls;
269 * all other signals should NOT terminate them.
270 * This signal() emulation function attepts to do just that.
271 * (Derived from Advanced Programming in the UNIX Environment, Stevens, 1992)
272 *
273 **************************************************************/
274
275
276/* solaris 2.3 note: don't compile this with "gcc -ansi -pedantic";
277 * due to a bug in the header file, struct sigaction doesn't
278 * get declared. :(
279 */
280
281/* plp_signal will set flags so that signal handlers will continue
282 * Note that in Solaris,  you MUST reinstall the
283 * signal hanlders in the signal handler!  The default action is
284 * to try to restart the system call - note that the code should
285 * be written so that you check for error returns from a system call
286 * and continue if no error.
287 * WARNING: read/write may terminate early? who knows...
288 * See plp_signal_break.
289 */
290
291plp_sigfunc_t plp_signal (int signo, plp_sigfunc_t func)
292{
293#ifdef HAVE_SIGACTION
294	struct sigaction act, oact;
295
296	act.sa_handler = func;
297	(void) sigemptyset (&act.sa_mask);
298	act.sa_flags = 0;
299# ifdef SA_RESTART
300	act.sa_flags |= SA_RESTART;             /* SVR4, 4.3+BSD */
301# endif
302	if (sigaction (signo, &act, &oact) < 0) {
303		return (SIG_ERR);
304	}
305	return (plp_sigfunc_t) oact.sa_handler;
306#else
307	/* sigaction is not supported. Just set the signals. */
308	return (plp_sigfunc_t)signal (signo, func);
309#endif
310}
311
312/* plp_signal_break is similar to plp_signal,  but will cause
313 * TERMINATION of a system call if possible.  This allows
314 * you to force a signal to cause termination of a system
315 * wait or other action.
316 * WARNING: read/write may terminate early? who knows... so
317 * beware if you are expecting this and don't believe that
318 * you got an entire buffer read/written.
319 */
320
321plp_sigfunc_t plp_signal_break (int signo, plp_sigfunc_t func)
322{
323#ifdef HAVE_SIGACTION
324	struct sigaction act, oact;
325
326	act.sa_handler = func;
327	(void) sigemptyset (&act.sa_mask);
328	act.sa_flags = 0;
329# ifdef SA_INTERRUPT
330	act.sa_flags |= SA_INTERRUPT;            /* SunOS */
331# endif
332	if (sigaction (signo, &act, &oact) < 0) {
333		return (SIG_ERR);
334	}
335	return (plp_sigfunc_t) oact.sa_handler;
336#else
337	/* sigaction is not supported. Just set the signals. */
338	return (plp_sigfunc_t)signal (signo, func);
339#endif
340}
341
342/**************************************************************/
343
344void plp_block_all_signals ( plp_block_mask *oblock )
345{
346#ifdef HAVE_SIGPROCMASK
347	sigset_t block;
348
349	(void) sigfillset (&block); /* block all signals */
350	if (sigprocmask (SIG_SETMASK, &block, oblock) < 0)
351		LOGERR_DIE(LOG_ERR) "plp_block_all_signals: sigprocmask failed");
352#else
353	*oblock = sigblock( ~0 ); /* block all signals */
354#endif
355}
356
357
358void plp_unblock_all_signals ( plp_block_mask *oblock )
359{
360#ifdef HAVE_SIGPROCMASK
361	sigset_t block;
362
363	(void) sigemptyset (&block); /* block all signals */
364	if (sigprocmask (SIG_SETMASK, &block, oblock) < 0)
365		LOGERR_DIE(LOG_ERR) "plp_unblock_all_signals: sigprocmask failed");
366#else
367	*oblock = sigblock( 0 ); /* unblock all signals */
368#endif
369}
370
371void plp_set_signal_mask ( plp_block_mask *in, plp_block_mask *out )
372{
373#ifdef HAVE_SIGPROCMASK
374	if (sigprocmask (SIG_SETMASK, in, out ) < 0)
375		LOGERR_DIE(LOG_ERR) "plp_set_signal_mask: sigprocmask failed");
376#else
377	sigset_t block;
378	if( in ) block = sigsetmask( *in );
379	else     block = sigblock( 0 );
380	if( out ) *out = block;
381#endif
382}
383
384void plp_unblock_one_signal ( int sig, plp_block_mask *oblock )
385{
386#ifdef HAVE_SIGPROCMASK
387	sigset_t block;
388
389	(void) sigemptyset (&block); /* clear out signals */
390	(void) sigaddset (&block, sig ); /* clear out signals */
391	if (sigprocmask (SIG_UNBLOCK, &block, oblock ) < 0)
392		LOGERR_DIE(LOG_ERR) "plp_unblock_one_signal: sigprocmask failed");
393#else
394	*oblock = sigblock( 0 );
395	(void) sigsetmask (*oblock & ~ sigmask(sig) );
396#endif
397}
398
399void plp_block_one_signal( int sig, plp_block_mask *oblock )
400{
401#ifdef HAVE_SIGPROCMASK
402	sigset_t block;
403
404	(void) sigemptyset (&block); /* clear out signals */
405	(void) sigaddset (&block, sig ); /* clear out signals */
406	if (sigprocmask (SIG_BLOCK, &block, oblock ) < 0)
407		LOGERR_DIE(LOG_ERR) "plp_block_one_signal: sigprocmask failed");
408#else
409	*oblock = sigblock( sigmask( sig ) );
410#endif
411}
412
413void plp_sigpause( void )
414{
415#ifdef HAVE_SIGPROCMASK
416	sigset_t block;
417	(void) sigemptyset (&block); /* clear out signals */
418	(void) sigsuspend( &block );
419#else
420	(void)sigpause( 0 );
421#endif
422}
423
424/**************************************************************
425 * Bombproof versions of strcasecmp() and strncasecmp();
426 **************************************************************/
427
428/* case insensitive compare for OS without it */
429int safestrcasecmp (const char *s1, const char *s2)
430{
431	int c1, c2, d = 0;
432	if( (s1 == s2) ) return(0);
433	if( (s1 == 0 ) && s2 ) return( -1 );
434	if( s1 && (s2 == 0 ) ) return( 1 );
435	for (;;) {
436		c1 = *((unsigned char *)s1); s1++;
437		c2 = *((unsigned char *)s2); s2++;
438		if( isupper(c1) ) c1 = tolower(c1);
439		if( isupper(c2) ) c2 = tolower(c2);
440		if( (d = (c1 - c2 )) || c1 == 0 ) break;
441	}
442	return( d );
443}
444
445/* case insensitive compare for OS without it */
446int safestrncasecmp (const char *s1, const char *s2, int len )
447{
448	int c1, c2, d = 0;
449	if( (s1 == s2) && s1 == 0 ) return(0);
450	if( (s1 == 0 ) && s2 ) return( -1 );
451	if( s1 && (s2 == 0 ) ) return( 1 );
452	for (;len>0;--len){
453		c1 = *((unsigned char *)s1); s1++;
454		c2 = *((unsigned char *)s2); s2++;
455		if( isupper(c1) ) c1 = tolower(c1);
456		if( isupper(c2) ) c2 = tolower(c2);
457		if( (d = (c1 - c2 )) || c1 == 0 ) return(d);
458	}
459	return( 0 );
460}
461
462/* perform safe comparison, even with null pointers */
463int safestrcmp( const char *s1, const char *s2 )
464{
465	if( (s1 == s2) ) return(0);
466	if( (s1 == 0 ) && s2 ) return( -1 );
467	if( s1 && (s2 == 0 ) ) return( 1 );
468	return( strcmp(s1, s2) );
469}
470
471
472/* perform safe comparison, even with null pointers */
473int safestrlen( const char *s1 )
474{
475	if( s1 ) return(strlen(s1));
476	return(0);
477}
478
479
480/* perform safe comparison, even with null pointers */
481int safestrncmp( const char *s1, const char *s2, int len )
482{
483	if( (s1 == s2) && s1 == 0 ) return(0);
484	if( (s1 == 0 ) && s2 ) return( -1 );
485	if( s1 && (s2 == 0 ) ) return( 1 );
486	return( strncmp(s1, s2, len) );
487}
488
489
490/* perform safe strchr, even with null pointers */
491char *safestrchr( const char *s1, int c )
492{
493	if( s1 ) return( strchr( s1, c ) );
494	return( 0 );
495}
496
497
498/* perform safe strrchr, even with null pointers */
499char *safestrrchr( const char *s1, int c )
500{
501	if( s1 ) return( strrchr( s1, c ) );
502	return( 0 );
503}
504
505
506/* perform safe strchr, even with null pointers */
507char *safestrpbrk( const char *s1, const char *s2 )
508{
509	if( s1 && s2 ) return( strpbrk( s1, s2 ) );
510	return( 0 );
511}
512
513/* perform string concatentaton with malloc */
514char *safestrappend4( char *s1, const char *s2, const char *s3, const char *s4 )
515{
516	int m, len;
517	m = safestrlen(s1);
518	len = m + safestrlen(s2) + safestrlen(s3) + safestrlen(s4);
519	s1 = realloc(s1,len+1);
520	len = m;
521	if( s2 ) strcpy( s1+len, s2 ); len += strlen(s1+len);
522	if( s3 ) strcpy( s1+len, s3 ); len += strlen(s1+len);
523	if( s4 ) strcpy( s1+len, s4 ); len += strlen(s1+len);
524	s1[ len ] = 0;
525	return(s1);
526}
527
528/***************************************************************************
529 * plp_usleep() with select - simple minded way to avoid problems
530 ***************************************************************************/
531int plp_usleep( int i )
532{
533	struct timeval t;
534	DEBUG3("plp_usleep: starting usleep %d", i );
535	if( i > 0 ){
536		memset( &t, 0, sizeof(t) );
537		t.tv_usec = i%1000000;
538		t.tv_sec =  i/1000000;
539		i = select( 0,
540			FD_SET_FIX((fd_set *))(0),
541			FD_SET_FIX((fd_set *))(0),
542			FD_SET_FIX((fd_set *))(0),
543			&t );
544		DEBUG3("plp_usleep: select done, status %d", i );
545	}
546	return( i );
547}
548
549
550/***************************************************************************
551 * plp_sleep() with select - simple minded way to avoid problems
552 ***************************************************************************/
553int plp_sleep( int i )
554{
555	struct timeval t;
556	DEBUG3("plp_sleep: starting sleep %d", i );
557	if( i > 0 ){
558		memset( &t, 0, sizeof(t) );
559		t.tv_sec = i;
560		i = select( 0,
561			FD_SET_FIX((fd_set *))(0),
562			FD_SET_FIX((fd_set *))(0),
563			FD_SET_FIX((fd_set *))(0),
564			&t );
565		DEBUG3("plp_sleep: select done, status %d", i );
566	}
567	return( i );
568}
569
570
571/***************************************************************************
572 * int get_max_processes()
573 *  get the maximum number of processes allowed
574 ***************************************************************************/
575
576int Get_max_servers( void )
577{
578	int n = 0;	/* We need some sort of limit here */
579
580#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NPROC)
581	struct rlimit pcount;
582	if( getrlimit(RLIMIT_NPROC, &pcount) == -1 ){
583		FATAL(LOG_ERR) "Get_max_servers: getrlimit failed" );
584	}
585	n = pcount.rlim_cur;
586#ifdef RLIMIT_INFINITY
587	if( pcount.rlim_cur == RLIM_INFINITY ){
588		n = Max_servers_active_DYN;
589		DEBUG1("Get_max_servers: using %d", n );
590	}
591#endif
592
593	DEBUG1("Get_max_servers: getrlimit returns %d", n );
594#else
595# if defined(HAVE_SYSCONF) && defined(_SC_CHILD_MAX)
596	if( n == 0 && (n = sysconf(_SC_CHILD_MAX)) < 0 ){
597		FATAL(LOG_ERR) "Get_max_servers: sysconf failed" );
598	}
599	DEBUG1("Get_max_servers: sysconf returns %d", n );
600# else
601#  if defined(CHILD_MAX)
602		n = CHILD_MAX;
603		DEBUG1("Get_max_servers: CHILD_MAX %d", n );
604#  else
605		n = 0;
606		DEBUG1("Get_max_servers: default %d", n );
607#  endif
608# endif
609#endif
610	n = n/4;
611	if(( n > 0 && n > Max_servers_active_DYN)
612		|| (n <= 0 && Max_servers_active_DYN) ){
613		n = Max_servers_active_DYN;
614	}
615	if( n <= 0 ) n = 32;
616
617	DEBUG1("Get_max_servers: returning %d", n );
618	return( n );
619}
620
621
622/***************************************************************************
623 * int Get_max_fd()
624 *  get the maximum number of file descriptors allowed
625 ***************************************************************************/
626
627int Get_max_fd( void )
628#ifdef ORIGINAL_DEBUG//JY@1020
629{
630#else
631{}
632#endif
633#ifdef ORIGINAL_DEBUG//JY@1020
634	int n = 0;	/* We need some sort of limit here */
635
636#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
637	struct rlimit pcount;
638	if( getrlimit(RLIMIT_NOFILE, &pcount) == -1 ){
639		FATAL(LOG_ERR) "Get_max_fd: getrlimit failed" );
640	}
641	n = pcount.rlim_cur;
642	DEBUG4("Get_max_fd: getrlimit returns %d", n );
643#else
644# if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
645	if( n == 0 && (n = sysconf(_SC_OPEN_MAX)) < 0 ){
646		FATAL(LOG_ERR) "Get_max_servers: sysconf failed" );
647	}
648	DEBUG4("Get_max_fd: sysconf returns %d", n );
649# else
650	n = 20;
651	DEBUG4("Get_max_fd: using default %d", n );
652# endif
653#endif
654
655	if( n <= 0 || n > 10240 ){
656		/* we have some systems that will return a VERY
657		 * large or negative number for unlimited FD's.  Well, we
658		 * don't want to use a large number here.  So we
659		 * will make it a small number.  The actual number of
660		 * file descriptors open by processes is VERY conservative.
661		 */
662		n = 256;
663	}
664
665	DEBUG1("Get_max_fd: returning %d", n );
666	return( n );
667}
668#endif
669
670
671char *Brk_check_size( void )
672{
673	static char b[128];
674	static char* Top_of_mem;	/* top of allocated memory */
675	char *s = sbrk(0);
676	int   v = s - Top_of_mem;
677	if( Top_of_mem == 0 ){
678		SNPRINTF(b, sizeof(b)) "BRK: initial value 0x%lx", Cast_ptr_to_long(s) );
679	} else {
680		SNPRINTF(b, sizeof(b)) "BRK: new value 0x%lx, increment %d", Cast_ptr_to_long(s), v );
681	}
682	Top_of_mem = s;
683	return(b);
684}
685
686char *mystrncat( char *s1, const char *s2, int len )
687{
688	int size;
689	s1[len-1] = 0;
690	size = safestrlen( s1 );
691	if( s2 && len - size > 0  ){
692		strncpy( s1+size, s2, len - size );
693	}
694	return( s1 );
695}
696char *mystrncpy( char *s1, const char *s2, int len )
697{
698	s1[0] = 0;
699	if( s2 && len-1 > 0 ){
700		strncpy( s1, s2, len-1 );
701		s1[len-1] = 0;
702	}
703	return( s1 );
704}
705
706/*
707 * Set_non_block_io(fd)
708 * Set_block_io(fd)
709 *  Set blocking or non-blocking IO
710 *  Dies if unsuccessful
711 * Get_nonblock_io(fd)
712 *  Returns O_NONBLOCK flag value
713 */
714
715int Get_nonblock_io( int fd )
716{
717	int mask;
718	/* we set IO to non-blocking on fd */
719
720	if( (mask = fcntl( fd, F_GETFL, 0 ) ) == -1 ){
721		return(-1);
722	}
723	mask &= O_NONBLOCK;
724	return( mask );
725}
726
727int Set_nonblock_io( int fd )
728{
729	int mask;
730	/* we set IO to non-blocking on fd */
731
732	if( (mask = fcntl( fd, F_GETFL, 0 ) ) == -1 ){
733		return(-1);
734	}
735	mask |= O_NONBLOCK;
736	if( (mask = fcntl( fd, F_SETFL, mask ) ) == -1 ){
737		return(-1);
738	}
739	return(0);
740}
741
742int Set_block_io( int fd )
743{
744	int mask;
745	/* we set IO to blocking on fd */
746
747	if( (mask = fcntl( fd, F_GETFL, 0 ) ) == -1 ){
748		return(-1);
749	}
750	mask &= ~O_NONBLOCK;
751	if( (mask = fcntl( fd, F_SETFL, mask ) ) == -1 ){
752		return(-1);
753	}
754	return(0);
755}
756
757/*
758 * Read_write_timeout
759 *  int readfd, char *inbuffer, int maxinlen -
760 *    read data from this fd into this buffer before this timeout
761 *  int *readlen  - reports number of bytes read
762 *  int writefd, char **outbuffer, int *outlen -
763 *     **outbuffer and **outlen are updated after write
764 *     write data from to this fd from this buffer before this timeout
765 *  int timeout
766 *       > 0  - wait total of this long
767 *       0    - wait indefinitely
768 *      -1    - do not wait
769 *  Returns:
770 *   **outbuffer, *outlen updated
771 *    0    - success
772 *   JRDERR     - IO error on output
773 *   JTIMEOUT   - Timeout
774 *   JWRERR     - IO error on input
775 */
776
777int Read_write_timeout(
778	int readfd, char *inbuffer, int maxinlen, int *readlen,
779	int writefd, char **outbuffer, int *outlen, int timeout )
780#ifdef ORIGINAL_DEBUG//JY@1020
781{
782#else
783{}
784#endif
785#ifdef ORIGINAL_DEBUG//JY@1020
786	time_t start_t, current_t;
787	int elapsed, m, err, done, retval;
788	struct timeval timeval, *tp;
789    fd_set readfds, writefds; /* for select() */
790	struct stat statb;
791
792	DEBUG4( "Read_write_timeout: read(fd %d, buffer 0x%lx, maxinlen %d, readlen 0x%lx->%d",
793		readfd, Cast_ptr_to_long(inbuffer), maxinlen, Cast_ptr_to_long(readlen),
794		readlen?*readlen:0 );
795	DEBUG4( "Read_write_timeout: write(fd %d, buffer 0x%lx->0x%lx, len 0x%lx->%d, timeout %d)",
796		writefd, Cast_ptr_to_long(outbuffer), Cast_ptr_to_long(outbuffer?*outbuffer:0),
797		Cast_ptr_to_long(outlen), outlen?*outlen:0, timeout );
798
799	retval = done = 0;
800	time( &start_t );
801
802	if( *outlen == 0 ) return( retval );
803	if( readfd  > 0 ){
804		if( fstat( readfd, &statb ) ){
805			Errorcode = JABORT;
806			FATAL(LOG_ERR) "Read_write_timeout: readfd %d closed", readfd );
807		}
808		Set_nonblock_io( readfd );
809	} else {
810		Errorcode = JABORT;
811		FATAL(LOG_ERR) "Read_write_timeout: no readfd %d", readfd );
812	}
813	if( writefd  > 0 ){
814		if( fstat( writefd, &statb ) ){
815			Errorcode = JABORT;
816			FATAL(LOG_ERR) "Read_write_timeout: writefd %d closed",
817				writefd );
818		}
819		Set_nonblock_io( writefd );
820	} else {
821		Errorcode = JABORT;
822		FATAL(LOG_ERR) "Read_write_timeout: no write %d", writefd );
823	}
824
825	while(!done){
826		tp = 0;
827		memset( &timeval, 0, sizeof(timeval) );
828		m = 0;
829		if( timeout > 0 ){
830			time( &current_t );
831			elapsed = current_t - start_t;
832			if( timeout > 0 && elapsed >= timeout ){
833				break;
834			}
835			timeval.tv_sec = m = timeout - elapsed;
836			tp = &timeval;
837			DEBUG4("Read_write_timeout: timeout now %d", m );
838		} else if( timeout < 0 ){
839			/* we simply poll once */
840			tp = &timeval;
841		}
842		FD_ZERO( &writefds );
843		FD_ZERO( &readfds );
844		m = 0;
845		FD_SET( writefd, &writefds );
846		if( m <= writefd ) m = writefd+1;
847		FD_SET( readfd, &readfds );
848		if( m <= readfd ) m = readfd+1;
849		errno = 0;
850		DEBUG4("Read_write_timeout: starting select" );
851        m = select( m,
852            FD_SET_FIX((fd_set *))&readfds,
853            FD_SET_FIX((fd_set *))&writefds,
854            FD_SET_FIX((fd_set *))0, tp );
855		err = errno;
856#ifdef ORIGINAL_DEBUG//JY@1020
857		DEBUG4("Read_write_timeout: select returned %d, errno '%s'",
858			m, Errormsg(err) );
859#endif
860		if( m < 0 ){
861			if( err != EINTR ){
862#ifdef ORIGINAL_DEBUG//JY@1020
863				LOGERR(LOG_INFO)"Read_write_timeout: select returned %d, errno '%s'",
864				m, Errormsg(err) );
865#endif
866				retval = JTIMEOUT;
867				done = 1;
868			}
869		} else if( m == 0 ){
870			/* timeout */
871			retval = JTIMEOUT;
872			done = 1;
873		} else {
874			if( FD_ISSET( readfd, &readfds ) ){
875				DEBUG4("Read_write_timeout: read possible on fd %d", readfd );
876				m = read( readfd, inbuffer, maxinlen );
877				DEBUG4("Read_write_timeout: read() returned %d", m );
878				if( readlen ) *readlen = m;
879				/* caller leaves space for this */
880				if( m >= 0 ) inbuffer[m] = 0;
881				if( m < 0 ) retval = JRDERR;
882				done = 1;
883			}
884			if( FD_ISSET( writefd, &writefds ) ){
885				DEBUG4("Read_write_timeout: write possible on fd %d", writefd );
886				Set_nonblock_io( writefd );
887				m = write( writefd, *outbuffer, *outlen );
888				err = errno;
889				Set_block_io( writefd );
890				DEBUG4("Read_write_timeout: wrote %d", m );
891				if( m < 0 ){
892					/* we have EOF on the file descriptor */
893					retval = JWRERR;
894					done = 1;
895				} else {
896					*outlen -= m;
897					*outbuffer += m;
898					if( *outlen == 0 ){
899						done = 1;
900					}
901				}
902				errno = err;
903			}
904		}
905	}
906	err = errno;
907	errno = err;
908	return( retval );
909}
910#endif
911
912/***************************************************************************
913 * Set up alarms so LPRng doesn't hang forever during transfers.
914 ***************************************************************************/
915
916/*
917 * timeout_alarm
918 *  When we get the alarm,  we close the file descriptor (if any)
919 *  we are working with.  When we next do an option, it will fail
920 *  Note that this will cause any ongoing read/write operation to fail
921 * We then to a longjmp to the routine, returning a non-zero value
922 * We set an alarm using:
923 *
924 * if( (setjmp(Timeout_env)==0 && Set_timeout_alarm(t,s)) ){
925 *   timeout dependent stuff
926 * }
927 * Clear_alarm
928 * We define the Set_timeout macro as:
929 *  #define Set_timeout(t,s) (setjmp(Timeout_env)==0 && Set_timeout_alarm(t,s))
930 */
931
932 static plp_signal_t timeout_alarm (int sig)
933{
934	Alarm_timed_out = 1;
935	signal( SIGALRM, SIG_IGN );
936	errno = EINTR;
937#if 1//JY1110: timeout while writing
938/*JY1111*/
939	check_prn_status("BUSY or ERROR", clientaddr);
940	send_ack_packet(currten_sock, ACK_FAIL);//JY1120
941/**/
942exit(0);
943#endif
944#if defined(HAVE_SIGLONGJMP)
945	siglongjmp(Timeout_env,1);
946#else
947	longjmp(Timeout_env,1);
948#endif
949}
950
951
952 static plp_signal_t timeout_break (int sig)
953{
954	Alarm_timed_out = 1;
955	signal( SIGALRM, SIG_IGN );
956}
957
958
959/***************************************************************************
960 * Set_timeout( int timeout, int *socket )
961 *  Set up a timeout to occur; note that you can call this
962 *   routine several times without problems,  but you must call the
963 *   Clear_timeout routine sooner or later to reset the timeout function.
964 *  A timeout value of 0 never times out
965 * Clear_alarm()
966 *  Turns off the timeout alarm
967 ***************************************************************************/
968void Set_timeout_signal_handler( int timeout, plp_sigfunc_t handler )
969{
970	int err = errno;
971	sigset_t oblock;
972
973	alarm(0);
974	signal(SIGALRM, SIG_IGN);
975	plp_unblock_one_signal( SIGALRM, &oblock );
976	Alarm_timed_out = 0;
977	Timeout_pending = 0;
978
979	if( timeout > 0 ){
980		Timeout_pending = timeout;
981		plp_signal_break(SIGALRM, handler);
982		alarm (timeout);
983	}
984	errno = err;
985}
986
987
988void Set_timeout_alarm( int timeout )
989{
990	Set_timeout_signal_handler( timeout, timeout_alarm );
991}
992
993void Set_timeout_break( int timeout )
994{
995	Set_timeout_signal_handler( timeout, timeout_break );
996}
997
998void Clear_timeout( void )
999{
1000	int err = errno;
1001
1002	signal( SIGALRM, SIG_IGN );
1003	alarm(0);
1004	Timeout_pending = 0;
1005	errno = err;
1006}
1007
1008/*
1009 * setuid.c:
1010 * routines to manipulate user-ids securely (and hopefully, portably).
1011 * The * internals of this are very hairy, because
1012 * (a) there's lots of sanity checking
1013 * (b) there's at least three different setuid-swapping
1014 * semantics to support :(
1015 *
1016 *
1017 * Note that the various functions saves errno then restores it afterwards;
1018 * this means it's safe to do "root_to_user();some_syscall();user_to_root();"
1019 * and errno will be from the system call.
1020 *
1021 * "root" is the user who owns the setuid executable (privileged).
1022 * "user" is the user who runs it.
1023 * "daemon" owns data files used by the LPRng utilities (spool directories, etc).
1024 *   and is set by the 'user' entry in the configuration file.
1025 *
1026 * To_ruid( user );	-- set ruid to user, euid to root
1027 * To_euid( user );	-- set euid to user, ruid to root
1028 * To_euid_root();	-- set euid to root, ruid to root
1029 * To_daemon();	-- set euid to daemon, ruid to root
1030 * To_user();	-- set euid to user, ruid to root
1031 * Full_daemon_perms() -- set both UID and EUID, one way, no return
1032 *
1033 */
1034
1035/***************************************************************************
1036 * Commentary:
1037 * Patrick Powell Sat Apr 15 07:56:30 PDT 1995
1038 *
1039 * This has to be one of the ugliest parts of any portability suite.
1040 * The following models are available:
1041 * 1. process has <uid, euid>  (old SYSV, BSD)
1042 * 2. process has <uid, euid, saved uid, saved euid> (new SYSV, BSD)
1043 *
1044 * There are several possibilites:
1045 * 1. need euid root   to do some operations
1046 * 2. need euid user   to do some operations
1047 * 3. need euid daemon to do some operations
1048 *
1049 * Group permissions are almost useless for a server;
1050 * usually you are running as a specified group ID and do not
1051 * need to change.  Client programs are slightly different.
1052 * You need to worry about permissions when creating a file;
1053 * for this reason most client programs do a u mask(0277) before any
1054 * file creation to ensure that nobody can read the file, and create
1055 * it with only user access permissions.
1056 *
1057 * > int setuid(uid) uid_t uid;
1058 * > int seteuid(euid) uid_t euid;
1059 * > int setruid(ruid) uid_t ruid;
1060 * >
1061 * > DESCRIPTION
1062 * >      setuid() (setgid()) sets both the real and effective user ID
1063 * >      (group  ID) of the current process as specified by uid (gid)
1064 * >      (see NOTES).
1065 * >
1066 * >      seteuid() (setegid()) sets the effective user ID (group  ID)
1067 * >      of the current process.
1068 * >
1069 * >      setruid() (setrgid()) sets the real user ID  (group  ID)  of
1070 * >      the current process.
1071 * >
1072 * >      These calls are only permitted to the super-user or  if  the
1073 * >      argument  is  the  real  or effective user (group) ID of the
1074 * >      calling process.
1075 * >
1076 * > SYSTEM V DESCRIPTION
1077 * >      If the effective user ID  of  the  calling  process  is  not
1078 * >      super-user,  but if its real user (group) ID is equal to uid
1079 * >      (gid), or if the saved set-user (group) ID  from  execve(2V)
1080 * >      is equal to uid (gid), then the effective user (group) ID is
1081 * >      set to uid (gid).
1082 * >      .......  etc etc
1083 *
1084 * Conclusions:
1085 * 1. if EUID == ROOT or RUID == ROOT then you can set EUID, UID to anything
1086 * 3. if EUID is root, you can set EUID
1087 *
1088 * General technique:
1089 * Initialization
1090 *   - use setuid() system call to force EUID/RUID = ROOT
1091 *
1092 * Change
1093 *   - assumes that initialization has been carried out and
1094 * 	EUID == ROOT or RUID = ROOT
1095 *   - Use the seteuid() system call to set EUID
1096 *
1097 ***************************************************************************/
1098
1099#if !defined(HAVE_SETREUID) && !defined(HAVE_SETEUID) && !defined(HAVE_SETRESUID)
1100#error You need one of setreuid(), seteuid(), setresuid()
1101#endif
1102
1103/***************************************************************************
1104 * Commentary
1105 * setuid(), setreuid(), and now setresuid()
1106 *  This is probably the easiest road.
1107 *  Note: we will use the most feature ridden one first, as it probably
1108 *  is necessary on some wierd system.
1109 *   Patrick Powell Fri Aug 11 22:46:39 PDT 1995
1110 ***************************************************************************/
1111#if !defined(HAVE_SETEUID) && !defined(HAVE_SETREUID) && defined(HAVE_SETRESUID)
1112# define setreuid(x,y) (setresuid( (x), (y), -1))
1113# define HAVE_SETREUID
1114#endif
1115
1116/***************************************************************************
1117 * Setup_uid()
1118 * 1. gets the original EUID, RUID, EGID, RGID
1119 * 2. if UID 0 or EUID 0 forces both UID and EUID to 0 (test)
1120 * 3. Sets the EUID to the original RUID
1121 *    This leaves the UID (EUID)
1122 ***************************************************************************/
1123
1124void Setup_uid(void)
1125{
1126	int err = errno;
1127	static int SetRootUID;	/* did we set UID to root yet? */
1128
1129	if( SetRootUID == 0 ){
1130		OriginalEUID = geteuid();
1131		OriginalRUID = getuid();
1132		OriginalEGID = getegid();
1133		OriginalRGID = getgid();
1134		DEBUG1("Setup_uid: OriginalEUID %d, OriginalRUID %d",
1135			OriginalEUID, OriginalRUID );
1136		DEBUG1("Setup_uid: OriginalEGID %d, OriginalRGID %d",
1137			OriginalEGID, OriginalRGID );
1138		/* we now make sure that we are able to use setuid() */
1139		/* notice that setuid() will work if EUID or RUID is 0 */
1140		if( OriginalEUID == ROOTUID || OriginalRUID == ROOTUID ){
1141			/* set RUID/EUID to ROOT - possible if EUID or UID is 0 */
1142			if(
1143#				ifdef HAVE_SETEUID
1144					setuid( (uid_t)ROOTUID ) || seteuid( OriginalRUID )
1145#				else
1146					setuid( (uid_t)ROOTUID ) || setreuid( ROOTUID, OriginalRUID )
1147#				endif
1148				){
1149				FATAL(LOG_ERR)
1150					"Setup_uid: RUID/EUID Start %d/%d seteuid failed",
1151					OriginalRUID, OriginalEUID);
1152			}
1153			if( getuid() != ROOTUID ){
1154				FATAL(LOG_ERR)
1155				"Setup_uid: IMPOSSIBLE! RUID/EUID Start %d/%d, now %d/%d",
1156					OriginalRUID, OriginalEUID,
1157					getuid(), geteuid() );
1158			}
1159			UID_root = 1;
1160		}
1161		DEBUG1( "Setup_uid: Original RUID/EUID %d/%d, RUID/EUID %d/%d",
1162					OriginalRUID, OriginalEUID,
1163					getuid(), geteuid() );
1164		SetRootUID = 1;
1165	}
1166	errno = err;
1167}
1168
1169/***************************************************************************
1170 * seteuid_wrapper()
1171 * 1. you must have done the initialization
1172 * 2. check to see if you need to do anything
1173 * 3. check to make sure you can
1174 ***************************************************************************/
1175 static int seteuid_wrapper( uid_t to )
1176{
1177	int err = errno;
1178	uid_t euid;
1179
1180
1181	DEBUG4(
1182		"seteuid_wrapper: Before RUID/EUID %d/%d, DaemonUID %d, UID_root %d",
1183		OriginalRUID, OriginalEUID, DaemonUID, UID_root );
1184	if( UID_root ){
1185		/* be brutal: set both to root */
1186		if( setuid( ROOTUID ) ){
1187			LOGERR_DIE(LOG_ERR)
1188			"seteuid_wrapper: setuid() failed!!");
1189		}
1190#if defined(HAVE_SETEUID)
1191		if( seteuid( to ) ){
1192			LOGERR_DIE(LOG_ERR)
1193			"seteuid_wrapper: seteuid() failed!!");
1194		}
1195#else
1196		if( setreuid( ROOTUID, to) ){
1197			LOGERR_DIE(LOG_ERR)
1198			"seteuid_wrapper: setreuid() failed!!");
1199		}
1200#endif
1201	}
1202	euid = geteuid();
1203	DEBUG4( "seteuid_wrapper: After uid/euid %d/%d", getuid(), euid );
1204	errno = err;
1205	return( to != euid );
1206}
1207
1208
1209/***************************************************************************
1210 * setruid_wrapper()
1211 * 1. you must have done the initialization
1212 * 2. check to see if you need to do anything
1213 * 3. check to make sure you can
1214 ***************************************************************************/
1215 static int setruid_wrapper( uid_t to )
1216{
1217	int err = errno;
1218	uid_t ruid;
1219
1220
1221	DEBUG4(
1222		"setruid_wrapper: Before RUID/EUID %d/%d, DaemonUID %d, UID_root %d",
1223		OriginalRUID, OriginalEUID, DaemonUID, UID_root );
1224	if( UID_root ){
1225		/* be brutal: set both to root */
1226		if( setuid( ROOTUID ) ){
1227			LOGERR_DIE(LOG_ERR)
1228			"setruid_wrapper: setuid() failed!!");
1229		}
1230#if defined(HAVE_SETRUID)
1231		if( setruid( to ) ){
1232			LOGERR_DIE(LOG_ERR)
1233			"setruid_wrapper: setruid() failed!!");
1234		}
1235#elif defined(HAVE_SETREUID)
1236		if( setreuid( to, ROOTUID) ){
1237			LOGERR_DIE(LOG_ERR)
1238			"setruid_wrapper: setreuid() failed!!");
1239		}
1240#elif defined(__CYGWIN__)
1241		if( seteuid( to ) ){
1242			LOGERR_DIE(LOG_ERR)
1243			"setruid_wrapper: seteuid() failed!!");
1244		}
1245#else
1246# error - you do not have a way to set ruid
1247#endif
1248	}
1249	ruid = getuid();
1250	DEBUG4( "setruid_wrapper: After uid/euid %d/%d", getuid(), geteuid() );
1251	errno = err;
1252	return( to != ruid );
1253}
1254
1255
1256/*
1257 * Superhero functions - change the EUID to the requested one
1258 *  - these are really idiot level,  as all of the tough work is done
1259 * in Setup_uid() and seteuid_wrapper()
1260 *  We also change the groups, just to be nasty as well, except for
1261 *  To_ruid and To_uid,  which only does the RUID and EUID
1262 *    Sigh...  To every rule there is an exception.
1263 */
1264int To_euid_root(void)
1265{
1266	return( seteuid_wrapper( ROOTUID )	);
1267}
1268
1269 static int To_daemon_called;
1270
1271int To_daemon(void)
1272{
1273	Set_full_group( DaemonUID, DaemonGID );
1274	To_daemon_called = 1;
1275	return( seteuid_wrapper( DaemonUID )	);
1276}
1277
1278int To_user(void)
1279{
1280	if( To_daemon_called ){
1281		Errorcode = JABORT;
1282		LOGMSG(LOG_ERR) "To_user: LOGIC ERROR! To_daemon has been called");
1283		abort();
1284	}
1285	/* Set_full_group( OriginalRUID, OriginalRGID ); */
1286	return( seteuid_wrapper( OriginalRUID )	);
1287}
1288int To_ruid(int ruid)
1289{
1290	return( setruid_wrapper( ruid )	);
1291}
1292int To_euid( int euid )
1293{
1294	return( seteuid_wrapper( euid ) );
1295}
1296
1297/*
1298 * set both uid and euid to the same value, using setuid().
1299 * This is unrecoverable!
1300 */
1301
1302int setuid_wrapper(uid_t to)
1303{
1304	int err = errno;
1305	if( UID_root ){
1306		/* Note: you MUST use setuid() to force saved_setuid correctly */
1307		if( setuid( (uid_t)ROOTUID ) ){
1308			LOGERR_DIE(LOG_ERR) "setuid_wrapper: setuid(ROOTUID) failed!!");
1309		}
1310		if( setuid( (uid_t)to ) ){
1311			LOGERR_DIE(LOG_ERR) "setuid_wrapper: setuid(%d) failed!!", to);
1312		}
1313		if( to ) UID_root = 0;
1314	}
1315    DEBUG4("after setuid: (%d, %d)", getuid(),geteuid());
1316	errno = err;
1317	return( to != getuid() || to != geteuid() );
1318}
1319
1320int Full_daemon_perms(void)
1321{
1322	Setup_uid();
1323	Set_full_group( DaemonUID, DaemonGID );
1324	return(setuid_wrapper(DaemonUID));
1325}
1326
1327int Full_root_perms(void)
1328{
1329	Setup_uid();
1330	Set_full_group( ROOTUID, ROOTUID );
1331	return(setuid_wrapper( ROOTUID ));
1332}
1333
1334int Full_user_perms(void)
1335{
1336	Setup_uid();
1337	Set_full_group( OriginalRUID, OriginalRGID );
1338	return(setuid_wrapper(OriginalRUID));
1339}
1340
1341
1342/***************************************************************************
1343 * Getdaemon()
1344 *  get daemon uid
1345 *
1346 ***************************************************************************/
1347
1348int Getdaemon(void)
1349{
1350	char *str = 0;
1351	char *t;
1352	struct passwd *pw;
1353	int uid;
1354
1355	str = Daemon_user_DYN;
1356	DEBUG4( "Getdaemon: using '%s'", str );
1357	if(!str) str = "daemon";
1358	t = str;
1359	uid = strtol( str, &t, 10 );
1360	if( str == t || *t ){
1361		/* try getpasswd */
1362		pw = getpwnam( str );
1363		if( pw ){
1364			uid = pw->pw_uid;
1365		}
1366	}
1367	DEBUG4( "Getdaemon: uid '%d'", uid );
1368	if( uid == ROOTUID ) uid = getuid();
1369	DEBUG4( "Getdaemon: final uid '%d'", uid );
1370	return( uid );
1371}
1372
1373/***************************************************************************
1374 * Getdaemon_group()
1375 *  get daemon gid
1376 *
1377 ***************************************************************************/
1378
1379int Getdaemon_group(void)
1380{
1381	char *str = 0;
1382	char *t;
1383	struct group *gr;
1384	gid_t gid;
1385
1386	str = Daemon_group_DYN;
1387	DEBUG4( "Getdaemon_group: Daemon_group_DYN '%s'", str );
1388	if( !str ) str = "daemon";
1389	DEBUG4( "Getdaemon_group: name '%s'", str );
1390	t = str;
1391	gid = strtol( str, &t, 10 );
1392	if( str == t ){
1393		/* try getpasswd */
1394		gr = getgrnam( str );
1395		if( gr ){
1396			gid = gr->gr_gid;
1397		}
1398	}
1399	DEBUG4( "Getdaemon_group: gid '%d'", gid );
1400	if( gid == 0 ) gid = getgid();
1401	DEBUG4( "Getdaemon_group: final gid '%d'", gid );
1402	return( gid );
1403}
1404
1405/***************************************************************************
1406 * set daemon uid and group
1407 * 1. get the current EUID
1408 * 2. set up the permissions changing
1409 * 3. set the RGID/EGID
1410 ***************************************************************************/
1411
1412int Set_full_group( int euid, int gid )
1413{
1414	int status=0;
1415	int err;
1416	struct passwd *pw = 0;
1417
1418	DEBUG4( "Set_full_group: euid '%d'", euid );
1419
1420	/* get the user we want to set the groups for */
1421	pw = getpwuid(euid);
1422	if( UID_root ){
1423		setuid(ROOTUID);	/* set RUID/EUID to root */
1424#if defined(HAVE_INITGROUPS)
1425		if( pw ){
1426			/* froth froth... initgroups() uses the same buffer as
1427			 * getpwuid... SHRIEK  so we need to copy the user name
1428			 */
1429			char user[256];
1430			safestrncpy(user,pw->pw_name);
1431			if( safestrlen(user) != safestrlen(pw->pw_name) ){
1432				FATAL(LOG_ERR) "Set_full_group: CONFIGURATION BOTCH! safestrlen of user name '%s' = %d larger than buffer size %d",
1433					pw->pw_name, safestrlen(pw->pw_name), sizeof(user) );
1434			}
1435			if( initgroups(user, pw->pw_gid ) == -1 ){
1436				err = errno;
1437#ifdef ORIGINAL_DEBUG//JY@1020
1438				LOGERR_DIE(LOG_ERR) "Set_full_group: initgroups failed '%s'",
1439					Errormsg( err ) );
1440#endif
1441			}
1442		} else
1443#endif
1444#if defined(HAVE_SETGROUPS)
1445			if( setgroups(0,0) == -1 ){
1446				err = errno;
1447#ifdef ORIGINAL_DEBUG//JY@1020
1448				LOGERR_DIE(LOG_ERR) "Set_full_group: setgroups failed '%s'",
1449					Errormsg( err ) );
1450#endif
1451			}
1452#endif
1453		status = setgid( gid );
1454		if( status < 0 ){
1455			err = errno;
1456#ifdef ORIGINAL_DEBUG//JY@1020
1457			LOGERR_DIE(LOG_ERR) "Set_full_group: setgid '%d' failed '%s'",
1458				gid, Errormsg( err ) );
1459#endif
1460		}
1461	}
1462	return( 0 );
1463}
1464
1465int Setdaemon_group(void)
1466{
1467	Set_full_group( DaemonUID, DaemonGID );
1468	return( 0 );
1469}
1470
1471
1472/*
1473 * Testing magic:
1474 * if we are running SUID
1475 *   We have set our RUID to root and EUID daemon
1476 * However,  we may want to run as another UID for testing.
1477 * The config file allows us to do this, but we set the SUID values
1478 * from the hardwired defaults before we read the configuration file.
1479 * After reading the configuration file,  we check the current
1480 * DaemonUID and the requested Daemon UID.  If the requested
1481 * Daemon UID == 0, then we run as the user which started LPD.
1482 */
1483
1484void Reset_daemonuid(void)
1485{
1486	uid_t uid;
1487    uid = Getdaemon();  /* get the config file daemon id */
1488    DaemonGID = Getdaemon_group();  /* get the config file daemon id */
1489    if( uid != DaemonUID ){
1490        if( uid == ROOTUID ){
1491            DaemonUID = OriginalRUID;   /* special case for testing */
1492        } else {
1493            DaemonUID = uid;
1494        }
1495    }
1496    DEBUG4( "DaemonUID %d", DaemonUID );
1497}
1498
1499
1500#ifdef HAVE_SYS_MOUNT_H
1501# include <sys/mount.h>
1502#endif
1503#ifdef HAVE_SYS_STATVFS_H
1504# include <sys/statvfs.h>
1505#endif
1506#ifdef HAVE_SYS_STATFS_H
1507# include <sys/statfs.h>
1508#endif
1509#if defined(HAVE_SYS_VFS_H) && !defined(SOLARIS)
1510# include <sys/vfs.h>
1511#endif
1512
1513#ifdef SUNOS
1514 extern int statfs(const char *, struct statfs *);
1515#endif
1516
1517# if USE_STATFS_TYPE == STATVFS
1518#  define plp_statfs(path,buf) statvfs(path,buf)
1519#  define plp_struct_statfs struct statvfs
1520#  define statfs(path, buf) statvfs(path, buf)
1521#  define USING "STATVFS"
1522#  define BLOCKSIZE(f) (double)(f.f_frsize?f.f_frsize:f.f_bsize)
1523#  define BLOCKS(f)    (double)f.f_bavail
1524# endif
1525
1526# if USE_STATFS_TYPE == ULTRIX_STATFS
1527#  define plp_statfs(path,buf) statfs(path,buf)
1528#  define plp_struct_statfs struct fs_data
1529#  define USING "ULTRIX_STATFS"
1530#  define BLOCKSIZE(f) (double)f.fd_bsize
1531#  define BLOCKS(f)    (double)f.fd_bfree
1532# endif
1533
1534# if USE_STATFS_TYPE ==  SVR3_STATFS
1535#  define plp_struct_statfs struct statfs
1536#  define plp_statfs(path,buf) statfs(path,buf,sizeof(struct statfs),0)
1537#  define USING "SV3_STATFS"
1538#  define BLOCKSIZE(f) (double)f.f_bsize
1539#  define BLOCKS(f)    (double)f.f_bfree
1540# endif
1541
1542# if USE_STATFS_TYPE == STATFS
1543#  define plp_struct_statfs struct statfs
1544#  define plp_statfs(path,buf) statfs(path,buf)
1545#  define USING "STATFS"
1546#  define BLOCKSIZE(f) (double)f.f_bsize
1547#  define BLOCKS(f)    (double)f.f_bavail
1548# endif
1549
1550#ifdef JYDEBUG1//JYWeng
1551FILE *aaaaaa;
1552#endif
1553
1554/***************************************************************************
1555 * Check_space() - check to see if there is enough space
1556 ***************************************************************************/
1557
1558double Space_avail( char *pathname )
1559{
1560	double space = 0;
1561	plp_struct_statfs fsb;
1562
1563	if( plp_statfs( pathname, &fsb ) == -1 ){
1564		DEBUG2( "Check_space: cannot stat '%s'", pathname );
1565	} else {
1566		space = BLOCKS(fsb) * (BLOCKSIZE(fsb)/1024.0);
1567	}
1568#ifdef JYDEBUG//JYWeng
1569aaaaaa=fopen("/tmp/qqqqq", "a");
1570fprintf(aaaaaa, "TYPE=%d\n", USE_STATFS_TYPE);
1571fprintf(aaaaaa, "Space_avail: fsb_bsize=%d\n", fsb.f_bsize);
1572fprintf(aaaaaa, "Space_avail: fsb_frsize=%d\n", fsb.f_frsize);
1573fprintf(aaaaaa, "Space_avail: fsb_block=%d\n", fsb.f_blocks);
1574fprintf(aaaaaa, "Space_avail: fsb_bfree=%d\n", fsb.f_bfree);
1575fprintf(aaaaaa, "Space_avail: fsb_bavail=%d\n", fsb.f_bavail);
1576fprintf(aaaaaa, "Space_avail: fsb_files=%d\n", fsb.f_files);
1577fprintf(aaaaaa, "Space_avail: fsb_ffree=%d\n", fsb.f_ffree);
1578fprintf(aaaaaa, "Space_avail: fsb_favail=%d\n", fsb.f_favail);
1579fprintf(aaaaaa, "Space_avail: fsb_f_flag=%d\n", fsb.f_flag);
1580fprintf(aaaaaa, "BLOCKS(fsb)=%f\n", BLOCKS(fsb));
1581fprintf(aaaaaa, "BLOCKSIZE(fsb)=%f\n", BLOCKSIZE(fsb));
1582fprintf(aaaaaa, "space=%f\n", space);
1583fclose(aaaaaa);
1584#endif
1585#ifdef JYDEBUG//JYWeng
1586space=3000.0;
1587#endif
1588	return(space);
1589}
1590
1591/* VARARGS2 */
1592#ifdef HAVE_STDARGS
1593 void safefprintf (int fd, char *format,...)
1594#else
1595 void safefprintf (va_alist) va_dcl
1596#endif
1597{
1598#ifndef HAVE_STDARGS
1599	int fd;
1600    char *format;
1601#endif
1602	char buf[1024];
1603    VA_LOCAL_DECL
1604
1605    VA_START (format);
1606    VA_SHIFT (fd, int);
1607    VA_SHIFT (format, char *);
1608
1609	(void) VSNPRINTF (buf, sizeof(buf)) format, ap);
1610	Write_fd_str( fd, buf );
1611}
1612