This commit was manufactured by cvs2svn to create branch 'RELENG_6'.
This commit is contained in:
parent
00cf7c7fec
commit
e417d4dff3
22
contrib/sendmail/cf/feature/badmx.m4
Normal file
22
contrib/sendmail/cf/feature/badmx.m4
Normal file
@ -0,0 +1,22 @@
|
||||
divert(-1)
|
||||
#
|
||||
# Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
# All rights reserved.
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set
|
||||
# forth in the LICENSE file which can be found at the top level of
|
||||
# the sendmail distribution.
|
||||
#
|
||||
#
|
||||
|
||||
divert(0)
|
||||
VERSIONID(`$Id: badmx.m4,v 1.1 2006/12/16 00:56:32 ca Exp $')
|
||||
divert(-1)
|
||||
|
||||
define(`_BADMX_CHK_', 1)
|
||||
|
||||
LOCAL_CONFIG
|
||||
Kmxlist bestmx -z: -T<TEMP>
|
||||
Kbadmx regex -a<BADMX> ^(([0-9]{1,3}\.){3}[0-9]){0,1}\.$
|
||||
KdnsA dns -R A -a. -T<TEMP>
|
||||
KBadMXIP regex -a<BADMXIP> ifelse(defn(`_ARG_'), `', `^(127\.|10\.|0\.0\.0\.0)', `_ARG_')
|
18
contrib/sendmail/cf/feature/block_bad_helo.m4
Normal file
18
contrib/sendmail/cf/feature/block_bad_helo.m4
Normal file
@ -0,0 +1,18 @@
|
||||
divert(-1)
|
||||
#
|
||||
# Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
# All rights reserved.
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set
|
||||
# forth in the LICENSE file which can be found at the top level of
|
||||
# the sendmail distribution.
|
||||
#
|
||||
#
|
||||
|
||||
divert(0)dnl
|
||||
VERSIONID(`$Id: block_bad_helo.m4,v 1.1 2006/06/15 22:49:30 ca Exp $')
|
||||
divert(-1)
|
||||
|
||||
define(`_BLOCK_BAD_HELO_', `')dnl
|
||||
RELAY_DOMAIN(`127.0.0.1')dnl
|
||||
LOCAL_DOMAIN(`[127.0.0.1]')dnl
|
16
contrib/sendmail/cf/feature/require_rdns.m4
Normal file
16
contrib/sendmail/cf/feature/require_rdns.m4
Normal file
@ -0,0 +1,16 @@
|
||||
divert(-1)
|
||||
#
|
||||
# Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
# All rights reserved.
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set
|
||||
# forth in the LICENSE file which can be found at the top level of
|
||||
# the sendmail distribution.
|
||||
#
|
||||
#
|
||||
|
||||
divert(0)dnl
|
||||
VERSIONID(`$Id: require_rdns.m4,v 1.1 2006/06/15 22:49:30 ca Exp $')
|
||||
divert(-1)
|
||||
|
||||
define(`_REQUIRE_RDNS_', `')
|
19
contrib/sendmail/include/sm/misc.h
Normal file
19
contrib/sendmail/include/sm/misc.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*
|
||||
* $Id: misc.h,v 1.1 2006/06/28 23:57:59 ca Exp $
|
||||
*/
|
||||
|
||||
#ifndef SM_MISC_H
|
||||
# define SM_MISC_H 1
|
||||
|
||||
int sm_memstat_open __P((void));
|
||||
int sm_memstat_close __P((void));
|
||||
int sm_memstat_get __P((char *, long *));
|
||||
|
||||
#endif /* ! SM_MISC_H */
|
20
contrib/sendmail/include/sm/os/sm_os_qnx.h
Normal file
20
contrib/sendmail/include/sm/os/sm_os_qnx.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*
|
||||
* $Id: sm_os_qnx.h,v 1.1 2007/03/21 23:56:20 ca Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
** sm_os_qnx.h -- platform definitions for QNX
|
||||
*/
|
||||
|
||||
#define SM_CONF_SYS_CDEFS_H 1
|
||||
|
||||
#ifndef SM_CONF_SETITIMER
|
||||
# define SM_CONF_SETITIMER 0
|
||||
#endif /* SM_CONF_SETITIMER */
|
24
contrib/sendmail/include/sm/sendmail.h
Normal file
24
contrib/sendmail/include/sm/sendmail.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
** SENDMAIL.H -- MTA-specific definitions for sendmail.
|
||||
*/
|
||||
|
||||
#ifndef _SM_SENDMAIL_H
|
||||
# define _SM_SENDMAIL_H 1
|
||||
|
||||
/* "out of band" indicator */
|
||||
#define METAQUOTE ((unsigned char)0377) /* quotes the next octet */
|
||||
|
||||
extern int dequote_internal_chars __P((char *, char *, int));
|
||||
extern char *quote_internal_chars __P((char *, char *, int *));
|
||||
extern char *str2prt __P((char *));
|
||||
|
||||
#endif /* ! _SM_SENDMAIL_H */
|
153
contrib/sendmail/include/sm/tailq.h
Normal file
153
contrib/sendmail/include/sm/tailq.h
Normal file
@ -0,0 +1,153 @@
|
||||
/* $OpenBSD: queue.h,v 1.30 2005/10/25 06:37:47 otto Exp $ */
|
||||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef SM_TAILQ_H_
|
||||
#define SM_TAILQ_H_
|
||||
|
||||
/*
|
||||
* This file is a modified copy of queue.h from a BSD system:
|
||||
* we only need tail queues here.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define SM_TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define SM_TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define SM_TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* tail queue access methods
|
||||
*/
|
||||
#define SM_TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define SM_TAILQ_END(head) NULL
|
||||
#define SM_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
#define SM_TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
/* XXX */
|
||||
#define SM_TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
#define SM_TAILQ_EMPTY(head) \
|
||||
(SM_TAILQ_FIRST(head) == SM_TAILQ_END(head))
|
||||
|
||||
#define SM_TAILQ_FOREACH(var, head, field) \
|
||||
for((var) = SM_TAILQ_FIRST(head); \
|
||||
(var) != SM_TAILQ_END(head); \
|
||||
(var) = SM_TAILQ_NEXT(var, field))
|
||||
|
||||
#define SM_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for((var) = SM_TAILQ_LAST(head, headname); \
|
||||
(var) != SM_TAILQ_END(head); \
|
||||
(var) = SM_TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define SM_TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define SM_TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define SM_TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SM_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SM_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SM_TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SM_TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm2)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
*(elm2)->field.tqe_prev = (elm2); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !SM_TAILQ_H_ */
|
88
contrib/sendmail/libmilter/docs/smfi_addrcpt_par.html
Normal file
88
contrib/sendmail/libmilter/docs/smfi_addrcpt_par.html
Normal file
@ -0,0 +1,88 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>smfi_addrcpt_par</TITLE></HEAD>
|
||||
<BODY>
|
||||
<!--
|
||||
$Id: smfi_addrcpt_par.html,v 1.4 2007/03/19 16:38:02 ca Exp $
|
||||
-->
|
||||
<H1>smfi_addrcpt_par</H1>
|
||||
|
||||
<TABLE border="0" cellspacing=4 cellpadding=4>
|
||||
<!---------- Synopsis ----------->
|
||||
<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD>
|
||||
<PRE>
|
||||
#include <libmilter/mfapi.h>
|
||||
int smfi_addrcpt_par(
|
||||
SMFICTX *ctx,
|
||||
char *rcpt,
|
||||
char *args
|
||||
);
|
||||
</PRE>
|
||||
Add a recipient for the current message including ESMTP arguments.
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Description ---------->
|
||||
<TR><TH valign="top" align=left>DESCRIPTION</TH><TD>
|
||||
<TABLE border="1" cellspacing=1 cellpadding=4>
|
||||
<TR align="left" valign=top>
|
||||
<TH width="80">Called When</TH>
|
||||
<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD>
|
||||
</TR>
|
||||
<TR align="left" valign=top>
|
||||
<TH width="80">Effects</TH>
|
||||
<TD>Add a recipient to the message envelope.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<!----------- Arguments ---------->
|
||||
<TR><TH valign="top" align=left>ARGUMENTS</TH><TD>
|
||||
<TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR>
|
||||
<TR valign="top"><TD>ctx</TD>
|
||||
<TD>Opaque context structure.
|
||||
</TD></TR>
|
||||
<TR valign="top"><TD>rcpt</TD>
|
||||
<TD>The new recipient's address.
|
||||
</TD></TR>
|
||||
<TR valign="top"><TD>args</TD>
|
||||
<TD>The new recipient's ESMTP parameters.
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Return values ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>RETURN VALUES</TH>
|
||||
|
||||
<TD>smfi_addrcpt will fail and return MI_FAILURE if:
|
||||
<UL><LI>rcpt is NULL.
|
||||
<LI>Adding recipients in the current connection state is invalid.
|
||||
<LI>A network error occurs.
|
||||
<LI>SMFIF_ADDRCPT_PAR was not set when
|
||||
<A href="smfi_register.html">smfi_register</A> was called.
|
||||
</UL>
|
||||
Otherwise, it will return MI_SUCCESS.
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<!----------- Notes ---------->
|
||||
<TR align="left" valign=top>
|
||||
<TH>NOTES</TH>
|
||||
<TD>
|
||||
A filter which calls smfi_addrcpt must have set the SMFIF_ADDRCPT_PAR flag
|
||||
in the smfiDesc_str passed to
|
||||
<A href="smfi_register.html">smfi_register</A>.
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
</TABLE>
|
||||
|
||||
<HR size="1">
|
||||
<FONT size="-1">
|
||||
Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
All rights reserved.
|
||||
<BR>
|
||||
By using this file, you agree to the terms and conditions set
|
||||
forth in the LICENSE.
|
||||
</FONT>
|
||||
</BODY>
|
||||
</HTML>
|
94
contrib/sendmail/libmilter/docs/smfi_chgfrom.html
Normal file
94
contrib/sendmail/libmilter/docs/smfi_chgfrom.html
Normal file
@ -0,0 +1,94 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>smfi_chgfrom</TITLE></HEAD>
|
||||
<BODY>
|
||||
<!--
|
||||
$Id: smfi_chgfrom.html,v 1.3 2006/12/21 18:30:35 ca Exp $
|
||||
-->
|
||||
<H1>smfi_chgfrom</H1>
|
||||
|
||||
<TABLE border="0" cellspacing=4 cellpadding=4>
|
||||
<!---------- Synopsis ----------->
|
||||
<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD>
|
||||
<PRE>
|
||||
#include <libmilter/mfapi.h>
|
||||
int smfi_chgfrom(
|
||||
SMFICTX *ctx,
|
||||
const char *mail,
|
||||
char *args
|
||||
);
|
||||
</PRE>
|
||||
Change the envelope sender (MAIL From) of the current message.
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Description ---------->
|
||||
<TR><TH valign="top" align=left>DESCRIPTION</TH><TD>
|
||||
<TABLE border="1" cellspacing=1 cellpadding=4>
|
||||
<TR align="left" valign=top>
|
||||
<TH width="80">Called When</TH>
|
||||
<TD>Called only from <A href="xxfi_eom.html">xxfi_eom</A>.</TD>
|
||||
</TR>
|
||||
<TR align="left" valign=top>
|
||||
<TH width="80">Effects</TH>
|
||||
<TD>Change the envelope sender (MAIL From) of the current message.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<!----------- Arguments ---------->
|
||||
<TR><TH valign="top" align=left>ARGUMENTS</TH><TD>
|
||||
<TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR>
|
||||
<TR valign="top"><TD>ctx</TD>
|
||||
<TD>Opaque context structure.
|
||||
</TD></TR>
|
||||
<TR valign="top"><TD>mail</TD>
|
||||
<TD>The new sender address.
|
||||
</TD></TR>
|
||||
<TR valign="top"><TD>args</TD>
|
||||
<TD>ESMTP arguments.
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Return values ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>RETURN VALUES</TH>
|
||||
|
||||
<TD>smfi_chgfrom will fail and return MI_FAILURE if:
|
||||
<UL><LI>mail is NULL.
|
||||
<LI>Changing the sender in the current connection state is invalid.
|
||||
<LI>A network error occurs.
|
||||
<LI>SMFIF_CHGFROM was not set when <A href="smfi_register.html">smfi_register</A> was called.
|
||||
</UL>
|
||||
Otherwise, it will return MI_SUCCESS.
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<!----------- Notes ---------->
|
||||
<TR align="left" valign=top>
|
||||
<TH>NOTES</TH>
|
||||
<TD>
|
||||
A filter which calls smfi_chgfrom must have set the SMFIF_CHGFROM flag
|
||||
in the smfiDesc_str passed to
|
||||
<A href="smfi_register.html">smfi_register</A>.
|
||||
<BR>
|
||||
Even though all ESMTP arguments could be set via this call,
|
||||
it does not make sense to do so for many of them,
|
||||
e.g., SIZE and BODY.
|
||||
Setting those may cause problems, proper care must be taken.
|
||||
Moreover, there is no feedback from the MTA to the milter
|
||||
whether the call was successful.
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
</TABLE>
|
||||
|
||||
<HR size="1">
|
||||
<FONT size="-1">
|
||||
Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
All rights reserved.
|
||||
<BR>
|
||||
By using this file, you agree to the terms and conditions set
|
||||
forth in the LICENSE.
|
||||
</FONT>
|
||||
</BODY>
|
||||
</HTML>
|
107
contrib/sendmail/libmilter/docs/smfi_setsymlist.html
Normal file
107
contrib/sendmail/libmilter/docs/smfi_setsymlist.html
Normal file
@ -0,0 +1,107 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>smfi_setsymlist</TITLE></HEAD>
|
||||
<BODY>
|
||||
<!--
|
||||
$Id: smfi_setsymlist.html,v 1.5 2006/12/21 18:30:35 ca Exp $
|
||||
-->
|
||||
<H1>smfi_setsymlist</H1>
|
||||
|
||||
<TABLE border="0" cellspacing=4 cellpadding=4>
|
||||
<!---------- Synopsis ----------->
|
||||
<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD>
|
||||
<PRE>
|
||||
#include <libmilter/mfapi.h>
|
||||
int smfi_setsymlist(
|
||||
SMFICTX *ctx,
|
||||
int stage,
|
||||
char *macros
|
||||
);
|
||||
</PRE>
|
||||
Set the list of macros that the milter wants to receive from the MTA
|
||||
for a protocol stage.
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Description ---------->
|
||||
<TR><TH valign="top" align=left>DESCRIPTION</TH><TD>
|
||||
<TABLE border="1" cellspacing=1 cellpadding=4>
|
||||
<TR align="left" valign=top>
|
||||
<TH width="80">Called When</TH>
|
||||
<TD>This function must only be called during
|
||||
<A HREF="xxfi_negotiate.html">xxfi_negotiate()</A>.
|
||||
</TD>
|
||||
</TR>
|
||||
<TR align="left" valign=top>
|
||||
<TH width="80">Effects</TH>
|
||||
<TD>This function can be used to override the list of macros that the
|
||||
milter wants to receive from the MTA.
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<!----------- Arguments ---------->
|
||||
<TR><TH valign="top" align=left>ARGUMENTS</TH><TD>
|
||||
<TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR>
|
||||
|
||||
<TR><TD>ctx</TD>
|
||||
<TD>the opaque context structure.
|
||||
</TD></TR>
|
||||
|
||||
<TR><TD>stage</TD>
|
||||
<TD>the protocol stage during which the macro list should be used.
|
||||
See the file
|
||||
<CODE>include/libmilter/mfapi.h</CODE> for legal values,
|
||||
look for the C macros with the prefix
|
||||
<CODE>SMFIM_</CODE>.
|
||||
Available protocol stages are at least
|
||||
the initial connection, HELO/EHLO, MAIL, RCPT, DATA,
|
||||
end of header, and
|
||||
the end of a message.
|
||||
</TD></TR>
|
||||
|
||||
<TR><TD>macros</TD>
|
||||
<TD>list of macros (separated by space).
|
||||
Example: "{rcpt_mailer} {rcpt_host}"
|
||||
</TD></TR>
|
||||
|
||||
</TABLE>
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Return values ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>RETURN VALUES</TH>
|
||||
|
||||
<TD>MI_FAILURE is returned if
|
||||
<UL>
|
||||
<LI>there is not enough free memory to make a copy of the macro list,
|
||||
<LI><CODE>macros</CODE> is <CODE>NULL</CODE> or empty,
|
||||
<LI><CODE>stage</CODE> is not a valid protocol stage,
|
||||
<LI>the macro list for
|
||||
<CODE>stage</CODE> has been set before.
|
||||
</UL>
|
||||
Otherwise MI_SUCCESS is returned.
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<!----------- Notes ---------->
|
||||
<TR align="left" valign=top>
|
||||
<TH>NOTES</TH>
|
||||
<TD>There is an internal limit on the number of macros that can be
|
||||
set (currently 5),
|
||||
however, this limit is not enforced by libmilter, only by the MTA,
|
||||
but a possible violation of this restriction is not communicated back to
|
||||
the milter.</TD>
|
||||
</TR>
|
||||
|
||||
</TABLE>
|
||||
|
||||
<HR size="1">
|
||||
<FONT size="-1">
|
||||
Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
All rights reserved.
|
||||
<BR>
|
||||
By using this file, you agree to the terms and conditions set
|
||||
forth in the LICENSE.
|
||||
</FONT>
|
||||
</BODY>
|
||||
</HTML>
|
86
contrib/sendmail/libmilter/docs/smfi_version.html
Normal file
86
contrib/sendmail/libmilter/docs/smfi_version.html
Normal file
@ -0,0 +1,86 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>smfi_version()</TITLE></HEAD>
|
||||
<BODY>
|
||||
<!--
|
||||
$Id: smfi_version.html,v 1.5 2007/03/22 17:30:57 ca Exp $
|
||||
-->
|
||||
<H1>smfi_version()</H1>
|
||||
|
||||
<TABLE BORDER="0" CELLSPACING=4 CELLPADDING=4>
|
||||
<!---------- Synopsis ----------->
|
||||
<TR><TH VALIGN="TOP" ALIGN=LEFT WIDTH=100>SYNOPSIS</TH><TD>
|
||||
<PRE>
|
||||
#include <libmilter/mfapi.h>
|
||||
int smfi_version(
|
||||
unsigned int *pmajor,
|
||||
unsigned int *pminor,
|
||||
unsigned int *ppl
|
||||
);
|
||||
</PRE>
|
||||
Get the (runtime) version of libmilter.
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Description ---------->
|
||||
<TR><TH VALIGN="TOP" ALIGN=LEFT>DESCRIPTION</TH><TD>
|
||||
<TABLE BORDER="1" CELLSPACING=1 CELLPADDING=4>
|
||||
<TR ALIGN="LEFT" VALIGN=TOP>
|
||||
<TH WIDTH="80">Called When</TH>
|
||||
<TD>smfi_version may be called at any time.</TD>
|
||||
</TR>
|
||||
<TR ALIGN="LEFT" VALIGN=TOP>
|
||||
<TH WIDTH="80">Effects</TH>
|
||||
<TD>None.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<!----------- Arguments ---------->
|
||||
<TR><TH VALIGN="TOP" ALIGN=LEFT>ARGUMENTS</TH><TD>
|
||||
<TABLE BORDER="1" CELLSPACING=0>
|
||||
<TR BGCOLOR="#dddddd"><TH>Argument</TH><TH>Description</TH></TR>
|
||||
<TR VALIGN="TOP"><TD>pmajor</TD>
|
||||
<TD>Pointer to an unsigned int variable to store major version number.
|
||||
</TD></TR>
|
||||
<TR VALIGN="TOP"><TD>pminor</TD>
|
||||
<TD>Pointer to an unsigned int variable to store minor version number.
|
||||
</TD></TR>
|
||||
<TR VALIGN="TOP"><TD>ppl</TD>
|
||||
<TD>Pointer to an unsigned int variable to store patch level number.
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Return values ---------->
|
||||
<TR>
|
||||
<TH VALIGN="TOP" ALIGN=LEFT>RETURN VALUES</TH>
|
||||
<TD>smfi_version returns MI_SUCCESS.</TD>
|
||||
</TR>
|
||||
|
||||
</TABLE>
|
||||
|
||||
Note: the compile time version of libmilter is available in the macro
|
||||
<CODE>SMFI_VERSION</CODE>.
|
||||
A milter can check this macro to determine which functions to use
|
||||
(at compile time via C preprocessor statements).
|
||||
Using this macro and the
|
||||
<CODE>smfi_version()</CODE>
|
||||
function,
|
||||
a milter can determine at runtime whether it has been (dynamically)
|
||||
linked against the expected libmilter version.
|
||||
To extract the major and minor version as well as the current patch level
|
||||
from this macro, the macros
|
||||
<CODE>SM_LM_VRS_MAJOR(v)</CODE>,
|
||||
<CODE>SM_LM_VRS_MINOR(v)</CODE>, and
|
||||
<CODE>SM_LM_VRS_PLVL(v)</CODE>
|
||||
can be used, respectively.
|
||||
|
||||
|
||||
<HR SIZE="1">
|
||||
<FONT SIZE="-1">
|
||||
Copyright (c) 2006, 2007 Sendmail, Inc. and its suppliers.
|
||||
All rights reserved.
|
||||
<BR>
|
||||
By using this file, you agree to the terms and conditions set
|
||||
forth in the LICENSE.
|
||||
</FONT>
|
||||
</BODY>
|
||||
</HTML>
|
89
contrib/sendmail/libmilter/docs/xxfi_data.html
Normal file
89
contrib/sendmail/libmilter/docs/xxfi_data.html
Normal file
@ -0,0 +1,89 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>xxfi_data</TITLE></HEAD>
|
||||
<BODY>
|
||||
<!--
|
||||
$Id: xxfi_data.html,v 1.4 2007/01/25 01:00:20 ca Exp $
|
||||
-->
|
||||
<H1>xxfi_data</H1>
|
||||
|
||||
<TABLE border="0" cellspacing=4 cellpadding=4>
|
||||
<!---------- Synopsis ----------->
|
||||
<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD>
|
||||
<PRE>
|
||||
#include <libmilter/mfapi.h>
|
||||
sfsistat (*xxfi_data)(
|
||||
SMFICTX *ctx
|
||||
);
|
||||
</PRE>
|
||||
Handle the DATA command.
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Description ---------->
|
||||
<TR><TH valign="top" align=left>DESCRIPTION</TH><TD>
|
||||
<TABLE border="1" cellspacing=1 cellpadding=4>
|
||||
<TR align="left" valign=top>
|
||||
<TH width="80">Called When</TH>
|
||||
<TD>xxfi_data is called when the client uses the DATA command.
|
||||
</TR>
|
||||
<TR align="left" valign=top>
|
||||
<TH>Default Behavior</TH>
|
||||
<TD>Do nothing; return SMFIS_CONTINUE.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<!----------- Arguments ---------->
|
||||
<TR><TH valign="top" align=left>ARGUMENTS</TH><TD>
|
||||
<TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR>
|
||||
<TR valign="top"><TD>ctx</TD>
|
||||
<TD>Opaque context structure.
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Return values ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>SPECIAL RETURN VALUES</TH>
|
||||
<TD><TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_TEMPFAIL</TD>
|
||||
<TD>Reject this message with a temporary error.
|
||||
</TD>
|
||||
</TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_REJECT</TD>
|
||||
<TD>Reject this message.
|
||||
</TD>
|
||||
</TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_DISCARD</TD>
|
||||
<TD>Accept and silently discard this message.
|
||||
</TD>
|
||||
</TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_ACCEPT</TD>
|
||||
<TD>Accept this message.
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TR>
|
||||
|
||||
<!----------- Notes ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>NOTES</TH>
|
||||
<TD>For more details on ESMTP responses, please see RFC
|
||||
<A href="http://www.rfc-editor.org/rfc/rfc1869.txt">1869</A>.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<HR size="1">
|
||||
<FONT size="-1">
|
||||
Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
All rights reserved.
|
||||
<BR>
|
||||
By using this file, you agree to the terms and conditions set
|
||||
forth in the LICENSE.
|
||||
</FONT>
|
||||
</BODY>
|
||||
</HTML>
|
277
contrib/sendmail/libmilter/docs/xxfi_negotiate.html
Normal file
277
contrib/sendmail/libmilter/docs/xxfi_negotiate.html
Normal file
@ -0,0 +1,277 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>xxfi_negotiate</TITLE></HEAD>
|
||||
<BODY>
|
||||
<!--
|
||||
$Id: xxfi_negotiate.html,v 1.23 2006/12/20 18:57:08 ca Exp $
|
||||
-->
|
||||
<H1>xxfi_negotiate</H1>
|
||||
|
||||
<TABLE border="0" cellspacing=4 cellpadding=4>
|
||||
<!---------- Synopsis ----------->
|
||||
<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD>
|
||||
<PRE>
|
||||
#include <libmilter/mfapi.h>
|
||||
#include <libmilter/mfdef.h>
|
||||
sfsistat (*xxfi_negotiate)(
|
||||
SMFICTX *ctx,
|
||||
unsigned long f0,
|
||||
unsigned long f1,
|
||||
unsigned long f2,
|
||||
unsigned long f3,
|
||||
unsigned long *pf0,
|
||||
unsigned long *pf1,
|
||||
unsigned long *pf2,
|
||||
unsigned long *pf3);
|
||||
</PRE>
|
||||
</TD></TR>
|
||||
<!----------- Description ---------->
|
||||
<TR><TH valign="top" align=left>DESCRIPTION</TH><TD>
|
||||
<TABLE border="1" cellspacing=1 cellpadding=4>
|
||||
<TR>
|
||||
<TH valign="top" align=left width=80>Called When</TH>
|
||||
<TD>Once, at the start of each SMTP connection.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TH valign="top" align=left width=80>Default Behavior</TH>
|
||||
<TD>Return SMFIS_ALL_OPTS to change nothing.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<!----------- Arguments ---------->
|
||||
<TR><TH valign="top" align=left>ARGUMENTS</TH><TD>
|
||||
<TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR>
|
||||
<TR><TD>ctx</TD>
|
||||
<TD>the opaque context structure.
|
||||
</TD></TR>
|
||||
<TR><TD>f0</TD>
|
||||
<TD>the actions offered by the MTA.
|
||||
</TD></TR>
|
||||
<TR><TD>f1</TD>
|
||||
<TD>the protocol steps offered by the MTA.
|
||||
<TR><TD>f2</TD>
|
||||
<TD>for future extensions.
|
||||
</TD></TR>
|
||||
<TR><TD>f3</TD>
|
||||
<TD>for future extensions.
|
||||
</TD></TR>
|
||||
<TR><TD>pf0</TD>
|
||||
<TD>the actions requested by the milter.
|
||||
</TD></TR>
|
||||
<TR><TD>pf1</TD>
|
||||
<TD>the protocol steps requested by the milter.
|
||||
<TR><TD>pf2</TD>
|
||||
<TD>for future extensions.
|
||||
</TD></TR>
|
||||
<TR><TD>pf3</TD>
|
||||
<TD>for future extensions.
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Return values ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>SPECIAL RETURN VALUES</TH>
|
||||
<TD><TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_ALL_OPTS</TD>
|
||||
<TD>
|
||||
If a milter just wants to inspect the available protocol steps
|
||||
and actions, then it can return
|
||||
SMFIS_ALL_OPTS
|
||||
and the MTA will make all protocol steps and actions available
|
||||
to the milter.
|
||||
In this case, no values should be assigned to the output parameters
|
||||
<CODE>pf0</CODE> - <CODE>pf3</CODE>
|
||||
as they will be ignored.
|
||||
</TD>
|
||||
</TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_REJECT</TD>
|
||||
<TD>Milter startup fails and it will not be contacted again
|
||||
(for the current connection).
|
||||
</TD>
|
||||
</TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_CONTINUE</TD>
|
||||
<TD>Continue processing.
|
||||
In this case the milter <EM>must</EM> set all output parameters
|
||||
<CODE>pf0</CODE> - <CODE>pf3</CODE>.
|
||||
See below for an explanation how to set those output parameters.
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TR>
|
||||
|
||||
<!----------- Notes ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>NOTES</TH>
|
||||
<TD>This function allows a milter to dynamically determine and
|
||||
request operations and actions during startup.
|
||||
In previous versions, the actions (f0) were fixed in the
|
||||
<A HREF="smfi_register.html#flags">flags</A> field of the
|
||||
<A HREF="smfi_register.html#smfiDesc">smfiDesc</A>
|
||||
structure
|
||||
and the protocol steps (f1) were implicitly derived by checking whether
|
||||
a callback was defined.
|
||||
Due to the extensions in the new milter version,
|
||||
such a static selection will not work if a milter requires
|
||||
new actions that are not available when talking to an older MTA.
|
||||
Hence in the negotiation callback a milter can determine
|
||||
which operations are available and dynamically select
|
||||
those which it needs and which are offered.
|
||||
If some operations are not available, the milter may either fall back
|
||||
to an older mode or abort the session and ask the user to upgrade.
|
||||
|
||||
<!--
|
||||
<P>
|
||||
The protocol steps are defined in
|
||||
<CODE>include/libmilter/mfdef.h</CODE>:
|
||||
the macros start with
|
||||
<CODE>SMFIP_</CODE>.
|
||||
-->
|
||||
|
||||
<P>
|
||||
Protocol steps
|
||||
(<CODE>f1</CODE>, <CODE>*pf1</CODE>):
|
||||
<UL>
|
||||
<LI><A NAME="SMFIP_RCPT_REJ"><CODE>SMFIP_RCPT_REJ</CODE></A>:
|
||||
By setting this bit, a milter can request that the
|
||||
MTA should also send <CODE>RCPT</CODE> commands that have been rejected
|
||||
because the user is unknown (or similar reasons), but not those
|
||||
which have been rejected because of syntax errors etc.
|
||||
If a milter requests this protocol step,
|
||||
then it should check the macro
|
||||
<CODE>{rcpt_mailer}</CODE>:
|
||||
if that is set to
|
||||
<CODE>error</CODE>,
|
||||
then the recipient will be rejected by the MTA.
|
||||
Usually the macros
|
||||
<CODE>{rcpt_host}</CODE> and <CODE>{rcpt_addr}</CODE>
|
||||
will contain an enhanced status code and an error text
|
||||
in that case, respectively.
|
||||
|
||||
<LI><A NAME="SMFIP_SKIP"><CODE>SMFIP_SKIP</CODE></A>
|
||||
indicates that the MTA understand the
|
||||
<A HREF="api.html#SMFIS_SKIP">SMFIS_SKIP</A>
|
||||
return code.
|
||||
|
||||
<LI><A NAME="SMFIP_NR_"><CODE>SMFIP_NR_*</CODE></A>
|
||||
indicates that the MTA understand the
|
||||
<A HREF="api.html#SMFIS_NOREPLY">SMFIS_NOREPLY</A>
|
||||
return code.
|
||||
There are flags for various protocol stages:
|
||||
|
||||
<UL>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_CONN"><CODE>SMFIP_NR_CONN</CODE></A>:
|
||||
<A HREF="xxfi_connect.html">xxfi_connect()</A>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_HELO"><CODE>SMFIP_NR_HELO</CODE></A>:
|
||||
<A HREF="xxfi_helo.html">xxfi_helo()</A>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_MAIL"><CODE>SMFIP_NR_MAIL</CODE></A>:
|
||||
<A HREF="xxfi_envfrom.html">xxfi_envfrom()</A>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_RCPT"><CODE>SMFIP_NR_RCPT</CODE></A>:
|
||||
<A HREF="xxfi_envrcpt.html">xxfi_envrcpt()</A>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_DATA"><CODE>SMFIP_NR_DATA</CODE></A>:
|
||||
<A HREF="xxfi_data.html">xxfi_data()</A>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_UNKN"><CODE>SMFIP_NR_UNKN</CODE></A>:
|
||||
<A HREF="xxfi_unknown.html">xxfi_unknown()</A>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_EOH"><CODE>SMFIP_NR_EOH</CODE></A>:
|
||||
<A HREF="xxfi_eoh.html">xxfi_eoh()</A>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_BODY"><CODE>SMFIP_NR_BODY</CODE></A>:
|
||||
<A HREF="xxfi_body.html">xxfi_body()</A>
|
||||
|
||||
<LI><A NAME="SMFIP_NR_HDR"><CODE>SMFIP_NR_HDR</CODE></A>:
|
||||
<A HREF="xxfi_header.html">xxfi_header()</A>
|
||||
|
||||
</UL>
|
||||
|
||||
<LI><A NAME="SMFIP_HDR_LEADSPC"><CODE>SMFIP_HDR_LEADSPC</CODE></A>
|
||||
indicates that the MTA can send header values with leading space intact.
|
||||
If this protocol step is requested, then the MTA will also not add a leading
|
||||
space to headers when they are added, inserted, or changed.
|
||||
|
||||
<!--
|
||||
:'a,.s;^#define \(SMFIP_NO[A-Z]*\)[ ].*;<LI><A NAME="\1"><CODE>\1</CODE></A>:;
|
||||
-->
|
||||
<LI>The MTA can be instructed not to send information about
|
||||
various SMTP stages, these flags start with:
|
||||
<A NAME="SMFIP_NO"><CODE>SMFIP_NO*</CODE></A>.
|
||||
<UL>
|
||||
<LI><A NAME="SMFIP_NOCONNECT"><CODE>SMFIP_NOCONNECT</CODE></A>:
|
||||
<A HREF="xxfi_connect.html">xxfi_connect()</A>
|
||||
<LI><A NAME="SMFIP_NOHELO"><CODE>SMFIP_NOHELO</CODE></A>:
|
||||
<A HREF="xxfi_header.html">xxfi_header()</A>
|
||||
<LI><A NAME="SMFIP_NOMAIL"><CODE>SMFIP_NOMAIL</CODE></A>:
|
||||
<A HREF="xxfi_envfrom.html">xxfi_envfrom()</A>
|
||||
<LI><A NAME="SMFIP_NORCPT"><CODE>SMFIP_NORCPT</CODE></A>:
|
||||
<A HREF="xxfi_envrcpt.html">xxfi_envrcpt()</A>
|
||||
<LI><A NAME="SMFIP_NOBODY"><CODE>SMFIP_NOBODY</CODE></A>:
|
||||
<A HREF="xxfi_body.html">xxfi_body()</A>
|
||||
<LI><A NAME="SMFIP_NOHDRS"><CODE>SMFIP_NOHDRS</CODE></A>:
|
||||
<A HREF="xxfi_header.html">xxfi_header()</A>
|
||||
<LI><A NAME="SMFIP_NOEOH"><CODE>SMFIP_NOEOH</CODE></A>:
|
||||
<A HREF="xxfi_eoh.html">xxfi_eoh()</A>
|
||||
<LI><A NAME="SMFIP_NOUNKNOWN"><CODE>SMFIP_NOUNKNOWN</CODE></A>:
|
||||
<A HREF="xxfi_unknown.html">xxfi_unknown()</A>
|
||||
<LI><A NAME="SMFIP_NODATA"><CODE>SMFIP_NODATA</CODE></A>:
|
||||
<A HREF="xxfi_data.html">xxfi_data()</A>
|
||||
</UL>
|
||||
|
||||
For each of these xxfi_* callbacks that a milter does not use
|
||||
the corresponding flag <EM>should</EM> be set in
|
||||
<CODE>*pf1</CODE>.
|
||||
|
||||
</UL>
|
||||
|
||||
<P>
|
||||
The available actions
|
||||
(<CODE>f0</CODE>, <CODE>*pf0</CODE>)
|
||||
are
|
||||
<!--
|
||||
defined in
|
||||
<CODE>include/libmilter/mfapi.h</CODE>:
|
||||
the macros start with
|
||||
<CODE>SMFIF_</CODE>;
|
||||
these are
|
||||
-->
|
||||
described
|
||||
<A HREF="smfi_register.html#flags">elsewhere (xxfi_flags)</A>.
|
||||
|
||||
<P>
|
||||
If a milter returns SMFIS_CONTINUE, then it <EM>must</EM>
|
||||
set the desired actions and protocol steps
|
||||
via the (output) parameters
|
||||
<CODE>pf0</CODE>
|
||||
and
|
||||
<CODE>pf1</CODE>
|
||||
(which correspond to
|
||||
<CODE>f0</CODE>
|
||||
and
|
||||
<CODE>f1</CODE>, respectively).
|
||||
The (output) parameters
|
||||
<CODE>pf2</CODE> and
|
||||
<CODE>pf3</CODE>
|
||||
should be set to 0 for compatibility with future versions.
|
||||
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<HR size="1">
|
||||
<FONT size="-1">
|
||||
Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
All rights reserved.
|
||||
<BR>
|
||||
By using this file, you agree to the terms and conditions set
|
||||
forth in the LICENSE.
|
||||
</FONT>
|
||||
</BODY>
|
||||
</HTML>
|
84
contrib/sendmail/libmilter/docs/xxfi_unknown.html
Normal file
84
contrib/sendmail/libmilter/docs/xxfi_unknown.html
Normal file
@ -0,0 +1,84 @@
|
||||
<HTML>
|
||||
<HEAD><TITLE>xxfi_unknown</TITLE></HEAD>
|
||||
<BODY>
|
||||
<!--
|
||||
$Id: xxfi_unknown.html,v 1.3 2006/12/21 18:30:36 ca Exp $
|
||||
-->
|
||||
<H1>xxfi_unknown</H1>
|
||||
|
||||
<TABLE border="0" cellspacing=4 cellpadding=4>
|
||||
<!---------- Synopsis ----------->
|
||||
<TR><TH valign="top" align=left width=100>SYNOPSIS</TH><TD>
|
||||
<PRE>
|
||||
#include <libmilter/mfapi.h>
|
||||
sfsistat (*xxfi_unknown)(
|
||||
SMFICTX *ctx,
|
||||
const char *arg
|
||||
);
|
||||
</PRE>
|
||||
Handle unknown and unimplemented SMTP commands.
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Description ---------->
|
||||
<TR><TH valign="top" align=left>DESCRIPTION</TH><TD>
|
||||
<TABLE border="1" cellspacing=1 cellpadding=4>
|
||||
<TR align="left" valign=top>
|
||||
<TH width="80">Called When</TH>
|
||||
<TD>xxfi_unknown is called when the client uses an SMTP command
|
||||
that is either unknown or not implemented by the MTA.
|
||||
</TR>
|
||||
<TR align="left" valign=top>
|
||||
<TH>Default Behavior</TH>
|
||||
<TD>Do nothing; return SMFIS_CONTINUE.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<!----------- Arguments ---------->
|
||||
<TR><TH valign="top" align=left>ARGUMENTS</TH><TD>
|
||||
<TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Argument</TH><TH>Description</TH></TR>
|
||||
<TR valign="top"><TD>ctx</TD>
|
||||
<TD>Opaque context structure.
|
||||
</TD></TR>
|
||||
<TR valign="top"><TD>arg</TD>
|
||||
<TD>SMTP command including all arguments.
|
||||
</TD></TR>
|
||||
</TABLE>
|
||||
</TD></TR>
|
||||
|
||||
<!----------- Return values ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>SPECIAL RETURN VALUES</TH>
|
||||
<TD><TABLE border="1" cellspacing=0>
|
||||
<TR bgcolor="#dddddd"><TH>Return value</TH><TH>Description</TH></TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_TEMPFAIL</TD>
|
||||
<TD>Reject this message with a temporary error.
|
||||
</TD>
|
||||
</TR>
|
||||
<TR valign="top">
|
||||
<TD>SMFIS_REJECT</TD>
|
||||
<TD>Reject this message.
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TR>
|
||||
|
||||
<!----------- Notes ---------->
|
||||
<TR>
|
||||
<TH valign="top" align=left>NOTES</TH>
|
||||
<TD>The SMTP command will always be rejected by the server,
|
||||
it is only possible to return a different error code.
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<HR size="1">
|
||||
<FONT size="-1">
|
||||
Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
All rights reserved.
|
||||
<BR>
|
||||
By using this file, you agree to the terms and conditions set
|
||||
forth in the LICENSE.
|
||||
</FONT>
|
||||
</BODY>
|
||||
</HTML>
|
298
contrib/sendmail/libmilter/example.c
Normal file
298
contrib/sendmail/libmilter/example.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*
|
||||
* $Id: example.c,v 8.3 2006/12/20 21:22:34 ca Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
** A trivial example filter that logs all email to a file.
|
||||
** This milter also has some callbacks which it does not really use,
|
||||
** but they are defined to serve as an example.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libmilter/mfapi.h"
|
||||
#include "libmilter/mfdef.h"
|
||||
|
||||
#ifndef true
|
||||
# define false 0
|
||||
# define true 1
|
||||
#endif /* ! true */
|
||||
|
||||
struct mlfiPriv
|
||||
{
|
||||
char *mlfi_fname;
|
||||
FILE *mlfi_fp;
|
||||
};
|
||||
|
||||
#define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx))
|
||||
|
||||
static unsigned long mta_caps = 0;
|
||||
|
||||
sfsistat
|
||||
mlfi_cleanup(ctx, ok)
|
||||
SMFICTX *ctx;
|
||||
bool ok;
|
||||
{
|
||||
sfsistat rstat = SMFIS_CONTINUE;
|
||||
struct mlfiPriv *priv = MLFIPRIV;
|
||||
char *p;
|
||||
char host[512];
|
||||
char hbuf[1024];
|
||||
|
||||
if (priv == NULL)
|
||||
return rstat;
|
||||
|
||||
/* close the archive file */
|
||||
if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF)
|
||||
{
|
||||
/* failed; we have to wait until later */
|
||||
rstat = SMFIS_TEMPFAIL;
|
||||
(void) unlink(priv->mlfi_fname);
|
||||
}
|
||||
else if (ok)
|
||||
{
|
||||
/* add a header to the message announcing our presence */
|
||||
if (gethostname(host, sizeof host) < 0)
|
||||
snprintf(host, sizeof host, "localhost");
|
||||
p = strrchr(priv->mlfi_fname, '/');
|
||||
if (p == NULL)
|
||||
p = priv->mlfi_fname;
|
||||
else
|
||||
p++;
|
||||
snprintf(hbuf, sizeof hbuf, "%s@%s", p, host);
|
||||
smfi_addheader(ctx, "X-Archived", hbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* message was aborted -- delete the archive file */
|
||||
(void) unlink(priv->mlfi_fname);
|
||||
}
|
||||
|
||||
/* release private memory */
|
||||
free(priv->mlfi_fname);
|
||||
free(priv);
|
||||
smfi_setpriv(ctx, NULL);
|
||||
|
||||
/* return status */
|
||||
return rstat;
|
||||
}
|
||||
|
||||
|
||||
sfsistat
|
||||
mlfi_envfrom(ctx, envfrom)
|
||||
SMFICTX *ctx;
|
||||
char **envfrom;
|
||||
{
|
||||
struct mlfiPriv *priv;
|
||||
int fd = -1;
|
||||
|
||||
/* allocate some private memory */
|
||||
priv = malloc(sizeof *priv);
|
||||
if (priv == NULL)
|
||||
{
|
||||
/* can't accept this message right now */
|
||||
return SMFIS_TEMPFAIL;
|
||||
}
|
||||
memset(priv, '\0', sizeof *priv);
|
||||
|
||||
/* open a file to store this message */
|
||||
priv->mlfi_fname = strdup("/tmp/msg.XXXXXXXX");
|
||||
if (priv->mlfi_fname == NULL)
|
||||
{
|
||||
free(priv);
|
||||
return SMFIS_TEMPFAIL;
|
||||
}
|
||||
if ((fd = mkstemp(priv->mlfi_fname)) < 0 ||
|
||||
(priv->mlfi_fp = fdopen(fd, "w+")) == NULL)
|
||||
{
|
||||
if (fd >= 0)
|
||||
(void) close(fd);
|
||||
free(priv->mlfi_fname);
|
||||
free(priv);
|
||||
return SMFIS_TEMPFAIL;
|
||||
}
|
||||
|
||||
/* save the private data */
|
||||
smfi_setpriv(ctx, priv);
|
||||
|
||||
/* continue processing */
|
||||
return SMFIS_CONTINUE;
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_header(ctx, headerf, headerv)
|
||||
SMFICTX *ctx;
|
||||
char *headerf;
|
||||
char *headerv;
|
||||
{
|
||||
/* write the header to the log file */
|
||||
fprintf(MLFIPRIV->mlfi_fp, "%s: %s\r\n", headerf, headerv);
|
||||
|
||||
/* continue processing */
|
||||
return ((mta_caps & SMFIP_NR_HDR) != 0)
|
||||
? SMFIS_NOREPLY : SMFIS_CONTINUE;
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_eoh(ctx)
|
||||
SMFICTX *ctx;
|
||||
{
|
||||
/* output the blank line between the header and the body */
|
||||
fprintf(MLFIPRIV->mlfi_fp, "\r\n");
|
||||
|
||||
/* continue processing */
|
||||
return SMFIS_CONTINUE;
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_body(ctx, bodyp, bodylen)
|
||||
SMFICTX *ctx;
|
||||
u_char *bodyp;
|
||||
size_t bodylen;
|
||||
{
|
||||
/* output body block to log file */
|
||||
if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0)
|
||||
{
|
||||
/* write failed */
|
||||
(void) mlfi_cleanup(ctx, false);
|
||||
return SMFIS_TEMPFAIL;
|
||||
}
|
||||
|
||||
/* continue processing */
|
||||
return SMFIS_CONTINUE;
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_eom(ctx)
|
||||
SMFICTX *ctx;
|
||||
{
|
||||
return mlfi_cleanup(ctx, true);
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_close(ctx)
|
||||
SMFICTX *ctx;
|
||||
{
|
||||
return SMFIS_ACCEPT;
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_abort(ctx)
|
||||
SMFICTX *ctx;
|
||||
{
|
||||
return mlfi_cleanup(ctx, false);
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_unknown(ctx, cmd)
|
||||
SMFICTX *ctx;
|
||||
char *cmd;
|
||||
{
|
||||
return SMFIS_CONTINUE;
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_data(ctx)
|
||||
SMFICTX *ctx;
|
||||
{
|
||||
return SMFIS_CONTINUE;
|
||||
}
|
||||
|
||||
sfsistat
|
||||
mlfi_negotiate(ctx, f0, f1, f2, f3, pf0, pf1, pf2, pf3)
|
||||
SMFICTX *ctx;
|
||||
unsigned long f0;
|
||||
unsigned long f1;
|
||||
unsigned long f2;
|
||||
unsigned long f3;
|
||||
unsigned long *pf0;
|
||||
unsigned long *pf1;
|
||||
unsigned long *pf2;
|
||||
unsigned long *pf3;
|
||||
{
|
||||
/* milter actions: add headers */
|
||||
*pf0 = SMFIF_ADDHDRS;
|
||||
|
||||
/* milter protocol steps: all but connect, HELO, RCPT */
|
||||
*pf1 = SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NORCPT;
|
||||
mta_caps = f1;
|
||||
if ((mta_caps & SMFIP_NR_HDR) != 0)
|
||||
*pf1 |= SMFIP_NR_HDR;
|
||||
*pf2 = 0;
|
||||
*pf3 = 0;
|
||||
return SMFIS_CONTINUE;
|
||||
}
|
||||
|
||||
struct smfiDesc smfilter =
|
||||
{
|
||||
"SampleFilter", /* filter name */
|
||||
SMFI_VERSION, /* version code -- do not change */
|
||||
SMFIF_ADDHDRS, /* flags */
|
||||
NULL, /* connection info filter */
|
||||
NULL, /* SMTP HELO command filter */
|
||||
mlfi_envfrom, /* envelope sender filter */
|
||||
NULL, /* envelope recipient filter */
|
||||
mlfi_header, /* header filter */
|
||||
mlfi_eoh, /* end of header */
|
||||
mlfi_body, /* body block filter */
|
||||
mlfi_eom, /* end of message */
|
||||
mlfi_abort, /* message aborted */
|
||||
mlfi_close, /* connection cleanup */
|
||||
mlfi_unknown, /* unknown/unimplemented SMTP commands */
|
||||
mlfi_data, /* DATA command filter */
|
||||
mlfi_negotiate /* option negotation at connection startup */
|
||||
};
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
bool setconn;
|
||||
int c;
|
||||
|
||||
setconn = false;
|
||||
|
||||
/* Process command line options */
|
||||
while ((c = getopt(argc, argv, "p:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'p':
|
||||
if (optarg == NULL || *optarg == '\0')
|
||||
{
|
||||
(void) fprintf(stderr, "Illegal conn: %s\n",
|
||||
optarg);
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
(void) smfi_setconn(optarg);
|
||||
setconn = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
if (!setconn)
|
||||
{
|
||||
fprintf(stderr, "%s: Missing required -p argument\n", argv[0]);
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
if (smfi_register(smfilter) == MI_FAILURE)
|
||||
{
|
||||
fprintf(stderr, "smfi_register failed\n");
|
||||
exit(EX_UNAVAILABLE);
|
||||
}
|
||||
return smfi_main();
|
||||
}
|
||||
|
225
contrib/sendmail/libmilter/monitor.c
Normal file
225
contrib/sendmail/libmilter/monitor.c
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "libmilter.h"
|
||||
|
||||
#if _FFR_THREAD_MONITOR
|
||||
|
||||
/*
|
||||
** Thread Monitoring
|
||||
** Todo: more error checking (return code from function calls)
|
||||
** add comments.
|
||||
*/
|
||||
|
||||
bool Monitor = false; /* use monitoring? */
|
||||
static unsigned int Mon_exec_time = 0;
|
||||
|
||||
/* mutex protects Mon_cur_ctx, Mon_ctx_head, and ctx_start */
|
||||
static smutex_t Mon_mutex;
|
||||
static scond_t Mon_cv;
|
||||
|
||||
/*
|
||||
** Current ctx to monitor.
|
||||
** Invariant:
|
||||
** Mon_cur_ctx == NULL || Mon_cur_ctx is thread which was started the longest
|
||||
** time ago.
|
||||
**
|
||||
** Basically the entries in the list are ordered by time because new
|
||||
** entries are appended at the end. However, due to the concurrent
|
||||
** execution (multi-threaded) and no guaranteed order of wakeups
|
||||
** after a mutex_lock() attempt, the order might not be strict,
|
||||
** i.e., if the list contains e1 and e2 (in that order) then
|
||||
** the the start time of e2 can be (slightly) smaller than that of e1.
|
||||
** However, this slight inaccurracy should not matter for the proper
|
||||
** working of this algorithm.
|
||||
*/
|
||||
|
||||
static SMFICTX_PTR Mon_cur_ctx = NULL;
|
||||
static smfi_hd_T Mon_ctx_head; /* head of the linked list of active contexts */
|
||||
|
||||
/*
|
||||
** SMFI_SET_MAX_EXEC_TIME -- set maximum execution time for a thread
|
||||
**
|
||||
** Parameters:
|
||||
** tm -- maximum execution time for a thread
|
||||
**
|
||||
** Returns:
|
||||
** MI_SUCCESS
|
||||
*/
|
||||
|
||||
int
|
||||
smfi_set_max_exec_time(tm)
|
||||
unsigned int tm;
|
||||
{
|
||||
Mon_exec_time = tm;
|
||||
return MI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_MONITOR_THREAD -- monitoring thread
|
||||
**
|
||||
** Parameters:
|
||||
** arg -- ignored (required by pthread_create())
|
||||
**
|
||||
** Returns:
|
||||
** NULL on termination.
|
||||
*/
|
||||
|
||||
static void *
|
||||
mi_monitor_thread(arg)
|
||||
void *arg;
|
||||
{
|
||||
sthread_t tid;
|
||||
int r;
|
||||
time_t now, end;
|
||||
|
||||
SM_ASSERT(Monitor);
|
||||
SM_ASSERT(Mon_exec_time > 0);
|
||||
tid = (sthread_t) sthread_get_id();
|
||||
if (pthread_detach(tid) != 0)
|
||||
{
|
||||
/* log an error */
|
||||
return (void *)1;
|
||||
}
|
||||
|
||||
/*
|
||||
** NOTE: this is "flow through" code,
|
||||
** do NOT use do { } while ("break" is used here!)
|
||||
*/
|
||||
|
||||
#define MON_CHK_STOP \
|
||||
now = time(NULL); \
|
||||
end = Mon_cur_ctx->ctx_start + Mon_exec_time; \
|
||||
if (now > end) \
|
||||
{ \
|
||||
smi_log(SMI_LOG_ERR, \
|
||||
"WARNING: monitor timeout triggered, now=%ld, end=%ld, tid=%ld, state=0x%x",\
|
||||
(long) now, (long) end, \
|
||||
(long) Mon_cur_ctx->ctx_id, Mon_cur_ctx->ctx_state);\
|
||||
mi_stop_milters(MILTER_STOP); \
|
||||
break; \
|
||||
}
|
||||
|
||||
(void) smutex_lock(&Mon_mutex);
|
||||
while (mi_stop() == MILTER_CONT)
|
||||
{
|
||||
if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0)
|
||||
{
|
||||
struct timespec abstime;
|
||||
|
||||
MON_CHK_STOP;
|
||||
abstime.tv_sec = end;
|
||||
abstime.tv_nsec = 0;
|
||||
r = pthread_cond_timedwait(&Mon_cv, &Mon_mutex,
|
||||
&abstime);
|
||||
}
|
||||
else
|
||||
r = pthread_cond_wait(&Mon_cv, &Mon_mutex);
|
||||
if (mi_stop() != MILTER_CONT)
|
||||
break;
|
||||
if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0)
|
||||
{
|
||||
MON_CHK_STOP;
|
||||
}
|
||||
}
|
||||
(void) smutex_unlock(&Mon_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_MONITOR_INIT -- initialize monitoring thread
|
||||
**
|
||||
** Parameters: none
|
||||
**
|
||||
** Returns:
|
||||
** MI_SUCCESS/MI_FAILURE
|
||||
*/
|
||||
|
||||
int
|
||||
mi_monitor_init()
|
||||
{
|
||||
int r;
|
||||
sthread_t tid;
|
||||
|
||||
SM_ASSERT(!Monitor);
|
||||
if (Mon_exec_time <= 0)
|
||||
return MI_SUCCESS;
|
||||
Monitor = true;
|
||||
if (!smutex_init(&Mon_mutex))
|
||||
return MI_FAILURE;
|
||||
if (scond_init(&Mon_cv) != 0)
|
||||
return MI_FAILURE;
|
||||
SM_TAILQ_INIT(&Mon_ctx_head);
|
||||
|
||||
r = thread_create(&tid, mi_monitor_thread, (void *)NULL);
|
||||
if (r != 0)
|
||||
return r;
|
||||
return MI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_MONITOR_WORK_BEGIN -- record start of thread execution
|
||||
**
|
||||
** Parameters:
|
||||
** ctx -- session context
|
||||
** cmd -- milter command char
|
||||
**
|
||||
** Returns:
|
||||
** 0
|
||||
*/
|
||||
|
||||
int
|
||||
mi_monitor_work_begin(ctx, cmd)
|
||||
SMFICTX_PTR ctx;
|
||||
int cmd;
|
||||
{
|
||||
(void) smutex_lock(&Mon_mutex);
|
||||
if (NULL == Mon_cur_ctx)
|
||||
{
|
||||
Mon_cur_ctx = ctx;
|
||||
(void) scond_signal(&Mon_cv);
|
||||
}
|
||||
ctx->ctx_start = time(NULL);
|
||||
SM_TAILQ_INSERT_TAIL(&Mon_ctx_head, ctx, ctx_mon_link);
|
||||
(void) smutex_unlock(&Mon_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_MONITOR_WORK_END -- record end of thread execution
|
||||
**
|
||||
** Parameters:
|
||||
** ctx -- session context
|
||||
** cmd -- milter command char
|
||||
**
|
||||
** Returns:
|
||||
** 0
|
||||
*/
|
||||
|
||||
int
|
||||
mi_monitor_work_end(ctx, cmd)
|
||||
SMFICTX_PTR ctx;
|
||||
int cmd;
|
||||
{
|
||||
(void) smutex_lock(&Mon_mutex);
|
||||
ctx->ctx_start = 0;
|
||||
SM_TAILQ_REMOVE(&Mon_ctx_head, ctx, ctx_mon_link);
|
||||
if (Mon_cur_ctx == ctx)
|
||||
{
|
||||
if (SM_TAILQ_EMPTY(&Mon_ctx_head))
|
||||
Mon_cur_ctx = NULL;
|
||||
else
|
||||
Mon_cur_ctx = SM_TAILQ_FIRST(&Mon_ctx_head);
|
||||
}
|
||||
(void) smutex_unlock(&Mon_mutex);
|
||||
return 0;
|
||||
}
|
||||
#endif /* _FFR_THREAD_MONITOR */
|
792
contrib/sendmail/libmilter/worker.c
Normal file
792
contrib/sendmail/libmilter/worker.c
Normal file
@ -0,0 +1,792 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004, 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*
|
||||
* Contributed by Jose Marcio Martins da Cruz - Ecole des Mines de Paris
|
||||
* Jose-Marcio.Martins@ensmp.fr
|
||||
*/
|
||||
|
||||
#include <sm/gen.h>
|
||||
SM_RCSID("@(#)$Id: worker.c,v 8.9 2006/12/18 18:26:51 ca Exp $")
|
||||
|
||||
#include "libmilter.h"
|
||||
|
||||
#if _FFR_WORKERS_POOL
|
||||
|
||||
typedef struct taskmgr_S taskmgr_T;
|
||||
|
||||
#define TM_SIGNATURE 0x23021957
|
||||
|
||||
struct taskmgr_S
|
||||
{
|
||||
long tm_signature; /* has the controller been initialized */
|
||||
sthread_t tm_tid; /* thread id of controller */
|
||||
smfi_hd_T tm_ctx_head; /* head of the linked list of contexts */
|
||||
|
||||
int tm_nb_workers; /* number of workers in the pool */
|
||||
int tm_nb_idle; /* number of workers waiting */
|
||||
|
||||
int tm_p[2]; /* poll control pipe */
|
||||
|
||||
smutex_t tm_w_mutex; /* linked list access mutex */
|
||||
scond_t tm_w_cond; /* */
|
||||
};
|
||||
|
||||
static taskmgr_T Tskmgr = {0};
|
||||
|
||||
#define WRK_CTX_HEAD Tskmgr.tm_ctx_head
|
||||
|
||||
#define RD_PIPE (Tskmgr.tm_p[0])
|
||||
#define WR_PIPE (Tskmgr.tm_p[1])
|
||||
|
||||
#define PIPE_SEND_SIGNAL() \
|
||||
do \
|
||||
{ \
|
||||
char evt = 0x5a; \
|
||||
int fd = WR_PIPE; \
|
||||
if (write(fd, &evt, sizeof(evt)) != sizeof(evt)) \
|
||||
smi_log(SMI_LOG_ERR, \
|
||||
"Error writing to event pipe: %s", \
|
||||
sm_errstring(errno)); \
|
||||
} while (0)
|
||||
|
||||
#ifndef USE_PIPE_WAKE_POLL
|
||||
# define USE_PIPE_WAKE_POLL 1
|
||||
#endif /* USE_PIPE_WAKE_POLL */
|
||||
|
||||
/* poll check periodicity (default 10000 - 10 s) */
|
||||
#define POLL_TIMEOUT 10000
|
||||
|
||||
/* worker conditional wait timeout (default 10 s) */
|
||||
#define COND_TIMEOUT 10
|
||||
|
||||
/* functions */
|
||||
static int mi_close_session __P((SMFICTX_PTR));
|
||||
|
||||
static void *mi_worker __P((void *));
|
||||
static void *mi_pool_controller __P((void *));
|
||||
|
||||
static int mi_list_add_ctx __P((SMFICTX_PTR));
|
||||
static int mi_list_del_ctx __P((SMFICTX_PTR));
|
||||
|
||||
/*
|
||||
** periodicity of cleaning up old sessions (timedout)
|
||||
** sessions list will be checked to find old inactive
|
||||
** sessions each DT_CHECK_OLD_SESSIONS sec
|
||||
*/
|
||||
|
||||
#define DT_CHECK_OLD_SESSIONS 600
|
||||
|
||||
#ifndef OLD_SESSION_TIMEOUT
|
||||
# define OLD_SESSION_TIMEOUT ctx->ctx_timeout
|
||||
#endif /* OLD_SESSION_TIMEOUT */
|
||||
|
||||
/* session states - with respect to the pool of workers */
|
||||
#define WKST_INIT 0 /* initial state */
|
||||
#define WKST_READY_TO_RUN 1 /* command ready do be read */
|
||||
#define WKST_RUNNING 2 /* session running on a worker */
|
||||
#define WKST_READY_TO_WAIT 3 /* session just finished by a worker */
|
||||
#define WKST_WAITING 4 /* waiting for new command */
|
||||
#define WKST_CLOSING 5 /* session finished */
|
||||
|
||||
#ifndef MIN_WORKERS
|
||||
# define MIN_WORKERS 2 /* minimum number of threads to keep around */
|
||||
#endif
|
||||
|
||||
#define MIN_IDLE 1 /* minimum number of idle threads */
|
||||
|
||||
|
||||
/*
|
||||
** Macros for threads and mutex management
|
||||
*/
|
||||
|
||||
#define TASKMGR_LOCK() \
|
||||
do \
|
||||
{ \
|
||||
if (!smutex_lock(&Tskmgr.tm_w_mutex)) \
|
||||
smi_log(SMI_LOG_ERR, "TASKMGR_LOCK error"); \
|
||||
} while (0)
|
||||
|
||||
#define TASKMGR_UNLOCK() \
|
||||
do \
|
||||
{ \
|
||||
if (!smutex_unlock(&Tskmgr.tm_w_mutex)) \
|
||||
smi_log(SMI_LOG_ERR, "TASKMGR_UNLOCK error"); \
|
||||
} while (0)
|
||||
|
||||
#define TASKMGR_COND_WAIT() \
|
||||
scond_timedwait(&Tskmgr.tm_w_cond, &Tskmgr.tm_w_mutex, COND_TIMEOUT)
|
||||
|
||||
#define TASKMGR_COND_SIGNAL() \
|
||||
do \
|
||||
{ \
|
||||
if (scond_signal(&Tskmgr.tm_w_cond) != 0) \
|
||||
smi_log(SMI_LOG_ERR, "TASKMGR_COND_SIGNAL error"); \
|
||||
} while (0)
|
||||
|
||||
#define LAUNCH_WORKER(ctx) \
|
||||
do \
|
||||
{ \
|
||||
int r; \
|
||||
sthread_t tid; \
|
||||
\
|
||||
if ((r = thread_create(&tid, mi_worker, ctx)) != 0) \
|
||||
smi_log(SMI_LOG_ERR, "LAUNCH_WORKER error: %s",\
|
||||
sm_errstring(r)); \
|
||||
} while (0)
|
||||
|
||||
#if POOL_DEBUG
|
||||
# define POOL_LEV_DPRINTF(lev, x) \
|
||||
do { \
|
||||
if ((lev) < ctx->ctx_dbg) \
|
||||
sm_dprintf x; \
|
||||
} while (0)
|
||||
#else /* POOL_DEBUG */
|
||||
# define POOL_LEV_DPRINTF(lev, x)
|
||||
#endif /* POOL_DEBUG */
|
||||
|
||||
/*
|
||||
** MI_START_SESSION -- Start a session in the pool of workers
|
||||
**
|
||||
** Parameters:
|
||||
** ctx -- context structure
|
||||
**
|
||||
** Returns:
|
||||
** MI_SUCCESS/MI_FAILURE
|
||||
*/
|
||||
|
||||
int
|
||||
mi_start_session(ctx)
|
||||
SMFICTX_PTR ctx;
|
||||
{
|
||||
static long id = 0;
|
||||
|
||||
SM_ASSERT(Tskmgr.tm_signature == TM_SIGNATURE);
|
||||
SM_ASSERT(ctx != NULL);
|
||||
POOL_LEV_DPRINTF(4, ("PIPE r=[%d] w=[%d]", RD_PIPE, WR_PIPE));
|
||||
TASKMGR_LOCK();
|
||||
|
||||
if (mi_list_add_ctx(ctx) != MI_SUCCESS)
|
||||
{
|
||||
TASKMGR_UNLOCK();
|
||||
return MI_FAILURE;
|
||||
}
|
||||
|
||||
ctx->ctx_sid = id++;
|
||||
|
||||
/* if there is an idle worker, signal it, otherwise start new worker */
|
||||
if (Tskmgr.tm_nb_idle > 0)
|
||||
{
|
||||
ctx->ctx_wstate = WKST_READY_TO_RUN;
|
||||
TASKMGR_COND_SIGNAL();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->ctx_wstate = WKST_RUNNING;
|
||||
LAUNCH_WORKER(ctx);
|
||||
}
|
||||
TASKMGR_UNLOCK();
|
||||
return MI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_CLOSE_SESSION -- Close a session and clean up data structures
|
||||
**
|
||||
** Parameters:
|
||||
** ctx -- context structure
|
||||
**
|
||||
** Returns:
|
||||
** MI_SUCCESS/MI_FAILURE
|
||||
*/
|
||||
|
||||
static int
|
||||
mi_close_session(ctx)
|
||||
SMFICTX_PTR ctx;
|
||||
{
|
||||
SM_ASSERT(ctx != NULL);
|
||||
|
||||
(void) mi_list_del_ctx(ctx);
|
||||
if (ValidSocket(ctx->ctx_sd))
|
||||
{
|
||||
(void) closesocket(ctx->ctx_sd);
|
||||
ctx->ctx_sd = INVALID_SOCKET;
|
||||
}
|
||||
if (ctx->ctx_reply != NULL)
|
||||
{
|
||||
free(ctx->ctx_reply);
|
||||
ctx->ctx_reply = NULL;
|
||||
}
|
||||
if (ctx->ctx_privdata != NULL)
|
||||
{
|
||||
smi_log(SMI_LOG_WARN, "%s: private data not NULL",
|
||||
ctx->ctx_smfi->xxfi_name);
|
||||
}
|
||||
mi_clr_macros(ctx, 0);
|
||||
free(ctx);
|
||||
|
||||
return MI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_POOL_CONTROLER_INIT -- Launch the worker pool controller
|
||||
** Must be called before starting sessions.
|
||||
**
|
||||
** Parameters:
|
||||
** none
|
||||
**
|
||||
** Returns:
|
||||
** MI_SUCCESS/MI_FAILURE
|
||||
*/
|
||||
|
||||
int
|
||||
mi_pool_controller_init()
|
||||
{
|
||||
sthread_t tid;
|
||||
int r, i;
|
||||
|
||||
if (Tskmgr.tm_signature == TM_SIGNATURE)
|
||||
return MI_SUCCESS;
|
||||
|
||||
SM_TAILQ_INIT(&WRK_CTX_HEAD);
|
||||
Tskmgr.tm_tid = (sthread_t) -1;
|
||||
Tskmgr.tm_nb_workers = 0;
|
||||
Tskmgr.tm_nb_idle = 0;
|
||||
|
||||
if (pipe(Tskmgr.tm_p) != 0)
|
||||
{
|
||||
smi_log(SMI_LOG_ERR, "can't create event pipe: %s",
|
||||
sm_errstring(r));
|
||||
return MI_FAILURE;
|
||||
}
|
||||
|
||||
POOL_LEV_DPRINTF(4, ("PIPE r=[%d] w=[%d]", RD_PIPE, WR_PIPE));
|
||||
|
||||
(void) smutex_init(&Tskmgr.tm_w_mutex);
|
||||
(void) scond_init(&Tskmgr.tm_w_cond);
|
||||
|
||||
/* Launch the pool controller */
|
||||
if ((r = thread_create(&tid, mi_pool_controller, (void *) NULL)) != 0)
|
||||
{
|
||||
smi_log(SMI_LOG_ERR, "can't create controller thread: %s",
|
||||
sm_errstring(r));
|
||||
return MI_FAILURE;
|
||||
}
|
||||
Tskmgr.tm_tid = tid;
|
||||
Tskmgr.tm_signature = TM_SIGNATURE;
|
||||
|
||||
/* Create the pool of workers */
|
||||
for (i = 0; i < MIN_WORKERS; i++)
|
||||
{
|
||||
if ((r = thread_create(&tid, mi_worker, (void *) NULL)) != 0)
|
||||
{
|
||||
smi_log(SMI_LOG_ERR, "can't create workers crew: %s",
|
||||
sm_errstring(r));
|
||||
return MI_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return MI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_POOL_CONTROLLER -- manage the pool of workers
|
||||
** This thread must be running when listener begins
|
||||
** starting sessions
|
||||
**
|
||||
** Parameters:
|
||||
** arg -- unused
|
||||
**
|
||||
** Returns:
|
||||
** NULL
|
||||
**
|
||||
** Control flow:
|
||||
** for (;;)
|
||||
** Look for timed out sessions
|
||||
** Select sessions to wait for sendmail command
|
||||
** Poll set of file descriptors
|
||||
** if timeout
|
||||
** continue
|
||||
** For each file descriptor ready
|
||||
** launch new thread if no worker available
|
||||
** else
|
||||
** signal waiting worker
|
||||
*/
|
||||
|
||||
/* Poll structure array (pollfd) size step */
|
||||
#define PFD_STEP 256
|
||||
|
||||
#define WAIT_FD(i) (pfd[i].fd)
|
||||
#define WAITFN "POLL"
|
||||
|
||||
static void *
|
||||
mi_pool_controller(arg)
|
||||
void *arg;
|
||||
{
|
||||
struct pollfd *pfd = NULL;
|
||||
int dim_pfd = 0;
|
||||
bool rebuild_set = true;
|
||||
int pcnt = 0; /* error count for poll() failures */
|
||||
|
||||
Tskmgr.tm_tid = sthread_get_id();
|
||||
if (pthread_detach(Tskmgr.tm_tid) != 0)
|
||||
{
|
||||
smi_log(SMI_LOG_ERR, "Failed to detach pool controller thread");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pfd = (struct pollfd *) malloc(PFD_STEP * sizeof(struct pollfd));
|
||||
if (pfd == NULL)
|
||||
{
|
||||
smi_log(SMI_LOG_ERR, "Failed to malloc pollfd array: %s",
|
||||
sm_errstring(errno));
|
||||
return NULL;
|
||||
}
|
||||
dim_pfd = PFD_STEP;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
SMFICTX_PTR ctx;
|
||||
int nfd, rfd, i;
|
||||
time_t now;
|
||||
time_t lastcheck;
|
||||
|
||||
POOL_LEV_DPRINTF(4, ("Let's %s again...", WAITFN));
|
||||
|
||||
if (mi_stop() != MILTER_CONT)
|
||||
break;
|
||||
|
||||
TASKMGR_LOCK();
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
/* check for timed out sessions? */
|
||||
if (lastcheck + DT_CHECK_OLD_SESSIONS < now)
|
||||
{
|
||||
SM_TAILQ_FOREACH(ctx, &WRK_CTX_HEAD, ctx_link)
|
||||
{
|
||||
if (ctx->ctx_wstate == WKST_WAITING)
|
||||
{
|
||||
if (ctx->ctx_wait == 0)
|
||||
{
|
||||
ctx->ctx_wait = now;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if session timed out, close it */
|
||||
if (ctx->ctx_wait + OLD_SESSION_TIMEOUT
|
||||
< now)
|
||||
{
|
||||
sfsistat (*fi_close) __P((SMFICTX *));
|
||||
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("Closing old connection: sd=%d id=%d",
|
||||
ctx->ctx_sd,
|
||||
ctx->ctx_sid));
|
||||
|
||||
if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL)
|
||||
(void) (*fi_close)(ctx);
|
||||
|
||||
mi_close_session(ctx);
|
||||
ctx = SM_TAILQ_FIRST(&WRK_CTX_HEAD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastcheck = now;
|
||||
}
|
||||
|
||||
if (rebuild_set)
|
||||
{
|
||||
/*
|
||||
** Initialize poll set.
|
||||
** Insert into the poll set the file descriptors of
|
||||
** all sessions waiting for a command from sendmail.
|
||||
*/
|
||||
|
||||
nfd = 0;
|
||||
|
||||
/* begin with worker pipe */
|
||||
pfd[nfd].fd = RD_PIPE;
|
||||
pfd[nfd].events = MI_POLL_RD_FLAGS;
|
||||
pfd[nfd].revents = 0;
|
||||
nfd++;
|
||||
|
||||
SM_TAILQ_FOREACH(ctx, &WRK_CTX_HEAD, ctx_link)
|
||||
{
|
||||
/*
|
||||
** update ctx_wait - start of wait moment -
|
||||
** for timeout
|
||||
*/
|
||||
|
||||
if (ctx->ctx_wstate == WKST_READY_TO_WAIT)
|
||||
ctx->ctx_wait = now;
|
||||
|
||||
/* add the session to the pollfd array? */
|
||||
if ((ctx->ctx_wstate == WKST_READY_TO_WAIT) ||
|
||||
(ctx->ctx_wstate == WKST_WAITING))
|
||||
{
|
||||
/*
|
||||
** Resize the pollfd array if it
|
||||
** isn't large enough.
|
||||
*/
|
||||
|
||||
if (nfd >= dim_pfd)
|
||||
{
|
||||
struct pollfd *tpfd;
|
||||
size_t new;
|
||||
|
||||
new = (dim_pfd + PFD_STEP) *
|
||||
sizeof(*tpfd);
|
||||
tpfd = (struct pollfd *)
|
||||
realloc(pfd, new);
|
||||
if (tpfd != NULL)
|
||||
{
|
||||
pfd = tpfd;
|
||||
dim_pfd += PFD_STEP;
|
||||
}
|
||||
else
|
||||
{
|
||||
smi_log(SMI_LOG_ERR,
|
||||
"Failed to realloc pollfd array:%s",
|
||||
sm_errstring(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* add the session to pollfd array */
|
||||
if (nfd < dim_pfd)
|
||||
{
|
||||
ctx->ctx_wstate = WKST_WAITING;
|
||||
pfd[nfd].fd = ctx->ctx_sd;
|
||||
pfd[nfd].events = MI_POLL_RD_FLAGS;
|
||||
pfd[nfd].revents = 0;
|
||||
nfd++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TASKMGR_UNLOCK();
|
||||
|
||||
/* Everything is ready, let's wait for an event */
|
||||
rfd = poll(pfd, nfd, POLL_TIMEOUT);
|
||||
|
||||
POOL_LEV_DPRINTF(4, ("%s returned: at epoch %d value %d",
|
||||
WAITFN, now, nfd));
|
||||
|
||||
/* timeout */
|
||||
if (rfd == 0)
|
||||
continue;
|
||||
|
||||
rebuild_set = true;
|
||||
|
||||
/* error */
|
||||
if (rfd < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
pcnt++;
|
||||
smi_log(SMI_LOG_ERR,
|
||||
"%s() failed (%s), %s",
|
||||
WAITFN, sm_errstring(errno),
|
||||
pcnt >= MAX_FAILS_S ? "abort" : "try again");
|
||||
|
||||
if (pcnt >= MAX_FAILS_S)
|
||||
goto err;
|
||||
}
|
||||
pcnt = 0;
|
||||
|
||||
/* something happened */
|
||||
for (i = 0; i < nfd; i++)
|
||||
{
|
||||
if (pfd[i].revents == 0)
|
||||
continue;
|
||||
|
||||
POOL_LEV_DPRINTF(4, ("%s event on pfd[%d/%d]=%d ",
|
||||
WAITFN, i, nfd,
|
||||
WAIT_FD(i)));
|
||||
|
||||
/* has a worker signaled an end of task ? */
|
||||
if (WAIT_FD(i) == RD_PIPE)
|
||||
{
|
||||
char evt = 0;
|
||||
int r = 0;
|
||||
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("PIPE WILL READ evt = %08X %08X",
|
||||
pfd[i].events, pfd[i].revents));
|
||||
|
||||
if ((pfd[i].revents & MI_POLL_RD_FLAGS) != 0)
|
||||
{
|
||||
r = read(RD_PIPE, &evt, sizeof(evt));
|
||||
if (r == sizeof(evt))
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
}
|
||||
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("PIPE DONE READ i=[%d] fd=[%d] r=[%d] evt=[%d]",
|
||||
i, RD_PIPE, r, evt));
|
||||
|
||||
if ((pfd[i].revents & ~MI_POLL_RD_FLAGS) != 0)
|
||||
{
|
||||
/* Exception handling */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* no ! sendmail wants to send a command */
|
||||
SM_TAILQ_FOREACH(ctx, &WRK_CTX_HEAD, ctx_link)
|
||||
{
|
||||
if (ctx->ctx_wstate != WKST_WAITING)
|
||||
continue;
|
||||
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("Checking context sd=%d - fd=%d ",
|
||||
ctx->ctx_sd , WAIT_FD(i)));
|
||||
|
||||
if (ctx->ctx_sd == pfd[i].fd)
|
||||
{
|
||||
TASKMGR_LOCK();
|
||||
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("TASK: found %d for fd[%d]=%d",
|
||||
ctx->ctx_sid, i, WAIT_FD(i)));
|
||||
|
||||
if (Tskmgr.tm_nb_idle > 0)
|
||||
{
|
||||
ctx->ctx_wstate = WKST_READY_TO_RUN;
|
||||
TASKMGR_COND_SIGNAL();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->ctx_wstate = WKST_RUNNING;
|
||||
LAUNCH_WORKER(ctx);
|
||||
}
|
||||
TASKMGR_UNLOCK();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("TASK %s FOUND - Checking PIPE for fd[%d]",
|
||||
ctx != NULL ? "" : "NOT", WAIT_FD(i)));
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (pfd != NULL)
|
||||
free(pfd);
|
||||
|
||||
Tskmgr.tm_signature = 0;
|
||||
for (;;)
|
||||
{
|
||||
SMFICTX_PTR ctx;
|
||||
|
||||
ctx = SM_TAILQ_FIRST(&WRK_CTX_HEAD);
|
||||
if (ctx == NULL)
|
||||
break;
|
||||
mi_close_session(ctx);
|
||||
}
|
||||
|
||||
(void) smutex_destroy(&Tskmgr.tm_w_mutex);
|
||||
(void) scond_destroy(&Tskmgr.tm_w_cond);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** Look for a task ready to run.
|
||||
** Value of ctx is NULL or a pointer to a task ready to run.
|
||||
*/
|
||||
|
||||
#define GET_TASK_READY_TO_RUN() \
|
||||
SM_TAILQ_FOREACH(ctx, &WRK_CTX_HEAD, ctx_link) \
|
||||
{ \
|
||||
if (ctx->ctx_wstate == WKST_READY_TO_RUN) \
|
||||
{ \
|
||||
ctx->ctx_wstate = WKST_RUNNING; \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_WORKER -- worker thread
|
||||
** executes tasks distributed by the mi_pool_controller
|
||||
** or by mi_start_session
|
||||
**
|
||||
** Parameters:
|
||||
** arg -- pointer to context structure
|
||||
**
|
||||
** Returns:
|
||||
** NULL pointer
|
||||
*/
|
||||
|
||||
static void *
|
||||
mi_worker(arg)
|
||||
void *arg;
|
||||
{
|
||||
SMFICTX_PTR ctx;
|
||||
bool done;
|
||||
sthread_t t_id;
|
||||
int r;
|
||||
|
||||
ctx = (SMFICTX_PTR) arg;
|
||||
done = false;
|
||||
if (ctx != NULL)
|
||||
ctx->ctx_wstate = WKST_RUNNING;
|
||||
|
||||
t_id = sthread_get_id();
|
||||
if (pthread_detach(t_id) != 0)
|
||||
{
|
||||
smi_log(SMI_LOG_ERR, "Failed to detach worker thread");
|
||||
if (ctx != NULL)
|
||||
ctx->ctx_wstate = WKST_READY_TO_RUN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TASKMGR_LOCK();
|
||||
Tskmgr.tm_nb_workers++;
|
||||
TASKMGR_UNLOCK();
|
||||
|
||||
while (!done)
|
||||
{
|
||||
if (mi_stop() != MILTER_CONT)
|
||||
break;
|
||||
|
||||
/* let's handle next task... */
|
||||
if (ctx != NULL)
|
||||
{
|
||||
int res;
|
||||
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("worker %d: new task -> let's handle it",
|
||||
t_id));
|
||||
res = mi_engine(ctx);
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("worker %d: mi_engine returned %d", t_id, res));
|
||||
|
||||
TASKMGR_LOCK();
|
||||
if (res != MI_CONTINUE)
|
||||
{
|
||||
ctx->ctx_wstate = WKST_CLOSING;
|
||||
|
||||
/*
|
||||
** Delete context from linked list of
|
||||
** sessions and close session.
|
||||
*/
|
||||
|
||||
mi_close_session(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->ctx_wstate = WKST_READY_TO_WAIT;
|
||||
|
||||
POOL_LEV_DPRINTF(4,
|
||||
("writing to event pipe..."));
|
||||
|
||||
/*
|
||||
** Signal task controller to add new session
|
||||
** to poll set.
|
||||
*/
|
||||
|
||||
PIPE_SEND_SIGNAL();
|
||||
}
|
||||
TASKMGR_UNLOCK();
|
||||
ctx = NULL;
|
||||
|
||||
}
|
||||
|
||||
/* check if there is any task waiting to be served */
|
||||
TASKMGR_LOCK();
|
||||
|
||||
GET_TASK_READY_TO_RUN();
|
||||
|
||||
/* Got a task? */
|
||||
if (ctx != NULL)
|
||||
{
|
||||
TASKMGR_UNLOCK();
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** if not, let's check if there is enough idle workers
|
||||
** if yes: quit
|
||||
*/
|
||||
|
||||
if (Tskmgr.tm_nb_workers > MIN_WORKERS &&
|
||||
Tskmgr.tm_nb_idle > MIN_IDLE)
|
||||
done = true;
|
||||
|
||||
POOL_LEV_DPRINTF(4, ("worker %d: checking ... %d %d", t_id,
|
||||
Tskmgr.tm_nb_workers, Tskmgr.tm_nb_idle + 1));
|
||||
|
||||
if (done)
|
||||
{
|
||||
POOL_LEV_DPRINTF(4, ("worker %d: quitting... ", t_id));
|
||||
Tskmgr.tm_nb_workers--;
|
||||
TASKMGR_UNLOCK();
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** if no task ready to run, wait for another one
|
||||
*/
|
||||
|
||||
Tskmgr.tm_nb_idle++;
|
||||
TASKMGR_COND_WAIT();
|
||||
Tskmgr.tm_nb_idle--;
|
||||
|
||||
/* look for a task */
|
||||
GET_TASK_READY_TO_RUN();
|
||||
|
||||
TASKMGR_UNLOCK();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_LIST_ADD_CTX -- add new session to linked list
|
||||
**
|
||||
** Parameters:
|
||||
** ctx -- context structure
|
||||
**
|
||||
** Returns:
|
||||
** MI_FAILURE/MI_SUCCESS
|
||||
*/
|
||||
|
||||
static int
|
||||
mi_list_add_ctx(ctx)
|
||||
SMFICTX_PTR ctx;
|
||||
{
|
||||
SM_ASSERT(ctx != NULL);
|
||||
SM_TAILQ_INSERT_TAIL(&WRK_CTX_HEAD, ctx, ctx_link);
|
||||
return MI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
** MI_LIST_DEL_CTX -- remove session from linked list when finished
|
||||
**
|
||||
** Parameters:
|
||||
** ctx -- context structure
|
||||
**
|
||||
** Returns:
|
||||
** MI_FAILURE/MI_SUCCESS
|
||||
*/
|
||||
|
||||
static int
|
||||
mi_list_del_ctx(ctx)
|
||||
SMFICTX_PTR ctx;
|
||||
{
|
||||
SM_ASSERT(ctx != NULL);
|
||||
if (SM_TAILQ_EMPTY(&WRK_CTX_HEAD))
|
||||
return MI_FAILURE;
|
||||
|
||||
SM_TAILQ_REMOVE(&WRK_CTX_HEAD, ctx, ctx_link);
|
||||
return MI_SUCCESS;
|
||||
}
|
||||
#endif /* _FFR_WORKERS_POOL */
|
235
contrib/sendmail/libsm/t-qic.c
Normal file
235
contrib/sendmail/libsm/t-qic.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*/
|
||||
|
||||
#include <sm/gen.h>
|
||||
SM_IDSTR(id, "@(#)$Id: t-qic.c,v 1.9 2006/08/24 21:26:13 ca Exp $")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sm/sendmail.h>
|
||||
#include <sm/assert.h>
|
||||
#include <sm/heap.h>
|
||||
#include <sm/string.h>
|
||||
#include <sm/test.h>
|
||||
|
||||
extern bool SmTestVerbose;
|
||||
|
||||
|
||||
void
|
||||
show_diff(s1, s2)
|
||||
const char *s1;
|
||||
const char *s2;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; s1[i] != '\0' && s2[i] != '\0'; i++)
|
||||
{
|
||||
if (s1[i] != s2[i])
|
||||
{
|
||||
fprintf(stderr, "i=%d, s1[]=%u, s2[]=%u\n",
|
||||
i, (unsigned char) s1[i],
|
||||
(unsigned char) s2[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (s1[i] != s2[i])
|
||||
{
|
||||
fprintf(stderr, "i=%d, s1[]=%u, s2[]=%u\n",
|
||||
i, (unsigned char) s1[i], (unsigned char) s2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char *quote_unquote __P((char *, char *, int, int));
|
||||
|
||||
char *
|
||||
quote_unquote(in, out, outlen, exp)
|
||||
char *in;
|
||||
char *out;
|
||||
int outlen;
|
||||
int exp;
|
||||
{
|
||||
char *obp, *bp;
|
||||
char line_back[1024];
|
||||
char line_in[1024];
|
||||
int cmp;
|
||||
|
||||
sm_strlcpy(line_in, in, sizeof(line_in));
|
||||
obp = quote_internal_chars(in, out, &outlen);
|
||||
bp = str2prt(line_in);
|
||||
dequote_internal_chars(obp, line_back, sizeof(line_back));
|
||||
cmp = strcmp(line_in, line_back);
|
||||
SM_TEST(exp == cmp);
|
||||
if (cmp != exp && !SmTestVerbose)
|
||||
{
|
||||
fprintf(stderr, "in: %s\n", bp);
|
||||
bp = str2prt(line_back);
|
||||
fprintf(stderr, "out:%s\n", bp);
|
||||
fprintf(stderr, "cmp=%d\n", cmp);
|
||||
show_diff(in, line_back);
|
||||
}
|
||||
if (SmTestVerbose)
|
||||
{
|
||||
fprintf(stderr, "%s -> ", bp);
|
||||
bp = str2prt(obp);
|
||||
fprintf(stderr, "%s\n", bp);
|
||||
fprintf(stderr, "cmp=%d\n", cmp);
|
||||
}
|
||||
return obp;
|
||||
}
|
||||
|
||||
struct sm_qic_S
|
||||
{
|
||||
char *qic_in;
|
||||
char *qic_out;
|
||||
int qic_exp;
|
||||
};
|
||||
|
||||
typedef struct sm_qic_S sm_qic_T;
|
||||
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char line_in[1024], line[256], line_out[32], *obp;
|
||||
int i, los, cmp;
|
||||
sm_qic_T inout[] = {
|
||||
{ "", "", 0 }
|
||||
, { "abcdef", "abcdef", 0 }
|
||||
, { "01234567890123456789", "01234567890123456789", 0 }
|
||||
, { "01234567890123456789\001", "01234567890123456789\001",
|
||||
0 }
|
||||
, { "012345\2067890123456789", "012345\377\2067890123456789",
|
||||
0 }
|
||||
, { "\377", "\377\377", 0 }
|
||||
, { "\240", "\240", 0 }
|
||||
, { "\220", "\377\220", 0 }
|
||||
, { "\240\220", "\240\377\220", 0 }
|
||||
, { "\377\377", "\377\377\377\377", 0 }
|
||||
, { "\377a\377b", "\377\377a\377\377b", 0 }
|
||||
, { "\376a\377b", "\376a\377\377b", 0 }
|
||||
, { "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240",
|
||||
"\377\200\377\201\377\202\377\203\377\204\377\205\377\206\377\207\377\210\377\211\377\212\377\213\377\214\377\215\377\216\377\217\377\220\377\221\377\222\377\223\377\224\377\225\377\226\377\227\377\230\377\231\377\232\377\233\377\234\377\235\377\236\377\237\240",
|
||||
0 }
|
||||
, { NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
sm_test_begin(argc, argv, "test meta quoting");
|
||||
for (i = 0; i < sizeof(line_out); i++)
|
||||
line_out[i] = '\0';
|
||||
for (i = 0; i < sizeof(line_in); i++)
|
||||
line_in[i] = '\0';
|
||||
for (i = 0; i < sizeof(line_in) / 2; i++)
|
||||
{
|
||||
char ch;
|
||||
|
||||
ch = 0200 + i;
|
||||
if ('\0' == ch)
|
||||
ch = '0';
|
||||
line_in[i] = ch;
|
||||
}
|
||||
los = sizeof(line_out) / 2;
|
||||
obp = quote_unquote(line_in, line_out, los, 0);
|
||||
if (obp != line_out)
|
||||
SM_FREE(obp);
|
||||
|
||||
for (i = 0; i < sizeof(line_in); i++)
|
||||
line_in[i] = '\0';
|
||||
for (i = 0; i < sizeof(line_in) / 2; i++)
|
||||
{
|
||||
char ch;
|
||||
|
||||
ch = 0200 + i;
|
||||
if ('\0' == ch)
|
||||
ch = '0';
|
||||
line_in[i] = ch;
|
||||
}
|
||||
los = sizeof(line_in);
|
||||
obp = quote_unquote(line_in, line_in, los, 0);
|
||||
if (obp != line_in)
|
||||
SM_FREE(obp);
|
||||
|
||||
for (i = 0; inout[i].qic_in != NULL; i++)
|
||||
{
|
||||
los = sizeof(line_out) / 2;
|
||||
obp = quote_unquote(inout[i].qic_in, line_out, los,
|
||||
inout[i].qic_exp);
|
||||
cmp = strcmp(inout[i].qic_out, obp);
|
||||
SM_TEST(inout[i].qic_exp == cmp);
|
||||
if (inout[i].qic_exp != cmp && !SmTestVerbose)
|
||||
{
|
||||
char *bp;
|
||||
|
||||
bp = str2prt(obp);
|
||||
fprintf(stderr, "got: %s\n", bp);
|
||||
bp = str2prt(inout[i].qic_out);
|
||||
fprintf(stderr, "exp:%s\n", bp);
|
||||
fprintf(stderr, "cmp=%d\n", cmp);
|
||||
show_diff(inout[i].qic_in, inout[i].qic_out);
|
||||
}
|
||||
if (obp != line_out)
|
||||
SM_FREE(obp);
|
||||
}
|
||||
|
||||
/* use same buffer for in and out */
|
||||
for (i = 0; inout[i].qic_in != NULL; i++)
|
||||
{
|
||||
bool same;
|
||||
|
||||
same = strcmp(inout[i].qic_in, inout[i].qic_out) == 0;
|
||||
los = sm_strlcpy(line, inout[i].qic_in, sizeof(line));
|
||||
SM_TEST(los + 1 < sizeof(line));
|
||||
++los;
|
||||
obp = quote_unquote(line, line, los, inout[i].qic_exp);
|
||||
cmp = strcmp(inout[i].qic_out, obp);
|
||||
SM_TEST(inout[i].qic_exp == cmp);
|
||||
if (inout[i].qic_exp != cmp && !SmTestVerbose)
|
||||
{
|
||||
char *bp;
|
||||
|
||||
bp = str2prt(obp);
|
||||
fprintf(stderr, "got: %s\n", bp);
|
||||
bp = str2prt(inout[i].qic_out);
|
||||
fprintf(stderr, "exp:%s\n", bp);
|
||||
fprintf(stderr, "cmp=%d\n", cmp);
|
||||
show_diff(inout[i].qic_in, inout[i].qic_out);
|
||||
}
|
||||
if (obp != line)
|
||||
{
|
||||
SM_TEST(!same);
|
||||
if (same)
|
||||
show_diff(obp, inout[i].qic_out);
|
||||
SM_FREE(obp);
|
||||
}
|
||||
}
|
||||
|
||||
/* use NULL buffer for out */
|
||||
for (i = 0; inout[i].qic_in != NULL; i++)
|
||||
{
|
||||
los = 0;
|
||||
obp = quote_unquote(inout[i].qic_in, NULL, los,
|
||||
inout[i].qic_exp);
|
||||
SM_TEST(obp != NULL);
|
||||
cmp = strcmp(inout[i].qic_out, obp);
|
||||
SM_TEST(inout[i].qic_exp == cmp);
|
||||
if (inout[i].qic_exp != cmp && !SmTestVerbose)
|
||||
{
|
||||
char *bp;
|
||||
|
||||
bp = str2prt(obp);
|
||||
fprintf(stderr, "got: %s\n", bp);
|
||||
bp = str2prt(inout[i].qic_out);
|
||||
fprintf(stderr, "exp:%s\n", bp);
|
||||
fprintf(stderr, "cmp=%d\n", cmp);
|
||||
show_diff(inout[i].qic_in, inout[i].qic_out);
|
||||
}
|
||||
}
|
||||
|
||||
return sm_test_end();
|
||||
}
|
250
contrib/sendmail/libsm/util.c
Normal file
250
contrib/sendmail/libsm/util.c
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sm/gen.h>
|
||||
|
||||
SM_RCSID("@(#)$Id: util.c,v 1.9 2006/08/30 18:35:51 ca Exp $")
|
||||
#include <sm/setjmp.h>
|
||||
#include <sm/conf.h>
|
||||
#include <sm/assert.h>
|
||||
#include <sm/heap.h>
|
||||
#include <sm/string.h>
|
||||
#include <sm/sendmail.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** STR2PRT -- convert "unprintable" characters in a string to \oct
|
||||
**
|
||||
** Parameters:
|
||||
** s -- string to convert
|
||||
**
|
||||
** Returns:
|
||||
** converted string.
|
||||
** This is a static local buffer, string must be copied
|
||||
** before this function is called again!
|
||||
*/
|
||||
|
||||
char *
|
||||
str2prt(s)
|
||||
char *s;
|
||||
{
|
||||
int l;
|
||||
char c, *h;
|
||||
bool ok;
|
||||
static int len = 0;
|
||||
static char *buf = NULL;
|
||||
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
ok = true;
|
||||
for (h = s, l = 1; *h != '\0'; h++, l++)
|
||||
{
|
||||
if (*h == '\\')
|
||||
{
|
||||
++l;
|
||||
ok = false;
|
||||
}
|
||||
else if (!(isascii(*h) && isprint(*h)))
|
||||
{
|
||||
l += 3;
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok)
|
||||
return s;
|
||||
if (l > len)
|
||||
{
|
||||
char *nbuf = sm_pmalloc_x(l);
|
||||
|
||||
if (buf != NULL)
|
||||
sm_free(buf);
|
||||
len = l;
|
||||
buf = nbuf;
|
||||
}
|
||||
for (h = buf; *s != '\0' && l > 0; s++, l--)
|
||||
{
|
||||
c = *s;
|
||||
if (isascii(c) && isprint(c) && c != '\\')
|
||||
{
|
||||
*h++ = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
*h++ = '\\';
|
||||
--l;
|
||||
switch (c)
|
||||
{
|
||||
case '\\':
|
||||
*h++ = '\\';
|
||||
break;
|
||||
case '\t':
|
||||
*h++ = 't';
|
||||
break;
|
||||
case '\n':
|
||||
*h++ = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*h++ = 'r';
|
||||
break;
|
||||
default:
|
||||
SM_ASSERT(l >= 2);
|
||||
(void) sm_snprintf(h, l, "%03o",
|
||||
(unsigned int)((unsigned char) c));
|
||||
|
||||
/*
|
||||
** XXX since l is unsigned this may
|
||||
** wrap around if the calculation is screwed
|
||||
** up...
|
||||
*/
|
||||
|
||||
l -= 2;
|
||||
h += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*h = '\0';
|
||||
buf[len - 1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
** QUOTE_INTERNAL_CHARS -- do quoting of internal characters
|
||||
**
|
||||
** Necessary to make sure that we don't have metacharacters such
|
||||
** as the internal versions of "$*" or "$&" in a string.
|
||||
** The input and output pointers can be the same.
|
||||
**
|
||||
** Parameters:
|
||||
** ibp -- a pointer to the string to translate
|
||||
** obp -- a pointer to an output buffer
|
||||
** bsp -- pointer to the length of the output buffer
|
||||
**
|
||||
** Returns:
|
||||
** A possibly new bp (if the buffer needed to grow); if
|
||||
** it is different, *bsp will updated to the size of
|
||||
** the new buffer and the caller is responsible for
|
||||
** freeing the memory.
|
||||
*/
|
||||
|
||||
#define SM_MM_QUOTE(ch) (((ch) & 0377) == METAQUOTE || (((ch) & 0340) == 0200))
|
||||
|
||||
char *
|
||||
quote_internal_chars(ibp, obp, bsp)
|
||||
char *ibp;
|
||||
char *obp;
|
||||
int *bsp;
|
||||
{
|
||||
char *ip, *op;
|
||||
int bufused, olen;
|
||||
bool buffer_same, needs_quoting;
|
||||
|
||||
buffer_same = ibp == obp;
|
||||
needs_quoting = false;
|
||||
|
||||
/* determine length of output string (starts at 1 for trailing '\0') */
|
||||
for (ip = ibp, olen = 1; *ip != '\0'; ip++, olen++)
|
||||
{
|
||||
if (SM_MM_QUOTE(*ip))
|
||||
{
|
||||
olen++;
|
||||
needs_quoting = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* is the output buffer big enough? */
|
||||
if (olen > *bsp)
|
||||
{
|
||||
obp = sm_malloc_x(olen);
|
||||
buffer_same = false;
|
||||
*bsp = olen;
|
||||
}
|
||||
|
||||
/*
|
||||
** shortcut: no change needed?
|
||||
** Note: we don't check this first as some bozo may use the same
|
||||
** buffers but restrict the size of the output buffer to less
|
||||
** than the length of the input buffer in which case we need to
|
||||
** allocate a new buffer.
|
||||
*/
|
||||
|
||||
if (!needs_quoting)
|
||||
{
|
||||
if (!buffer_same)
|
||||
{
|
||||
bufused = sm_strlcpy(obp, ibp, *bsp);
|
||||
SM_ASSERT(bufused <= olen);
|
||||
}
|
||||
return obp;
|
||||
}
|
||||
|
||||
if (buffer_same)
|
||||
{
|
||||
obp = sm_malloc_x(olen);
|
||||
buffer_same = false;
|
||||
*bsp = olen;
|
||||
}
|
||||
|
||||
for (ip = ibp, op = obp, bufused = 0; *ip != '\0'; ip++)
|
||||
{
|
||||
if (SM_MM_QUOTE(*ip))
|
||||
{
|
||||
SM_ASSERT(bufused < olen);
|
||||
op[bufused++] = METAQUOTE;
|
||||
}
|
||||
SM_ASSERT(bufused < olen);
|
||||
op[bufused++] = *ip;
|
||||
}
|
||||
op[bufused] = '\0';
|
||||
return obp;
|
||||
}
|
||||
|
||||
/*
|
||||
** DEQUOTE_INTERNAL_CHARS -- undo the effect of quote_internal_chars
|
||||
**
|
||||
** Parameters:
|
||||
** ibp -- a pointer to the string to be translated.
|
||||
** obp -- a pointer to the output buffer. Can be the
|
||||
** same as ibp.
|
||||
** obs -- the size of the output buffer.
|
||||
**
|
||||
** Returns:
|
||||
** number of character added to obp
|
||||
*/
|
||||
|
||||
int
|
||||
dequote_internal_chars(ibp, obp, obs)
|
||||
char *ibp;
|
||||
char *obp;
|
||||
int obs;
|
||||
{
|
||||
char *ip, *op;
|
||||
int len;
|
||||
bool quoted;
|
||||
|
||||
quoted = false;
|
||||
len = 0;
|
||||
for (ip = ibp, op = obp; *ip != '\0'; ip++)
|
||||
{
|
||||
if ((*ip & 0377) == METAQUOTE && !quoted)
|
||||
{
|
||||
quoted = true;
|
||||
continue;
|
||||
}
|
||||
if (op < &obp[obs - 1])
|
||||
{
|
||||
*op++ = *ip;
|
||||
++len;
|
||||
}
|
||||
quoted = false;
|
||||
}
|
||||
*op = '\0';
|
||||
return len;
|
||||
}
|
62
contrib/sendmail/src/daemon.h
Normal file
62
contrib/sendmail/src/daemon.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*
|
||||
* $Id: daemon.h,v 8.3 2006/07/13 22:57:03 ca Exp $
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_H
|
||||
#define DAEMON_H 1
|
||||
|
||||
#if DAEMON_C
|
||||
# define EXTERN
|
||||
#else
|
||||
# define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* structure to describe a daemon or a client */
|
||||
struct daemon
|
||||
{
|
||||
int d_socket; /* fd for socket */
|
||||
SOCKADDR d_addr; /* socket for incoming */
|
||||
unsigned short d_port; /* port number */
|
||||
int d_listenqueue; /* size of listen queue */
|
||||
int d_tcprcvbufsize; /* size of TCP receive buffer */
|
||||
int d_tcpsndbufsize; /* size of TCP send buffer */
|
||||
time_t d_refuse_connections_until;
|
||||
bool d_firsttime;
|
||||
int d_socksize;
|
||||
BITMAP256 d_flags; /* flags; see sendmail.h */
|
||||
char *d_mflags; /* flags for use in macro */
|
||||
char *d_name; /* user-supplied name */
|
||||
|
||||
int d_dm; /* DeliveryMode */
|
||||
int d_refuseLA;
|
||||
int d_queueLA;
|
||||
int d_delayLA;
|
||||
int d_maxchildren;
|
||||
|
||||
#if MILTER
|
||||
char *d_inputfilterlist;
|
||||
struct milter *d_inputfilters[MAXFILTERS];
|
||||
#endif /* MILTER */
|
||||
#if _FFR_SS_PER_DAEMON
|
||||
int d_supersafe;
|
||||
#endif /* _FFR_SS_PER_DAEMON */
|
||||
};
|
||||
|
||||
typedef struct daemon DAEMON_T;
|
||||
|
||||
EXTERN DAEMON_T Daemons[MAXDAEMONS];
|
||||
|
||||
#define DPO_NOTSET (-1) /* daemon option (int) not set */
|
||||
/* see also sendmail.h: SuperSafe values */
|
||||
|
||||
extern bool refuseconnections __P((ENVELOPE *, int, bool));
|
||||
|
||||
#undef EXTERN
|
||||
#endif /* ! DAEMON_H */
|
86
contrib/sendmail/src/map.h
Normal file
86
contrib/sendmail/src/map.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sendmail, Inc. and its suppliers.
|
||||
* All rights reserved.
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the sendmail distribution.
|
||||
*
|
||||
* $Id: map.h,v 8.3 2006/12/19 19:49:51 ca Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MAP_H
|
||||
# define _MAP_H 1
|
||||
|
||||
extern char *arith_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern char *bestmx_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern char *bogus_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool bt_map_open __P((MAP *, int));
|
||||
|
||||
extern char *db_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern void db_map_store __P((MAP *, char *, char *));
|
||||
extern void db_map_close __P((MAP *));
|
||||
|
||||
extern bool dequote_init __P((MAP *, char *));
|
||||
extern char *dequote_map __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool dns_map_open __P((MAP *, int));
|
||||
extern bool dns_map_parseargs __P((MAP *, char *));
|
||||
extern char *dns_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool dprintf_map_parseargs __P((MAP *, char *));
|
||||
extern char *dprintf_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool hash_map_open __P((MAP *, int));
|
||||
|
||||
extern bool host_map_init __P((MAP *, char *));
|
||||
extern char *host_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern char *impl_map_lookup __P((MAP *, char *, char **, int *));
|
||||
extern void impl_map_store __P((MAP *, char *, char *));
|
||||
extern bool impl_map_open __P((MAP *, int));
|
||||
extern void impl_map_close __P((MAP *));
|
||||
|
||||
extern char *macro_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool map_parseargs __P((MAP *, char *));
|
||||
|
||||
extern bool nis_map_open __P((MAP *, int));
|
||||
extern char *nis_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool null_map_open __P((MAP *, int));
|
||||
extern void null_map_close __P((MAP *));
|
||||
extern char *null_map_lookup __P((MAP *, char *, char **, int *));
|
||||
extern void null_map_store __P((MAP *, char *, char *));
|
||||
|
||||
extern char *prog_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool regex_map_init __P((MAP *, char *));
|
||||
extern char *regex_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern char *seq_map_lookup __P((MAP *, char *, char **, int *));
|
||||
extern void seq_map_store __P((MAP *, char *, char *));
|
||||
extern bool seq_map_parse __P((MAP *, char *));
|
||||
|
||||
extern char *stab_map_lookup __P((MAP *, char *, char **, int *));
|
||||
extern void stab_map_store __P((MAP *, char *, char *));
|
||||
extern bool stab_map_open __P((MAP *, int));
|
||||
|
||||
extern bool switch_map_open __P((MAP *, int));
|
||||
|
||||
extern bool syslog_map_parseargs __P((MAP *, char *));
|
||||
extern char *syslog_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool text_map_open __P((MAP *, int));
|
||||
extern char *text_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern char *udb_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
extern bool user_map_open __P((MAP *, int));
|
||||
extern char *user_map_lookup __P((MAP *, char *, char **, int *));
|
||||
|
||||
#endif /* ! _MAP_H */
|
12
etc/rc.d/FILESYSTEMS
Normal file
12
etc/rc.d/FILESYSTEMS
Normal file
@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
# PROVIDE: FILESYSTEMS
|
||||
# REQUIRE: root mountcritlocal zfs
|
||||
|
||||
# This is a dummy dependency, for services which require file systems
|
||||
# to be mounted before starting. It also serves as the default early /
|
||||
# late divider; after this point, rc.d directories are rescanned to
|
||||
# catch scripts from other file systems than /.
|
111
share/man/man4/edsc.4
Normal file
111
share/man/man4/edsc.4
Normal file
@ -0,0 +1,111 @@
|
||||
.\" Copyright (c) 1983, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" From: @(#)lo.4 8.1 (Berkeley) 6/5/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 25, 2007
|
||||
.Dt EDSC 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm edsc
|
||||
.Nd Ethernet discard network interface
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device edsc"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
interface is a software discard mechanism which may be
|
||||
used for performance analysis and software testing.
|
||||
It imitates an Ethernet device, which
|
||||
allows for its use in conjunction with such drivers as
|
||||
.Xr if_bridge 4
|
||||
and
|
||||
.Xr vlan 4 .
|
||||
.Pp
|
||||
As with other network interfaces, an
|
||||
.Nm
|
||||
interface must have network addresses assigned for each address family
|
||||
with which it is to be used.
|
||||
These addresses may be set or changed with the
|
||||
.Dv SIOCSIFADDR
|
||||
.Xr ioctl 2
|
||||
or
|
||||
.Xr ifconfig 8
|
||||
utility.
|
||||
.Pp
|
||||
Each
|
||||
.Nm
|
||||
interface is created at runtime using interface cloning.
|
||||
This is most easily done with the
|
||||
.Xr ifconfig 8
|
||||
.Cm create
|
||||
command or using the
|
||||
.Va cloned_interfaces
|
||||
variable in
|
||||
.Xr rc.conf 5 .
|
||||
.Sh SEE ALSO
|
||||
.Xr ioctl 2 ,
|
||||
.Xr arp 4 ,
|
||||
.Xr if_bridge 4 ,
|
||||
.Xr inet 4 ,
|
||||
.Xr intro 4 ,
|
||||
.Xr vlan 4 ,
|
||||
.Xr rc.conf 5 ,
|
||||
.Xr arp 8 ,
|
||||
.Xr ifconfig 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
device was derived from the
|
||||
.Xr disc 4
|
||||
device and first appeared in
|
||||
.Fx 7.0 .
|
||||
This manpage was adapted from
|
||||
.Xr disc 4 .
|
||||
.Sh CAVEATS
|
||||
Since outgoing packets are just discarded by
|
||||
.Nm ,
|
||||
ARP requests stay unreplied.
|
||||
Consequently, an IP packet cannot be sent via
|
||||
.Nm
|
||||
until a static
|
||||
.Xr arp 4
|
||||
entry is created for its next hop using
|
||||
.Xr arp 8 .
|
||||
.Pp
|
||||
Initially an
|
||||
.Nm
|
||||
interface has a zero link level address.
|
||||
It can be changed with
|
||||
.Xr ifconfig 8
|
||||
.Cm lladdr
|
||||
if needed.
|
994
sys/cam/scsi/scsi_sg.c
Normal file
994
sys/cam/scsi/scsi_sg.c
Normal file
@ -0,0 +1,994 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Scott Long
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* scsi_sg peripheral driver. This driver is meant to implement the Linux
|
||||
* SG passthrough interface for SCSI.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/bio.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/devicestat.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_periph.h>
|
||||
#include <cam/cam_queue.h>
|
||||
#include <cam/cam_xpt_periph.h>
|
||||
#include <cam/cam_debug.h>
|
||||
#include <cam/cam_sim.h>
|
||||
|
||||
#include <cam/scsi/scsi_all.h>
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
#include <cam/scsi/scsi_sg.h>
|
||||
|
||||
#include <compat/linux/linux_ioctl.h>
|
||||
|
||||
typedef enum {
|
||||
SG_FLAG_OPEN = 0x01,
|
||||
SG_FLAG_LOCKED = 0x02,
|
||||
SG_FLAG_INVALID = 0x04
|
||||
} sg_flags;
|
||||
|
||||
typedef enum {
|
||||
SG_STATE_NORMAL
|
||||
} sg_state;
|
||||
|
||||
typedef enum {
|
||||
SG_RDWR_FREE,
|
||||
SG_RDWR_INPROG,
|
||||
SG_RDWR_DONE
|
||||
} sg_rdwr_state;
|
||||
|
||||
typedef enum {
|
||||
SG_CCB_RDWR_IO,
|
||||
SG_CCB_WAITING
|
||||
} sg_ccb_types;
|
||||
|
||||
#define ccb_type ppriv_field0
|
||||
#define ccb_rdwr ppriv_ptr1
|
||||
|
||||
struct sg_rdwr {
|
||||
TAILQ_ENTRY(sg_rdwr) rdwr_link;
|
||||
int tag;
|
||||
int state;
|
||||
int buf_len;
|
||||
char *buf;
|
||||
union ccb *ccb;
|
||||
union {
|
||||
struct sg_header hdr;
|
||||
struct sg_io_hdr io_hdr;
|
||||
} hdr;
|
||||
};
|
||||
|
||||
struct sg_softc {
|
||||
sg_state state;
|
||||
sg_flags flags;
|
||||
struct devstat *device_stats;
|
||||
TAILQ_HEAD(, sg_rdwr) rdwr_done;
|
||||
struct cdev *dev;
|
||||
struct cdev *devalias;
|
||||
int sg_timeout;
|
||||
int sg_user_timeout;
|
||||
uint8_t pd_type;
|
||||
union ccb saved_ccb;
|
||||
};
|
||||
|
||||
static d_open_t sgopen;
|
||||
static d_close_t sgclose;
|
||||
static d_ioctl_t sgioctl;
|
||||
static d_write_t sgwrite;
|
||||
static d_read_t sgread;
|
||||
|
||||
static periph_init_t sginit;
|
||||
static periph_ctor_t sgregister;
|
||||
static periph_oninv_t sgoninvalidate;
|
||||
static periph_dtor_t sgcleanup;
|
||||
static periph_start_t sgstart;
|
||||
static void sgasync(void *callback_arg, uint32_t code,
|
||||
struct cam_path *path, void *arg);
|
||||
static void sgdone(struct cam_periph *periph, union ccb *done_ccb);
|
||||
static int sgsendccb(struct cam_periph *periph, union ccb *ccb);
|
||||
static int sgsendrdwr(struct cam_periph *periph, union ccb *ccb);
|
||||
static int sgerror(union ccb *ccb, uint32_t cam_flags,
|
||||
uint32_t sense_flags);
|
||||
static void sg_scsiio_status(struct ccb_scsiio *csio,
|
||||
u_short *hoststat, u_short *drvstat);
|
||||
|
||||
static int scsi_group_len(u_char cmd);
|
||||
|
||||
static struct periph_driver sgdriver =
|
||||
{
|
||||
sginit, "sg",
|
||||
TAILQ_HEAD_INITIALIZER(sgdriver.units), /* gen */ 0
|
||||
};
|
||||
PERIPHDRIVER_DECLARE(sg, sgdriver);
|
||||
|
||||
static struct cdevsw sg_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_flags = D_NEEDGIANT,
|
||||
.d_open = sgopen,
|
||||
.d_close = sgclose,
|
||||
.d_ioctl = sgioctl,
|
||||
.d_write = sgwrite,
|
||||
.d_read = sgread,
|
||||
.d_name = "sg",
|
||||
};
|
||||
|
||||
static int sg_version = 30125;
|
||||
|
||||
static void
|
||||
sginit(void)
|
||||
{
|
||||
cam_status status;
|
||||
struct cam_path *path;
|
||||
|
||||
/*
|
||||
* Install a global async callback. This callback will receive aync
|
||||
* callbacks like "new device found".
|
||||
*/
|
||||
status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
|
||||
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
|
||||
|
||||
if (status == CAM_REQ_CMP) {
|
||||
struct ccb_setasync csa;
|
||||
|
||||
xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = AC_FOUND_DEVICE;
|
||||
csa.callback = sgasync;
|
||||
csa.callback_arg = NULL;
|
||||
xpt_action((union ccb *)&csa);
|
||||
status = csa.ccb_h.status;
|
||||
xpt_free_path(path);
|
||||
}
|
||||
|
||||
if (status != CAM_REQ_CMP) {
|
||||
printf("sg: Failed to attach master async callbac "
|
||||
"due to status 0x%x!\n", status);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sgoninvalidate(struct cam_periph *periph)
|
||||
{
|
||||
struct sg_softc *softc;
|
||||
struct ccb_setasync csa;
|
||||
|
||||
softc = (struct sg_softc *)periph->softc;
|
||||
|
||||
/*
|
||||
* Deregister any async callbacks.
|
||||
*/
|
||||
xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = 0;
|
||||
csa.callback = sgasync;
|
||||
csa.callback_arg = periph;
|
||||
xpt_action((union ccb *)&csa);
|
||||
|
||||
softc->flags |= SG_FLAG_INVALID;
|
||||
|
||||
/*
|
||||
* XXX Return all queued I/O with ENXIO.
|
||||
* XXX Handle any transactions queued to the card
|
||||
* with XPT_ABORT_CCB.
|
||||
*/
|
||||
|
||||
if (bootverbose) {
|
||||
xpt_print(periph->path, "lost device\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sgcleanup(struct cam_periph *periph)
|
||||
{
|
||||
struct sg_softc *softc;
|
||||
|
||||
softc = (struct sg_softc *)periph->softc;
|
||||
devstat_remove_entry(softc->device_stats);
|
||||
destroy_dev(softc->dev);
|
||||
destroy_dev(softc->devalias);
|
||||
if (bootverbose) {
|
||||
xpt_print(periph->path, "removing device entry\n");
|
||||
}
|
||||
free(softc, M_DEVBUF);
|
||||
}
|
||||
|
||||
static void
|
||||
sgasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
|
||||
periph = (struct cam_periph *)callback_arg;
|
||||
|
||||
switch (code) {
|
||||
case AC_FOUND_DEVICE:
|
||||
{
|
||||
struct ccb_getdev *cgd;
|
||||
cam_status status;
|
||||
|
||||
cgd = (struct ccb_getdev *)arg;
|
||||
if (cgd == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Allocate a peripheral instance for this device and
|
||||
* start the probe process.
|
||||
*/
|
||||
status = cam_periph_alloc(sgregister, sgoninvalidate,
|
||||
sgcleanup, sgstart, "sg",
|
||||
CAM_PERIPH_BIO, cgd->ccb_h.path,
|
||||
sgasync, AC_FOUND_DEVICE, cgd);
|
||||
if ((status != CAM_REQ_CMP) && (status != CAM_REQ_INPROG)) {
|
||||
const struct cam_status_entry *entry;
|
||||
|
||||
entry = cam_fetch_status_entry(status);
|
||||
printf("sgasync: Unable to attach new device "
|
||||
"due to status %#x: %s\n", status, entry ?
|
||||
entry->status_text : "Unknown");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cam_periph_async(periph, code, path, arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static cam_status
|
||||
sgregister(struct cam_periph *periph, void *arg)
|
||||
{
|
||||
struct sg_softc *softc;
|
||||
struct ccb_setasync csa;
|
||||
struct ccb_getdev *cgd;
|
||||
int no_tags;
|
||||
|
||||
cgd = (struct ccb_getdev *)arg;
|
||||
if (periph == NULL) {
|
||||
printf("sgregister: periph was NULL!!\n");
|
||||
return (CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
if (cgd == NULL) {
|
||||
printf("sgregister: no getdev CCB, can't register device\n");
|
||||
return (CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
softc = malloc(sizeof(*softc), M_DEVBUF, M_ZERO | M_NOWAIT);
|
||||
if (softc == NULL) {
|
||||
printf("sgregister: Unable to allocate softc\n");
|
||||
return (CAM_REQ_CMP_ERR);
|
||||
}
|
||||
|
||||
softc->state = SG_STATE_NORMAL;
|
||||
softc->pd_type = SID_TYPE(&cgd->inq_data);
|
||||
softc->sg_timeout = SG_DEFAULT_TIMEOUT / SG_DEFAULT_HZ * hz;
|
||||
softc->sg_user_timeout = SG_DEFAULT_TIMEOUT;
|
||||
TAILQ_INIT(&softc->rdwr_done);
|
||||
periph->softc = softc;
|
||||
|
||||
/*
|
||||
* We pass in 0 for all blocksize, since we don't know what the
|
||||
* blocksize of the device is, if it even has a blocksize.
|
||||
*/
|
||||
no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
|
||||
softc->device_stats = devstat_new_entry("sg",
|
||||
unit2minor(periph->unit_number), 0,
|
||||
DEVSTAT_NO_BLOCKSIZE
|
||||
| (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0),
|
||||
softc->pd_type |
|
||||
DEVSTAT_TYPE_IF_SCSI |
|
||||
DEVSTAT_TYPE_PASS,
|
||||
DEVSTAT_PRIORITY_PASS);
|
||||
|
||||
/* Register the device */
|
||||
softc->dev = make_dev(&sg_cdevsw, unit2minor(periph->unit_number),
|
||||
UID_ROOT, GID_OPERATOR, 0600, "%s%d",
|
||||
periph->periph_name, periph->unit_number);
|
||||
softc->devalias = make_dev_alias(softc->dev, "sg%c",
|
||||
'a' + periph->unit_number);
|
||||
softc->dev->si_drv1 = periph;
|
||||
|
||||
/*
|
||||
* Add as async callback so that we get
|
||||
* notified if this device goes away.
|
||||
*/
|
||||
xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
|
||||
csa.ccb_h.func_code = XPT_SASYNC_CB;
|
||||
csa.event_enable = AC_LOST_DEVICE;
|
||||
csa.callback = sgasync;
|
||||
csa.callback_arg = periph;
|
||||
xpt_action((union ccb *)&csa);
|
||||
|
||||
if (bootverbose)
|
||||
xpt_announce_periph(periph, NULL);
|
||||
|
||||
return (CAM_REQ_CMP);
|
||||
}
|
||||
|
||||
static void
|
||||
sgstart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
{
|
||||
struct sg_softc *softc;
|
||||
|
||||
softc = (struct sg_softc *)periph->softc;
|
||||
|
||||
switch (softc->state) {
|
||||
case SG_STATE_NORMAL:
|
||||
start_ccb->ccb_h.ccb_type = SG_CCB_WAITING;
|
||||
SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
|
||||
periph_links.sle);
|
||||
periph->immediate_priority = CAM_PRIORITY_NONE;
|
||||
wakeup(&periph->ccb_list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sgdone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
{
|
||||
struct sg_softc *softc;
|
||||
struct ccb_scsiio *csio;
|
||||
|
||||
softc = (struct sg_softc *)periph->softc;
|
||||
csio = &done_ccb->csio;
|
||||
switch (csio->ccb_h.ccb_type) {
|
||||
case SG_CCB_WAITING:
|
||||
/* Caller will release the CCB */
|
||||
wakeup(&done_ccb->ccb_h.cbfcnp);
|
||||
return;
|
||||
case SG_CCB_RDWR_IO:
|
||||
{
|
||||
struct sg_rdwr *rdwr;
|
||||
int state;
|
||||
|
||||
devstat_end_transaction(softc->device_stats,
|
||||
csio->dxfer_len,
|
||||
csio->tag_action & 0xf,
|
||||
((csio->ccb_h.flags & CAM_DIR_MASK) ==
|
||||
CAM_DIR_NONE) ? DEVSTAT_NO_DATA :
|
||||
(csio->ccb_h.flags & CAM_DIR_OUT) ?
|
||||
DEVSTAT_WRITE : DEVSTAT_READ,
|
||||
NULL, NULL);
|
||||
|
||||
rdwr = done_ccb->ccb_h.ccb_rdwr;
|
||||
state = rdwr->state;
|
||||
rdwr->state = SG_RDWR_DONE;
|
||||
wakeup(rdwr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("unknown sg CCB type");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sgopen(struct cdev *dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct sg_softc *softc;
|
||||
int error = 0;
|
||||
|
||||
periph = (struct cam_periph *)dev->si_drv1;
|
||||
if (periph == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
softc = (struct sg_softc *)periph->softc;
|
||||
if (softc->flags & SG_FLAG_INVALID)
|
||||
return (ENXIO);
|
||||
|
||||
/*
|
||||
* Don't allow access when we're running at a high securelevel.
|
||||
*/
|
||||
error = securelevel_gt(td->td_ucred, 1);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0)
|
||||
return (error);
|
||||
|
||||
if ((softc->flags & SG_FLAG_OPEN) == 0) {
|
||||
if (cam_periph_acquire(periph) != CAM_REQ_CMP)
|
||||
return (ENXIO);
|
||||
softc->flags |= SG_FLAG_OPEN;
|
||||
}
|
||||
|
||||
cam_periph_unlock(periph);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
sgclose(struct cdev *dev, int flag, int fmt, struct thread *td)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct sg_softc *softc;
|
||||
int error;
|
||||
|
||||
periph = (struct cam_periph *)dev->si_drv1;
|
||||
if (periph == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
softc = (struct sg_softc *)periph->softc;
|
||||
|
||||
if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
|
||||
return (error);
|
||||
|
||||
softc->flags &= ~SG_FLAG_OPEN;
|
||||
|
||||
cam_periph_unlock(periph);
|
||||
cam_periph_release(periph);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
|
||||
{
|
||||
union ccb *ccb;
|
||||
struct ccb_scsiio *csio;
|
||||
struct cam_periph *periph;
|
||||
struct sg_softc *softc;
|
||||
struct sg_io_hdr req;
|
||||
int dir, error;
|
||||
|
||||
periph = (struct cam_periph *)dev->si_drv1;
|
||||
if (periph == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
softc = (struct sg_softc *)periph->softc;
|
||||
error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case LINUX_SCSI_GET_BUS_NUMBER: {
|
||||
int busno;
|
||||
|
||||
busno = xpt_path_path_id(periph->path);
|
||||
error = copyout(&busno, arg, sizeof(busno));
|
||||
break;
|
||||
}
|
||||
case LINUX_SCSI_GET_IDLUN: {
|
||||
struct scsi_idlun idlun;
|
||||
struct cam_sim *sim;
|
||||
|
||||
idlun.dev_id = xpt_path_target_id(periph->path);
|
||||
sim = xpt_path_sim(periph->path);
|
||||
idlun.host_unique_id = sim->unit_number;
|
||||
error = copyout(&idlun, arg, sizeof(idlun));
|
||||
break;
|
||||
}
|
||||
case SG_GET_VERSION_NUM:
|
||||
case LINUX_SG_GET_VERSION_NUM:
|
||||
error = copyout(&sg_version, arg, sizeof(sg_version));
|
||||
break;
|
||||
case SG_SET_TIMEOUT:
|
||||
case LINUX_SG_SET_TIMEOUT: {
|
||||
u_int user_timeout;
|
||||
|
||||
error = copyin(arg, &user_timeout, sizeof(u_int));
|
||||
if (error == 0) {
|
||||
softc->sg_user_timeout = user_timeout;
|
||||
softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SG_GET_TIMEOUT:
|
||||
case LINUX_SG_GET_TIMEOUT:
|
||||
/*
|
||||
* The value is returned directly to the syscall.
|
||||
*/
|
||||
td->td_retval[0] = softc->sg_user_timeout;
|
||||
error = 0;
|
||||
break;
|
||||
case SG_IO:
|
||||
case LINUX_SG_IO:
|
||||
error = copyin(arg, &req, sizeof(req));
|
||||
if (error)
|
||||
break;
|
||||
|
||||
if (req.cmd_len > IOCDBLEN) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (req.iovec_count != 0) {
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
ccb = cam_periph_getccb(periph, /*priority*/5);
|
||||
csio = &ccb->csio;
|
||||
|
||||
error = copyin(req.cmdp, &csio->cdb_io.cdb_bytes,
|
||||
req.cmd_len);
|
||||
if (error) {
|
||||
xpt_release_ccb(ccb);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(req.dxfer_direction) {
|
||||
case SG_DXFER_TO_DEV:
|
||||
dir = CAM_DIR_OUT;
|
||||
break;
|
||||
case SG_DXFER_FROM_DEV:
|
||||
dir = CAM_DIR_IN;
|
||||
break;
|
||||
case SG_DXFER_TO_FROM_DEV:
|
||||
dir = CAM_DIR_IN | CAM_DIR_OUT;
|
||||
break;
|
||||
case SG_DXFER_NONE:
|
||||
default:
|
||||
dir = CAM_DIR_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
cam_fill_csio(csio,
|
||||
/*retries*/1,
|
||||
sgdone,
|
||||
dir|CAM_DEV_QFRZDIS,
|
||||
MSG_SIMPLE_Q_TAG,
|
||||
req.dxferp,
|
||||
req.dxfer_len,
|
||||
req.mx_sb_len,
|
||||
req.cmd_len,
|
||||
req.timeout);
|
||||
|
||||
error = sgsendccb(periph, ccb);
|
||||
if (error) {
|
||||
req.host_status = DID_ERROR;
|
||||
req.driver_status = DRIVER_INVALID;
|
||||
xpt_release_ccb(ccb);
|
||||
break;
|
||||
}
|
||||
|
||||
req.status = csio->scsi_status;
|
||||
req.masked_status = (csio->scsi_status >> 1) & 0x7f;
|
||||
sg_scsiio_status(csio, &req.host_status, &req.driver_status);
|
||||
req.resid = csio->resid;
|
||||
req.duration = csio->ccb_h.timeout;
|
||||
req.info = 0;
|
||||
|
||||
error = copyout(&req, arg, sizeof(req));
|
||||
if ((error == 0) && (csio->ccb_h.status & CAM_AUTOSNS_VALID)
|
||||
&& (req.sbp != NULL)) {
|
||||
req.sb_len_wr = req.mx_sb_len - csio->sense_resid;
|
||||
error = copyout(&csio->sense_data, req.sbp,
|
||||
req.sb_len_wr);
|
||||
}
|
||||
|
||||
xpt_release_ccb(ccb);
|
||||
break;
|
||||
|
||||
case SG_GET_RESERVED_SIZE:
|
||||
case LINUX_SG_GET_RESERVED_SIZE: {
|
||||
int size = 32768;
|
||||
|
||||
error = copyout(&size, arg, sizeof(size));
|
||||
break;
|
||||
}
|
||||
|
||||
case SG_GET_SCSI_ID:
|
||||
case LINUX_SG_GET_SCSI_ID:
|
||||
{
|
||||
struct sg_scsi_id id;
|
||||
|
||||
id.host_no = 0; /* XXX */
|
||||
id.channel = xpt_path_path_id(periph->path);
|
||||
id.scsi_id = xpt_path_target_id(periph->path);
|
||||
id.lun = xpt_path_lun_id(periph->path);
|
||||
id.scsi_type = softc->pd_type;
|
||||
id.h_cmd_per_lun = 1;
|
||||
id.d_queue_depth = 1;
|
||||
id.unused[0] = 0;
|
||||
id.unused[1] = 0;
|
||||
|
||||
error = copyout(&id, arg, sizeof(id));
|
||||
break;
|
||||
}
|
||||
|
||||
case SG_EMULATED_HOST:
|
||||
case SG_SET_TRANSFORM:
|
||||
case SG_GET_TRANSFORM:
|
||||
case SG_GET_NUM_WAITING:
|
||||
case SG_SCSI_RESET:
|
||||
case SG_GET_REQUEST_TABLE:
|
||||
case SG_SET_KEEP_ORPHAN:
|
||||
case SG_GET_KEEP_ORPHAN:
|
||||
case SG_GET_ACCESS_COUNT:
|
||||
case SG_SET_FORCE_LOW_DMA:
|
||||
case SG_GET_LOW_DMA:
|
||||
case SG_GET_SG_TABLESIZE:
|
||||
case SG_SET_FORCE_PACK_ID:
|
||||
case SG_GET_PACK_ID:
|
||||
case SG_SET_RESERVED_SIZE:
|
||||
case SG_GET_COMMAND_Q:
|
||||
case SG_SET_COMMAND_Q:
|
||||
case SG_SET_DEBUG:
|
||||
case SG_NEXT_CMD_LEN:
|
||||
case LINUX_SG_EMULATED_HOST:
|
||||
case LINUX_SG_SET_TRANSFORM:
|
||||
case LINUX_SG_GET_TRANSFORM:
|
||||
case LINUX_SG_GET_NUM_WAITING:
|
||||
case LINUX_SG_SCSI_RESET:
|
||||
case LINUX_SG_GET_REQUEST_TABLE:
|
||||
case LINUX_SG_SET_KEEP_ORPHAN:
|
||||
case LINUX_SG_GET_KEEP_ORPHAN:
|
||||
case LINUX_SG_GET_ACCESS_COUNT:
|
||||
case LINUX_SG_SET_FORCE_LOW_DMA:
|
||||
case LINUX_SG_GET_LOW_DMA:
|
||||
case LINUX_SG_GET_SG_TABLESIZE:
|
||||
case LINUX_SG_SET_FORCE_PACK_ID:
|
||||
case LINUX_SG_GET_PACK_ID:
|
||||
case LINUX_SG_SET_RESERVED_SIZE:
|
||||
case LINUX_SG_GET_COMMAND_Q:
|
||||
case LINUX_SG_SET_COMMAND_Q:
|
||||
case LINUX_SG_SET_DEBUG:
|
||||
case LINUX_SG_NEXT_CMD_LEN:
|
||||
default:
|
||||
#ifdef CAMDEBUG
|
||||
printf("sgioctl: rejecting cmd 0x%lx\n", cmd);
|
||||
#endif
|
||||
error = ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
sgwrite(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
union ccb *ccb;
|
||||
struct cam_periph *periph;
|
||||
struct ccb_scsiio *csio;
|
||||
struct sg_softc *sc;
|
||||
struct sg_header *hdr;
|
||||
struct sg_rdwr *rdwr;
|
||||
u_char cdb_cmd;
|
||||
char *buf;
|
||||
int error = 0, cdb_len, buf_len, dir;
|
||||
|
||||
periph = dev->si_drv1;
|
||||
sc = periph->softc;
|
||||
rdwr = malloc(sizeof(*rdwr), M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
hdr = &rdwr->hdr.hdr;
|
||||
|
||||
/* Copy in the header block and sanity check it */
|
||||
if (uio->uio_resid < sizeof(*hdr)) {
|
||||
error = EINVAL;
|
||||
goto out_hdr;
|
||||
}
|
||||
error = uiomove(hdr, sizeof(*hdr), uio);
|
||||
if (error)
|
||||
goto out_hdr;
|
||||
|
||||
ccb = xpt_alloc_ccb();
|
||||
if (ccb == NULL) {
|
||||
error = ENOMEM;
|
||||
goto out_hdr;
|
||||
}
|
||||
xpt_setup_ccb(&ccb->ccb_h, periph->path, /*priority*/5);
|
||||
csio = &ccb->csio;
|
||||
|
||||
/*
|
||||
* Copy in the CDB block. The designers of the interface didn't
|
||||
* bother to provide a size for this in the header, so we have to
|
||||
* figure it out ourselves.
|
||||
*/
|
||||
if (uio->uio_resid < 1)
|
||||
goto out_ccb;
|
||||
error = uiomove(&cdb_cmd, 1, uio);
|
||||
if (error)
|
||||
goto out_ccb;
|
||||
if (hdr->twelve_byte)
|
||||
cdb_len = 12;
|
||||
else
|
||||
cdb_len = scsi_group_len(cdb_cmd);
|
||||
/*
|
||||
* We've already read the first byte of the CDB and advanced the uio
|
||||
* pointer. Just read the rest.
|
||||
*/
|
||||
csio->cdb_io.cdb_bytes[0] = cdb_cmd;
|
||||
error = uiomove(&csio->cdb_io.cdb_bytes[1], cdb_len - 1, uio);
|
||||
if (error)
|
||||
goto out_ccb;
|
||||
|
||||
/*
|
||||
* Now set up the data block. Again, the designers didn't bother
|
||||
* to make this reliable.
|
||||
*/
|
||||
buf_len = uio->uio_resid;
|
||||
if (buf_len != 0) {
|
||||
buf = malloc(buf_len, M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
error = uiomove(buf, buf_len, uio);
|
||||
if (error)
|
||||
goto out_buf;
|
||||
dir = CAM_DIR_OUT;
|
||||
} else if (hdr->reply_len != 0) {
|
||||
buf = malloc(hdr->reply_len, M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
buf_len = hdr->reply_len;
|
||||
dir = CAM_DIR_IN;
|
||||
} else {
|
||||
buf = NULL;
|
||||
buf_len = 0;
|
||||
dir = CAM_DIR_NONE;
|
||||
}
|
||||
|
||||
cam_fill_csio(csio,
|
||||
/*retries*/1,
|
||||
sgdone,
|
||||
dir|CAM_DEV_QFRZDIS,
|
||||
MSG_SIMPLE_Q_TAG,
|
||||
buf,
|
||||
buf_len,
|
||||
SG_MAX_SENSE,
|
||||
cdb_len,
|
||||
sc->sg_timeout);
|
||||
|
||||
/*
|
||||
* Send off the command and hope that it works. This path does not
|
||||
* go through sgstart because the I/O is supposed to be asynchronous.
|
||||
*/
|
||||
rdwr->buf = buf;
|
||||
rdwr->buf_len = buf_len;
|
||||
rdwr->tag = hdr->pack_id;
|
||||
rdwr->ccb = ccb;
|
||||
rdwr->state = SG_RDWR_INPROG;
|
||||
ccb->ccb_h.ccb_rdwr = rdwr;
|
||||
ccb->ccb_h.ccb_type = SG_CCB_RDWR_IO;
|
||||
TAILQ_INSERT_TAIL(&sc->rdwr_done, rdwr, rdwr_link);
|
||||
return (sgsendrdwr(periph, ccb));
|
||||
|
||||
out_buf:
|
||||
free(buf, M_DEVBUF);
|
||||
out_ccb:
|
||||
xpt_free_ccb(ccb);
|
||||
out_hdr:
|
||||
free(rdwr, M_DEVBUF);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
sgread(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
struct ccb_scsiio *csio;
|
||||
struct cam_periph *periph;
|
||||
struct sg_softc *sc;
|
||||
struct sg_header *hdr;
|
||||
struct sg_rdwr *rdwr;
|
||||
u_short hstat, dstat;
|
||||
int error, pack_len, reply_len, pack_id;
|
||||
|
||||
periph = dev->si_drv1;
|
||||
sc = periph->softc;
|
||||
|
||||
/* XXX The pack len field needs to be updated and written out instead
|
||||
* of discarded. Not sure how to do that.
|
||||
*/
|
||||
uio->uio_rw = UIO_WRITE;
|
||||
if ((error = uiomove(&pack_len, 4, uio)) != 0)
|
||||
return (error);
|
||||
if ((error = uiomove(&reply_len, 4, uio)) != 0)
|
||||
return (error);
|
||||
if ((error = uiomove(&pack_id, 4, uio)) != 0)
|
||||
return (error);
|
||||
uio->uio_rw = UIO_READ;
|
||||
|
||||
search:
|
||||
TAILQ_FOREACH(rdwr, &sc->rdwr_done, rdwr_link) {
|
||||
if (rdwr->tag == pack_id)
|
||||
break;
|
||||
}
|
||||
if ((rdwr == NULL) || (rdwr->state != SG_RDWR_DONE)) {
|
||||
if (tsleep(rdwr, PCATCH, "sgread", 0) == ERESTART)
|
||||
return (EAGAIN);
|
||||
goto search;
|
||||
}
|
||||
TAILQ_REMOVE(&sc->rdwr_done, rdwr, rdwr_link);
|
||||
|
||||
hdr = &rdwr->hdr.hdr;
|
||||
csio = &rdwr->ccb->csio;
|
||||
sg_scsiio_status(csio, &hstat, &dstat);
|
||||
hdr->host_status = hstat;
|
||||
hdr->driver_status = dstat;
|
||||
hdr->target_status = csio->scsi_status >> 1;
|
||||
|
||||
switch (hstat) {
|
||||
case DID_OK:
|
||||
case DID_PASSTHROUGH:
|
||||
case DID_SOFT_ERROR:
|
||||
hdr->result = 0;
|
||||
break;
|
||||
case DID_NO_CONNECT:
|
||||
case DID_BUS_BUSY:
|
||||
case DID_TIME_OUT:
|
||||
hdr->result = EBUSY;
|
||||
break;
|
||||
case DID_BAD_TARGET:
|
||||
case DID_ABORT:
|
||||
case DID_PARITY:
|
||||
case DID_RESET:
|
||||
case DID_BAD_INTR:
|
||||
case DID_ERROR:
|
||||
default:
|
||||
hdr->result = EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dstat == DRIVER_SENSE) {
|
||||
bcopy(&csio->sense_data, hdr->sense_buffer,
|
||||
min(csio->sense_len, SG_MAX_SENSE));
|
||||
#ifdef CAMDEBUG
|
||||
scsi_sense_print(csio);
|
||||
#endif
|
||||
}
|
||||
|
||||
error = uiomove(&hdr->result, sizeof(*hdr) -
|
||||
offsetof(struct sg_header, result), uio);
|
||||
if ((error == 0) && (hdr->result == 0))
|
||||
error = uiomove(rdwr->buf, rdwr->buf_len, uio);
|
||||
|
||||
xpt_free_ccb(rdwr->ccb);
|
||||
free(rdwr->buf, M_DEVBUF);
|
||||
free(rdwr, M_DEVBUF);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
sgsendccb(struct cam_periph *periph, union ccb *ccb)
|
||||
{
|
||||
struct sg_softc *softc;
|
||||
struct cam_periph_map_info mapinfo;
|
||||
int error, need_unmap = 0;
|
||||
|
||||
softc = periph->softc;
|
||||
if (((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
|
||||
&& (ccb->csio.data_ptr != NULL)) {
|
||||
bzero(&mapinfo, sizeof(mapinfo));
|
||||
error = cam_periph_mapmem(ccb, &mapinfo);
|
||||
if (error)
|
||||
return (error);
|
||||
need_unmap = 1;
|
||||
}
|
||||
|
||||
error = cam_periph_runccb(ccb,
|
||||
sgerror,
|
||||
CAM_RETRY_SELTO,
|
||||
SF_RETRY_UA,
|
||||
softc->device_stats);
|
||||
|
||||
if (need_unmap)
|
||||
cam_periph_unmapmem(ccb, &mapinfo);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
sgsendrdwr(struct cam_periph *periph, union ccb *ccb)
|
||||
{
|
||||
struct sg_softc *softc;
|
||||
|
||||
softc = periph->softc;
|
||||
devstat_start_transaction(softc->device_stats, NULL);
|
||||
xpt_action(ccb);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
sgerror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct sg_softc *softc;
|
||||
|
||||
periph = xpt_path_periph(ccb->ccb_h.path);
|
||||
softc = (struct sg_softc *)periph->softc;
|
||||
|
||||
return (cam_periph_error(ccb, cam_flags, sense_flags,
|
||||
&softc->saved_ccb));
|
||||
}
|
||||
|
||||
static void
|
||||
sg_scsiio_status(struct ccb_scsiio *csio, u_short *hoststat, u_short *drvstat)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = csio->ccb_h.status;
|
||||
|
||||
switch (status & CAM_STATUS_MASK) {
|
||||
case CAM_REQ_CMP:
|
||||
*hoststat = DID_OK;
|
||||
*drvstat = 0;
|
||||
break;
|
||||
case CAM_REQ_CMP_ERR:
|
||||
*hoststat = DID_ERROR;
|
||||
*drvstat = 0;
|
||||
break;
|
||||
case CAM_REQ_ABORTED:
|
||||
*hoststat = DID_ABORT;
|
||||
*drvstat = 0;
|
||||
break;
|
||||
case CAM_REQ_INVALID:
|
||||
*hoststat = DID_ERROR;
|
||||
*drvstat = DRIVER_INVALID;
|
||||
break;
|
||||
case CAM_DEV_NOT_THERE:
|
||||
*hoststat = DID_BAD_TARGET;
|
||||
*drvstat = 0;
|
||||
case CAM_SEL_TIMEOUT:
|
||||
*hoststat = DID_NO_CONNECT;
|
||||
*drvstat = 0;
|
||||
break;
|
||||
case CAM_CMD_TIMEOUT:
|
||||
*hoststat = DID_TIME_OUT;
|
||||
*drvstat = 0;
|
||||
break;
|
||||
case CAM_SCSI_STATUS_ERROR:
|
||||
*hoststat = DID_ERROR;
|
||||
*drvstat = 0;
|
||||
case CAM_SCSI_BUS_RESET:
|
||||
*hoststat = DID_RESET;
|
||||
*drvstat = 0;
|
||||
break;
|
||||
case CAM_UNCOR_PARITY:
|
||||
*hoststat = DID_PARITY;
|
||||
*drvstat = 0;
|
||||
break;
|
||||
case CAM_SCSI_BUSY:
|
||||
*hoststat = DID_BUS_BUSY;
|
||||
*drvstat = 0;
|
||||
default:
|
||||
*hoststat = DID_ERROR;
|
||||
*drvstat = DRIVER_ERROR;
|
||||
}
|
||||
|
||||
if (status & CAM_AUTOSNS_VALID)
|
||||
*drvstat = DRIVER_SENSE;
|
||||
}
|
||||
|
||||
static int
|
||||
scsi_group_len(u_char cmd)
|
||||
{
|
||||
int len[] = {6, 10, 10, 12, 12, 12, 10, 10};
|
||||
int group;
|
||||
|
||||
group = (cmd >> 5) & 0x7;
|
||||
return (len[group]);
|
||||
}
|
||||
|
144
sys/cam/scsi/scsi_sg.h
Normal file
144
sys/cam/scsi/scsi_sg.h
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Structures and definitions for SCSI commands to the SG passthrough device.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SG_H
|
||||
#define _SCSI_SG_H
|
||||
|
||||
#define SGIOC '"'
|
||||
#define SG_SET_TIMEOUT _IO(SGIOC, 0x01)
|
||||
#define SG_GET_TIMEOUT _IO(SGIOC, 0x02)
|
||||
#define SG_EMULATED_HOST _IO(SGIOC, 0x03)
|
||||
#define SG_SET_TRANSFORM _IO(SGIOC, 0x04)
|
||||
#define SG_GET_TRANSFORM _IO(SGIOC, 0x05)
|
||||
#define SG_GET_COMMAND_Q _IO(SGIOC, 0x70)
|
||||
#define SG_SET_COMMAND_Q _IO(SGIOC, 0x71)
|
||||
#define SG_GET_RESERVED_SIZE _IO(SGIOC, 0x72)
|
||||
#define SG_SET_RESERVED_SIZE _IO(SGIOC, 0x75)
|
||||
#define SG_GET_SCSI_ID _IO(SGIOC, 0x76)
|
||||
#define SG_SET_FORCE_LOW_DMA _IO(SGIOC, 0x79)
|
||||
#define SG_GET_LOW_DMA _IO(SGIOC, 0x7a)
|
||||
#define SG_SET_FORCE_PACK_ID _IO(SGIOC, 0x7b)
|
||||
#define SG_GET_PACK_ID _IO(SGIOC, 0x7c)
|
||||
#define SG_GET_NUM_WAITING _IO(SGIOC, 0x7d)
|
||||
#define SG_SET_DEBUG _IO(SGIOC, 0x7e)
|
||||
#define SG_GET_SG_TABLESIZE _IO(SGIOC, 0x7f)
|
||||
#define SG_GET_VERSION_NUM _IO(SGIOC, 0x82)
|
||||
#define SG_NEXT_CMD_LEN _IO(SGIOC, 0x83)
|
||||
#define SG_SCSI_RESET _IO(SGIOC, 0x84)
|
||||
#define SG_IO _IO(SGIOC, 0x85)
|
||||
#define SG_GET_REQUEST_TABLE _IO(SGIOC, 0x86)
|
||||
#define SG_SET_KEEP_ORPHAN _IO(SGIOC, 0x87)
|
||||
#define SG_GET_KEEP_ORPHAN _IO(SGIOC, 0x88)
|
||||
#define SG_GET_ACCESS_COUNT _IO(SGIOC, 0x89)
|
||||
|
||||
struct sg_io_hdr {
|
||||
int interface_id;
|
||||
int dxfer_direction;
|
||||
u_char cmd_len;
|
||||
u_char mx_sb_len;
|
||||
u_short iovec_count;
|
||||
u_int dxfer_len;
|
||||
void *dxferp;
|
||||
u_char *cmdp;
|
||||
u_char *sbp;
|
||||
u_int timeout;
|
||||
u_int flags;
|
||||
int pack_id;
|
||||
void *usr_ptr;
|
||||
u_char status;
|
||||
u_char masked_status;
|
||||
u_char msg_status;
|
||||
u_char sb_len_wr;
|
||||
u_short host_status;
|
||||
u_short driver_status;
|
||||
int resid;
|
||||
u_int duration;
|
||||
u_int info;
|
||||
};
|
||||
|
||||
#define SG_DXFER_NONE -1
|
||||
#define SG_DXFER_TO_DEV -2
|
||||
#define SG_DXFER_FROM_DEV -3
|
||||
#define SG_DXFER_TO_FROM_DEV -4
|
||||
#define SG_DXFER_UNKNOWN -5
|
||||
|
||||
#define SG_MAX_SENSE 16
|
||||
struct sg_header {
|
||||
int pack_len;
|
||||
int reply_len;
|
||||
int pack_id;
|
||||
int result;
|
||||
u_int twelve_byte:1;
|
||||
u_int target_status:5;
|
||||
u_int host_status:8;
|
||||
u_int driver_status:8;
|
||||
u_int other_flags:10;
|
||||
u_char sense_buffer[SG_MAX_SENSE];
|
||||
};
|
||||
|
||||
struct sg_scsi_id {
|
||||
int host_no;
|
||||
int channel;
|
||||
int scsi_id;
|
||||
int lun;
|
||||
int scsi_type;
|
||||
short h_cmd_per_lun;
|
||||
short d_queue_depth;
|
||||
int unused[2];
|
||||
};
|
||||
|
||||
struct scsi_idlun {
|
||||
uint32_t dev_id;
|
||||
uint32_t host_unique_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* Host codes
|
||||
*/
|
||||
#define DID_OK 0x00 /* OK */
|
||||
#define DID_NO_CONNECT 0x01 /* timeout during connect */
|
||||
#define DID_BUS_BUSY 0x02 /* timeout during command */
|
||||
#define DID_TIME_OUT 0x03 /* other timeout */
|
||||
#define DID_BAD_TARGET 0x04 /* bad target */
|
||||
#define DID_ABORT 0x05 /* abort */
|
||||
#define DID_PARITY 0x06 /* parity error */
|
||||
#define DID_ERROR 0x07 /* internal error */
|
||||
#define DID_RESET 0x08 /* reset by somebody */
|
||||
#define DID_BAD_INTR 0x09 /* unexpected interrupt */
|
||||
#define DID_PASSTHROUGH 0x0a /* passthrough */
|
||||
#define DID_SOFT_ERROR 0x0b /* low driver wants retry */
|
||||
#define DID_IMM_RETRY 0x0c /* retry without decreasing retrycnt */
|
||||
|
||||
/*
|
||||
* Driver codes
|
||||
*/
|
||||
#define DRIVER_OK 0x00
|
||||
#define DRIVER_BUSY 0x01
|
||||
#define DRIVER_SOFT 0x02
|
||||
#define DRIVER_MEDIA 0x03
|
||||
#define DRIVER_ERROR 0x04
|
||||
|
||||
#define DRIVER_INVALID 0x05
|
||||
#define DRIVER_TIMEOUT 0x06
|
||||
#define DRIVER_HARD 0x07
|
||||
#define DRIVER_SENSE 0x08
|
||||
|
||||
#define SUGGEST_RETRY 0x10
|
||||
#define SUGGEST_ABORT 0x20
|
||||
#define SUGGEST_REMAP 0x30
|
||||
#define SUGGEST_DIE 0x40
|
||||
#define SUGGEST_SENSE 0x80
|
||||
#define SUGGEST_IS_OK 0xff
|
||||
|
||||
#define DRIVER_MASK 0x0f
|
||||
#define SUGGEST_MASK 0xf0
|
||||
|
||||
/* Other definitions */
|
||||
/* HZ isn't always available, so simulate it */
|
||||
#define SG_DEFAULT_HZ 1000
|
||||
#define SG_DEFAULT_TIMEOUT (60*SG_DEFAULT_HZ)
|
||||
|
||||
#endif /* !_SCSI_SG_H */
|
8
sys/modules/if_edsc/Makefile
Normal file
8
sys/modules/if_edsc/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../net
|
||||
|
||||
KMOD= if_edsc
|
||||
SRCS= if_edsc.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
354
sys/net/if_edsc.c
Normal file
354
sys/net/if_edsc.c
Normal file
@ -0,0 +1,354 @@
|
||||
/*-
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following edsclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following edsclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE EDSCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* From: @(#)if_loop.c 8.1 (Berkeley) 6/10/93
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Discard interface driver for protocol testing and timing.
|
||||
* Mimics an Ethernet device so that VLANs can be attached to it etc.
|
||||
*/
|
||||
|
||||
#include <sys/param.h> /* types, important constants */
|
||||
#include <sys/kernel.h> /* SYSINIT for load-time initializations */
|
||||
#include <sys/malloc.h> /* malloc(9) */
|
||||
#include <sys/module.h> /* module(9) */
|
||||
#include <sys/mbuf.h> /* mbuf(9) */
|
||||
#include <sys/socket.h> /* struct ifreq */
|
||||
#include <sys/sockio.h> /* socket ioctl's */
|
||||
/* #include <sys/systm.h> if you need printf(9) or other all-purpose globals */
|
||||
|
||||
#include <net/bpf.h> /* bpf(9) */
|
||||
#include <net/ethernet.h> /* Ethernet related constants and types */
|
||||
#include <net/if.h> /* basic part of ifnet(9) */
|
||||
#include <net/if_clone.h> /* network interface cloning */
|
||||
#include <net/if_types.h> /* IFT_ETHER and friends */
|
||||
#include <net/if_var.h> /* kernel-only part of ifnet(9) */
|
||||
|
||||
/*
|
||||
* Software configuration of an interface specific to this device type.
|
||||
*/
|
||||
struct edsc_softc {
|
||||
struct ifnet *sc_ifp; /* ptr to generic interface configuration */
|
||||
|
||||
/*
|
||||
* A non-null driver can keep various things here, for instance,
|
||||
* the hardware revision, cached values of write-only registers, etc.
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple cloning methods.
|
||||
* IFC_SIMPLE_DECLARE() expects precisely these names.
|
||||
*/
|
||||
static int edsc_clone_create(struct if_clone *, int, caddr_t);
|
||||
static void edsc_clone_destroy(struct ifnet *);
|
||||
|
||||
/*
|
||||
* Interface driver methods.
|
||||
*/
|
||||
static void edsc_init(void *dummy);
|
||||
/* static void edsc_input(struct ifnet *ifp, struct mbuf *m); would be here */
|
||||
static int edsc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
|
||||
static void edsc_start(struct ifnet *ifp);
|
||||
|
||||
/*
|
||||
* We'll allocate softc instances from this.
|
||||
*/
|
||||
static MALLOC_DEFINE(M_EDSC, "edsc", "Ethernet discard interface");
|
||||
|
||||
/*
|
||||
* Attach to the interface cloning framework under the name of "edsc".
|
||||
* The second argument is the number of units to be created from
|
||||
* the outset. It's also the minimum number of units allowed.
|
||||
* We don't want any units created as soon as the driver is loaded.
|
||||
*/
|
||||
IFC_SIMPLE_DECLARE(edsc, 0);
|
||||
|
||||
/*
|
||||
* Create an interface instance.
|
||||
*/
|
||||
static int
|
||||
edsc_clone_create(struct if_clone *ifc, int unit, caddr_t params)
|
||||
{
|
||||
struct edsc_softc *sc;
|
||||
struct ifnet *ifp;
|
||||
static u_char eaddr[ETHER_ADDR_LEN]; /* 0:0:0:0:0:0 */
|
||||
|
||||
/*
|
||||
* Allocate soft and ifnet structures. Link each to the other.
|
||||
*/
|
||||
sc = malloc(sizeof(struct edsc_softc), M_EDSC, M_WAITOK | M_ZERO);
|
||||
ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
|
||||
if (ifp == NULL) {
|
||||
free(sc, M_EDSC);
|
||||
return (ENOSPC);
|
||||
}
|
||||
|
||||
ifp->if_softc = sc;
|
||||
|
||||
/*
|
||||
* Get a name for this particular interface in its ifnet structure.
|
||||
*/
|
||||
if_initname(ifp, ifc->ifc_name, unit);
|
||||
|
||||
/*
|
||||
* Typical Ethernet interface flags: we can do broadcast and
|
||||
* multicast but can't hear our own broadcasts or multicasts.
|
||||
*/
|
||||
ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
|
||||
|
||||
/*
|
||||
* We can pretent we have the whole set of hardware features
|
||||
* because we just discard all packets we get from the upper layer.
|
||||
* However, the features are disabled initially. They can be
|
||||
* enabled via edsc_ioctl() when needed.
|
||||
*/
|
||||
ifp->if_capabilities =
|
||||
IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM |
|
||||
IFCAP_HWCSUM | IFCAP_TSO |
|
||||
IFCAP_JUMBO_MTU;
|
||||
ifp->if_capenable = 0;
|
||||
|
||||
/*
|
||||
* Set the interface driver methods.
|
||||
*/
|
||||
ifp->if_init = edsc_init;
|
||||
/* ifp->if_input = edsc_input; */
|
||||
ifp->if_ioctl = edsc_ioctl;
|
||||
ifp->if_start = edsc_start;
|
||||
|
||||
/*
|
||||
* Set the maximum output queue length from the global parameter.
|
||||
*/
|
||||
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
||||
|
||||
/*
|
||||
* Do ifnet initializations common to all Ethernet drivers
|
||||
* and attach to the network interface framework.
|
||||
* TODO: Pick a non-zero link level address.
|
||||
*/
|
||||
ether_ifattach(ifp, eaddr);
|
||||
|
||||
/*
|
||||
* Now we can mark the interface as running, i.e., ready
|
||||
* for operation.
|
||||
*/
|
||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy an interface instance.
|
||||
*/
|
||||
static void
|
||||
edsc_clone_destroy(struct ifnet *ifp)
|
||||
{
|
||||
struct edsc_softc *sc = ifp->if_softc;
|
||||
|
||||
/*
|
||||
* Detach from the network interface framework.
|
||||
*/
|
||||
ether_ifdetach(ifp);
|
||||
|
||||
/*
|
||||
* Free memory occupied by ifnet and softc.
|
||||
*/
|
||||
if_free(ifp);
|
||||
free(sc, M_EDSC);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is invoked from ether_ioctl() when it's time
|
||||
* to bring up the hardware.
|
||||
*/
|
||||
static void
|
||||
edsc_init(void *dummy)
|
||||
{
|
||||
#if 0 /* what a hardware driver would do here... */
|
||||
struct edsc_soft *sc = (struct edsc_softc *)dummy;
|
||||
struct ifnet *ifp = sc->sc_ifp;
|
||||
|
||||
/* blah-blah-blah */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Network interfaces are controlled via the ioctl(2) syscall.
|
||||
*/
|
||||
static int
|
||||
edsc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
{
|
||||
struct ifreq *ifr = (struct ifreq *)data;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCSIFCAP:
|
||||
#if 1
|
||||
/*
|
||||
* Just turn on any capabilities requested.
|
||||
* The generic ifioctl() function has already made sure
|
||||
* that they are supported, i.e., set in if_capabilities.
|
||||
*/
|
||||
ifp->if_capenable = ifr->ifr_reqcap;
|
||||
#else
|
||||
/*
|
||||
* A h/w driver would need to analyze the requested
|
||||
* bits and program the hardware, e.g.:
|
||||
*/
|
||||
mask = ifp->if_capenable ^ ifr->ifr_reqcap;
|
||||
|
||||
if (mask & IFCAP_VLAN_HWTAGGING) {
|
||||
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
|
||||
|
||||
if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
|
||||
/* blah-blah-blah */
|
||||
else
|
||||
/* etc-etc-etc */
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Offload the rest onto the common Ethernet handler.
|
||||
*/
|
||||
return (ether_ioctl(ifp, cmd, data));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the output queue.
|
||||
*/
|
||||
static void
|
||||
edsc_start(struct ifnet *ifp)
|
||||
{
|
||||
struct mbuf *m;
|
||||
|
||||
/*
|
||||
* A hardware interface driver can set IFF_DRV_OACTIVE
|
||||
* in ifp->if_drv_flags:
|
||||
*
|
||||
* ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
||||
*
|
||||
* to prevent if_start from being invoked again while the
|
||||
* transmission is under way. The flag is to protect the
|
||||
* device's transmitter, not the method itself. The output
|
||||
* queue is locked and several threads can process it in
|
||||
* parallel safely, so the driver can use other means to
|
||||
* serialize access to the transmitter.
|
||||
*
|
||||
* If using IFF_DRV_OACTIVE, the driver should clear the flag
|
||||
* not earlier than the current transmission is complete, e.g.,
|
||||
* upon an interrupt from the device, not just before returning
|
||||
* from if_start. This method merely starts the transmission,
|
||||
* which may proceed asynchronously.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We loop getting packets from the queue until it's empty.
|
||||
* A h/w driver would loop until the device can accept more
|
||||
* data into its buffer, or while there are free transmit
|
||||
* descriptors, or whatever.
|
||||
*/
|
||||
for (;;) {
|
||||
/*
|
||||
* Try to dequeue one packet. Stop if the queue is empty.
|
||||
* Use IF_DEQUEUE() here if ALTQ(9) support is unneeded.
|
||||
*/
|
||||
IFQ_DEQUEUE(&ifp->if_snd, m);
|
||||
if (m == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Let bpf(9) at the packet.
|
||||
*/
|
||||
BPF_MTAP(ifp, m);
|
||||
|
||||
/*
|
||||
* Update the interface counters.
|
||||
*/
|
||||
ifp->if_obytes += m->m_pkthdr.len;
|
||||
ifp->if_opackets++;
|
||||
|
||||
/*
|
||||
* Finally, just drop the packet.
|
||||
* TODO: Reply to ARP requests unless IFF_NOARP is set.
|
||||
*/
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
||||
* would be here only if the transmission were synchronous.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* This function provides handlers for module events, namely load and unload.
|
||||
*/
|
||||
static int
|
||||
edsc_modevent(module_t mod, int type, void *data)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
/*
|
||||
* Connect to the network interface cloning framework.
|
||||
*/
|
||||
if_clone_attach(&edsc_cloner);
|
||||
break;
|
||||
|
||||
case MOD_UNLOAD:
|
||||
/*
|
||||
* Disconnect from the cloning framework.
|
||||
* Existing interfaces will be disposed of properly.
|
||||
*/
|
||||
if_clone_detach(&edsc_cloner);
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* There are other event types, but we don't handle them.
|
||||
* See module(9).
|
||||
*/
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static moduledata_t edsc_mod = {
|
||||
"if_edsc", /* name */
|
||||
edsc_modevent, /* event handler */
|
||||
NULL /* additional data */
|
||||
};
|
||||
|
||||
DECLARE_MODULE(if_edsc, edsc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
|
43
sys/sys/_sx.h
Normal file
43
sys/sys/_sx.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Attilio Rao <attilio@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer as
|
||||
* the first lines of this file unmodified other than the possible
|
||||
* addition of one or more copyright notices.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS__SX_H_
|
||||
#define _SYS__SX_H_
|
||||
|
||||
/*
|
||||
* Shared/exclusive lock main structure definition.
|
||||
*/
|
||||
struct sx {
|
||||
struct lock_object lock_object;
|
||||
volatile uintptr_t sx_lock;
|
||||
volatile unsigned sx_recurse;
|
||||
};
|
||||
|
||||
#endif /* !_SYS__SX_H_ */
|
3
tools/regression/usr.bin/sed/regress.b2a.out
Normal file
3
tools/regression/usr.bin/sed/regress.b2a.out
Normal file
@ -0,0 +1,3 @@
|
||||
data
|
||||
for validation
|
||||
of sed(1)
|
4
tools/regression/usr.bin/sed/regress.c0.out
Normal file
4
tools/regression/usr.bin/sed/regress.c0.out
Normal file
@ -0,0 +1,4 @@
|
||||
foo
|
||||
foo
|
||||
foo
|
||||
foo
|
4
tools/regression/usr.bin/sed/regress.c1.out
Normal file
4
tools/regression/usr.bin/sed/regress.c1.out
Normal file
@ -0,0 +1,4 @@
|
||||
input
|
||||
data
|
||||
for validation
|
||||
foo
|
3
tools/regression/usr.bin/sed/regress.c2.out
Normal file
3
tools/regression/usr.bin/sed/regress.c2.out
Normal file
@ -0,0 +1,3 @@
|
||||
input
|
||||
data
|
||||
foo
|
3
tools/regression/usr.bin/sed/regress.c3.out
Normal file
3
tools/regression/usr.bin/sed/regress.c3.out
Normal file
@ -0,0 +1,3 @@
|
||||
input
|
||||
data
|
||||
foo
|
Loading…
x
Reference in New Issue
Block a user