1 /*
2  * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Chris Torek.
9  *
10  * By using this file, you agree to the terms and conditions set
11  * forth in the LICENSE file which can be found at the top level of
12  * the sendmail distribution.
13  */
14 
15 #pragma ident	"%Z%%M%	%I%	%E% SMI"
16 
17 #include <sm/gen.h>
18 SM_RCSID("@(#)$Id: makebuf.c,v 1.26 2001/10/31 16:04:08 ca Exp $")
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sm/io.h>
24 #include <sm/heap.h>
25 #include <sm/conf.h>
26 #include "local.h"
27 
28 /*
29 **  SM_MAKEBUF -- make a buffer for the file
30 **
31 **	Parameters:
32 **		fp -- the file to be buffered
33 **
34 **	Returns:
35 **		nothing
36 **
37 **	Allocate a file buffer, or switch to unbuffered I/O.
38 **	By default tty devices default to line buffered.
39 */
40 
41 void
42 sm_makebuf(fp)
43 	register SM_FILE_T *fp;
44 {
45 	register void *p;
46 	register int flags;
47 	size_t size;
48 	int couldbetty;
49 
50 	if (fp->f_flags & SMNBF)
51 	{
52 		fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
53 		fp->f_bf.smb_size = 1;
54 		return;
55 	}
56 	flags = sm_whatbuf(fp, &size, &couldbetty);
57 	if ((p = sm_malloc(size)) == NULL)
58 	{
59 		fp->f_flags |= SMNBF;
60 		fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
61 		fp->f_bf.smb_size = 1;
62 		return;
63 	}
64 	if (!Sm_IO_DidInit)
65 		sm_init();
66 	flags |= SMMBF;
67 	fp->f_bf.smb_base = fp->f_p = p;
68 	fp->f_bf.smb_size = size;
69 	if (couldbetty && isatty(fp->f_file))
70 		flags |= SMLBF;
71 	fp->f_flags |= flags;
72 }
73 
74 /*
75 **  SM_WHATBUF -- determine proper buffer for a file (internal)
76 **
77 **  Plus it fills in 'bufsize' for recommended buffer size and
78 **  fills in flag to indicate if 'fp' could be a tty (nothing
79 **  to do with "betty" :-) ).
80 **
81 **	Parameters:
82 **		fp -- file pointer to be buffered
83 **		bufsize -- new buffer size (a return)
84 **		couldbetty -- could be a tty (returns)
85 **
86 **	Returns:
87 **		Success:
88 **		on error:
89 **			SMNPT -- not seek opimized
90 **			SMOPT -- seek opimized
91 */
92 
93 int
94 sm_whatbuf(fp, bufsize, couldbetty)
95 	register SM_FILE_T *fp;
96 	size_t *bufsize;
97 	int *couldbetty;
98 {
99 	struct stat st;
100 
101 	if (fp->f_file < 0 || fstat(fp->f_file, &st) < 0)
102 	{
103 		*couldbetty = 0;
104 		*bufsize = SM_IO_BUFSIZ;
105 		return SMNPT;
106 	}
107 
108 	/* could be a tty iff it is a character device */
109 	*couldbetty = S_ISCHR(st.st_mode);
110 	if (st.st_blksize == 0)
111 	{
112 		*bufsize = SM_IO_BUFSIZ;
113 		return SMNPT;
114 	}
115 
116 #if SM_IO_MAX_BUF_FILE > 0
117 	if (S_ISREG(st.st_mode) && st.st_blksize > SM_IO_MAX_BUF_FILE)
118 		st.st_blksize = SM_IO_MAX_BUF_FILE;
119 #endif /* SM_IO_MAX_BUF_FILE > 0 */
120 
121 #if SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0
122 	if (!S_ISREG(st.st_mode))
123 	{
124 # if SM_IO_MAX_BUF > 0
125 		if (st.st_blksize > SM_IO_MAX_BUF)
126 			st.st_blksize = SM_IO_MAX_BUF;
127 #  if SM_IO_MIN_BUF > 0
128 		else
129 #  endif /* SM_IO_MIN_BUF > 0 */
130 # endif /* SM_IO_MAX_BUF > 0 */
131 # if SM_IO_MIN_BUF > 0
132 		if (st.st_blksize < SM_IO_MIN_BUF)
133 			st.st_blksize = SM_IO_MIN_BUF;
134 # endif /* SM_IO_MIN_BUF > 0 */
135 	}
136 #endif /* SM_IO_MAX_BUF > 0 || SM_IO_MIN_BUF > 0 */
137 
138 	/*
139 	**  Optimise fseek() only if it is a regular file.  (The test for
140 	**  sm_std_seek is mainly paranoia.)  It is safe to set _blksize
141 	**  unconditionally; it will only be used if SMOPT is also set.
142 	*/
143 
144 	if ((fp->f_flags & SMSTR) == 0)
145 	{
146 		*bufsize = st.st_blksize;
147 		fp->f_blksize = st.st_blksize;
148 	}
149 	else
150 		*bufsize = SM_IO_BUFSIZ;
151 	if ((st.st_mode & S_IFMT) == S_IFREG &&
152 	    fp->f_seek == sm_stdseek)
153 		return SMOPT;
154 	else
155 		return SMNPT;
156 }
157