diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 4b5fa101d1f0..32cb81ec8422 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1,1528 +1,1528 @@ /*- * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 * 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. * 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. * * @(#)tcp_output.c 8.4 (Berkeley) 5/24/95 */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" #include "opt_tcpdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #include #include #endif #define TCPOUTFLAGS #include #include #include #include #include #ifdef TCPDEBUG #include #endif #ifdef IPSEC #include #endif /*IPSEC*/ #include #include #ifdef notyet extern struct mbuf *m_copypack(); #endif VNET_DEFINE(int, path_mtu_discovery) = 1; SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, path_mtu_discovery, CTLFLAG_RW, &VNET_NAME(path_mtu_discovery), 1, "Enable Path MTU Discovery"); VNET_DEFINE(int, ss_fltsz) = 1; SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, slowstart_flightsize, CTLFLAG_RW, &VNET_NAME(ss_fltsz), 1, "Slow start flight size"); VNET_DEFINE(int, ss_fltsz_local) = 4; SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, local_slowstart_flightsize, CTLFLAG_RW, &VNET_NAME(ss_fltsz_local), 1, "Slow start flight size for local networks"); VNET_DEFINE(int, tcp_do_tso) = 1; #define V_tcp_do_tso VNET(tcp_do_tso) SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, tso, CTLFLAG_RW, &VNET_NAME(tcp_do_tso), 0, "Enable TCP Segmentation Offload"); VNET_DEFINE(int, tcp_do_autosndbuf) = 1; #define V_tcp_do_autosndbuf VNET(tcp_do_autosndbuf) SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, sendbuf_auto, CTLFLAG_RW, &VNET_NAME(tcp_do_autosndbuf), 0, "Enable automatic send buffer sizing"); VNET_DEFINE(int, tcp_autosndbuf_inc) = 8*1024; #define V_tcp_autosndbuf_inc VNET(tcp_autosndbuf_inc) SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, sendbuf_inc, CTLFLAG_RW, &VNET_NAME(tcp_autosndbuf_inc), 0, "Incrementor step size of automatic send buffer"); VNET_DEFINE(int, tcp_autosndbuf_max) = 256*1024; #define V_tcp_autosndbuf_max VNET(tcp_autosndbuf_max) SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, sendbuf_max, CTLFLAG_RW, &VNET_NAME(tcp_autosndbuf_max), 0, "Max size of automatic send buffer"); static void inline hhook_run_tcp_est_out(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to, long len, int tso); static void inline cc_after_idle(struct tcpcb *tp); /* * Wrapper for the TCP established ouput helper hook. */ static void inline hhook_run_tcp_est_out(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to, long len, int tso) { struct tcp_hhook_data hhook_data; if (V_tcp_hhh[HHOOK_TCP_EST_OUT]->hhh_nhooks > 0) { hhook_data.tp = tp; hhook_data.th = th; hhook_data.to = to; hhook_data.len = len; hhook_data.tso = tso; hhook_run_hooks(V_tcp_hhh[HHOOK_TCP_EST_OUT], &hhook_data, tp->osd); } } /* * CC wrapper hook functions */ static void inline cc_after_idle(struct tcpcb *tp) { INP_WLOCK_ASSERT(tp->t_inpcb); if (CC_ALGO(tp)->after_idle != NULL) CC_ALGO(tp)->after_idle(tp->ccv); } /* * Tcp output routine: figure out what should be sent and send it. */ int tcp_output(struct tcpcb *tp) { struct socket *so = tp->t_inpcb->inp_socket; long len, recwin, sendwin; int off, flags, error = 0; /* Keep compiler happy */ struct mbuf *m; struct ip *ip = NULL; struct ipovly *ipov = NULL; struct tcphdr *th; u_char opt[TCP_MAXOLEN]; unsigned ipoptlen, optlen, hdrlen; #ifdef IPSEC unsigned ipsec_optlen = 0; #endif int idle, sendalot; int sack_rxmit, sack_bytes_rxmt; struct sackhole *p; int tso; struct tcpopt to; #if 0 int maxburst = TCP_MAXBURST; #endif #ifdef INET6 struct ip6_hdr *ip6 = NULL; int isipv6; isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; #endif INP_WLOCK_ASSERT(tp->t_inpcb); /* * Determine length of data that should be transmitted, * and flags that will be used. * If there is some data or critical controls (SYN, RST) * to send, then transmit; otherwise, investigate further. */ idle = (tp->t_flags & TF_LASTIDLE) || (tp->snd_max == tp->snd_una); if (idle && ticks - tp->t_rcvtime >= tp->t_rxtcur) cc_after_idle(tp); tp->t_flags &= ~TF_LASTIDLE; if (idle) { if (tp->t_flags & TF_MORETOCOME) { tp->t_flags |= TF_LASTIDLE; idle = 0; } } again: /* * If we've recently taken a timeout, snd_max will be greater than * snd_nxt. There may be SACK information that allows us to avoid * resending already delivered data. Adjust snd_nxt accordingly. */ if ((tp->t_flags & TF_SACK_PERMIT) && SEQ_LT(tp->snd_nxt, tp->snd_max)) tcp_sack_adjust(tp); sendalot = 0; tso = 0; off = tp->snd_nxt - tp->snd_una; sendwin = min(tp->snd_wnd, tp->snd_cwnd); flags = tcp_outflags[tp->t_state]; /* * Send any SACK-generated retransmissions. If we're explicitly trying * to send out new data (when sendalot is 1), bypass this function. * If we retransmit in fast recovery mode, decrement snd_cwnd, since * we're replacing a (future) new transmission with a retransmission * now, and we previously incremented snd_cwnd in tcp_input(). */ /* * Still in sack recovery , reset rxmit flag to zero. */ sack_rxmit = 0; sack_bytes_rxmt = 0; len = 0; p = NULL; if ((tp->t_flags & TF_SACK_PERMIT) && IN_FASTRECOVERY(tp->t_flags) && (p = tcp_sack_output(tp, &sack_bytes_rxmt))) { long cwin; cwin = min(tp->snd_wnd, tp->snd_cwnd) - sack_bytes_rxmt; if (cwin < 0) cwin = 0; /* Do not retransmit SACK segments beyond snd_recover */ if (SEQ_GT(p->end, tp->snd_recover)) { /* * (At least) part of sack hole extends beyond * snd_recover. Check to see if we can rexmit data * for this hole. */ if (SEQ_GEQ(p->rxmit, tp->snd_recover)) { /* * Can't rexmit any more data for this hole. * That data will be rexmitted in the next * sack recovery episode, when snd_recover * moves past p->rxmit. */ p = NULL; goto after_sack_rexmit; } else /* Can rexmit part of the current hole */ len = ((long)ulmin(cwin, tp->snd_recover - p->rxmit)); } else len = ((long)ulmin(cwin, p->end - p->rxmit)); off = p->rxmit - tp->snd_una; KASSERT(off >= 0,("%s: sack block to the left of una : %d", __func__, off)); if (len > 0) { sack_rxmit = 1; sendalot = 1; TCPSTAT_INC(tcps_sack_rexmits); TCPSTAT_ADD(tcps_sack_rexmit_bytes, min(len, tp->t_maxseg)); } } after_sack_rexmit: /* * Get standard flags, and add SYN or FIN if requested by 'hidden' * state flags. */ if (tp->t_flags & TF_NEEDFIN) flags |= TH_FIN; if (tp->t_flags & TF_NEEDSYN) flags |= TH_SYN; SOCKBUF_LOCK(&so->so_snd); /* * If in persist timeout with window of 0, send 1 byte. * Otherwise, if window is small but nonzero * and timer expired, we will send what we can * and go to transmit state. */ if (tp->t_flags & TF_FORCEDATA) { if (sendwin == 0) { /* * If we still have some data to send, then * clear the FIN bit. Usually this would * happen below when it realizes that we * aren't sending all the data. However, * if we have exactly 1 byte of unsent data, * then it won't clear the FIN bit below, * and if we are in persist state, we wind * up sending the packet without recording * that we sent the FIN bit. * * We can't just blindly clear the FIN bit, * because if we don't have any more data * to send then the probe will be the FIN * itself. */ if (off < so->so_snd.sb_cc) flags &= ~TH_FIN; sendwin = 1; } else { tcp_timer_activate(tp, TT_PERSIST, 0); tp->t_rxtshift = 0; } } /* * If snd_nxt == snd_max and we have transmitted a FIN, the * offset will be > 0 even if so_snd.sb_cc is 0, resulting in * a negative length. This can also occur when TCP opens up * its congestion window while receiving additional duplicate * acks after fast-retransmit because TCP will reset snd_nxt * to snd_max after the fast-retransmit. * * In the normal retransmit-FIN-only case, however, snd_nxt will * be set to snd_una, the offset will be 0, and the length may * wind up 0. * * If sack_rxmit is true we are retransmitting from the scoreboard * in which case len is already set. */ if (sack_rxmit == 0) { if (sack_bytes_rxmt == 0) len = ((long)ulmin(so->so_snd.sb_cc, sendwin) - off); else { long cwin; /* * We are inside of a SACK recovery episode and are * sending new data, having retransmitted all the * data possible in the scoreboard. */ len = ((long)ulmin(so->so_snd.sb_cc, tp->snd_wnd) - off); /* * Don't remove this (len > 0) check ! * We explicitly check for len > 0 here (although it * isn't really necessary), to work around a gcc * optimization issue - to force gcc to compute * len above. Without this check, the computation * of len is bungled by the optimizer. */ if (len > 0) { cwin = tp->snd_cwnd - (tp->snd_nxt - tp->sack_newdata) - sack_bytes_rxmt; if (cwin < 0) cwin = 0; len = lmin(len, cwin); } } } /* * Lop off SYN bit if it has already been sent. However, if this * is SYN-SENT state and if segment contains data and if we don't * know that foreign host supports TAO, suppress sending segment. */ if ((flags & TH_SYN) && SEQ_GT(tp->snd_nxt, tp->snd_una)) { if (tp->t_state != TCPS_SYN_RECEIVED) flags &= ~TH_SYN; off--, len++; } /* * Be careful not to send data and/or FIN on SYN segments. * This measure is needed to prevent interoperability problems * with not fully conformant TCP implementations. */ if ((flags & TH_SYN) && (tp->t_flags & TF_NOOPT)) { len = 0; flags &= ~TH_FIN; } if (len < 0) { /* * If FIN has been sent but not acked, * but we haven't been called to retransmit, * len will be < 0. Otherwise, window shrank * after we sent into it. If window shrank to 0, * cancel pending retransmit, pull snd_nxt back * to (closed) window, and set the persist timer * if it isn't already going. If the window didn't * close completely, just wait for an ACK. */ len = 0; if (sendwin == 0) { tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rxtshift = 0; tp->snd_nxt = tp->snd_una; if (!tcp_timer_active(tp, TT_PERSIST)) tcp_setpersist(tp); } } /* len will be >= 0 after this point. */ KASSERT(len >= 0, ("[%s:%d]: len < 0", __func__, __LINE__)); /* * Automatic sizing of send socket buffer. Often the send buffer * size is not optimally adjusted to the actual network conditions * at hand (delay bandwidth product). Setting the buffer size too * small limits throughput on links with high bandwidth and high * delay (eg. trans-continental/oceanic links). Setting the * buffer size too big consumes too much real kernel memory, * especially with many connections on busy servers. * * The criteria to step up the send buffer one notch are: * 1. receive window of remote host is larger than send buffer * (with a fudge factor of 5/4th); * 2. send buffer is filled to 7/8th with data (so we actually * have data to make use of it); * 3. send buffer fill has not hit maximal automatic size; * 4. our send window (slow start and cogestion controlled) is * larger than sent but unacknowledged data in send buffer. * * The remote host receive window scaling factor may limit the * growing of the send buffer before it reaches its allowed * maximum. * * It scales directly with slow start or congestion window * and does at most one step per received ACK. This fast * scaling has the drawback of growing the send buffer beyond * what is strictly necessary to make full use of a given * delay*bandwith product. However testing has shown this not * to be much of an problem. At worst we are trading wasting * of available bandwith (the non-use of it) for wasting some * socket buffer memory. * * TODO: Shrink send buffer during idle periods together * with congestion window. Requires another timer. Has to * wait for upcoming tcp timer rewrite. */ if (V_tcp_do_autosndbuf && so->so_snd.sb_flags & SB_AUTOSIZE) { if ((tp->snd_wnd / 4 * 5) >= so->so_snd.sb_hiwat && so->so_snd.sb_cc >= (so->so_snd.sb_hiwat / 8 * 7) && so->so_snd.sb_cc < V_tcp_autosndbuf_max && sendwin >= (so->so_snd.sb_cc - (tp->snd_nxt - tp->snd_una))) { if (!sbreserve_locked(&so->so_snd, min(so->so_snd.sb_hiwat + V_tcp_autosndbuf_inc, V_tcp_autosndbuf_max), so, curthread)) so->so_snd.sb_flags &= ~SB_AUTOSIZE; } } /* * Decide if we can use TCP Segmentation Offloading (if supported by * hardware). * * TSO may only be used if we are in a pure bulk sending state. The * presence of TCP-MD5, SACK retransmits, SACK advertizements and * IP options prevent using TSO. With TSO the TCP header is the same * (except for the sequence number) for all generated packets. This * makes it impossible to transmit any options which vary per generated * segment or packet. */ #ifdef IPSEC /* * Pre-calculate here as we save another lookup into the darknesses * of IPsec that way and can actually decide if TSO is ok. */ ipsec_optlen = ipsec_hdrsiz_tcp(tp); #endif if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > tp->t_maxseg && ((tp->t_flags & TF_SIGNATURE) == 0) && tp->rcv_numsacks == 0 && sack_rxmit == 0 && #ifdef IPSEC ipsec_optlen == 0 && #endif tp->t_inpcb->inp_options == NULL && tp->t_inpcb->in6p_options == NULL) tso = 1; if (sack_rxmit) { if (SEQ_LT(p->rxmit + len, tp->snd_una + so->so_snd.sb_cc)) flags &= ~TH_FIN; } else { if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) flags &= ~TH_FIN; } recwin = sbspace(&so->so_rcv); /* * Sender silly window avoidance. We transmit under the following * conditions when len is non-zero: * * - We have a full segment (or more with TSO) * - This is the last buffer in a write()/send() and we are * either idle or running NODELAY * - we've timed out (e.g. persist timer) * - we have more then 1/2 the maximum send window's worth of * data (receiver may be limited the window size) * - we need to retransmit */ if (len) { if (len >= tp->t_maxseg) goto send; /* * NOTE! on localhost connections an 'ack' from the remote * end may occur synchronously with the output and cause * us to flush a buffer queued with moretocome. XXX * * note: the len + off check is almost certainly unnecessary. */ if (!(tp->t_flags & TF_MORETOCOME) && /* normal case */ (idle || (tp->t_flags & TF_NODELAY)) && len + off >= so->so_snd.sb_cc && (tp->t_flags & TF_NOPUSH) == 0) { goto send; } if (tp->t_flags & TF_FORCEDATA) /* typ. timeout case */ goto send; if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) goto send; if (SEQ_LT(tp->snd_nxt, tp->snd_max)) /* retransmit case */ goto send; if (sack_rxmit) goto send; } /* * Compare available window to amount of window * known to peer (as advertised window less * next expected input). If the difference is at least two * max size segments, or at least 50% of the maximum possible * window, then want to send a window update to peer. * Skip this if the connection is in T/TCP half-open state. * Don't send pure window updates when the peer has closed * the connection and won't ever send more data. */ if (recwin > 0 && !(tp->t_flags & TF_NEEDSYN) && !TCPS_HAVERCVDFIN(tp->t_state)) { /* * "adv" is the amount we can increase the window, * taking into account that we are limited by * TCP_MAXWIN << tp->rcv_scale. */ long adv; int oldwin; adv = min(recwin, (long)TCP_MAXWIN << tp->rcv_scale); if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) { oldwin = (tp->rcv_adv - tp->rcv_nxt); adv -= oldwin; } else oldwin = 0; /* * If the new window size ends up being the same as the old * size when it is scaled, then don't force a window update. */ if (oldwin >> tp->rcv_scale == (adv + oldwin) >> tp->rcv_scale) goto dontupdate; if (adv >= (long) (2 * tp->t_maxseg)) goto send; if (2 * adv >= (long) so->so_rcv.sb_hiwat) goto send; } dontupdate: /* * Send if we owe the peer an ACK, RST, SYN, or urgent data. ACKNOW * is also a catch-all for the retransmit timer timeout case. */ if (tp->t_flags & TF_ACKNOW) goto send; if ((flags & TH_RST) || ((flags & TH_SYN) && (tp->t_flags & TF_NEEDSYN) == 0)) goto send; if (SEQ_GT(tp->snd_up, tp->snd_una)) goto send; /* * If our state indicates that FIN should be sent * and we have not yet done so, then we need to send. */ if (flags & TH_FIN && ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) goto send; /* * In SACK, it is possible for tcp_output to fail to send a segment * after the retransmission timer has been turned off. Make sure * that the retransmission timer is set. */ if ((tp->t_flags & TF_SACK_PERMIT) && SEQ_GT(tp->snd_max, tp->snd_una) && !tcp_timer_active(tp, TT_REXMT) && !tcp_timer_active(tp, TT_PERSIST)) { tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); goto just_return; } /* * TCP window updates are not reliable, rather a polling protocol * using ``persist'' packets is used to insure receipt of window * updates. The three ``states'' for the output side are: * idle not doing retransmits or persists * persisting to move a small or zero window * (re)transmitting and thereby not persisting * * tcp_timer_active(tp, TT_PERSIST) * is true when we are in persist state. * (tp->t_flags & TF_FORCEDATA) * is set when we are called to send a persist packet. * tcp_timer_active(tp, TT_REXMT) * is set when we are retransmitting * The output side is idle when both timers are zero. * * If send window is too small, there is data to transmit, and no * retransmit or persist is pending, then go to persist state. * If nothing happens soon, send when timer expires: * if window is nonzero, transmit what we can, * otherwise force out a byte. */ if (so->so_snd.sb_cc && !tcp_timer_active(tp, TT_REXMT) && !tcp_timer_active(tp, TT_PERSIST)) { tp->t_rxtshift = 0; tcp_setpersist(tp); } /* * No reason to send a segment, just return. */ just_return: SOCKBUF_UNLOCK(&so->so_snd); return (0); send: SOCKBUF_LOCK_ASSERT(&so->so_snd); /* * Before ESTABLISHED, force sending of initial options * unless TCP set not to do any options. * NOTE: we assume that the IP/TCP header plus TCP options * always fit in a single mbuf, leaving room for a maximum * link header, i.e. * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MCLBYTES */ optlen = 0; #ifdef INET6 if (isipv6) hdrlen = sizeof (struct ip6_hdr) + sizeof (struct tcphdr); else #endif hdrlen = sizeof (struct tcpiphdr); /* * Compute options for segment. * We only have to care about SYN and established connection * segments. Options for SYN-ACK segments are handled in TCP * syncache. */ if ((tp->t_flags & TF_NOOPT) == 0) { to.to_flags = 0; /* Maximum segment size. */ if (flags & TH_SYN) { tp->snd_nxt = tp->iss; to.to_mss = tcp_mssopt(&tp->t_inpcb->inp_inc); to.to_flags |= TOF_MSS; } /* Window scaling. */ if ((flags & TH_SYN) && (tp->t_flags & TF_REQ_SCALE)) { to.to_wscale = tp->request_r_scale; to.to_flags |= TOF_SCALE; } /* Timestamps. */ if ((tp->t_flags & TF_RCVD_TSTMP) || ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) { to.to_tsval = ticks + tp->ts_offset; to.to_tsecr = tp->ts_recent; to.to_flags |= TOF_TS; /* Set receive buffer autosizing timestamp. */ if (tp->rfbuf_ts == 0 && (so->so_rcv.sb_flags & SB_AUTOSIZE)) tp->rfbuf_ts = ticks; } /* Selective ACK's. */ if (tp->t_flags & TF_SACK_PERMIT) { if (flags & TH_SYN) to.to_flags |= TOF_SACKPERM; else if (TCPS_HAVEESTABLISHED(tp->t_state) && (tp->t_flags & TF_SACK_PERMIT) && tp->rcv_numsacks > 0) { to.to_flags |= TOF_SACK; to.to_nsacks = tp->rcv_numsacks; to.to_sacks = (u_char *)tp->sackblks; } } #ifdef TCP_SIGNATURE /* TCP-MD5 (RFC2385). */ if (tp->t_flags & TF_SIGNATURE) to.to_flags |= TOF_SIGNATURE; #endif /* TCP_SIGNATURE */ /* Processing the options. */ hdrlen += optlen = tcp_addoptions(&to, opt); } #ifdef INET6 if (isipv6) ipoptlen = ip6_optlen(tp->t_inpcb); else #endif if (tp->t_inpcb->inp_options) ipoptlen = tp->t_inpcb->inp_options->m_len - offsetof(struct ipoption, ipopt_list); else ipoptlen = 0; #ifdef IPSEC ipoptlen += ipsec_optlen; #endif /* * Adjust data length if insertion of options will * bump the packet length beyond the t_maxopd length. * Clear the FIN bit because we cut off the tail of * the segment. */ if (len + optlen + ipoptlen > tp->t_maxopd) { flags &= ~TH_FIN; if (tso) { KASSERT(ipoptlen == 0, ("%s: TSO can't do IP options", __func__)); /* * Limit a burst to IP_MAXPACKET minus IP, * TCP and options length to keep ip->ip_len * from overflowing. */ if (len > IP_MAXPACKET - hdrlen) { len = IP_MAXPACKET - hdrlen; sendalot = 1; } /* * Prevent the last segment from being * fractional unless the send sockbuf can * be emptied. */ if (sendalot && off + len < so->so_snd.sb_cc) { len -= len % (tp->t_maxopd - optlen); sendalot = 1; } /* * Send the FIN in a separate segment * after the bulk sending is done. * We don't trust the TSO implementations * to clear the FIN flag on all but the * last segment. */ if (tp->t_flags & TF_NEEDFIN) sendalot = 1; } else { len = tp->t_maxopd - optlen - ipoptlen; sendalot = 1; } } else tso = 0; KASSERT(len + hdrlen + ipoptlen <= IP_MAXPACKET, ("%s: len > IP_MAXPACKET", __func__)); /*#ifdef DIAGNOSTIC*/ #ifdef INET6 if (max_linkhdr + hdrlen > MCLBYTES) #else if (max_linkhdr + hdrlen > MHLEN) #endif panic("tcphdr too big"); /*#endif*/ /* * This KASSERT is here to catch edge cases at a well defined place. * Before, those had triggered (random) panic conditions further down. */ KASSERT(len >= 0, ("[%s:%d]: len < 0", __func__, __LINE__)); /* * Grab a header mbuf, attaching a copy of data to * be transmitted, and initialize the header from * the template for sends on this connection. */ if (len) { struct mbuf *mb; u_int moff; if ((tp->t_flags & TF_FORCEDATA) && len == 1) TCPSTAT_INC(tcps_sndprobe); else if (SEQ_LT(tp->snd_nxt, tp->snd_max) || sack_rxmit) { tp->t_sndrexmitpack++; TCPSTAT_INC(tcps_sndrexmitpack); TCPSTAT_ADD(tcps_sndrexmitbyte, len); } else { TCPSTAT_INC(tcps_sndpack); TCPSTAT_ADD(tcps_sndbyte, len); } #ifdef notyet if ((m = m_copypack(so->so_snd.sb_mb, off, (int)len, max_linkhdr + hdrlen)) == 0) { SOCKBUF_UNLOCK(&so->so_snd); error = ENOBUFS; goto out; } /* * m_copypack left space for our hdr; use it. */ m->m_len += hdrlen; m->m_data -= hdrlen; #else MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { SOCKBUF_UNLOCK(&so->so_snd); error = ENOBUFS; goto out; } #ifdef INET6 if (MHLEN < hdrlen + max_linkhdr) { MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { SOCKBUF_UNLOCK(&so->so_snd); m_freem(m); error = ENOBUFS; goto out; } } #endif m->m_data += max_linkhdr; m->m_len = hdrlen; /* * Start the m_copy functions from the closest mbuf * to the offset in the socket buffer chain. */ mb = sbsndptr(&so->so_snd, off, len, &moff); if (len <= MHLEN - hdrlen - max_linkhdr) { m_copydata(mb, moff, (int)len, mtod(m, caddr_t) + hdrlen); m->m_len += len; } else { m->m_next = m_copy(mb, moff, (int)len); if (m->m_next == NULL) { SOCKBUF_UNLOCK(&so->so_snd); (void) m_free(m); error = ENOBUFS; goto out; } } #endif /* notyet */ /* * If we're sending everything we've got, set PUSH. * (This will keep happy those implementations which only * give data to the user when a buffer fills or * a PUSH comes in.) */ if (off + len == so->so_snd.sb_cc) flags |= TH_PUSH; SOCKBUF_UNLOCK(&so->so_snd); } else { SOCKBUF_UNLOCK(&so->so_snd); if (tp->t_flags & TF_ACKNOW) TCPSTAT_INC(tcps_sndacks); else if (flags & (TH_SYN|TH_FIN|TH_RST)) TCPSTAT_INC(tcps_sndctrl); else if (SEQ_GT(tp->snd_up, tp->snd_una)) TCPSTAT_INC(tcps_sndurg); else TCPSTAT_INC(tcps_sndwinup); MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { error = ENOBUFS; goto out; } #ifdef INET6 if (isipv6 && (MHLEN < hdrlen + max_linkhdr) && MHLEN >= hdrlen) { MH_ALIGN(m, hdrlen); } else #endif m->m_data += max_linkhdr; m->m_len = hdrlen; } SOCKBUF_UNLOCK_ASSERT(&so->so_snd); m->m_pkthdr.rcvif = (struct ifnet *)0; #ifdef MAC mac_inpcb_create_mbuf(tp->t_inpcb, m); #endif #ifdef INET6 if (isipv6) { ip6 = mtod(m, struct ip6_hdr *); th = (struct tcphdr *)(ip6 + 1); tcpip_fillheaders(tp->t_inpcb, ip6, th); } else #endif /* INET6 */ { ip = mtod(m, struct ip *); ipov = (struct ipovly *)ip; th = (struct tcphdr *)(ip + 1); tcpip_fillheaders(tp->t_inpcb, ip, th); } /* * Fill in fields, remembering maximum advertised * window for use in delaying messages about window sizes. * If resending a FIN, be sure not to use a new sequence number. */ if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && tp->snd_nxt == tp->snd_max) tp->snd_nxt--; /* * If we are starting a connection, send ECN setup * SYN packet. If we are on a retransmit, we may * resend those bits a number of times as per * RFC 3168. */ if (tp->t_state == TCPS_SYN_SENT && V_tcp_do_ecn) { if (tp->t_rxtshift >= 1) { if (tp->t_rxtshift <= V_tcp_ecn_maxretries) flags |= TH_ECE|TH_CWR; } else flags |= TH_ECE|TH_CWR; } if (tp->t_state == TCPS_ESTABLISHED && (tp->t_flags & TF_ECN_PERMIT)) { /* * If the peer has ECN, mark data packets with * ECN capable transmission (ECT). * Ignore pure ack packets, retransmissions and window probes. */ if (len > 0 && SEQ_GEQ(tp->snd_nxt, tp->snd_max) && !((tp->t_flags & TF_FORCEDATA) && len == 1)) { #ifdef INET6 if (isipv6) ip6->ip6_flow |= htonl(IPTOS_ECN_ECT0 << 20); else #endif ip->ip_tos |= IPTOS_ECN_ECT0; TCPSTAT_INC(tcps_ecn_ect0); } /* * Reply with proper ECN notifications. */ if (tp->t_flags & TF_ECN_SND_CWR) { flags |= TH_CWR; tp->t_flags &= ~TF_ECN_SND_CWR; } if (tp->t_flags & TF_ECN_SND_ECE) flags |= TH_ECE; } /* * If we are doing retransmissions, then snd_nxt will * not reflect the first unsent octet. For ACK only * packets, we do not want the sequence number of the * retransmitted packet, we want the sequence number * of the next unsent octet. So, if there is no data * (and no SYN or FIN), use snd_max instead of snd_nxt * when filling in ti_seq. But if we are in persist * state, snd_max might reflect one byte beyond the * right edge of the window, so use snd_nxt in that * case, since we know we aren't doing a retransmission. * (retransmit and persist are mutually exclusive...) */ if (sack_rxmit == 0) { if (len || (flags & (TH_SYN|TH_FIN)) || tcp_timer_active(tp, TT_PERSIST)) th->th_seq = htonl(tp->snd_nxt); else th->th_seq = htonl(tp->snd_max); } else { th->th_seq = htonl(p->rxmit); p->rxmit += len; tp->sackhint.sack_bytes_rexmit += len; } th->th_ack = htonl(tp->rcv_nxt); if (optlen) { bcopy(opt, th + 1, optlen); th->th_off = (sizeof (struct tcphdr) + optlen) >> 2; } th->th_flags = flags; /* * Calculate receive window. Don't shrink window, * but avoid silly window syndrome. */ if (recwin < (long)(so->so_rcv.sb_hiwat / 4) && recwin < (long)tp->t_maxseg) recwin = 0; if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt) && recwin < (long)(tp->rcv_adv - tp->rcv_nxt)) recwin = (long)(tp->rcv_adv - tp->rcv_nxt); if (recwin > (long)TCP_MAXWIN << tp->rcv_scale) recwin = (long)TCP_MAXWIN << tp->rcv_scale; /* * According to RFC1323 the window field in a SYN (i.e., a * or ) segment itself is never scaled. The * case is handled in syncache. */ if (flags & TH_SYN) th->th_win = htons((u_short) (min(sbspace(&so->so_rcv), TCP_MAXWIN))); else th->th_win = htons((u_short)(recwin >> tp->rcv_scale)); /* * Adjust the RXWIN0SENT flag - indicate that we have advertised * a 0 window. This may cause the remote transmitter to stall. This * flag tells soreceive() to disable delayed acknowledgements when * draining the buffer. This can occur if the receiver is attempting * to read more data than can be buffered prior to transmitting on * the connection. */ if (th->th_win == 0) { tp->t_sndzerowin++; tp->t_flags |= TF_RXWIN0SENT; } else tp->t_flags &= ~TF_RXWIN0SENT; if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { th->th_urp = htons((u_short)(tp->snd_up - tp->snd_nxt)); th->th_flags |= TH_URG; } else /* * If no urgent pointer to send, then we pull * the urgent pointer to the left edge of the send window * so that it doesn't drift into the send window on sequence * number wraparound. */ tp->snd_up = tp->snd_una; /* drag it along */ #ifdef TCP_SIGNATURE if (tp->t_flags & TF_SIGNATURE) { int sigoff = to.to_signature - opt; tcp_signature_compute(m, 0, len, optlen, (u_char *)(th + 1) + sigoff, IPSEC_DIR_OUTBOUND); } #endif /* * Put TCP length in extended header, and then * checksum extended header and data. */ m->m_pkthdr.len = hdrlen + len; /* in6_cksum() need this */ #ifdef INET6 if (isipv6) /* * ip6_plen is not need to be filled now, and will be filled * in ip6_output. */ th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), sizeof(struct tcphdr) + optlen + len); else #endif /* INET6 */ { m->m_pkthdr.csum_flags = CSUM_TCP; m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, htons(sizeof(struct tcphdr) + IPPROTO_TCP + len + optlen)); /* IP version must be set here for ipv4/ipv6 checking later */ KASSERT(ip->ip_v == IPVERSION, ("%s: IP version incorrect: %d", __func__, ip->ip_v)); } /* * Enable TSO and specify the size of the segments. * The TCP pseudo header checksum is always provided. * XXX: Fixme: This is currently not the case for IPv6. */ if (tso) { KASSERT(len > tp->t_maxopd - optlen, ("%s: len <= tso_segsz", __func__)); m->m_pkthdr.csum_flags |= CSUM_TSO; m->m_pkthdr.tso_segsz = tp->t_maxopd - optlen; } KASSERT(len + hdrlen + ipoptlen == m_length(m, NULL), ("%s: mbuf chain shorter than expected", __func__)); /* * In transmit state, time the transmission and arrange for * the retransmit. In persist state, just set snd_max. */ if ((tp->t_flags & TF_FORCEDATA) == 0 || !tcp_timer_active(tp, TT_PERSIST)) { tcp_seq startseq = tp->snd_nxt; /* * Advance snd_nxt over sequence space of this segment. */ if (flags & (TH_SYN|TH_FIN)) { if (flags & TH_SYN) tp->snd_nxt++; if (flags & TH_FIN) { tp->snd_nxt++; tp->t_flags |= TF_SENTFIN; } } if (sack_rxmit) goto timer; tp->snd_nxt += len; if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { tp->snd_max = tp->snd_nxt; /* * Time this transmission if not a retransmission and * not currently timing anything. */ if (tp->t_rtttime == 0) { tp->t_rtttime = ticks; tp->t_rtseq = startseq; TCPSTAT_INC(tcps_segstimed); } } /* * Set retransmit timer if not currently set, * and not doing a pure ack or a keep-alive probe. * Initial value for retransmit timer is smoothed * round-trip time + 2 * round-trip time variance. * Initialize shift counter which is used for backoff * of retransmit time. */ timer: if (!tcp_timer_active(tp, TT_REXMT) && ((sack_rxmit && tp->snd_nxt != tp->snd_max) || (tp->snd_nxt != tp->snd_una))) { if (tcp_timer_active(tp, TT_PERSIST)) { tcp_timer_activate(tp, TT_PERSIST, 0); tp->t_rxtshift = 0; } tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); } } else { /* * Persist case, update snd_max but since we are in * persist mode (no window) we do not update snd_nxt. */ int xlen = len; if (flags & TH_SYN) ++xlen; if (flags & TH_FIN) { ++xlen; tp->t_flags |= TF_SENTFIN; } if (SEQ_GT(tp->snd_nxt + xlen, tp->snd_max)) tp->snd_max = tp->snd_nxt + len; } /* Run HHOOK_TCP_ESTABLISHED_OUT helper hooks. */ hhook_run_tcp_est_out(tp, th, &to, len, tso); #ifdef TCPDEBUG /* * Trace. */ if (so->so_options & SO_DEBUG) { u_short save = 0; #ifdef INET6 if (!isipv6) #endif { save = ipov->ih_len; ipov->ih_len = htons(m->m_pkthdr.len /* - hdrlen + (th->th_off << 2) */); } tcp_trace(TA_OUTPUT, tp->t_state, tp, mtod(m, void *), th, 0); #ifdef INET6 if (!isipv6) #endif ipov->ih_len = save; } #endif /* TCPDEBUG */ /* * Fill in IP length and desired time to live and * send to IP level. There should be a better way * to handle ttl and tos; we could keep them in * the template, but need a way to checksum without them. */ /* * m->m_pkthdr.len should have been set before cksum calcuration, * because in6_cksum() need it. */ #ifdef INET6 if (isipv6) { /* * we separately set hoplimit for every segment, since the * user might want to change the value via setsockopt. * Also, desired default hop limit might be changed via * Neighbor Discovery. */ ip6->ip6_hlim = in6_selecthlim(tp->t_inpcb, NULL); /* TODO: IPv6 IP6TOS_ECT bit on */ error = ip6_output(m, tp->t_inpcb->in6p_outputopts, NULL, ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), NULL, NULL, tp->t_inpcb); } #endif /* INET6 */ #if defined(INET) && defined(INET6) else #endif #ifdef INET { ip->ip_len = m->m_pkthdr.len; #ifdef INET6 if (tp->t_inpcb->inp_vflag & INP_IPV6PROTO) ip->ip_ttl = in6_selecthlim(tp->t_inpcb, NULL); #endif /* INET6 */ /* * If we do path MTU discovery, then we set DF on every packet. * This might not be the best thing to do according to RFC3390 * Section 2. However the tcp hostcache migitates the problem * so it affects only the first tcp connection with a host. * * NB: Don't set DF on small MTU/MSS to have a safe fallback. */ if (V_path_mtu_discovery && tp->t_maxopd > V_tcp_minmss) ip->ip_off |= IP_DF; error = ip_output(m, tp->t_inpcb->inp_options, NULL, ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), 0, tp->t_inpcb); } #endif /* INET */ if (error) { /* * We know that the packet was lost, so back out the * sequence number advance, if any. * * If the error is EPERM the packet got blocked by the * local firewall. Normally we should terminate the * connection but the blocking may have been spurious * due to a firewall reconfiguration cycle. So we treat * it like a packet loss and let the retransmit timer and * timeouts do their work over time. * XXX: It is a POLA question whether calling tcp_drop right * away would be the really correct behavior instead. */ if (((tp->t_flags & TF_FORCEDATA) == 0 || !tcp_timer_active(tp, TT_PERSIST)) && ((flags & TH_SYN) == 0) && (error != EPERM)) { if (sack_rxmit) { p->rxmit -= len; tp->sackhint.sack_bytes_rexmit -= len; KASSERT(tp->sackhint.sack_bytes_rexmit >= 0, ("sackhint bytes rtx >= 0")); } else tp->snd_nxt -= len; } out: SOCKBUF_UNLOCK_ASSERT(&so->so_snd); /* Check gotos. */ switch (error) { case EPERM: tp->t_softerror = error; return (error); case ENOBUFS: if (!tcp_timer_active(tp, TT_REXMT) && !tcp_timer_active(tp, TT_PERSIST)) tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); tp->snd_cwnd = tp->t_maxseg; return (0); case EMSGSIZE: /* * For some reason the interface we used initially * to send segments changed to another or lowered * its MTU. * * tcp_mtudisc() will find out the new MTU and as * its last action, initiate retransmission, so it * is important to not do so here. * * If TSO was active we either got an interface * without TSO capabilits or TSO was turned off. * Disable it for this connection as too and * immediatly retry with MSS sized segments generated * by this function. */ if (tso) tp->t_flags &= ~TF_TSO; tcp_mtudisc(tp->t_inpcb, 0); return (0); case EHOSTDOWN: case EHOSTUNREACH: case ENETDOWN: case ENETUNREACH: if (TCPS_HAVERCVDSYN(tp->t_state)) { tp->t_softerror = error; return (0); } /* FALLTHROUGH */ default: return (error); } } TCPSTAT_INC(tcps_sndtotal); /* * Data sent (as far as we can tell). * If this advertises a larger window than any other segment, * then remember the size of the advertised window. * Any pending ACK has now been sent. */ - if (recwin > 0 && SEQ_GT(tp->rcv_nxt + recwin, tp->rcv_adv)) + if (recwin >= 0 && SEQ_GT(tp->rcv_nxt + recwin, tp->rcv_adv)) tp->rcv_adv = tp->rcv_nxt + recwin; tp->last_ack_sent = tp->rcv_nxt; tp->t_flags &= ~(TF_ACKNOW | TF_DELACK); if (tcp_timer_active(tp, TT_DELACK)) tcp_timer_activate(tp, TT_DELACK, 0); #if 0 /* * This completely breaks TCP if newreno is turned on. What happens * is that if delayed-acks are turned on on the receiver, this code * on the transmitter effectively destroys the TCP window, forcing * it to four packets (1.5Kx4 = 6K window). */ if (sendalot && --maxburst) goto again; #endif if (sendalot) goto again; return (0); } void tcp_setpersist(struct tcpcb *tp) { int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; int tt; tp->t_flags &= ~TF_PREVVALID; if (tcp_timer_active(tp, TT_REXMT)) panic("tcp_setpersist: retransmit pending"); /* * Start/restart persistance timer. */ TCPT_RANGESET(tt, t * tcp_backoff[tp->t_rxtshift], TCPTV_PERSMIN, TCPTV_PERSMAX); tcp_timer_activate(tp, TT_PERSIST, tt); if (tp->t_rxtshift < TCP_MAXRXTSHIFT) tp->t_rxtshift++; } /* * Insert TCP options according to the supplied parameters to the place * optp in a consistent way. Can handle unaligned destinations. * * The order of the option processing is crucial for optimal packing and * alignment for the scarce option space. * * The optimal order for a SYN/SYN-ACK segment is: * MSS (4) + NOP (1) + Window scale (3) + SACK permitted (2) + * Timestamp (10) + Signature (18) = 38 bytes out of a maximum of 40. * * The SACK options should be last. SACK blocks consume 8*n+2 bytes. * So a full size SACK blocks option is 34 bytes (with 4 SACK blocks). * At minimum we need 10 bytes (to generate 1 SACK block). If both * TCP Timestamps (12 bytes) and TCP Signatures (18 bytes) are present, * we only have 10 bytes for SACK options (40 - (12 + 18)). */ int tcp_addoptions(struct tcpopt *to, u_char *optp) { u_int mask, optlen = 0; for (mask = 1; mask < TOF_MAXOPT; mask <<= 1) { if ((to->to_flags & mask) != mask) continue; if (optlen == TCP_MAXOLEN) break; switch (to->to_flags & mask) { case TOF_MSS: while (optlen % 4) { optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } if (TCP_MAXOLEN - optlen < TCPOLEN_MAXSEG) continue; optlen += TCPOLEN_MAXSEG; *optp++ = TCPOPT_MAXSEG; *optp++ = TCPOLEN_MAXSEG; to->to_mss = htons(to->to_mss); bcopy((u_char *)&to->to_mss, optp, sizeof(to->to_mss)); optp += sizeof(to->to_mss); break; case TOF_SCALE: while (!optlen || optlen % 2 != 1) { optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } if (TCP_MAXOLEN - optlen < TCPOLEN_WINDOW) continue; optlen += TCPOLEN_WINDOW; *optp++ = TCPOPT_WINDOW; *optp++ = TCPOLEN_WINDOW; *optp++ = to->to_wscale; break; case TOF_SACKPERM: while (optlen % 2) { optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } if (TCP_MAXOLEN - optlen < TCPOLEN_SACK_PERMITTED) continue; optlen += TCPOLEN_SACK_PERMITTED; *optp++ = TCPOPT_SACK_PERMITTED; *optp++ = TCPOLEN_SACK_PERMITTED; break; case TOF_TS: while (!optlen || optlen % 4 != 2) { optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } if (TCP_MAXOLEN - optlen < TCPOLEN_TIMESTAMP) continue; optlen += TCPOLEN_TIMESTAMP; *optp++ = TCPOPT_TIMESTAMP; *optp++ = TCPOLEN_TIMESTAMP; to->to_tsval = htonl(to->to_tsval); to->to_tsecr = htonl(to->to_tsecr); bcopy((u_char *)&to->to_tsval, optp, sizeof(to->to_tsval)); optp += sizeof(to->to_tsval); bcopy((u_char *)&to->to_tsecr, optp, sizeof(to->to_tsecr)); optp += sizeof(to->to_tsecr); break; case TOF_SIGNATURE: { int siglen = TCPOLEN_SIGNATURE - 2; while (!optlen || optlen % 4 != 2) { optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } if (TCP_MAXOLEN - optlen < TCPOLEN_SIGNATURE) continue; optlen += TCPOLEN_SIGNATURE; *optp++ = TCPOPT_SIGNATURE; *optp++ = TCPOLEN_SIGNATURE; to->to_signature = optp; while (siglen--) *optp++ = 0; break; } case TOF_SACK: { int sackblks = 0; struct sackblk *sack = (struct sackblk *)to->to_sacks; tcp_seq sack_seq; while (!optlen || optlen % 4 != 2) { optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } if (TCP_MAXOLEN - optlen < TCPOLEN_SACKHDR + TCPOLEN_SACK) continue; optlen += TCPOLEN_SACKHDR; *optp++ = TCPOPT_SACK; sackblks = min(to->to_nsacks, (TCP_MAXOLEN - optlen) / TCPOLEN_SACK); *optp++ = TCPOLEN_SACKHDR + sackblks * TCPOLEN_SACK; while (sackblks--) { sack_seq = htonl(sack->start); bcopy((u_char *)&sack_seq, optp, sizeof(sack_seq)); optp += sizeof(sack_seq); sack_seq = htonl(sack->end); bcopy((u_char *)&sack_seq, optp, sizeof(sack_seq)); optp += sizeof(sack_seq); optlen += TCPOLEN_SACK; sack++; } TCPSTAT_INC(tcps_sack_send_blocks); break; } default: panic("%s: unknown TCP option type", __func__); break; } } /* Terminate and pad TCP options to a 4 byte boundary. */ if (optlen % 4) { optlen += TCPOLEN_EOL; *optp++ = TCPOPT_EOL; } /* * According to RFC 793 (STD0007): * "The content of the header beyond the End-of-Option option * must be header padding (i.e., zero)." * and later: "The padding is composed of zeros." */ while (optlen % 4) { optlen += TCPOLEN_PAD; *optp++ = TCPOPT_PAD; } KASSERT(optlen <= TCP_MAXOLEN, ("%s: TCP options too long", __func__)); return (optlen); } diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC index 0fac1a957997..e2bed44764b7 100644 --- a/sys/pc98/conf/GENERIC +++ b/sys/pc98/conf/GENERIC @@ -1,290 +1,291 @@ # # GENERIC -- Generic kernel configuration file for FreeBSD/pc98 # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ cpu I486_CPU cpu I586_CPU cpu I686_CPU ident GENERIC makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options SCHED_4BSD # 4BSD scheduler #options PREEMPTION # Enable kernel thread preemption options INET # InterNETworking options INET6 # IPv6 communications protocols options SCTP # Stream Control Transmission Protocol options FFS # Berkeley Fast Filesystem options SOFTUPDATES # Enable FFS soft updates support options UFS_ACL # Support for access control lists options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCLIENT options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) options PSEUDOFS # Pseudo-filesystem framework options GEOM_PART_GPT # GUID Partition Tables. options GEOM_LABEL # Provides labelization options COMPAT_FREEBSD4 # Compatible with FreeBSD4 options COMPAT_FREEBSD5 # Compatible with FreeBSD5 options COMPAT_FREEBSD6 # Compatible with FreeBSD6 options COMPAT_FREEBSD7 # Compatible with FreeBSD7 options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI options EPSON_BOUNCEDMA # use bounce buffer for 15-16M #options EPSON_MEMWIN # EPSON memory window support #options LINE30 options KTRACE # ktrace(1) support options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options KBD_INSTALL_CDEV # install a CDEV entry in /dev options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) options AUDIT # Security event auditing options MAC # TrustedBSD MAC Framework options INCLUDE_CONFIG_FILE # Include this file in kernel # Debugging for use in -current options KDB # Enable kernel debugger support. options DDB # Support DDB. options GDB # Support remote GDB. options DEADLKRES # Enable the deadlock resolver options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones # To make an SMP kernel, the next two lines are needed #options SMP # Symmetric MultiProcessor Kernel #device apic # I/O APIC # Bus support. device pci # Floppy drives device fdc # ATA controllers device ahci # AHCI-compatible SATA controllers device ata # Legacy ATA/SATA controllers options ATA_CAM # Handle legacy controllers with CAM options ATA_STATIC_ID # Static device numbering device mvs # Marvell 88SX50XX/88SX60XX/88SX70XX/SoC SATA device siis # SiliconImage SiI3124/SiI3132/SiI3531 SATA # SCSI Controllers device adv # Advansys SCSI adapters device ahc # AHA2940 and onboard AIC7xxx devices device amd # AMD 53C974 (Tekram DC-390(T)) device isp # Qlogic family #device ncr # NCR/Symbios Logic device sym # NCR/Symbios Logic (newer chipsets + those of `ncr') device aic # PC-9801-100 device ct # host adapter using WD33C93[ABC] chip (C bus) device ncv # NCR 53C500 device nsp # Workbit Ninja SCSI-3 device stg # TMC 18C30/18C50 # ATA/SCSI peripherals device scbus # SCSI bus (required for ATA/SCSI) device ch # SCSI media changers device da # Direct Access (disks) device sa # Sequential Access (tape etc) device cd # CD device pass # Passthrough device (direct ATA/SCSI access) device ses # SCSI Environmental Services (and SAF-TE) # keyboard driver device pckbd # PC98 keyboard device gdc # GDC screen device splash # Splash screen and screen saver support # syscons is the default console driver, resembling an SCO console device sc #device agp # support several AGP chipsets # Power management support (see NOTES for more options) #device apm #device pmc #device canbus #device canbepm # Add suspend/resume support for the i8254. #device pmtimer -# Audio support -#device sound # Generic sound driver -#device snd_mss # Microsoft Sound System -#device "snd_sb16" # Sound Blaster 16 -#device snd_sbc # Sound Blaster - # PCCARD (PCMCIA) support # PCMCIA and cardbus bridge support device cbb # cardbus (yenta) bridge device pccard # PC Card (16-bit) bus device cardbus # CardBus (32-bit) bus # Serial (COM) ports #options COM_MULTIPORT #options COM_ESP # ESP98 #device sio # 8250, 16[45]50, 8251 based serial ports device uart # Generic UART driver device mse #device joy # NEW Parallel port device ppc device ppbus # Parallel port bus (required) device lpt # Printer device plip # TCP/IP over parallel device ppi # Parallel port interface device #device vpo # Requires scbus and da # OLD Parallel port # Please stay olpt driver after ppc driver device olpt # PCI Ethernet NICs. device de # DEC/Intel DC21x4x (``Tulip'') #device em # Intel PRO/1000 adapter Gigabit Ethernet Card device le # AMD Am7900 LANCE and Am79C9xx PCnet #device ti # Alteon Networks Tigon I/II gigabit Ethernet device txp # 3Com 3cR990 (``Typhoon'') device vx # 3Com 3c590, 3c595 (``Vortex'') # PCI Ethernet NICs that use the common MII bus controller code. # NOTE: Be sure to keep the 'device miibus' line in order to use these NICs! device miibus # MII bus support device bfe # Broadcom BCM440x 10/100 Ethernet #device bge # Broadcom BCM570xx Gigabit Ethernet device dc # DEC/Intel 21143 and various workalikes device fxp # Intel EtherExpress PRO/100B (82557, 82558) #device lge # Level 1 LXT1001 gigabit Ethernet #device nge # NatSemi DP83820 gigabit Ethernet device pcn # AMD Am79C97x PCI 10/100 (precedence over 'le') device re # RealTek 8139C+/8169/8169S/8110S device rl # RealTek 8129/8139 device sf # Adaptec AIC-6915 (``Starfire'') device sis # Silicon Integrated Systems SiS 900/SiS 7016 #device sk # SysKonnect SK-984x & SK-982x gigabit Ethernet device ste # Sundance ST201 (D-Link DFE-550TX) device tl # Texas Instruments ThunderLAN device tx # SMC EtherPower II (83c170 ``EPIC'') #device vge # VIA VT612x gigabit Ethernet device vr # VIA Rhine, Rhine II device wb # Winbond W89C840F device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') # ISA Ethernet NICs. pccard NICs included. # 'device ed' requires 'device miibus' device ed # NE[12]000, SMC Ultra, 3c503, DS8390 cards device ep # Etherlink III based cards device fe # Fujitsu MB8696x based cards device sn # SMC's 9000 series of Ethernet chips device snc device xe # Xircom pccard Ethernet # Wireless NIC cards #device wlan # 802.11 support #options IEEE80211_DEBUG # enable debug msgs #options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's #options IEEE80211_SUPPORT_MESH # enable 802.11s draft support #device wlan_wep # 802.11 WEP support #device wlan_ccmp # 802.11 CCMP support #device wlan_tkip # 802.11 TKIP support #device wlan_amrr # AMRR transmit rate control algorithm #device an # Aironet 4500/4800 802.11 wireless NICs. #device ath # Atheros NIC's #device ath_pci # Atheros pci/cardbus glue #device ath_hal # pci/cardbus chip support #options AH_SUPPORT_AR5416 # enable AR5416 tx/rx descriptors #device ath_rate_sample # SampleRate tx rate control for ath #device ral # Ralink Technology RT2500 wireless NICs. #device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. #device wl # Older non 802.11 Wavelan wireless NIC. # Pseudo devices. device loop # Network loopback device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tun # Packet tunnel. device pty # BSD-style compatibility pseudo ttys device md # Memory "disks" device gif # IPv6 and IPv4 tunneling device faith # IPv6-to-IPv4 relaying (translation) device firmware # firmware assist module # The `bpf' device enables the Berkeley Packet Filter. # Be aware of the administrative consequences of enabling this! # Note that 'bpf' is required for DHCP. device bpf # Berkeley packet filter # USB support #options USB_DEBUG # enable debug msgs #device uhci # UHCI PCI->USB interface #device ohci # OHCI PCI->USB interface #device ehci # EHCI PCI->USB interface (USB 2.0) #device usb # USB Bus (required) #device udbp # USB Double Bulk Pipe devices (needs netgraph) #device uhid # "Human Interface Devices" #device ukbd # Keyboard #device ulpt # Printer #device umass # Disks/Mass storage - Requires scbus and da #device ums # Mouse #device urio # Diamond Rio 500 MP3 player # USB Serial devices #device uark # Technologies ARK3116 based serial adapters #device ubsa # Belkin F5U103 and compatible serial adapters #device ubser # BWCT console serial adapters #device uftdi # For FTDI usb serial adapters #device uipaq # Some WinCE based devices #device uplcom # Prolific PL-2303 serial adapters #device uslcom # SI Labs CP2101/CP2102 serial adapters #device uvisor # Visor and Palm devices #device uvscom # USB serial support for DDI pocket's PHS # USB Ethernet, requires miibus #device aue # ADMtek USB Ethernet #device axe # ASIX Electronics USB Ethernet #device cdce # Generic USB over Ethernet #device cue # CATC USB Ethernet #device kue # Kawasaki LSI USB Ethernet #device rue # RealTek RTL8150 USB Ethernet #device udav # Davicom DM9601E USB # USB Wireless #device rum # Ralink Technology RT2501USB wireless NICs #device uath # Atheros AR5523 wireless NICs #device ural # Ralink Technology RT2500USB wireless NICs #device zyd # ZyDAS zb1211/zb1211b wireless NICs # FireWire support #device firewire # FireWire bus code #device sbp # SCSI over FireWire (Requires scbus and da) #device fwe # Ethernet over FireWire (non-standard!) + +# Sound support +#device sound # Generic sound driver (required) +#device snd_mss # Microsoft Sound System +#device "snd_sb16" # Sound Blaster 16 +#device snd_sbc # Sound Blaster +#device snd_uaudio # USB Audio diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC index 406dcf698ec8..11c5d35f71a2 100644 --- a/sys/sparc64/conf/GENERIC +++ b/sys/sparc64/conf/GENERIC @@ -1,268 +1,275 @@ # # GENERIC -- Generic kernel configuration file for FreeBSD/sparc64 # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ cpu SUN4U ident GENERIC makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols # Platforms supported # At this time all platforms are supported, as-is. options SCHED_4BSD # 4BSD scheduler #options PREEMPTION # Enable kernel thread preemption options INET # InterNETworking options INET6 # IPv6 communications protocols options SCTP # Stream Control Transmission Protocol options FFS # Berkeley Fast Filesystem options SOFTUPDATES # Enable FFS soft updates support options UFS_ACL # Support for access control lists options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCLIENT #options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) options PSEUDOFS # Pseudo-filesystem framework options GEOM_PART_GPT # GUID Partition Tables. options GEOM_LABEL # Provides labelization options COMPAT_FREEBSD5 # Compatible with FreeBSD5 options COMPAT_FREEBSD6 # Compatible with FreeBSD6 options COMPAT_FREEBSD7 # Compatible with FreeBSD7 options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI options KTRACE # ktrace(1) support options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) options AUDIT # Security event auditing options MAC # TrustedBSD MAC Framework -options INCLUDE_CONFIG_FILE # Include this file in kernel +options INCLUDE_CONFIG_FILE # Include this file in kernel # Debugging for use in -current options KDB # Enable kernel debugger support. options DDB # Support DDB. options GDB # Support remote GDB. -options DEADLKRES # Enable the deadlock resolver +options DEADLKRES # Enable the deadlock resolver options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones # Make an SMP-capable kernel by default options SMP # Symmetric MultiProcessor Kernel # Standard busses device ebus device isa device pci device sbus device central device fhc # Floppy drives #device fdc # ATA controllers device ahci # AHCI-compatible SATA controllers device ata # Legacy ATA/SATA controllers options ATA_CAM # Handle legacy controllers with CAM device mvs # Marvell 88SX50XX/88SX60XX/88SX70XX/SoC SATA device siis # SiliconImage SiI3124/SiI3132/SiI3531 SATA # SCSI Controllers device ahc # AHA2940 and onboard AIC7xxx devices options AHC_ALLOW_MEMIO # Attempt to use memory mapped I/O options AHC_REG_PRETTY_PRINT # Print register bitfields in debug # output. Adds ~128k to driver. device isp # Qlogic family device ispfw # Firmware module for Qlogic host adapters device mpt # LSI-Logic MPT-Fusion device sym # NCR/Symbios/LSI Logic 53C8XX/53C1010/53C1510D device esp # NCR53c9x (FEPS/FAS366) # ATA/SCSI peripherals device scbus # SCSI bus (required for ATA/SCSI) device ch # SCSI media changers device da # Direct Access (disks) device sa # Sequential Access (tape etc) device cd # CD device pass # Passthrough device (direct ATA/SCSI access) device ses # SCSI Environmental Services (and SAF-TE) # RAID controllers #device amr # AMI MegaRAID #device mlx # Mylex DAC960 family # atkbdc0 controls both the keyboard and the PS/2 mouse device atkbdc # AT keyboard controller device atkbd # AT keyboard device psm # PS/2 mouse device kbdmux # keyboard multiplexer # syscons is the default console driver, resembling an SCO console device sc device creator # Creator, Creator3D and Elite3D framebuffers device machfb # ATI Mach64 framebuffers device splash # Splash screen and screen saver support options KBD_INSTALL_CDEV # install a CDEV entry in /dev # Builtin hardware device auxio # auxiliary I/O device device eeprom # eeprom (really a front-end for the MK48Txx) device mk48txx # Mostek MK48Txx clocks device rtc # rtc (really a front-end for the MC146818) device mc146818 # Motorola MC146818 and compatible clocks device epic # Sun Fire V215/V245 LEDs device sbbc # Sun BootBus controller (time-of-day clock for # Serengeti and StarCat, console for Serengeti, # requires device uart) # Serial (COM) ports device puc # Multi-channel uarts device scc # Serial communications controllers. device uart # Multi-uart driver # Parallel port #device ppc #device ppbus # Parallel port bus (required) #device lpt # Printer #device plip # TCP/IP over parallel #device ppi # Parallel port interface device #device vpo # Requires scbus and da # PCI Ethernet NICs. #device de # DEC/Intel DC21x4x (``Tulip'') device em # Intel PRO/1000 adapter Gigabit Ethernet Card #device ixgb # Intel PRO/10GbE Ethernet Card device le # AMD Am7900 LANCE and Am79C9xx PCnet device ti # Alteon Networks Tigon I/II gigabit Ethernet device txp # 3Com 3cR990 (``Typhoon'') #device vx # 3Com 3c590, 3c595 (``Vortex'') # PCI Ethernet NICs that use the common MII bus controller code. # NOTE: Be sure to keep the 'device miibus' line in order to use these NICs! device miibus # MII bus support #device bfe # Broadcom BCM440x 10/100 Ethernet device bge # Broadcom BCM570xx Gigabit Ethernet device cas # Sun Cassini/Cassini+ and NS DP83065 Saturn device dc # DEC/Intel 21143 and various workalikes device fxp # Intel EtherExpress PRO/100B (82557, 82558) device gem # Sun GEM/Sun ERI/Apple GMAC device hme # Sun HME (Happy Meal Ethernet) device nge # NatSemi DP83820 gigabit Ethernet #device pcn # AMD Am79C97x PCI 10/100 (precedence over 'le') device re # RealTek 8139C+/8169/8169S/8110S device rl # RealTek 8129/8139 device sf # Adaptec AIC-6915 (``Starfire'') device sis # Silicon Integrated Systems SiS 900/SiS 7016 device sk # SysKonnect SK-984x & SK-982x gigabit Ethernet device ste # Sundance ST201 (D-Link DFE-550TX) device stge # Sundance/Tamarack TC9021 gigabit Ethernet #device tl # Texas Instruments ThunderLAN #device tx # SMC EtherPower II (83c170 ``EPIC'') device vr # VIA Rhine, Rhine II #device wb # Winbond W89C840F device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') # Wireless NIC cards device wlan # 802.11 support options IEEE80211_DEBUG # enable debug msgs options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's options IEEE80211_SUPPORT_MESH # enable 802.11s D3.0 support device wlan_wep # 802.11 WEP support device wlan_ccmp # 802.11 CCMP support device wlan_tkip # 802.11 TKIP support device wlan_amrr # AMRR transmit rate control algorithm device ath # Atheros NIC's device ath_pci # Atheros pci/cardbus glue device ath_hal # Atheros HAL (Hardware Access Layer) options AH_SUPPORT_AR5416 # enable AR5416 tx/rx descriptors device ath_rate_sample # SampleRate tx rate control for ath # Pseudo devices. device loop # Network loopback device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tun # Packet tunnel. device pty # BSD-style compatibility pseudo ttys device md # Memory "disks" device gif # IPv6 and IPv4 tunneling device faith # IPv6-to-IPv4 relaying (translation) device firmware # firmware assist module # The `bpf' device enables the Berkeley Packet Filter. # Be aware of the administrative consequences of enabling this! # Note that 'bpf' is required for DHCP. device bpf # Berkeley packet filter # USB support options USB_DEBUG # enable debug msgs device uhci # UHCI PCI->USB interface device ohci # OHCI PCI->USB interface device ehci # EHCI PCI->USB interface (USB 2.0) device usb # USB Bus (required) #device udbp # USB Double Bulk Pipe devices (needs netgraph) device uhid # "Human Interface Devices" device ukbd # Keyboard device ulpt # Printer device umass # Disks/Mass storage - Requires scbus and da device ums # Mouse device urio # Diamond Rio 500 MP3 player # USB Serial devices device uark # Technologies ARK3116 based serial adapters device ubsa # Belkin F5U103 and compatible serial adapters device uftdi # For FTDI usb serial adapters device uipaq # Some WinCE based devices device uplcom # Prolific PL-2303 serial adapters device uslcom # SI Labs CP2101/CP2102 serial adapters device uvisor # Visor and Palm devices device uvscom # USB serial support for DDI pocket's PHS # USB Ethernet, requires miibus device aue # ADMtek USB Ethernet device axe # ASIX Electronics USB Ethernet device cdce # Generic USB over Ethernet device cue # CATC USB Ethernet device kue # Kawasaki LSI USB Ethernet device rue # RealTek RTL8150 USB Ethernet device udav # Davicom DM9601E USB # USB Wireless device rum # Ralink Technology RT2501USB wireless NICs device uath # Atheros AR5523 wireless NICs device ural # Ralink Technology RT2500USB wireless NICs device zyd # ZyDAS zb1211/zb1211b wireless NICs # FireWire support device firewire # FireWire bus code device sbp # SCSI over FireWire (Requires scbus and da) device fwe # Ethernet over FireWire (non-standard!) device fwip # IP over FireWire (RFC 2734,3146) device dcons # Dumb console driver device dcons_crom # Configuration ROM for dcons + +# Sound support +device sound # Generic sound driver (required) +device snd_audiocs # Crystal Semiconductor CS4231 +device snd_es137x # Ensoniq AudioPCI ES137x +device snd_t4dwave # Acer Labs M5451 +device snd_uaudio # USB Audio diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index fbda5a8956b3..75f9d380ec4a 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -1,179 +1,181 @@ /*- * Copyright (c) 1991, 1993, 1994 * 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. * 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. * * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95 * $FreeBSD$ */ #ifndef _UFS_FFS_EXTERN_H #define _UFS_FFS_EXTERN_H struct buf; struct cg; struct fid; struct fs; struct inode; struct malloc_type; struct mount; struct thread; struct sockaddr; struct statfs; struct ucred; struct vnode; struct vop_fsync_args; struct vop_reallocblks_args; struct workhead; int ffs_alloc(struct inode *, ufs2_daddr_t, ufs2_daddr_t, int, int, struct ucred *, ufs2_daddr_t *); int ffs_balloc_ufs1(struct vnode *a_vp, off_t a_startoffset, int a_size, struct ucred *a_cred, int a_flags, struct buf **a_bpp); int ffs_balloc_ufs2(struct vnode *a_vp, off_t a_startoffset, int a_size, struct ucred *a_cred, int a_flags, struct buf **a_bpp); int ffs_blkatoff(struct vnode *, off_t, char **, struct buf **); void ffs_blkfree(struct ufsmount *, struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t, struct workhead *); ufs2_daddr_t ffs_blkpref_ufs1(struct inode *, ufs_lbn_t, int, ufs1_daddr_t *); ufs2_daddr_t ffs_blkpref_ufs2(struct inode *, ufs_lbn_t, int, ufs2_daddr_t *); int ffs_checkfreefile(struct fs *, struct vnode *, ino_t); void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t); void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int); void ffs_bdflush(struct bufobj *, struct buf *); int ffs_copyonwrite(struct vnode *, struct buf *); int ffs_flushfiles(struct mount *, int, struct thread *); void ffs_fragacct(struct fs *, int, int32_t [], int); int ffs_freefile(struct ufsmount *, struct fs *, struct vnode *, ino_t, int, struct workhead *); int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t); int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t); void ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t); int ffs_mountroot(void); void ffs_oldfscompat_write(struct fs *, struct ufsmount *); void ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end); int ffs_reallocblks(struct vop_reallocblks_args *); int ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t, ufs2_daddr_t, int, int, int, struct ucred *, struct buf **); int ffs_sbupdate(struct ufsmount *, int, int); void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); int ffs_snapblkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t, struct workhead *); void ffs_snapremove(struct vnode *vp); int ffs_snapshot(struct mount *mp, char *snapfile); void ffs_snapshot_mount(struct mount *mp); void ffs_snapshot_unmount(struct mount *mp); void process_deferred_inactive(struct mount *mp); void ffs_sync_snap(struct mount *, int); int ffs_syncvnode(struct vnode *vp, int waitfor); int ffs_truncate(struct vnode *, off_t, int, struct ucred *, struct thread *); int ffs_update(struct vnode *, int); int ffs_valloc(struct vnode *, int, struct ucred *, struct vnode **); int ffs_vfree(struct vnode *, ino_t, int); vfs_vget_t ffs_vget; int ffs_vgetf(struct mount *, ino_t, int, struct vnode **, int); #define FFSV_FORCEINSMQ 0x0001 extern struct vop_vector ffs_vnodeops1; extern struct vop_vector ffs_fifoops1; extern struct vop_vector ffs_vnodeops2; extern struct vop_vector ffs_fifoops2; /* * Soft update function prototypes. */ int softdep_check_suspend(struct mount *, struct vnode *, int, int, int, int); void softdep_get_depcounts(struct mount *, int *, int *); void softdep_initialize(void); void softdep_uninitialize(void); int softdep_mount(struct vnode *, struct mount *, struct fs *, struct ucred *); void softdep_unmount(struct mount *); int softdep_move_dependencies(struct buf *, struct buf *); int softdep_flushworklist(struct mount *, int *, struct thread *); int softdep_flushfiles(struct mount *, int, struct thread *); void softdep_update_inodeblock(struct inode *, struct buf *, int); void softdep_load_inodeblock(struct inode *); void softdep_freefile(struct vnode *, ino_t, int); int softdep_request_cleanup(struct fs *, struct vnode *, struct ucred *, int); void softdep_setup_freeblocks(struct inode *, off_t, int); void softdep_setup_inomapdep(struct buf *, struct inode *, ino_t); void softdep_setup_blkmapdep(struct buf *, struct mount *, ufs2_daddr_t, int, int); void softdep_setup_allocdirect(struct inode *, ufs_lbn_t, ufs2_daddr_t, ufs2_daddr_t, long, long, struct buf *); void softdep_setup_allocext(struct inode *, ufs_lbn_t, ufs2_daddr_t, ufs2_daddr_t, long, long, struct buf *); void softdep_setup_allocindir_meta(struct buf *, struct inode *, struct buf *, int, ufs2_daddr_t); void softdep_setup_allocindir_page(struct inode *, ufs_lbn_t, struct buf *, int, ufs2_daddr_t, ufs2_daddr_t, struct buf *); void softdep_setup_blkfree(struct mount *, struct buf *, ufs2_daddr_t, int, struct workhead *); void softdep_setup_inofree(struct mount *, struct buf *, ino_t, struct workhead *); void softdep_setup_sbupdate(struct ufsmount *, struct fs *, struct buf *); void softdep_fsync_mountdev(struct vnode *); int softdep_sync_metadata(struct vnode *); int softdep_sync_buf(struct vnode *, struct buf *, int); int softdep_process_worklist(struct mount *, int); int softdep_fsync(struct vnode *); int softdep_waitidle(struct mount *); int softdep_prealloc(struct vnode *, int); int softdep_journal_lookup(struct mount *, struct vnode **); void softdep_journal_freeblocks(struct inode *, struct ucred *, off_t, int); void softdep_journal_fsync(struct inode *); void softdep_buf_append(struct buf *, struct workhead *); void softdep_inode_append(struct inode *, struct ucred *, struct workhead *); void softdep_freework(struct workhead *); /* * Things to request flushing in softdep_request_cleanup() */ #define FLUSH_INODES 1 #define FLUSH_INODES_WAIT 2 #define FLUSH_BLOCKS 3 #define FLUSH_BLOCKS_WAIT 4 int ffs_rdonly(struct inode *); +#ifdef _KERNEL TAILQ_HEAD(snaphead, inode); struct snapdata { LIST_ENTRY(snapdata) sn_link; struct snaphead sn_head; daddr_t sn_listsize; daddr_t *sn_blklist; struct lock sn_lock; }; +#endif /* _KERNEL */ #endif /* !_UFS_FFS_EXTERN_H */ diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c index 26c022c59ba0..eabb0549f73c 100644 --- a/usr.bin/find/function.c +++ b/usr.bin/find/function.c @@ -1,1703 +1,1689 @@ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Cimarron D. Taylor of the University of California, Berkeley. * * 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. * 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. */ #ifndef lint #if 0 static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "find.h" static PLAN *palloc(OPTION *); static long long find_parsenum(PLAN *, const char *, char *, char *); static long long find_parsetime(PLAN *, const char *, char *); static char *nextarg(OPTION *, char ***); extern char **environ; static PLAN *lastexecplus = NULL; #define COMPARE(a, b) do { \ switch (plan->flags & F_ELG_MASK) { \ case F_EQUAL: \ return (a == b); \ case F_LESSTHAN: \ return (a < b); \ case F_GREATER: \ return (a > b); \ default: \ abort(); \ } \ } while(0) static PLAN * palloc(OPTION *option) { PLAN *new; if ((new = malloc(sizeof(PLAN))) == NULL) err(1, NULL); new->execute = option->execute; new->flags = option->flags; new->next = NULL; return new; } /* * find_parsenum -- * Parse a string of the form [+-]# and return the value. */ static long long find_parsenum(PLAN *plan, const char *option, char *vp, char *endch) { long long value; char *endchar, *str; /* Pointer to character ending conversion. */ /* Determine comparison from leading + or -. */ str = vp; switch (*str) { case '+': ++str; plan->flags |= F_GREATER; break; case '-': ++str; plan->flags |= F_LESSTHAN; break; default: plan->flags |= F_EQUAL; break; } /* * Convert the string with strtoq(). Note, if strtoq() returns zero * and endchar points to the beginning of the string we know we have * a syntax error. */ value = strtoq(str, &endchar, 10); if (value == 0 && endchar == str) errx(1, "%s: %s: illegal numeric value", option, vp); if (endchar[0] && endch == NULL) errx(1, "%s: %s: illegal trailing character", option, vp); if (endch) *endch = endchar[0]; return value; } /* * find_parsetime -- * Parse a string of the form [+-]([0-9]+[smhdw]?)+ and return the value. */ static long long find_parsetime(PLAN *plan, const char *option, char *vp) { long long secs, value; char *str, *unit; /* Pointer to character ending conversion. */ /* Determine comparison from leading + or -. */ str = vp; switch (*str) { case '+': ++str; plan->flags |= F_GREATER; break; case '-': ++str; plan->flags |= F_LESSTHAN; break; default: plan->flags |= F_EQUAL; break; } value = strtoq(str, &unit, 10); if (value == 0 && unit == str) { errx(1, "%s: %s: illegal time value", option, vp); /* NOTREACHED */ } if (*unit == '\0') return value; /* Units syntax. */ secs = 0; for (;;) { switch(*unit) { case 's': /* seconds */ secs += value; break; case 'm': /* minutes */ secs += value * 60; break; case 'h': /* hours */ secs += value * 3600; break; case 'd': /* days */ secs += value * 86400; break; case 'w': /* weeks */ secs += value * 604800; break; default: errx(1, "%s: %s: bad unit '%c'", option, vp, *unit); /* NOTREACHED */ } str = unit + 1; if (*str == '\0') /* EOS */ break; value = strtoq(str, &unit, 10); if (value == 0 && unit == str) { errx(1, "%s: %s: illegal time value", option, vp); /* NOTREACHED */ } if (*unit == '\0') { errx(1, "%s: %s: missing trailing unit", option, vp); /* NOTREACHED */ } } plan->flags |= F_EXACTTIME; return secs; } /* * nextarg -- * Check that another argument still exists, return a pointer to it, * and increment the argument vector pointer. */ static char * nextarg(OPTION *option, char ***argvp) { char *arg; if ((arg = **argvp) == 0) errx(1, "%s: requires additional arguments", option->name); (*argvp)++; return arg; } /* nextarg() */ /* * The value of n for the inode times (atime, birthtime, ctime, mtime) is a * range, i.e. n matches from (n - 1) to n 24 hour periods. This interacts * with -n, such that "-mtime -1" would be less than 0 days, which isn't what * the user wanted. Correct so that -1 is "less than 1". */ #define TIME_CORRECT(p) \ if (((p)->flags & F_ELG_MASK) == F_LESSTHAN) \ ++((p)->t_data); /* * -[acm]min n functions -- * * True if the difference between the * file access time (-amin) * file birth time (-Bmin) * last change of file status information (-cmin) * file modification time (-mmin) * and the current time is n min periods. */ int f_Xmin(PLAN *plan, FTSENT *entry) { if (plan->flags & F_TIME_C) { COMPARE((now - entry->fts_statp->st_ctime + 60 - 1) / 60, plan->t_data); } else if (plan->flags & F_TIME_A) { COMPARE((now - entry->fts_statp->st_atime + 60 - 1) / 60, plan->t_data); } else if (plan->flags & F_TIME_B) { COMPARE((now - entry->fts_statp->st_birthtime + 60 - 1) / 60, plan->t_data); } else { COMPARE((now - entry->fts_statp->st_mtime + 60 - 1) / 60, plan->t_data); } } PLAN * c_Xmin(OPTION *option, char ***argvp) { char *nmins; PLAN *new; nmins = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); new->t_data = find_parsenum(new, option->name, nmins, NULL); TIME_CORRECT(new); return new; } /* * -[acm]time n functions -- * * True if the difference between the * file access time (-atime) * file birth time (-Btime) * last change of file status information (-ctime) * file modification time (-mtime) * and the current time is n 24 hour periods. */ int f_Xtime(PLAN *plan, FTSENT *entry) { time_t xtime; if (plan->flags & F_TIME_A) xtime = entry->fts_statp->st_atime; else if (plan->flags & F_TIME_B) xtime = entry->fts_statp->st_birthtime; else if (plan->flags & F_TIME_C) xtime = entry->fts_statp->st_ctime; else xtime = entry->fts_statp->st_mtime; if (plan->flags & F_EXACTTIME) COMPARE(now - xtime, plan->t_data); else COMPARE((now - xtime + 86400 - 1) / 86400, plan->t_data); } PLAN * c_Xtime(OPTION *option, char ***argvp) { char *value; PLAN *new; value = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); new->t_data = find_parsetime(new, option->name, value); if (!(new->flags & F_EXACTTIME)) TIME_CORRECT(new); return new; } /* * -maxdepth/-mindepth n functions -- * * Does the same as -prune if the level of the current file is * greater/less than the specified maximum/minimum depth. * * Note that -maxdepth and -mindepth are handled specially in * find_execute() so their f_* functions are set to f_always_true(). */ PLAN * c_mXXdepth(OPTION *option, char ***argvp) { char *dstr; PLAN *new; dstr = nextarg(option, argvp); if (dstr[0] == '-') /* all other errors handled by find_parsenum() */ errx(1, "%s: %s: value must be positive", option->name, dstr); new = palloc(option); if (option->flags & F_MAXDEPTH) maxdepth = find_parsenum(new, option->name, dstr, NULL); else mindepth = find_parsenum(new, option->name, dstr, NULL); return new; } /* * -acl function -- * * Show files with EXTENDED ACL attributes. */ int f_acl(PLAN *plan __unused, FTSENT *entry) { acl_t facl; acl_type_t acl_type; int acl_supported = 0, ret, trivial; if (S_ISLNK(entry->fts_statp->st_mode)) return 0; ret = pathconf(entry->fts_accpath, _PC_ACL_NFS4); if (ret > 0) { acl_supported = 1; acl_type = ACL_TYPE_NFS4; } else if (ret < 0 && errno != EINVAL) { warn("%s", entry->fts_accpath); return (0); } if (acl_supported == 0) { ret = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED); if (ret > 0) { acl_supported = 1; acl_type = ACL_TYPE_ACCESS; } else if (ret < 0 && errno != EINVAL) { warn("%s", entry->fts_accpath); return (0); } } if (acl_supported == 0) return (0); facl = acl_get_file(entry->fts_accpath, acl_type); if (facl == NULL) { warn("%s", entry->fts_accpath); return (0); } ret = acl_is_trivial_np(facl, &trivial); acl_free(facl); if (ret) { warn("%s", entry->fts_accpath); acl_free(facl); return (0); } if (trivial) return (0); return (1); } PLAN * c_acl(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; return (palloc(option)); } /* * -delete functions -- * * True always. Makes its best shot and continues on regardless. */ int f_delete(PLAN *plan __unused, FTSENT *entry) { /* ignore these from fts */ if (strcmp(entry->fts_accpath, ".") == 0 || strcmp(entry->fts_accpath, "..") == 0) return 1; /* sanity check */ if (isdepth == 0 || /* depth off */ (ftsoptions & FTS_NOSTAT)) /* not stat()ing */ errx(1, "-delete: insecure options got turned on"); if (!(ftsoptions & FTS_PHYSICAL) || /* physical off */ (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */ errx(1, "-delete: forbidden when symlinks are followed"); /* Potentially unsafe - do not accept relative paths whatsoever */ if (strchr(entry->fts_accpath, '/') != NULL) errx(1, "-delete: %s: relative path potentially not safe", entry->fts_accpath); /* Turn off user immutable bits if running as root */ if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) && !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && geteuid() == 0) lchflags(entry->fts_accpath, entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)); /* rmdir directories, unlink everything else */ if (S_ISDIR(entry->fts_statp->st_mode)) { if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY) warn("-delete: rmdir(%s)", entry->fts_path); } else { if (unlink(entry->fts_accpath) < 0) warn("-delete: unlink(%s)", entry->fts_path); } /* "succeed" */ return 1; } PLAN * c_delete(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; /* no optimise */ isoutput = 1; /* possible output */ isdepth = 1; /* -depth implied */ return palloc(option); } /* * always_true -- * * Always true, used for -maxdepth, -mindepth, -xdev, -follow, and -true */ int f_always_true(PLAN *plan __unused, FTSENT *entry __unused) { return 1; } /* * -depth functions -- * * With argument: True if the file is at level n. * Without argument: Always true, causes descent of the directory hierarchy * to be done so that all entries in a directory are acted on before the * directory itself. */ int f_depth(PLAN *plan, FTSENT *entry) { if (plan->flags & F_DEPTH) COMPARE(entry->fts_level, plan->d_data); else return 1; } PLAN * c_depth(OPTION *option, char ***argvp) { PLAN *new; char *str; new = palloc(option); str = **argvp; if (str && !(new->flags & F_DEPTH)) { /* skip leading + or - */ if (*str == '+' || *str == '-') str++; /* skip sign */ if (*str == '+' || *str == '-') str++; if (isdigit(*str)) new->flags |= F_DEPTH; } if (new->flags & F_DEPTH) { /* -depth n */ char *ndepth; ndepth = nextarg(option, argvp); new->d_data = find_parsenum(new, option->name, ndepth, NULL); } else { /* -d */ isdepth = 1; } return new; } /* * -empty functions -- * * True if the file or directory is empty */ int f_empty(PLAN *plan __unused, FTSENT *entry) { if (S_ISREG(entry->fts_statp->st_mode) && entry->fts_statp->st_size == 0) return 1; if (S_ISDIR(entry->fts_statp->st_mode)) { struct dirent *dp; int empty; DIR *dir; empty = 1; dir = opendir(entry->fts_accpath); if (dir == NULL) return 0; for (dp = readdir(dir); dp; dp = readdir(dir)) if (dp->d_name[0] != '.' || (dp->d_name[1] != '\0' && (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) { empty = 0; break; } closedir(dir); return empty; } return 0; } PLAN * c_empty(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; return palloc(option); } /* * [-exec | -execdir | -ok] utility [arg ... ] ; functions -- * * True if the executed utility returns a zero value as exit status. * The end of the primary expression is delimited by a semicolon. If * "{}" occurs anywhere, it gets replaced by the current pathname, * or, in the case of -execdir, the current basename (filename * without leading directory prefix). For -exec and -ok, * the current directory for the execution of utility is the same as * the current directory when the find utility was started, whereas * for -execdir, it is the directory the file resides in. * * The primary -ok differs from -exec in that it requests affirmation * of the user before executing the utility. */ int f_exec(PLAN *plan, FTSENT *entry) { int cnt; pid_t pid; int status; char *file; if (entry == NULL && plan->flags & F_EXECPLUS) { if (plan->e_ppos == plan->e_pbnum) return (1); plan->e_argv[plan->e_ppos] = NULL; goto doexec; } /* XXX - if file/dir ends in '/' this will not work -- can it? */ if ((plan->flags & F_EXECDIR) && \ (file = strrchr(entry->fts_path, '/'))) file++; else file = entry->fts_path; if (plan->flags & F_EXECPLUS) { if ((plan->e_argv[plan->e_ppos] = strdup(file)) == NULL) err(1, NULL); plan->e_len[plan->e_ppos] = strlen(file); plan->e_psize += plan->e_len[plan->e_ppos]; if (++plan->e_ppos < plan->e_pnummax && plan->e_psize < plan->e_psizemax) return (1); plan->e_argv[plan->e_ppos] = NULL; } else { for (cnt = 0; plan->e_argv[cnt]; ++cnt) if (plan->e_len[cnt]) brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt], file, plan->e_len[cnt]); } doexec: if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv)) return 0; /* make sure find output is interspersed correctly with subprocesses */ fflush(stdout); fflush(stderr); switch (pid = fork()) { case -1: err(1, "fork"); /* NOTREACHED */ case 0: /* change dir back from where we started */ if (!(plan->flags & F_EXECDIR) && fchdir(dotfd)) { warn("chdir"); _exit(1); } execvp(plan->e_argv[0], plan->e_argv); warn("%s", plan->e_argv[0]); _exit(1); } if (plan->flags & F_EXECPLUS) { while (--plan->e_ppos >= plan->e_pbnum) free(plan->e_argv[plan->e_ppos]); plan->e_ppos = plan->e_pbnum; plan->e_psize = plan->e_pbsize; } pid = waitpid(pid, &status, 0); return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status)); } /* * c_exec, c_execdir, c_ok -- * build three parallel arrays, one with pointers to the strings passed * on the command line, one with (possibly duplicated) pointers to the * argv array, and one with integer values that are lengths of the * strings, but also flags meaning that the string has to be massaged. */ PLAN * c_exec(OPTION *option, char ***argvp) { PLAN *new; /* node returned */ long argmax; int cnt, i; char **argv, **ap, **ep, *p; /* XXX - was in c_execdir, but seems unnecessary!? ftsoptions &= ~FTS_NOSTAT; */ isoutput = 1; /* XXX - this is a change from the previous coding */ new = palloc(option); for (ap = argv = *argvp;; ++ap) { if (!*ap) errx(1, "%s: no terminating \";\" or \"+\"", option->name); if (**ap == ';') break; if (**ap == '+' && ap != argv && strcmp(*(ap - 1), "{}") == 0) { new->flags |= F_EXECPLUS; break; } } if (ap == argv) errx(1, "%s: no command specified", option->name); cnt = ap - *argvp + 1; if (new->flags & F_EXECPLUS) { new->e_ppos = new->e_pbnum = cnt - 2; if ((argmax = sysconf(_SC_ARG_MAX)) == -1) { warn("sysconf(_SC_ARG_MAX)"); argmax = _POSIX_ARG_MAX; } argmax -= 1024; for (ep = environ; *ep != NULL; ep++) argmax -= strlen(*ep) + 1 + sizeof(*ep); argmax -= 1 + sizeof(*ep); new->e_pnummax = argmax / 16; argmax -= sizeof(char *) * new->e_pnummax; if (argmax <= 0) errx(1, "no space for arguments"); new->e_psizemax = argmax; new->e_pbsize = 0; cnt += new->e_pnummax + 1; new->e_next = lastexecplus; lastexecplus = new; } if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL) err(1, NULL); if ((new->e_orig = malloc(cnt * sizeof(char *))) == NULL) err(1, NULL); if ((new->e_len = malloc(cnt * sizeof(int))) == NULL) err(1, NULL); for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) { new->e_orig[cnt] = *argv; if (new->flags & F_EXECPLUS) new->e_pbsize += strlen(*argv) + 1; for (p = *argv; *p; ++p) if (!(new->flags & F_EXECPLUS) && p[0] == '{' && p[1] == '}') { if ((new->e_argv[cnt] = malloc(MAXPATHLEN)) == NULL) err(1, NULL); new->e_len[cnt] = MAXPATHLEN; break; } if (!*p) { new->e_argv[cnt] = *argv; new->e_len[cnt] = 0; } } if (new->flags & F_EXECPLUS) { new->e_psize = new->e_pbsize; cnt--; for (i = 0; i < new->e_pnummax; i++) { new->e_argv[cnt] = NULL; new->e_len[cnt] = 0; cnt++; } argv = ap; goto done; } new->e_argv[cnt] = new->e_orig[cnt] = NULL; done: *argvp = argv + 1; return new; } /* Finish any pending -exec ... {} + functions. */ void finish_execplus(void) { PLAN *p; p = lastexecplus; while (p != NULL) { (p->execute)(p, NULL); p = p->e_next; } } int f_flags(PLAN *plan, FTSENT *entry) { u_long flags; flags = entry->fts_statp->st_flags; if (plan->flags & F_ATLEAST) return (flags | plan->fl_flags) == flags && !(flags & plan->fl_notflags); else if (plan->flags & F_ANY) return (flags & plan->fl_flags) || (flags | plan->fl_notflags) != flags; else return flags == plan->fl_flags && !(plan->fl_flags & plan->fl_notflags); } PLAN * c_flags(OPTION *option, char ***argvp) { char *flags_str; PLAN *new; u_long flags, notflags; flags_str = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); if (*flags_str == '-') { new->flags |= F_ATLEAST; flags_str++; } else if (*flags_str == '+') { new->flags |= F_ANY; flags_str++; } if (strtofflags(&flags_str, &flags, ¬flags) == 1) errx(1, "%s: %s: illegal flags string", option->name, flags_str); new->fl_flags = flags; new->fl_notflags = notflags; return new; } /* * -follow functions -- * * Always true, causes symbolic links to be followed on a global * basis. */ PLAN * c_follow(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_PHYSICAL; ftsoptions |= FTS_LOGICAL; return palloc(option); } /* * -fstype functions -- * * True if the file is of a certain type. */ int f_fstype(PLAN *plan, FTSENT *entry) { static dev_t curdev; /* need a guaranteed illegal dev value */ static int first = 1; struct statfs sb; - static int val_type, val_flags; + static int val_flags; + static char fstype[sizeof(sb.f_fstypename)]; char *p, save[2] = {0,0}; if ((plan->flags & F_MTMASK) == F_MTUNKNOWN) return 0; /* Only check when we cross mount point. */ if (first || curdev != entry->fts_statp->st_dev) { curdev = entry->fts_statp->st_dev; /* * Statfs follows symlinks; find wants the link's filesystem, * not where it points. */ if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE) { if ((p = strrchr(entry->fts_accpath, '/')) != NULL) ++p; else p = entry->fts_accpath; save[0] = p[0]; p[0] = '.'; save[1] = p[1]; p[1] = '\0'; } else p = NULL; if (statfs(entry->fts_accpath, &sb)) err(1, "%s", entry->fts_accpath); if (p) { p[0] = save[0]; p[1] = save[1]; } first = 0; /* * Further tests may need both of these values, so * always copy both of them. */ val_flags = sb.f_flags; - val_type = sb.f_type; + strlcpy(fstype, sb.f_fstypename, sizeof(fstype)); } switch (plan->flags & F_MTMASK) { case F_MTFLAG: return val_flags & plan->mt_data; case F_MTTYPE: - return val_type == plan->mt_data; + return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0); default: abort(); } } PLAN * c_fstype(OPTION *option, char ***argvp) { char *fsname; PLAN *new; - struct xvfsconf vfc; fsname = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); - - /* - * Check first for a filesystem name. - */ - if (getvfsbyname(fsname, &vfc) == 0) { - new->flags |= F_MTTYPE; - new->mt_data = vfc.vfc_typenum; - return new; - } - switch (*fsname) { case 'l': if (!strcmp(fsname, "local")) { new->flags |= F_MTFLAG; new->mt_data = MNT_LOCAL; return new; } break; case 'r': if (!strcmp(fsname, "rdonly")) { new->flags |= F_MTFLAG; new->mt_data = MNT_RDONLY; return new; } break; } - /* - * We need to make filesystem checks for filesystems - * that exists but aren't in the kernel work. - */ - fprintf(stderr, "Warning: Unknown filesystem type %s\n", fsname); - new->flags |= F_MTUNKNOWN; + new->flags |= F_MTTYPE; + new->c_data = fsname; return new; } /* * -group gname functions -- * * True if the file belongs to the group gname. If gname is numeric and * an equivalent of the getgrnam() function does not return a valid group * name, gname is taken as a group ID. */ int f_group(PLAN *plan, FTSENT *entry) { COMPARE(entry->fts_statp->st_gid, plan->g_data); } PLAN * c_group(OPTION *option, char ***argvp) { char *gname; PLAN *new; struct group *g; gid_t gid; gname = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); g = getgrnam(gname); if (g == NULL) { char* cp = gname; if (gname[0] == '-' || gname[0] == '+') gname++; gid = atoi(gname); if (gid == 0 && gname[0] != '0') errx(1, "%s: %s: no such group", option->name, gname); gid = find_parsenum(new, option->name, cp, NULL); } else gid = g->gr_gid; new->g_data = gid; return new; } /* * -inum n functions -- * * True if the file has inode # n. */ int f_inum(PLAN *plan, FTSENT *entry) { COMPARE(entry->fts_statp->st_ino, plan->i_data); } PLAN * c_inum(OPTION *option, char ***argvp) { char *inum_str; PLAN *new; inum_str = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); new->i_data = find_parsenum(new, option->name, inum_str, NULL); return new; } /* * -samefile FN * * True if the file has the same inode (eg hard link) FN */ /* f_samefile is just f_inum */ PLAN * c_samefile(OPTION *option, char ***argvp) { char *fn; PLAN *new; struct stat sb; fn = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); if (stat(fn, &sb)) err(1, "%s", fn); new->i_data = sb.st_ino; return new; } /* * -links n functions -- * * True if the file has n links. */ int f_links(PLAN *plan, FTSENT *entry) { COMPARE(entry->fts_statp->st_nlink, plan->l_data); } PLAN * c_links(OPTION *option, char ***argvp) { char *nlinks; PLAN *new; nlinks = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); new->l_data = (nlink_t)find_parsenum(new, option->name, nlinks, NULL); return new; } /* * -ls functions -- * * Always true - prints the current entry to stdout in "ls" format. */ int f_ls(PLAN *plan __unused, FTSENT *entry) { printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp); return 1; } PLAN * c_ls(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; isoutput = 1; return palloc(option); } /* * -name functions -- * * True if the basename of the filename being examined * matches pattern using Pattern Matching Notation S3.14 */ int f_name(PLAN *plan, FTSENT *entry) { char fn[PATH_MAX]; const char *name; if (plan->flags & F_LINK) { name = fn; if (readlink(entry->fts_path, fn, sizeof(fn)) == -1) return 0; } else name = entry->fts_name; return !fnmatch(plan->c_data, name, plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0); } PLAN * c_name(OPTION *option, char ***argvp) { char *pattern; PLAN *new; pattern = nextarg(option, argvp); new = palloc(option); new->c_data = pattern; return new; } /* * -newer file functions -- * * True if the current file has been modified more recently * then the modification time of the file named by the pathname * file. */ int f_newer(PLAN *plan, FTSENT *entry) { if (plan->flags & F_TIME_C) return entry->fts_statp->st_ctime > plan->t_data; else if (plan->flags & F_TIME_A) return entry->fts_statp->st_atime > plan->t_data; else if (plan->flags & F_TIME_B) return entry->fts_statp->st_birthtime > plan->t_data; else return entry->fts_statp->st_mtime > plan->t_data; } PLAN * c_newer(OPTION *option, char ***argvp) { char *fn_or_tspec; PLAN *new; struct stat sb; fn_or_tspec = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); /* compare against what */ if (option->flags & F_TIME2_T) { new->t_data = get_date(fn_or_tspec); if (new->t_data == (time_t) -1) errx(1, "Can't parse date/time: %s", fn_or_tspec); } else { if (stat(fn_or_tspec, &sb)) err(1, "%s", fn_or_tspec); if (option->flags & F_TIME2_C) new->t_data = sb.st_ctime; else if (option->flags & F_TIME2_A) new->t_data = sb.st_atime; else if (option->flags & F_TIME2_B) new->t_data = sb.st_birthtime; else new->t_data = sb.st_mtime; } return new; } /* * -nogroup functions -- * * True if file belongs to a user ID for which the equivalent * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL. */ int f_nogroup(PLAN *plan __unused, FTSENT *entry) { return group_from_gid(entry->fts_statp->st_gid, 1) == NULL; } PLAN * c_nogroup(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; return palloc(option); } /* * -nouser functions -- * * True if file belongs to a user ID for which the equivalent * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL. */ int f_nouser(PLAN *plan __unused, FTSENT *entry) { return user_from_uid(entry->fts_statp->st_uid, 1) == NULL; } PLAN * c_nouser(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; return palloc(option); } /* * -path functions -- * * True if the path of the filename being examined * matches pattern using Pattern Matching Notation S3.14 */ int f_path(PLAN *plan, FTSENT *entry) { return !fnmatch(plan->c_data, entry->fts_path, plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0); } /* c_path is the same as c_name */ /* * -perm functions -- * * The mode argument is used to represent file mode bits. If it starts * with a leading digit, it's treated as an octal mode, otherwise as a * symbolic mode. */ int f_perm(PLAN *plan, FTSENT *entry) { mode_t mode; mode = entry->fts_statp->st_mode & (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO); if (plan->flags & F_ATLEAST) return (plan->m_data | mode) == mode; else if (plan->flags & F_ANY) return (mode & plan->m_data); else return mode == plan->m_data; /* NOTREACHED */ } PLAN * c_perm(OPTION *option, char ***argvp) { char *perm; PLAN *new; mode_t *set; perm = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); if (*perm == '-') { new->flags |= F_ATLEAST; ++perm; } else if (*perm == '+') { new->flags |= F_ANY; ++perm; } if ((set = setmode(perm)) == NULL) errx(1, "%s: %s: illegal mode string", option->name, perm); new->m_data = getmode(set, 0); free(set); return new; } /* * -print functions -- * * Always true, causes the current pathname to be written to * standard output. */ int f_print(PLAN *plan __unused, FTSENT *entry) { (void)puts(entry->fts_path); return 1; } PLAN * c_print(OPTION *option, char ***argvp __unused) { isoutput = 1; return palloc(option); } /* * -print0 functions -- * * Always true, causes the current pathname to be written to * standard output followed by a NUL character */ int f_print0(PLAN *plan __unused, FTSENT *entry) { fputs(entry->fts_path, stdout); fputc('\0', stdout); return 1; } /* c_print0 is the same as c_print */ /* * -prune functions -- * * Prune a portion of the hierarchy. */ int f_prune(PLAN *plan __unused, FTSENT *entry) { if (fts_set(tree, entry, FTS_SKIP)) err(1, "%s", entry->fts_path); return 1; } /* c_prune == c_simple */ /* * -regex functions -- * * True if the whole path of the file matches pattern using * regular expression. */ int f_regex(PLAN *plan, FTSENT *entry) { char *str; int len; regex_t *pre; regmatch_t pmatch; int errcode; char errbuf[LINE_MAX]; int matched; pre = plan->re_data; str = entry->fts_path; len = strlen(str); matched = 0; pmatch.rm_so = 0; pmatch.rm_eo = len; errcode = regexec(pre, str, 1, &pmatch, REG_STARTEND); if (errcode != 0 && errcode != REG_NOMATCH) { regerror(errcode, pre, errbuf, sizeof errbuf); errx(1, "%s: %s", plan->flags & F_IGNCASE ? "-iregex" : "-regex", errbuf); } if (errcode == 0 && pmatch.rm_so == 0 && pmatch.rm_eo == len) matched = 1; return matched; } PLAN * c_regex(OPTION *option, char ***argvp) { PLAN *new; char *pattern; regex_t *pre; int errcode; char errbuf[LINE_MAX]; if ((pre = malloc(sizeof(regex_t))) == NULL) err(1, NULL); pattern = nextarg(option, argvp); if ((errcode = regcomp(pre, pattern, regexp_flags | (option->flags & F_IGNCASE ? REG_ICASE : 0))) != 0) { regerror(errcode, pre, errbuf, sizeof errbuf); errx(1, "%s: %s: %s", option->flags & F_IGNCASE ? "-iregex" : "-regex", pattern, errbuf); } new = palloc(option); new->re_data = pre; return new; } /* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or, c_true, c_false */ PLAN * c_simple(OPTION *option, char ***argvp __unused) { return palloc(option); } /* * -size n[c] functions -- * * True if the file size in bytes, divided by an implementation defined * value and rounded up to the next integer, is n. If n is followed by * one of c k M G T P, the size is in bytes, kilobytes, * megabytes, gigabytes, terabytes or petabytes respectively. */ #define FIND_SIZE 512 static int divsize = 1; int f_size(PLAN *plan, FTSENT *entry) { off_t size; size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) / FIND_SIZE : entry->fts_statp->st_size; COMPARE(size, plan->o_data); } PLAN * c_size(OPTION *option, char ***argvp) { char *size_str; PLAN *new; char endch; off_t scale; size_str = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); endch = 'c'; new->o_data = find_parsenum(new, option->name, size_str, &endch); if (endch != '\0') { divsize = 0; switch (endch) { case 'c': /* characters */ scale = 0x1LL; break; case 'k': /* kilobytes 1<<10 */ scale = 0x400LL; break; case 'M': /* megabytes 1<<20 */ scale = 0x100000LL; break; case 'G': /* gigabytes 1<<30 */ scale = 0x40000000LL; break; case 'T': /* terabytes 1<<40 */ scale = 0x1000000000LL; break; case 'P': /* petabytes 1<<50 */ scale = 0x4000000000000LL; break; default: errx(1, "%s: %s: illegal trailing character", option->name, size_str); break; } if (new->o_data > QUAD_MAX / scale) errx(1, "%s: %s: value too large", option->name, size_str); new->o_data *= scale; } return new; } /* * -type c functions -- * * True if the type of the file is c, where c is b, c, d, p, f or w * for block special file, character special file, directory, FIFO, * regular file or whiteout respectively. */ int f_type(PLAN *plan, FTSENT *entry) { return (entry->fts_statp->st_mode & S_IFMT) == plan->m_data; } PLAN * c_type(OPTION *option, char ***argvp) { char *typestring; PLAN *new; mode_t mask; typestring = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; switch (typestring[0]) { case 'b': mask = S_IFBLK; break; case 'c': mask = S_IFCHR; break; case 'd': mask = S_IFDIR; break; case 'f': mask = S_IFREG; break; case 'l': mask = S_IFLNK; break; case 'p': mask = S_IFIFO; break; case 's': mask = S_IFSOCK; break; #ifdef FTS_WHITEOUT case 'w': mask = S_IFWHT; ftsoptions |= FTS_WHITEOUT; break; #endif /* FTS_WHITEOUT */ default: errx(1, "%s: %s: unknown type", option->name, typestring); } new = palloc(option); new->m_data = mask; return new; } /* * -user uname functions -- * * True if the file belongs to the user uname. If uname is numeric and * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not * return a valid user name, uname is taken as a user ID. */ int f_user(PLAN *plan, FTSENT *entry) { COMPARE(entry->fts_statp->st_uid, plan->u_data); } PLAN * c_user(OPTION *option, char ***argvp) { char *username; PLAN *new; struct passwd *p; uid_t uid; username = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); p = getpwnam(username); if (p == NULL) { char* cp = username; if( username[0] == '-' || username[0] == '+' ) username++; uid = atoi(username); if (uid == 0 && username[0] != '0') errx(1, "%s: %s: no such user", option->name, username); uid = find_parsenum(new, option->name, cp, NULL); } else uid = p->pw_uid; new->u_data = uid; return new; } /* * -xdev functions -- * * Always true, causes find not to descend past directories that have a * different device ID (st_dev, see stat() S5.6.2 [POSIX.1]) */ PLAN * c_xdev(OPTION *option, char ***argvp __unused) { ftsoptions |= FTS_XDEV; return palloc(option); } /* * ( expression ) functions -- * * True if expression is true. */ int f_expr(PLAN *plan, FTSENT *entry) { PLAN *p; int state = 0; for (p = plan->p_data[0]; p && (state = (p->execute)(p, entry)); p = p->next); return state; } /* * f_openparen and f_closeparen nodes are temporary place markers. They are * eliminated during phase 2 of find_formplan() --- the '(' node is converted * to a f_expr node containing the expression and the ')' node is discarded. * The functions themselves are only used as constants. */ int f_openparen(PLAN *plan __unused, FTSENT *entry __unused) { abort(); } int f_closeparen(PLAN *plan __unused, FTSENT *entry __unused) { abort(); } /* c_openparen == c_simple */ /* c_closeparen == c_simple */ /* * AND operator. Since AND is implicit, no node is allocated. */ PLAN * c_and(OPTION *option __unused, char ***argvp __unused) { return NULL; } /* * ! expression functions -- * * Negation of a primary; the unary NOT operator. */ int f_not(PLAN *plan, FTSENT *entry) { PLAN *p; int state = 0; for (p = plan->p_data[0]; p && (state = (p->execute)(p, entry)); p = p->next); return !state; } /* c_not == c_simple */ /* * expression -o expression functions -- * * Alternation of primaries; the OR operator. The second expression is * not evaluated if the first expression is true. */ int f_or(PLAN *plan, FTSENT *entry) { PLAN *p; int state = 0; for (p = plan->p_data[0]; p && (state = (p->execute)(p, entry)); p = p->next); if (state) return 1; for (p = plan->p_data[1]; p && (state = (p->execute)(p, entry)); p = p->next); return state; } /* c_or == c_simple */ /* * -false * * Always false. */ int f_false(PLAN *plan __unused, FTSENT *entry __unused) { return 0; } /* c_false == c_simple */ /* * -quit * * Exits the program */ int f_quit(PLAN *plan __unused, FTSENT *entry __unused) { exit(0); } /* c_quit == c_simple */ diff --git a/usr.sbin/makefs/ffs/ffs_bswap.c b/usr.sbin/makefs/ffs/ffs_bswap.c index 7049991168b8..18ace03123fc 100644 --- a/usr.sbin/makefs/ffs/ffs_bswap.c +++ b/usr.sbin/makefs/ffs/ffs_bswap.c @@ -1,271 +1,268 @@ /* $NetBSD: ffs_bswap.c,v 1.28 2004/05/25 14:54:59 hannken Exp $ */ /* * Copyright (c) 1998 Manuel Bouyer. * * 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 Manuel Bouyer. * 4. 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 ``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 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. * */ #include __FBSDID("$FreeBSD$"); #include -#include -#include -#include #if defined(_KERNEL) #include #endif #include #include "ffs/ufs_bswap.h" #include /* XXX temporary */ struct ufsmount; struct bufobj; struct mount; struct vnode; typedef int vfs_vget_t(struct mount *mp, ino_t ino, int flags, struct vnode **vpp); #include #if !defined(_KERNEL) #include #include #include #include #define panic(x) printf("%s\n", (x)), abort() #endif #define fs_old_postbloff fs_spare5[0] #define fs_old_rotbloff fs_spare5[1] #define fs_old_postbl_start fs_maxbsize #define fs_old_headswitch fs_id[0] #define fs_old_trkseek fs_id[1] #define fs_old_csmask fs_spare1[0] #define fs_old_csshift fs_spare1[1] #define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */ #define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */ void ffs_csum_swap(struct csum *o, struct csum *n, int size); void ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n); void ffs_sb_swap(struct fs *o, struct fs *n) { int i; u_int32_t *o32, *n32; /* * In order to avoid a lot of lines, as the first N fields (52) * of the superblock up to fs_fmod are u_int32_t, we just loop * here to convert them. */ o32 = (u_int32_t *)o; n32 = (u_int32_t *)n; for (i = 0; i < offsetof(struct fs, fs_fmod) / sizeof(u_int32_t); i++) n32[i] = bswap32(o32[i]); n->fs_swuid = bswap64(o->fs_swuid); n->fs_cgrotor = bswap32(o->fs_cgrotor); /* Unused */ n->fs_old_cpc = bswap32(o->fs_old_cpc); /* These fields overlap with a possible location for the * historic FS_DYNAMICPOSTBLFMT postbl table, and with the * first half of the historic FS_42POSTBLFMT postbl table. */ n->fs_maxbsize = bswap32(o->fs_maxbsize); n->fs_sblockloc = bswap64(o->fs_sblockloc); ffs_csumtotal_swap(&o->fs_cstotal, &n->fs_cstotal); n->fs_time = bswap64(o->fs_time); n->fs_size = bswap64(o->fs_size); n->fs_dsize = bswap64(o->fs_dsize); n->fs_csaddr = bswap64(o->fs_csaddr); n->fs_pendingblocks = bswap64(o->fs_pendingblocks); n->fs_pendinginodes = bswap32(o->fs_pendinginodes); /* These fields overlap with the second half of the * historic FS_42POSTBLFMT postbl table */ for (i = 0; i < FSMAXSNAP; i++) n->fs_snapinum[i] = bswap32(o->fs_snapinum[i]); n->fs_avgfilesize = bswap32(o->fs_avgfilesize); n->fs_avgfpdir = bswap32(o->fs_avgfpdir); /* fs_sparecon[28] - ignore for now */ n->fs_flags = bswap32(o->fs_flags); n->fs_contigsumsize = bswap32(o->fs_contigsumsize); n->fs_maxsymlinklen = bswap32(o->fs_maxsymlinklen); n->fs_old_inodefmt = bswap32(o->fs_old_inodefmt); n->fs_maxfilesize = bswap64(o->fs_maxfilesize); n->fs_qbmask = bswap64(o->fs_qbmask); n->fs_qfmask = bswap64(o->fs_qfmask); n->fs_state = bswap32(o->fs_state); n->fs_old_postblformat = bswap32(o->fs_old_postblformat); n->fs_old_nrpos = bswap32(o->fs_old_nrpos); n->fs_old_postbloff = bswap32(o->fs_old_postbloff); n->fs_old_rotbloff = bswap32(o->fs_old_rotbloff); n->fs_magic = bswap32(o->fs_magic); } void ffs_dinode1_swap(struct ufs1_dinode *o, struct ufs1_dinode *n) { n->di_mode = bswap16(o->di_mode); n->di_nlink = bswap16(o->di_nlink); n->di_size = bswap64(o->di_size); n->di_atime = bswap32(o->di_atime); n->di_atimensec = bswap32(o->di_atimensec); n->di_mtime = bswap32(o->di_mtime); n->di_mtimensec = bswap32(o->di_mtimensec); n->di_ctime = bswap32(o->di_ctime); n->di_ctimensec = bswap32(o->di_ctimensec); memcpy(n->di_db, o->di_db, (NDADDR + NIADDR) * sizeof(u_int32_t)); n->di_flags = bswap32(o->di_flags); n->di_blocks = bswap32(o->di_blocks); n->di_gen = bswap32(o->di_gen); n->di_uid = bswap32(o->di_uid); n->di_gid = bswap32(o->di_gid); } void ffs_dinode2_swap(struct ufs2_dinode *o, struct ufs2_dinode *n) { n->di_mode = bswap16(o->di_mode); n->di_nlink = bswap16(o->di_nlink); n->di_uid = bswap32(o->di_uid); n->di_gid = bswap32(o->di_gid); n->di_blksize = bswap32(o->di_blksize); n->di_size = bswap64(o->di_size); n->di_blocks = bswap64(o->di_blocks); n->di_atime = bswap64(o->di_atime); n->di_atimensec = bswap32(o->di_atimensec); n->di_mtime = bswap64(o->di_mtime); n->di_mtimensec = bswap32(o->di_mtimensec); n->di_ctime = bswap64(o->di_ctime); n->di_ctimensec = bswap32(o->di_ctimensec); n->di_birthtime = bswap64(o->di_ctime); n->di_birthnsec = bswap32(o->di_ctimensec); n->di_gen = bswap32(o->di_gen); n->di_kernflags = bswap32(o->di_kernflags); n->di_flags = bswap32(o->di_flags); n->di_extsize = bswap32(o->di_extsize); memcpy(n->di_extb, o->di_extb, (NXADDR + NDADDR + NIADDR) * 8); } void ffs_csum_swap(struct csum *o, struct csum *n, int size) { int i; u_int32_t *oint, *nint; oint = (u_int32_t*)o; nint = (u_int32_t*)n; for (i = 0; i < size / sizeof(u_int32_t); i++) nint[i] = bswap32(oint[i]); } void ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n) { n->cs_ndir = bswap64(o->cs_ndir); n->cs_nbfree = bswap64(o->cs_nbfree); n->cs_nifree = bswap64(o->cs_nifree); n->cs_nffree = bswap64(o->cs_nffree); } /* * Note that ffs_cg_swap may be called with o == n. */ void ffs_cg_swap(struct cg *o, struct cg *n, struct fs *fs) { int i; u_int32_t *n32, *o32; u_int16_t *n16, *o16; int32_t btotoff, boff, clustersumoff; n->cg_firstfield = bswap32(o->cg_firstfield); n->cg_magic = bswap32(o->cg_magic); n->cg_old_time = bswap32(o->cg_old_time); n->cg_cgx = bswap32(o->cg_cgx); n->cg_old_ncyl = bswap16(o->cg_old_ncyl); n->cg_old_niblk = bswap16(o->cg_old_niblk); n->cg_ndblk = bswap32(o->cg_ndblk); n->cg_cs.cs_ndir = bswap32(o->cg_cs.cs_ndir); n->cg_cs.cs_nbfree = bswap32(o->cg_cs.cs_nbfree); n->cg_cs.cs_nifree = bswap32(o->cg_cs.cs_nifree); n->cg_cs.cs_nffree = bswap32(o->cg_cs.cs_nffree); n->cg_rotor = bswap32(o->cg_rotor); n->cg_frotor = bswap32(o->cg_frotor); n->cg_irotor = bswap32(o->cg_irotor); for (i = 0; i < MAXFRAG; i++) n->cg_frsum[i] = bswap32(o->cg_frsum[i]); n->cg_old_btotoff = bswap32(o->cg_old_btotoff); n->cg_old_boff = bswap32(o->cg_old_boff); n->cg_iusedoff = bswap32(o->cg_iusedoff); n->cg_freeoff = bswap32(o->cg_freeoff); n->cg_nextfreeoff = bswap32(o->cg_nextfreeoff); n->cg_clustersumoff = bswap32(o->cg_clustersumoff); n->cg_clusteroff = bswap32(o->cg_clusteroff); n->cg_nclusterblks = bswap32(o->cg_nclusterblks); n->cg_niblk = bswap32(o->cg_niblk); n->cg_initediblk = bswap32(o->cg_initediblk); n->cg_time = bswap64(o->cg_time); if (fs->fs_magic == FS_UFS2_MAGIC) return; if (n->cg_magic == CG_MAGIC) { btotoff = n->cg_old_btotoff; boff = n->cg_old_boff; clustersumoff = n->cg_clustersumoff; } else { btotoff = bswap32(n->cg_old_btotoff); boff = bswap32(n->cg_old_boff); clustersumoff = bswap32(n->cg_clustersumoff); } n32 = (u_int32_t *)((u_int8_t *)n + btotoff); o32 = (u_int32_t *)((u_int8_t *)o + btotoff); n16 = (u_int16_t *)((u_int8_t *)n + boff); o16 = (u_int16_t *)((u_int8_t *)o + boff); for (i = 0; i < fs->fs_old_cpg; i++) n32[i] = bswap32(o32[i]); for (i = 0; i < fs->fs_old_cpg * fs->fs_old_nrpos; i++) n16[i] = bswap16(o16[i]); n32 = (u_int32_t *)((u_int8_t *)n + clustersumoff); o32 = (u_int32_t *)((u_int8_t *)o + clustersumoff); for (i = 1; i < fs->fs_contigsumsize + 1; i++) n32[i] = bswap32(o32[i]); } diff --git a/usr.sbin/makefs/ffs/ffs_subr.c b/usr.sbin/makefs/ffs/ffs_subr.c index 19d3543c292c..5f9b6f2b7dc9 100644 --- a/usr.sbin/makefs/ffs/ffs_subr.c +++ b/usr.sbin/makefs/ffs/ffs_subr.c @@ -1,205 +1,202 @@ /* $NetBSD: ffs_subr.c,v 1.32 2003/12/30 12:33:24 pk Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 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. * * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 */ #include __FBSDID("$FreeBSD$"); #include -#include -#include -#include #include #include /* XXX temporary */ struct ufsmount; struct bufobj; struct mount; struct vnode; typedef int vfs_vget_t(struct mount *mp, ino_t ino, int flags, struct vnode **vpp); #include #include "ffs/ufs_bswap.h" void panic __P((const char *, ...)) __attribute__((__noreturn__,__format__(__printf__,1,2))); /* * Update the frsum fields to reflect addition or deletion * of some frags. */ void ffs_fragacct_swap(struct fs *fs, int fragmap, int32_t fraglist[], int cnt, int needswap) { int inblk; int field, subfield; int siz, pos; inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; fragmap <<= 1; for (siz = 1; siz < fs->fs_frag; siz++) { if ((inblk & (1 << (siz + (fs->fs_frag & (NBBY - 1))))) == 0) continue; field = around[siz]; subfield = inside[siz]; for (pos = siz; pos <= fs->fs_frag; pos++) { if ((fragmap & field) == subfield) { fraglist[siz] = ufs_rw32( ufs_rw32(fraglist[siz], needswap) + cnt, needswap); pos += siz; field <<= siz; subfield <<= siz; } field <<= 1; subfield <<= 1; } } } /* * block operations * * check if a block is available * returns true if all the correponding bits in the free map are 1 * returns false if any corresponding bit in the free map is 0 */ int ffs_isblock(fs, cp, h) struct fs *fs; u_char *cp; int32_t h; { u_char mask; switch ((int)fs->fs_fragshift) { case 3: return (cp[h] == 0xff); case 2: mask = 0x0f << ((h & 0x1) << 2); return ((cp[h >> 1] & mask) == mask); case 1: mask = 0x03 << ((h & 0x3) << 1); return ((cp[h >> 2] & mask) == mask); case 0: mask = 0x01 << (h & 0x7); return ((cp[h >> 3] & mask) == mask); default: panic("ffs_isblock: unknown fs_fragshift %d", (int)fs->fs_fragshift); } } /* * check if a block is completely allocated * returns true if all the corresponding bits in the free map are 0 * returns false if any corresponding bit in the free map is 1 */ int ffs_isfreeblock(fs, cp, h) struct fs *fs; u_char *cp; int32_t h; { switch ((int)fs->fs_fragshift) { case 3: return (cp[h] == 0); case 2: return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); case 1: return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); case 0: return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); default: panic("ffs_isfreeblock: unknown fs_fragshift %d", (int)fs->fs_fragshift); } } /* * take a block out of the map */ void ffs_clrblock(fs, cp, h) struct fs *fs; u_char *cp; int32_t h; { switch ((int)fs->fs_fragshift) { case 3: cp[h] = 0; return; case 2: cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); return; case 1: cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); return; case 0: cp[h >> 3] &= ~(0x01 << (h & 0x7)); return; default: panic("ffs_clrblock: unknown fs_fragshift %d", (int)fs->fs_fragshift); } } /* * put a block into the map */ void ffs_setblock(fs, cp, h) struct fs *fs; u_char *cp; int32_t h; { switch ((int)fs->fs_fragshift) { case 3: cp[h] = 0xff; return; case 2: cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); return; case 1: cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); return; case 0: cp[h >> 3] |= (0x01 << (h & 0x7)); return; default: panic("ffs_setblock: unknown fs_fragshift %d", (int)fs->fs_fragshift); } }