1/*
2 * Copyright (c) 1999-2002, 2004, 2006 Proofpoint, Inc. and its suppliers.
3 *	All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 *
9 * Contributed by Exactis.com, Inc.
10 *
11 */
12
13/*
14**  This is in transition. Changed from the original bf_torek.c code
15**  to use sm_io function calls directly rather than through stdio
16**  translation layer. Will be made a built-in file type of libsm
17**  next (once safeopen() linkable from libsm).
18*/
19
20#include <sm/gen.h>
21SM_RCSID("@(#)$Id: bf.c,v 8.63 2013-11-22 20:51:55 ca Exp $")
22
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <sys/uio.h>
26#include <fcntl.h>
27#include <unistd.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
31#include "sendmail.h"
32#include "bf.h"
33
34#include <syslog.h>
35
36/* bf io functions */
37static ssize_t	sm_bfread __P((SM_FILE_T *, char *, size_t));
38static ssize_t	sm_bfwrite __P((SM_FILE_T *, const char *, size_t));
39static off_t	sm_bfseek __P((SM_FILE_T *, off_t, int));
40static int	sm_bfclose __P((SM_FILE_T *));
41static int	sm_bfcommit __P((SM_FILE_T *));
42static int	sm_bftruncate __P((SM_FILE_T *));
43
44static int	sm_bfopen __P((SM_FILE_T *, const void *, int, const void *));
45static int	sm_bfsetinfo __P((SM_FILE_T *, int , void *));
46static int	sm_bfgetinfo __P((SM_FILE_T *, int , void *));
47
48/*
49**  Data structure for storing information about each buffered file
50**  (Originally in sendmail/bf_torek.h for the curious.)
51*/
52
53struct bf
54{
55	bool	bf_committed;	/* Has this buffered file been committed? */
56	bool	bf_ondisk;	/* On disk: committed or buffer overflow */
57	long	bf_flags;
58	int	bf_disk_fd;	/* If on disk, associated file descriptor */
59	char	*bf_buf;	/* Memory buffer */
60	int	bf_bufsize;	/* Length of above buffer */
61	int	bf_buffilled;	/* Bytes of buffer actually filled */
62	char	*bf_filename;	/* Name of buffered file, if ever committed */
63	MODE_T	bf_filemode;	/* Mode of buffered file, if ever committed */
64	off_t	bf_offset;	/* Currect file offset */
65	int	bf_size;	/* Total current size of file */
66};
67
68#ifdef BF_STANDALONE
69# define OPEN(fn, omode, cmode, sff) open(fn, omode, cmode)
70#else
71# define OPEN(fn, omode, cmode, sff) safeopen(fn, omode, cmode, sff)
72#endif
73
74struct bf_info
75{
76	char	*bi_filename;
77	MODE_T	bi_fmode;
78	size_t	bi_bsize;
79	long	bi_flags;
80};
81
82/*
83**  SM_BFOPEN -- the "base" open function called by sm_io_open() for the
84**		internal, file-type-specific info setup.
85**
86**	Parameters:
87**		fp -- file pointer being filled-in for file being open'd
88**		info -- information about file being opened
89**		flags -- ignored
90**		rpool -- ignored (currently)
91**
92**	Returns:
93**		Failure: -1 and sets errno
94**		Success: 0 (zero)
95*/
96
97static int
98sm_bfopen(fp, info, flags, rpool)
99	SM_FILE_T *fp;
100	const void *info;
101	int flags;
102	const void *rpool;
103{
104	char *filename;
105	MODE_T fmode;
106	size_t bsize;
107	long sflags;
108	struct bf *bfp;
109	int l;
110	struct stat st;
111
112	filename = ((struct bf_info *) info)->bi_filename;
113	fmode = ((struct bf_info *) info)->bi_fmode;
114	bsize = ((struct bf_info *) info)->bi_bsize;
115	sflags = ((struct bf_info *) info)->bi_flags;
116
117	/* Sanity checks */
118	if (*filename == '\0')
119	{
120		/* Empty filename string */
121		errno = ENOENT;
122		return -1;
123	}
124	if (stat(filename, &st) == 0)
125	{
126		/* File already exists on disk */
127		errno = EEXIST;
128		return -1;
129	}
130
131	/* Allocate memory */
132	bfp = (struct bf *) sm_malloc(sizeof(struct bf));
133	if (bfp == NULL)
134	{
135		errno = ENOMEM;
136		return -1;
137	}
138
139	/* Assign data buffer */
140	/* A zero bsize is valid, just don't allocate memory */
141	if (bsize > 0)
142	{
143		bfp->bf_buf = (char *) sm_malloc(bsize);
144		if (bfp->bf_buf == NULL)
145		{
146			bfp->bf_bufsize = 0;
147			sm_free(bfp);
148			errno = ENOMEM;
149			return -1;
150		}
151	}
152	else
153		bfp->bf_buf = NULL;
154
155	/* Nearly home free, just set all the parameters now */
156	bfp->bf_committed = false;
157	bfp->bf_ondisk = false;
158	bfp->bf_flags = sflags;
159	bfp->bf_bufsize = bsize;
160	bfp->bf_buffilled = 0;
161	l = strlen(filename) + 1;
162	bfp->bf_filename = (char *) sm_malloc(l);
163	if (bfp->bf_filename == NULL)
164	{
165		if (bfp->bf_buf != NULL)
166			sm_free(bfp->bf_buf);
167		sm_free(bfp);
168		errno = ENOMEM;
169		return -1;
170	}
171	(void) sm_strlcpy(bfp->bf_filename, filename, l);
172	bfp->bf_filemode = fmode;
173	bfp->bf_offset = 0;
174	bfp->bf_size = 0;
175	bfp->bf_disk_fd = -1;
176	fp->f_cookie = bfp;
177
178	if (tTd(58, 8))
179		sm_dprintf("sm_bfopen(%s)\n", filename);
180
181	return 0;
182}
183
184/*
185**  BFOPEN -- create a new buffered file
186**
187**	Parameters:
188**		filename -- the file's name
189**		fmode -- what mode the file should be created as
190**		bsize -- amount of buffer space to allocate (may be 0)
191**		flags -- if running under sendmail, passed directly to safeopen
192**
193**	Returns:
194**		a SM_FILE_T * which may then be used with stdio functions,
195**		or NULL	on failure. SM_FILE_T * is opened for writing
196**		"SM_IO_WHAT_VECTORS").
197**
198**	Side Effects:
199**		none.
200**
201**	Sets errno:
202**		any value of errno specified by sm_io_setinfo_type()
203**		any value of errno specified by sm_io_open()
204**		any value of errno specified by sm_io_setinfo()
205*/
206
207#ifdef __STDC__
208/*
209**  XXX This is a temporary hack since MODE_T on HP-UX 10.x is short.
210**	If we use K&R here, the compiler will complain about
211**	Inconsistent parameter list declaration
212**	due to the change from short to int.
213*/
214
215SM_FILE_T *
216bfopen(char *filename, MODE_T fmode, size_t bsize, long flags)
217#else /* __STDC__ */
218SM_FILE_T *
219bfopen(filename, fmode, bsize, flags)
220	char *filename;
221	MODE_T fmode;
222	size_t bsize;
223	long flags;
224#endif /* __STDC__ */
225{
226	MODE_T omask;
227	SM_FILE_T SM_IO_SET_TYPE(vector, BF_FILE_TYPE, sm_bfopen, sm_bfclose,
228		sm_bfread, sm_bfwrite, sm_bfseek, sm_bfgetinfo, sm_bfsetinfo,
229		SM_TIME_FOREVER);
230	struct bf_info info;
231
232	/*
233	**  Apply current umask to fmode as it may change by the time
234	**  the file is actually created.  fmode becomes the true
235	**  permissions of the file, which OPEN() must obey.
236	*/
237
238	omask = umask(0);
239	fmode &= ~omask;
240	(void) umask(omask);
241
242	SM_IO_INIT_TYPE(vector, BF_FILE_TYPE, sm_bfopen, sm_bfclose,
243		sm_bfread, sm_bfwrite, sm_bfseek, sm_bfgetinfo, sm_bfsetinfo,
244		SM_TIME_FOREVER);
245	info.bi_filename = filename;
246	info.bi_fmode = fmode;
247	info.bi_bsize = bsize;
248	info.bi_flags = flags;
249
250	return sm_io_open(&vector, SM_TIME_DEFAULT, &info, SM_IO_RDWR, NULL);
251}
252
253/*
254**  SM_BFGETINFO -- returns info about an open file pointer
255**
256**	Parameters:
257**		fp -- file pointer to get info about
258**		what -- type of info to obtain
259**		valp -- thing to return the info in
260*/
261
262static int
263sm_bfgetinfo(fp, what, valp)
264	SM_FILE_T *fp;
265	int what;
266	void *valp;
267{
268	struct bf *bfp;
269
270	bfp = (struct bf *) fp->f_cookie;
271	switch (what)
272	{
273	  case SM_IO_WHAT_FD:
274		return bfp->bf_disk_fd;
275	  case SM_IO_WHAT_SIZE:
276		return bfp->bf_size;
277	  default:
278		return -1;
279	}
280}
281
282/*
283**  SM_BFCLOSE -- close a buffered file
284**
285**	Parameters:
286**		fp -- cookie of file to close
287**
288**	Returns:
289**		0 to indicate success
290**
291**	Side Effects:
292**		deletes backing file, sm_frees memory.
293**
294**	Sets errno:
295**		never.
296*/
297
298static int
299sm_bfclose(fp)
300	SM_FILE_T *fp;
301{
302	struct bf *bfp;
303
304	/* Cast cookie back to correct type */
305	bfp = (struct bf *) fp->f_cookie;
306
307	/* Need to clean up the file */
308	if (bfp->bf_ondisk && !bfp->bf_committed)
309		unlink(bfp->bf_filename);
310	sm_free(bfp->bf_filename);
311
312	if (bfp->bf_disk_fd != -1)
313		close(bfp->bf_disk_fd);
314
315	/* Need to sm_free the buffer */
316	if (bfp->bf_bufsize > 0)
317		sm_free(bfp->bf_buf);
318
319	/* Finally, sm_free the structure */
320	sm_free(bfp);
321	return 0;
322}
323
324/*
325**  SM_BFREAD -- read a buffered file
326**
327**	Parameters:
328**		cookie -- cookie of file to read
329**		buf -- buffer to fill
330**		nbytes -- how many bytes to read
331**
332**	Returns:
333**		number of bytes read or -1 indicate failure
334**
335**	Side Effects:
336**		none.
337**
338*/
339
340static ssize_t
341sm_bfread(fp, buf, nbytes)
342	SM_FILE_T *fp;
343	char *buf;
344	size_t nbytes;
345{
346	struct bf *bfp;
347	ssize_t count = 0;	/* Number of bytes put in buf so far */
348	int retval;
349
350	/* Cast cookie back to correct type */
351	bfp = (struct bf *) fp->f_cookie;
352
353	if (bfp->bf_offset < bfp->bf_buffilled)
354	{
355		/* Need to grab some from buffer */
356		count = nbytes;
357		if ((bfp->bf_offset + count) > bfp->bf_buffilled)
358			count = bfp->bf_buffilled - bfp->bf_offset;
359
360		memcpy(buf, bfp->bf_buf + bfp->bf_offset, count);
361	}
362
363	if ((bfp->bf_offset + nbytes) > bfp->bf_buffilled)
364	{
365		/* Need to grab some from file */
366		if (!bfp->bf_ondisk)
367		{
368			/* Oops, the file doesn't exist. EOF. */
369			if (tTd(58, 8))
370				sm_dprintf("sm_bfread(%s): to disk\n",
371					   bfp->bf_filename);
372			goto finished;
373		}
374
375		/* Catch a read() on an earlier failed write to disk */
376		if (bfp->bf_disk_fd < 0)
377		{
378			errno = EIO;
379			return -1;
380		}
381
382		if (lseek(bfp->bf_disk_fd,
383			  bfp->bf_offset + count, SEEK_SET) < 0)
384		{
385			if ((errno == EINVAL) || (errno == ESPIPE))
386			{
387				/*
388				**  stdio won't be expecting these
389				**  errnos from read()! Change them
390				**  into something it can understand.
391				*/
392
393				errno = EIO;
394			}
395			return -1;
396		}
397
398		while (count < nbytes)
399		{
400			retval = read(bfp->bf_disk_fd,
401				      buf + count,
402				      nbytes - count);
403			if (retval < 0)
404			{
405				/* errno is set implicitly by read() */
406				return -1;
407			}
408			else if (retval == 0)
409				goto finished;
410			else
411				count += retval;
412		}
413	}
414
415finished:
416	bfp->bf_offset += count;
417	return count;
418}
419
420/*
421**  SM_BFSEEK -- seek to a position in a buffered file
422**
423**	Parameters:
424**		fp     -- fp of file to seek
425**		offset -- position to seek to
426**		whence -- how to seek
427**
428**	Returns:
429**		new file offset or -1 indicate failure
430**
431**	Side Effects:
432**		none.
433**
434*/
435
436static off_t
437sm_bfseek(fp, offset, whence)
438	SM_FILE_T *fp;
439	off_t offset;
440	int whence;
441
442{
443	struct bf *bfp;
444
445	/* Cast cookie back to correct type */
446	bfp = (struct bf *) fp->f_cookie;
447
448	switch (whence)
449	{
450	  case SEEK_SET:
451		bfp->bf_offset = offset;
452		break;
453
454	  case SEEK_CUR:
455		bfp->bf_offset += offset;
456		break;
457
458	  case SEEK_END:
459		bfp->bf_offset = bfp->bf_size + offset;
460		break;
461
462	  default:
463		errno = EINVAL;
464		return -1;
465	}
466	return bfp->bf_offset;
467}
468
469/*
470**  SM_BFWRITE -- write to a buffered file
471**
472**	Parameters:
473**		fp -- fp of file to write
474**		buf -- data buffer
475**		nbytes -- how many bytes to write
476**
477**	Returns:
478**		number of bytes written or -1 indicate failure
479**
480**	Side Effects:
481**		may create backing file if over memory limit for file.
482**
483*/
484
485static ssize_t
486sm_bfwrite(fp, buf, nbytes)
487	SM_FILE_T *fp;
488	const char *buf;
489	size_t nbytes;
490{
491	struct bf *bfp;
492	ssize_t count = 0;	/* Number of bytes written so far */
493	int retval;
494
495	/* Cast cookie back to correct type */
496	bfp = (struct bf *) fp->f_cookie;
497
498	/* If committed, go straight to disk */
499	if (bfp->bf_committed)
500	{
501		if (lseek(bfp->bf_disk_fd, bfp->bf_offset, SEEK_SET) < 0)
502		{
503			if ((errno == EINVAL) || (errno == ESPIPE))
504			{
505				/*
506				**  stdio won't be expecting these
507				**  errnos from write()! Change them
508				**  into something it can understand.
509				*/
510
511				errno = EIO;
512			}
513			return -1;
514		}
515
516		count = write(bfp->bf_disk_fd, buf, nbytes);
517		if (count < 0)
518		{
519			/* errno is set implicitly by write() */
520			return -1;
521		}
522		goto finished;
523	}
524
525	if (bfp->bf_offset < bfp->bf_bufsize)
526	{
527		/* Need to put some in buffer */
528		count = nbytes;
529		if ((bfp->bf_offset + count) > bfp->bf_bufsize)
530			count = bfp->bf_bufsize - bfp->bf_offset;
531
532		memcpy(bfp->bf_buf + bfp->bf_offset, buf, count);
533		if ((bfp->bf_offset + count) > bfp->bf_buffilled)
534			bfp->bf_buffilled = bfp->bf_offset + count;
535	}
536
537	if ((bfp->bf_offset + nbytes) > bfp->bf_bufsize)
538	{
539		/* Need to put some in file */
540		if (!bfp->bf_ondisk)
541		{
542			MODE_T omask;
543			int save_errno;
544
545			/* Clear umask as bf_filemode are the true perms */
546			omask = umask(0);
547			retval = OPEN(bfp->bf_filename,
548				      O_RDWR | O_CREAT | O_TRUNC | QF_O_EXTRA,
549				      bfp->bf_filemode, bfp->bf_flags);
550			save_errno = errno;
551			(void) umask(omask);
552			errno = save_errno;
553
554			/* Couldn't create file: failure */
555			if (retval < 0)
556			{
557				/*
558				**  stdio may not be expecting these
559				**  errnos from write()! Change to
560				**  something which it can understand.
561				**  Note that ENOSPC and EDQUOT are saved
562				**  because they are actually valid for
563				**  write().
564				*/
565
566				if (!(errno == ENOSPC
567#ifdef EDQUOT
568				      || errno == EDQUOT
569#endif
570				     ))
571					errno = EIO;
572
573				return -1;
574			}
575			bfp->bf_disk_fd = retval;
576			bfp->bf_ondisk = true;
577		}
578
579		/* Catch a write() on an earlier failed write to disk */
580		if (bfp->bf_ondisk && bfp->bf_disk_fd < 0)
581		{
582			errno = EIO;
583			return -1;
584		}
585
586		if (lseek(bfp->bf_disk_fd,
587			  bfp->bf_offset + count, SEEK_SET) < 0)
588		{
589			if ((errno == EINVAL) || (errno == ESPIPE))
590			{
591				/*
592				**  stdio won't be expecting these
593				**  errnos from write()! Change them into
594				**  something which it can understand.
595				*/
596
597				errno = EIO;
598			}
599			return -1;
600		}
601
602		while (count < nbytes)
603		{
604			retval = write(bfp->bf_disk_fd, buf + count,
605				       nbytes - count);
606			if (retval < 0)
607			{
608				/* errno is set implicitly by write() */
609				return -1;
610			}
611			else
612				count += retval;
613		}
614	}
615
616finished:
617	bfp->bf_offset += count;
618	if (bfp->bf_offset > bfp->bf_size)
619		bfp->bf_size = bfp->bf_offset;
620	return count;
621}
622
623/*
624**  BFREWIND -- rewinds the SM_FILE_T *
625**
626**	Parameters:
627**		fp -- SM_FILE_T * to rewind
628**
629**	Returns:
630**		0 on success, -1 on error
631**
632**	Side Effects:
633**		rewinds the SM_FILE_T * and puts it into read mode. Normally
634**		one would bfopen() a file, write to it, then bfrewind() and
635**		fread(). If fp is not a buffered file, this is equivalent to
636**		rewind().
637**
638**	Sets errno:
639**		any value of errno specified by sm_io_rewind()
640*/
641
642int
643bfrewind(fp)
644	SM_FILE_T *fp;
645{
646	(void) sm_io_flush(fp, SM_TIME_DEFAULT);
647	sm_io_clearerr(fp); /* quicker just to do it */
648	return sm_io_seek(fp, SM_TIME_DEFAULT, 0, SM_IO_SEEK_SET);
649}
650
651/*
652**  SM_BFCOMMIT -- "commits" the buffered file
653**
654**	Parameters:
655**		fp -- SM_FILE_T * to commit to disk
656**
657**	Returns:
658**		0 on success, -1 on error
659**
660**	Side Effects:
661**		Forces the given SM_FILE_T * to be written to disk if it is not
662**		already, and ensures that it will be kept after closing. If
663**		fp is not a buffered file, this is a no-op.
664**
665**	Sets errno:
666**		any value of errno specified by open()
667**		any value of errno specified by write()
668**		any value of errno specified by lseek()
669*/
670
671static int
672sm_bfcommit(fp)
673	SM_FILE_T *fp;
674{
675	struct bf *bfp;
676	int retval;
677	int byteswritten;
678
679	/* Get associated bf structure */
680	bfp = (struct bf *) fp->f_cookie;
681
682	/* If already committed, noop */
683	if (bfp->bf_committed)
684		return 0;
685
686	/* Do we need to open a file? */
687	if (!bfp->bf_ondisk)
688	{
689		int save_errno;
690		MODE_T omask;
691		struct stat st;
692
693		if (tTd(58, 8))
694		{
695			sm_dprintf("bfcommit(%s): to disk\n", bfp->bf_filename);
696			if (tTd(58, 32))
697				sm_dprintf("bfcommit(): filemode %o flags %ld\n",
698					   (unsigned int) bfp->bf_filemode,
699					   bfp->bf_flags);
700		}
701
702		if (stat(bfp->bf_filename, &st) == 0)
703		{
704			errno = EEXIST;
705			return -1;
706		}
707
708		/* Clear umask as bf_filemode are the true perms */
709		omask = umask(0);
710		retval = OPEN(bfp->bf_filename,
711			      O_RDWR | O_CREAT | O_EXCL | QF_O_EXTRA,
712			      bfp->bf_filemode, bfp->bf_flags);
713		save_errno = errno;
714		(void) umask(omask);
715
716		/* Couldn't create file: failure */
717		if (retval < 0)
718		{
719			/* errno is set implicitly by open() */
720			errno = save_errno;
721			return -1;
722		}
723
724		bfp->bf_disk_fd = retval;
725		bfp->bf_ondisk = true;
726	}
727
728	/* Write out the contents of our buffer, if we have any */
729	if (bfp->bf_buffilled > 0)
730	{
731		byteswritten = 0;
732
733		if (lseek(bfp->bf_disk_fd, 0, SEEK_SET) < 0)
734		{
735			/* errno is set implicitly by lseek() */
736			return -1;
737		}
738
739		while (byteswritten < bfp->bf_buffilled)
740		{
741			retval = write(bfp->bf_disk_fd,
742				       bfp->bf_buf + byteswritten,
743				       bfp->bf_buffilled - byteswritten);
744			if (retval < 0)
745			{
746				/* errno is set implicitly by write() */
747				return -1;
748			}
749			else
750				byteswritten += retval;
751		}
752	}
753	bfp->bf_committed = true;
754
755	/* Invalidate buf; all goes to file now */
756	bfp->bf_buffilled = 0;
757	if (bfp->bf_bufsize > 0)
758	{
759		/* Don't need buffer anymore; free it */
760		bfp->bf_bufsize = 0;
761		sm_free(bfp->bf_buf);
762	}
763	return 0;
764}
765
766/*
767**  SM_BFTRUNCATE -- rewinds and truncates the SM_FILE_T *
768**
769**	Parameters:
770**		fp -- SM_FILE_T * to truncate
771**
772**	Returns:
773**		0 on success, -1 on error
774**
775**	Side Effects:
776**		rewinds the SM_FILE_T *, truncates it to zero length, and puts
777**		it into write mode.
778**
779**	Sets errno:
780**		any value of errno specified by fseek()
781**		any value of errno specified by ftruncate()
782*/
783
784static int
785sm_bftruncate(fp)
786	SM_FILE_T *fp;
787{
788	struct bf *bfp;
789
790	if (bfrewind(fp) < 0)
791		return -1;
792
793	/* Get bf structure */
794	bfp = (struct bf *) fp->f_cookie;
795	bfp->bf_buffilled = 0;
796	bfp->bf_size = 0;
797
798	/* Need to zero the buffer */
799	if (bfp->bf_bufsize > 0)
800		memset(bfp->bf_buf, '\0', bfp->bf_bufsize);
801	if (bfp->bf_ondisk)
802	{
803#if NOFTRUNCATE
804		/* XXX: Not much we can do except rewind it */
805		errno = EINVAL;
806		return -1;
807#else
808		return ftruncate(bfp->bf_disk_fd, 0);
809#endif
810	}
811	return 0;
812}
813
814/*
815**  SM_BFSETINFO -- set/change info for an open file pointer
816**
817**	Parameters:
818**		fp -- file pointer to get info about
819**		what -- type of info to set/change
820**		valp -- thing to set/change the info to
821**
822*/
823
824static int
825sm_bfsetinfo(fp, what, valp)
826	SM_FILE_T *fp;
827	int what;
828	void *valp;
829{
830	struct bf *bfp;
831	int bsize;
832
833	/* Get bf structure */
834	bfp = (struct bf *) fp->f_cookie;
835	switch (what)
836	{
837	  case SM_BF_SETBUFSIZE:
838		bsize = *((int *) valp);
839		bfp->bf_bufsize = bsize;
840
841		/* A zero bsize is valid, just don't allocate memory */
842		if (bsize > 0)
843		{
844			bfp->bf_buf = (char *) sm_malloc(bsize);
845			if (bfp->bf_buf == NULL)
846			{
847				bfp->bf_bufsize = 0;
848				errno = ENOMEM;
849				return -1;
850			}
851		}
852		else
853			bfp->bf_buf = NULL;
854		return 0;
855	  case SM_BF_COMMIT:
856		return sm_bfcommit(fp);
857	  case SM_BF_TRUNCATE:
858		return sm_bftruncate(fp);
859	  case SM_BF_TEST:
860		return 1; /* always */
861	  default:
862		errno = EINVAL;
863		return -1;
864	}
865}
866