Index: stable/11/sbin/natd/natd.c =================================================================== --- stable/11/sbin/natd/natd.c (revision 307696) +++ stable/11/sbin/natd/natd.c (revision 307697) @@ -1,2043 +1,2043 @@ /* * natd - Network Address Translation Daemon for FreeBSD. * * This software is provided free of charge, with no * warranty of any kind, either expressed or implied. * Use at your own risk. * * You may copy, modify and distribute this software (natd.c) freely. * * Ari Suutari */ #include __FBSDID("$FreeBSD$"); #define SYSLOG_NAMES #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "natd.h" struct instance { const char *name; struct libalias *la; LIST_ENTRY(instance) list; int ifIndex; int assignAliasAddr; char* ifName; int logDropped; u_short inPort; u_short outPort; u_short inOutPort; struct in_addr aliasAddr; int ifMTU; int aliasOverhead; int dropIgnoredIncoming; int divertIn; int divertOut; int divertInOut; }; static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root); struct libalias *mla; static struct instance *mip; static int ninstance = 1; /* * Default values for input and output * divert socket ports. */ #define DEFAULT_SERVICE "natd" /* * Definition of a port range, and macros to deal with values. * FORMAT: HI 16-bits == first port in range, 0 == all ports. * LO 16-bits == number of ports in range * NOTES: - Port values are not stored in network byte order. */ typedef u_long port_range; #define GETLOPORT(x) ((x) >> 0x10) #define GETNUMPORTS(x) ((x) & 0x0000ffff) #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) /* Set y to be the low-port value in port_range variable x. */ #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) /* Set y to be the number of ports in port_range variable x. */ #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) /* * Function prototypes. */ static void DoAliasing (int fd, int direction); static void DaemonMode (void); static void HandleRoutingInfo (int fd); static void Usage (void); static char* FormatPacket (struct ip*); static void PrintPacket (struct ip*); static void SyslogPacket (struct ip*, int priority, const char *label); static int SetAliasAddressFromIfName (const char *ifName); static void InitiateShutdown (int); static void Shutdown (int); static void RefreshAddr (int); static void ParseOption (const char* option, const char* parms); static void ReadConfigFile (const char* fileName); static void SetupPortRedirect (const char* parms); static void SetupProtoRedirect(const char* parms); static void SetupAddressRedirect (const char* parms); static void StrToAddr (const char* str, struct in_addr* addr); static u_short StrToPort (const char* str, const char* proto); static int StrToPortRange (const char* str, const char* proto, port_range *portRange); static int StrToProto (const char* str); static int StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange); static void ParseArgs (int argc, char** argv); static void SetupPunchFW(const char *strValue); static void SetupSkinnyPort(const char *strValue); static void NewInstance(const char *name); static void DoGlobal (int fd); static int CheckIpfwRulenum(unsigned int rnum); /* * Globals. */ static int verbose; static int background; static int running; static int logFacility; static int dynamicMode; static int icmpSock; static int logIpfwDenied; static const char* pidName; static int routeSock; static int globalPort; static int divertGlobal; static int exitDelay; int main (int argc, char** argv) { struct sockaddr_in addr; fd_set readMask; int fdMax; int rval; /* * Initialize packet aliasing software. * Done already here to be able to alter option bits * during command line and configuration file processing. */ NewInstance("default"); /* * Parse options. */ verbose = 0; background = 0; running = 1; dynamicMode = 0; logFacility = LOG_DAEMON; logIpfwDenied = -1; pidName = PIDFILE; routeSock = -1; icmpSock = -1; fdMax = -1; divertGlobal = -1; exitDelay = EXIT_DELAY; ParseArgs (argc, argv); /* * Log ipfw(8) denied packets by default in verbose mode. */ if (logIpfwDenied == -1) logIpfwDenied = verbose; /* * Open syslog channel. */ openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0), logFacility); LIST_FOREACH(mip, &root, list) { mla = mip->la; /* * If not doing the transparent proxying only, * check that valid aliasing address has been given. */ if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL && !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY)) errx (1, "instance %s: aliasing address not given", mip->name); if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL) errx (1, "both alias address and interface " "name are not allowed"); /* * Check that valid port number is known. */ if (mip->inPort != 0 || mip->outPort != 0) if (mip->inPort == 0 || mip->outPort == 0) errx (1, "both input and output ports are required"); if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0) ParseOption ("port", DEFAULT_SERVICE); /* * Check if ignored packets should be dropped. */ mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0); mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING; /* * Create divert sockets. Use only one socket if -p was specified * on command line. Otherwise, create separate sockets for * outgoing and incoming connections. */ if (mip->inOutPort) { mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); if (mip->divertInOut == -1) Quit ("Unable to create divert socket."); if (mip->divertInOut > fdMax) fdMax = mip->divertInOut; mip->divertIn = -1; mip->divertOut = -1; /* * Bind socket. */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = mip->inOutPort; if (bind (mip->divertInOut, (struct sockaddr*) &addr, sizeof addr) == -1) Quit ("Unable to bind divert socket."); } else { mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); if (mip->divertIn == -1) Quit ("Unable to create incoming divert socket."); if (mip->divertIn > fdMax) fdMax = mip->divertIn; mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); if (mip->divertOut == -1) Quit ("Unable to create outgoing divert socket."); if (mip->divertOut > fdMax) fdMax = mip->divertOut; mip->divertInOut = -1; /* * Bind divert sockets. */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = mip->inPort; if (bind (mip->divertIn, (struct sockaddr*) &addr, sizeof addr) == -1) Quit ("Unable to bind incoming divert socket."); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = mip->outPort; if (bind (mip->divertOut, (struct sockaddr*) &addr, sizeof addr) == -1) Quit ("Unable to bind outgoing divert socket."); } /* * Create routing socket if interface name specified and in dynamic mode. */ if (mip->ifName) { if (dynamicMode) { if (routeSock == -1) routeSock = socket (PF_ROUTE, SOCK_RAW, 0); if (routeSock == -1) Quit ("Unable to create routing info socket."); if (routeSock > fdMax) fdMax = routeSock; mip->assignAliasAddr = 1; } else { do { rval = SetAliasAddressFromIfName (mip->ifName); if (background == 0 || dynamicMode == 0) break; if (rval == EAGAIN) sleep(1); } while (rval == EAGAIN); if (rval != 0) exit(1); } } } if (globalPort) { divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); if (divertGlobal == -1) Quit ("Unable to create divert socket."); if (divertGlobal > fdMax) fdMax = divertGlobal; /* * Bind socket. */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = globalPort; if (bind (divertGlobal, (struct sockaddr*) &addr, sizeof addr) == -1) Quit ("Unable to bind global divert socket."); } /* * Create socket for sending ICMP messages. */ icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); if (icmpSock == -1) Quit ("Unable to create ICMP socket."); /* * And disable reads for the socket, otherwise it slowly fills * up with received icmps which we do not use. */ shutdown(icmpSock, SHUT_RD); /* * Become a daemon unless verbose mode was requested. */ if (!verbose) DaemonMode (); /* * Catch signals to manage shutdown and * refresh of interface address. */ siginterrupt(SIGTERM, 1); siginterrupt(SIGHUP, 1); if (exitDelay) signal(SIGTERM, InitiateShutdown); else signal(SIGTERM, Shutdown); signal (SIGHUP, RefreshAddr); /* * Set alias address if it has been given. */ mip = LIST_FIRST(&root); /* XXX: simon */ LIST_FOREACH(mip, &root, list) { mla = mip->la; if (mip->aliasAddr.s_addr != INADDR_NONE) LibAliasSetAddress (mla, mip->aliasAddr); } while (running) { mip = LIST_FIRST(&root); /* XXX: simon */ if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) { /* * When using only one socket, just call * DoAliasing repeatedly to process packets. */ DoAliasing (mip->divertInOut, DONT_KNOW); continue; } /* * Build read mask from socket descriptors to select. */ FD_ZERO (&readMask); /* * Check if new packets are available. */ LIST_FOREACH(mip, &root, list) { if (mip->divertIn != -1) FD_SET (mip->divertIn, &readMask); if (mip->divertOut != -1) FD_SET (mip->divertOut, &readMask); if (mip->divertInOut != -1) FD_SET (mip->divertInOut, &readMask); } /* * Routing info is processed always. */ if (routeSock != -1) FD_SET (routeSock, &readMask); if (divertGlobal != -1) FD_SET (divertGlobal, &readMask); if (select (fdMax + 1, &readMask, NULL, NULL, NULL) == -1) { if (errno == EINTR) continue; Quit ("Select failed."); } if (divertGlobal != -1) if (FD_ISSET (divertGlobal, &readMask)) DoGlobal (divertGlobal); LIST_FOREACH(mip, &root, list) { mla = mip->la; if (mip->divertIn != -1) if (FD_ISSET (mip->divertIn, &readMask)) DoAliasing (mip->divertIn, INPUT); if (mip->divertOut != -1) if (FD_ISSET (mip->divertOut, &readMask)) DoAliasing (mip->divertOut, OUTPUT); if (mip->divertInOut != -1) if (FD_ISSET (mip->divertInOut, &readMask)) DoAliasing (mip->divertInOut, DONT_KNOW); } if (routeSock != -1) if (FD_ISSET (routeSock, &readMask)) HandleRoutingInfo (routeSock); } if (background) unlink (pidName); return 0; } static void DaemonMode(void) { FILE* pidFile; daemon (0, 0); background = 1; pidFile = fopen (pidName, "w"); if (pidFile) { fprintf (pidFile, "%d\n", getpid ()); fclose (pidFile); } } static void ParseArgs (int argc, char** argv) { int arg; char* opt; char parmBuf[256]; int len; /* bounds checking */ for (arg = 1; arg < argc; arg++) { opt = argv[arg]; if (*opt != '-') { warnx ("invalid option %s", opt); Usage (); } parmBuf[0] = '\0'; len = 0; while (arg < argc - 1) { if (argv[arg + 1][0] == '-') break; if (len) { strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1)); len += strlen(parmBuf + len); } ++arg; strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1)); len += strlen(parmBuf + len); } ParseOption (opt + 1, (len ? parmBuf : NULL)); } } static void DoGlobal (int fd) { int bytes; int origBytes; char buf[IP_MAXPACKET]; struct sockaddr_in addr; int wrote; socklen_t addrSize; struct ip* ip; char msgBuf[80]; /* * Get packet from socket. */ addrSize = sizeof addr; origBytes = recvfrom (fd, buf, sizeof buf, 0, (struct sockaddr*) &addr, &addrSize); if (origBytes == -1) { if (errno != EINTR) Warn ("read from divert socket failed"); return; } #if 0 if (mip->assignAliasAddr) { if (SetAliasAddressFromIfName (mip->ifName) != 0) exit(1); mip->assignAliasAddr = 0; } #endif /* * This is an IP packet. */ ip = (struct ip*) buf; if (verbose) { /* * Print packet direction and protocol type. */ printf ("Glb "); switch (ip->ip_p) { case IPPROTO_TCP: printf ("[TCP] "); break; case IPPROTO_UDP: printf ("[UDP] "); break; case IPPROTO_ICMP: printf ("[ICMP] "); break; default: printf ("[%d] ", ip->ip_p); break; } /* * Print addresses. */ PrintPacket (ip); } LIST_FOREACH(mip, &root, list) { mla = mip->la; if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED) break; } /* * Length might have changed during aliasing. */ bytes = ntohs (ip->ip_len); /* * Update alias overhead size for outgoing packets. */ if (mip != NULL && bytes - origBytes > mip->aliasOverhead) mip->aliasOverhead = bytes - origBytes; if (verbose) { /* * Print addresses after aliasing. */ printf (" aliased to\n"); printf (" "); PrintPacket (ip); printf ("\n"); } /* * Put packet back for processing. */ wrote = sendto (fd, buf, bytes, 0, (struct sockaddr*) &addr, sizeof addr); if (wrote != bytes) { if (errno == EMSGSIZE && mip != NULL) { if (mip->ifMTU != -1) SendNeedFragIcmp (icmpSock, (struct ip*) buf, mip->ifMTU - mip->aliasOverhead); } else if (errno == EACCES && logIpfwDenied) { sprintf (msgBuf, "failed to write packet back"); Warn (msgBuf); } } } static void DoAliasing (int fd, int direction) { int bytes; int origBytes; char buf[IP_MAXPACKET]; struct sockaddr_in addr; int wrote; int status; socklen_t addrSize; struct ip* ip; char msgBuf[80]; int rval; if (mip->assignAliasAddr) { do { rval = SetAliasAddressFromIfName (mip->ifName); if (background == 0 || dynamicMode == 0) break; if (rval == EAGAIN) sleep(1); } while (rval == EAGAIN); if (rval != 0) exit(1); mip->assignAliasAddr = 0; } /* * Get packet from socket. */ addrSize = sizeof addr; origBytes = recvfrom (fd, buf, sizeof buf, 0, (struct sockaddr*) &addr, &addrSize); if (origBytes == -1) { if (errno != EINTR) Warn ("read from divert socket failed"); return; } /* * This is an IP packet. */ ip = (struct ip*) buf; if (direction == DONT_KNOW) { if (addr.sin_addr.s_addr == INADDR_ANY) direction = OUTPUT; else direction = INPUT; } if (verbose) { /* * Print packet direction and protocol type. */ printf (direction == OUTPUT ? "Out " : "In "); if (ninstance > 1) printf ("{%s}", mip->name); switch (ip->ip_p) { case IPPROTO_TCP: printf ("[TCP] "); break; case IPPROTO_UDP: printf ("[UDP] "); break; case IPPROTO_ICMP: printf ("[ICMP] "); break; default: printf ("[%d] ", ip->ip_p); break; } /* * Print addresses. */ PrintPacket (ip); } if (direction == OUTPUT) { /* * Outgoing packets. Do aliasing. */ LibAliasOut (mla, buf, IP_MAXPACKET); } else { /* * Do aliasing. */ status = LibAliasIn (mla, buf, IP_MAXPACKET); if (status == PKT_ALIAS_IGNORED && mip->dropIgnoredIncoming) { if (verbose) printf (" dropped.\n"); if (mip->logDropped) SyslogPacket (ip, LOG_WARNING, "denied"); return; } } /* * Length might have changed during aliasing. */ bytes = ntohs (ip->ip_len); /* * Update alias overhead size for outgoing packets. */ if (direction == OUTPUT && bytes - origBytes > mip->aliasOverhead) mip->aliasOverhead = bytes - origBytes; if (verbose) { /* * Print addresses after aliasing. */ printf (" aliased to\n"); printf (" "); PrintPacket (ip); printf ("\n"); } /* * Put packet back for processing. */ wrote = sendto (fd, buf, bytes, 0, (struct sockaddr*) &addr, sizeof addr); if (wrote != bytes) { if (errno == EMSGSIZE) { if (direction == OUTPUT && mip->ifMTU != -1) SendNeedFragIcmp (icmpSock, (struct ip*) buf, mip->ifMTU - mip->aliasOverhead); } else if (errno == EACCES && logIpfwDenied) { sprintf (msgBuf, "failed to write packet back"); Warn (msgBuf); } } } static void HandleRoutingInfo (int fd) { int bytes; struct if_msghdr ifMsg; /* * Get packet from socket. */ bytes = read (fd, &ifMsg, sizeof ifMsg); if (bytes == -1) { Warn ("read from routing socket failed"); return; } if (ifMsg.ifm_version != RTM_VERSION) { Warn ("unexpected packet read from routing socket"); return; } if (verbose) printf ("Routing message %#x received.\n", ifMsg.ifm_type); if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) { LIST_FOREACH(mip, &root, list) { mla = mip->la; if (ifMsg.ifm_index == mip->ifIndex) { if (verbose) printf("Interface address/MTU has probably changed.\n"); mip->assignAliasAddr = 1; } } } } static void PrintPacket (struct ip* ip) { printf ("%s", FormatPacket (ip)); } static void SyslogPacket (struct ip* ip, int priority, const char *label) { syslog (priority, "%s %s", label, FormatPacket (ip)); } static char* FormatPacket (struct ip* ip) { static char buf[256]; struct tcphdr* tcphdr; struct udphdr* udphdr; struct icmp* icmphdr; char src[20]; char dst[20]; strcpy (src, inet_ntoa (ip->ip_src)); strcpy (dst, inet_ntoa (ip->ip_dst)); switch (ip->ip_p) { case IPPROTO_TCP: tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); sprintf (buf, "[TCP] %s:%d -> %s:%d", src, ntohs (tcphdr->th_sport), dst, ntohs (tcphdr->th_dport)); break; case IPPROTO_UDP: udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); sprintf (buf, "[UDP] %s:%d -> %s:%d", src, ntohs (udphdr->uh_sport), dst, ntohs (udphdr->uh_dport)); break; case IPPROTO_ICMP: icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); sprintf (buf, "[ICMP] %s -> %s %u(%u)", src, dst, icmphdr->icmp_type, icmphdr->icmp_code); break; default: sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); break; } return buf; } static int SetAliasAddressFromIfName(const char *ifn) { size_t needed; int mib[6]; char *buf, *lim, *next; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *sdl; struct sockaddr_in *sin; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; /* Only IP addresses please */ mib[4] = NET_RT_IFLIST; mib[5] = 0; /* ifIndex??? */ /* * Get interface data. */ if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) err(1, "iflist-sysctl-estimate"); if ((buf = malloc(needed)) == NULL) errx(1, "malloc failed"); if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM) err(1, "iflist-sysctl-get"); lim = buf + needed; /* * Loop through interfaces until one with * given name is found. This is done to * find correct interface index for routing * message processing. */ mip->ifIndex = 0; next = buf; while (next < lim) { ifm = (struct if_msghdr *)next; next += ifm->ifm_msglen; if (ifm->ifm_version != RTM_VERSION) { if (verbose) warnx("routing message version %d " "not understood", ifm->ifm_version); continue; } if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); if (strlen(ifn) == sdl->sdl_nlen && strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { mip->ifIndex = ifm->ifm_index; mip->ifMTU = ifm->ifm_data.ifi_mtu; break; } } } if (!mip->ifIndex) errx(1, "unknown interface name %s", ifn); /* * Get interface address. */ sin = NULL; while (next < lim) { ifam = (struct ifa_msghdr *)next; next += ifam->ifam_msglen; if (ifam->ifam_version != RTM_VERSION) { if (verbose) warnx("routing message version %d " "not understood", ifam->ifam_version); continue; } if (ifam->ifam_type != RTM_NEWADDR) break; if (ifam->ifam_addrs & RTA_IFA) { int i; char *cp = (char *)(ifam + 1); for (i = 1; i < RTA_IFA; i <<= 1) if (ifam->ifam_addrs & i) cp += SA_SIZE((struct sockaddr *)cp); if (((struct sockaddr *)cp)->sa_family == AF_INET) { sin = (struct sockaddr_in *)cp; break; } } } if (sin == NULL) { warnx("%s: cannot get interface address", ifn); free(buf); return EAGAIN; } LibAliasSetAddress(mla, sin->sin_addr); syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes", inet_ntoa(sin->sin_addr), mip->ifMTU); free(buf); return 0; } void Quit (const char* msg) { Warn (msg); exit (1); } void Warn (const char* msg) { if (background) syslog (LOG_ALERT, "%s (%m)", msg); else warn ("%s", msg); } static void RefreshAddr (int sig __unused) { LibAliasRefreshModules(); if (mip != NULL && mip->ifName != NULL) mip->assignAliasAddr = 1; } static void InitiateShutdown (int sig __unused) { /* * Start timer to allow kernel gracefully * shutdown existing connections when system * is shut down. */ siginterrupt(SIGALRM, 1); signal (SIGALRM, Shutdown); ualarm(exitDelay*1000, 1000); } static void Shutdown (int sig __unused) { running = 0; } /* * Different options recognized by this program. */ enum Option { LibAliasOption, Instance, Verbose, InPort, OutPort, Port, GlobalPort, AliasAddress, TargetAddress, InterfaceName, RedirectPort, RedirectProto, RedirectAddress, ConfigFile, DynamicMode, ProxyRule, LogDenied, LogFacility, PunchFW, SkinnyPort, LogIpfwDenied, PidFile, ExitDelay }; enum Param { YesNo, Numeric, String, None, Address, Service }; /* * Option information structure (used by ParseOption). */ struct OptionInfo { enum Option type; int packetAliasOpt; enum Param parm; const char* parmDescription; const char* description; const char* name; const char* shortName; }; /* * Table of known options. */ static struct OptionInfo optionTable[] = { { LibAliasOption, PKT_ALIAS_UNREGISTERED_ONLY, YesNo, "[yes|no]", "alias only unregistered addresses", "unregistered_only", "u" }, { LibAliasOption, PKT_ALIAS_LOG, YesNo, "[yes|no]", "enable logging", "log", "l" }, { LibAliasOption, PKT_ALIAS_PROXY_ONLY, YesNo, "[yes|no]", "proxy only", "proxy_only", NULL }, { LibAliasOption, PKT_ALIAS_REVERSE, YesNo, "[yes|no]", "operate in reverse mode", "reverse", NULL }, { LibAliasOption, PKT_ALIAS_DENY_INCOMING, YesNo, "[yes|no]", "allow incoming connections", "deny_incoming", "d" }, { LibAliasOption, PKT_ALIAS_USE_SOCKETS, YesNo, "[yes|no]", "use sockets to inhibit port conflict", "use_sockets", "s" }, { LibAliasOption, PKT_ALIAS_SAME_PORTS, YesNo, "[yes|no]", "try to keep original port numbers for connections", "same_ports", "m" }, { Verbose, 0, YesNo, "[yes|no]", "verbose mode, dump packet information", "verbose", "v" }, { DynamicMode, 0, YesNo, "[yes|no]", "dynamic mode, automatically detect interface address changes", "dynamic", NULL }, { InPort, 0, Service, "number|service_name", "set port for incoming packets", "in_port", "i" }, { OutPort, 0, Service, "number|service_name", "set port for outgoing packets", "out_port", "o" }, { Port, 0, Service, "number|service_name", "set port (defaults to natd/divert)", "port", "p" }, { GlobalPort, 0, Service, "number|service_name", "set globalport", "globalport", NULL }, { AliasAddress, 0, Address, "x.x.x.x", "address to use for aliasing", "alias_address", "a" }, { TargetAddress, 0, Address, "x.x.x.x", "address to use for incoming sessions", "target_address", "t" }, { InterfaceName, 0, String, "network_if_name", "take aliasing address from interface", "interface", "n" }, { ProxyRule, 0, String, "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " "a.b.c.d:yyyy", "add transparent proxying / destination NAT", "proxy_rule", NULL }, { RedirectPort, 0, String, "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range" " [remote_addr[:remote_port_range]]", "redirect a port (or ports) for incoming traffic", "redirect_port", NULL }, { RedirectProto, 0, String, "proto local_addr [public_addr] [remote_addr]", "redirect packets of a given proto", "redirect_proto", NULL }, { RedirectAddress, 0, String, "local_addr[,...] public_addr", "define mapping between local and public addresses", "redirect_address", NULL }, { ConfigFile, 0, String, "file_name", "read options from configuration file", "config", "f" }, { LogDenied, 0, YesNo, "[yes|no]", "enable logging of denied incoming packets", "log_denied", NULL }, { LogFacility, 0, String, "facility", "name of syslog facility to use for logging", "log_facility", NULL }, { PunchFW, 0, String, "basenumber:count", "punch holes in the firewall for incoming FTP/IRC DCC connections", "punch_fw", NULL }, { SkinnyPort, 0, String, "port", "set the TCP port for use with the Skinny Station protocol", "skinny_port", NULL }, { LogIpfwDenied, 0, YesNo, "[yes|no]", "log packets converted by natd, but denied by ipfw", "log_ipfw_denied", NULL }, { PidFile, 0, String, "file_name", "store PID in an alternate file", "pid_file", "P" }, { Instance, 0, String, "instance name", "name of aliasing engine instance", "instance", NULL }, { ExitDelay, 0, Numeric, "ms", "delay in ms before daemon exit after signal", "exit_delay", NULL }, }; static void ParseOption (const char* option, const char* parms) { int i; struct OptionInfo* info; int yesNoValue; int aliasValue; int numValue; u_short uNumValue; const char* strValue; struct in_addr addrValue; int max; char* end; const CODE* fac_record = NULL; /* * Find option from table. */ max = sizeof (optionTable) / sizeof (struct OptionInfo); for (i = 0, info = optionTable; i < max; i++, info++) { if (!strcmp (info->name, option)) break; if (info->shortName) if (!strcmp (info->shortName, option)) break; } if (i >= max) { warnx ("unknown option %s", option); Usage (); } uNumValue = 0; yesNoValue = 0; numValue = 0; strValue = NULL; /* * Check parameters. */ switch (info->parm) { case YesNo: if (!parms) parms = "yes"; if (!strcmp (parms, "yes")) yesNoValue = 1; else if (!strcmp (parms, "no")) yesNoValue = 0; else errx (1, "%s needs yes/no parameter", option); break; case Service: if (!parms) errx (1, "%s needs service name or " "port number parameter", option); uNumValue = StrToPort (parms, "divert"); break; case Numeric: if (parms) numValue = strtol (parms, &end, 10); else end = NULL; if (end == parms) errx (1, "%s needs numeric parameter", option); break; case String: strValue = parms; if (!strValue) errx (1, "%s needs parameter", option); break; case None: if (parms) errx (1, "%s does not take parameters", option); break; case Address: if (!parms) errx (1, "%s needs address/host parameter", option); StrToAddr (parms, &addrValue); break; } switch (info->type) { case LibAliasOption: aliasValue = yesNoValue ? info->packetAliasOpt : 0; LibAliasSetMode (mla, aliasValue, info->packetAliasOpt); break; case Verbose: verbose = yesNoValue; break; case DynamicMode: dynamicMode = yesNoValue; break; case InPort: mip->inPort = uNumValue; break; case OutPort: mip->outPort = uNumValue; break; case Port: mip->inOutPort = uNumValue; break; case GlobalPort: globalPort = uNumValue; break; case AliasAddress: memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr)); break; case TargetAddress: LibAliasSetTarget(mla, addrValue); break; case RedirectPort: SetupPortRedirect (strValue); break; case RedirectProto: SetupProtoRedirect(strValue); break; case RedirectAddress: SetupAddressRedirect (strValue); break; case ProxyRule: LibAliasProxyRule (mla, strValue); break; case InterfaceName: if (mip->ifName) free (mip->ifName); mip->ifName = strdup (strValue); break; case ConfigFile: ReadConfigFile (strValue); break; case LogDenied: mip->logDropped = yesNoValue; break; case LogFacility: fac_record = facilitynames; while (fac_record->c_name != NULL) { if (!strcmp (fac_record->c_name, strValue)) { logFacility = fac_record->c_val; break; } else fac_record++; } if(fac_record->c_name == NULL) errx(1, "Unknown log facility name: %s", strValue); break; case PunchFW: SetupPunchFW(strValue); break; case SkinnyPort: SetupSkinnyPort(strValue); break; case LogIpfwDenied: logIpfwDenied = yesNoValue; break; case PidFile: pidName = strdup (strValue); break; case Instance: NewInstance(strValue); break; case ExitDelay: if (numValue < 0 || numValue > MAX_EXIT_DELAY) errx(1, "Incorrect exit delay: %d", numValue); exitDelay = numValue; break; } } void ReadConfigFile (const char* fileName) { FILE* file; char *buf; size_t len; char *ptr, *p; char* option; file = fopen (fileName, "r"); if (!file) err(1, "cannot open config file %s", fileName); while ((buf = fgetln(file, &len)) != NULL) { if (buf[len - 1] == '\n') buf[len - 1] = '\0'; else errx(1, "config file format error: " "last line should end with newline"); /* * Check for comments, strip off trailing spaces. */ if ((ptr = strchr(buf, '#'))) *ptr = '\0'; for (ptr = buf; isspace(*ptr); ++ptr) continue; if (*ptr == '\0') continue; for (p = strchr(buf, '\0'); isspace(*--p);) continue; *++p = '\0'; /* * Extract option name. */ option = ptr; while (*ptr && !isspace (*ptr)) ++ptr; if (*ptr != '\0') { *ptr = '\0'; ++ptr; } /* * Skip white space between name and parms. */ while (*ptr && isspace (*ptr)) ++ptr; ParseOption (option, *ptr ? ptr : NULL); } fclose (file); } static void Usage(void) { int i; int max; struct OptionInfo* info; fprintf (stderr, "Recognized options:\n\n"); max = sizeof (optionTable) / sizeof (struct OptionInfo); for (i = 0, info = optionTable; i < max; i++, info++) { fprintf (stderr, "-%-20s %s\n", info->name, info->parmDescription); if (info->shortName) fprintf (stderr, "-%-20s %s\n", info->shortName, info->parmDescription); fprintf (stderr, " %s\n\n", info->description); } exit (1); } void SetupPortRedirect (const char* parms) { char *buf; char* ptr; char* serverPool; struct in_addr localAddr; struct in_addr publicAddr; struct in_addr remoteAddr; port_range portRange; u_short localPort = 0; u_short publicPort = 0; u_short remotePort = 0; u_short numLocalPorts = 0; u_short numPublicPorts = 0; u_short numRemotePorts = 0; int proto; char* protoName; char* separator; int i; struct alias_link *aliaslink = NULL; buf = strdup (parms); if (!buf) errx (1, "redirect_port: strdup() failed"); /* * Extract protocol. */ protoName = strtok (buf, " \t"); if (!protoName) errx (1, "redirect_port: missing protocol"); proto = StrToProto (protoName); /* * Extract local address. */ ptr = strtok (NULL, " \t"); if (!ptr) errx (1, "redirect_port: missing local address"); separator = strchr(ptr, ','); if (separator) { /* LSNAT redirection syntax. */ localAddr.s_addr = INADDR_NONE; localPort = ~0; numLocalPorts = 1; serverPool = ptr; } else { if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) errx (1, "redirect_port: invalid local port range"); localPort = GETLOPORT(portRange); numLocalPorts = GETNUMPORTS(portRange); serverPool = NULL; } /* * Extract public port and optionally address. */ ptr = strtok (NULL, " \t"); if (!ptr) errx (1, "redirect_port: missing public port"); separator = strchr (ptr, ':'); if (separator) { if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) errx (1, "redirect_port: invalid public port range"); } else { publicAddr.s_addr = INADDR_ANY; if (StrToPortRange (ptr, protoName, &portRange) != 0) errx (1, "redirect_port: invalid public port range"); } publicPort = GETLOPORT(portRange); numPublicPorts = GETNUMPORTS(portRange); /* * Extract remote address and optionally port. */ ptr = strtok (NULL, " \t"); if (ptr) { separator = strchr (ptr, ':'); if (separator) { if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) errx (1, "redirect_port: invalid remote port range"); } else { SETLOPORT(portRange, 0); SETNUMPORTS(portRange, 1); StrToAddr (ptr, &remoteAddr); } } else { SETLOPORT(portRange, 0); SETNUMPORTS(portRange, 1); remoteAddr.s_addr = INADDR_ANY; } remotePort = GETLOPORT(portRange); numRemotePorts = GETNUMPORTS(portRange); /* * Make sure port ranges match up, then add the redirect ports. */ if (numLocalPorts != numPublicPorts) errx (1, "redirect_port: port ranges must be equal in size"); /* Remote port range is allowed to be '0' which means all ports. */ if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0)) errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); for (i = 0 ; i < numPublicPorts ; ++i) { /* If remotePort is all ports, set it to 0. */ u_short remotePortCopy = remotePort + i; if (numRemotePorts == 1 && remotePort == 0) remotePortCopy = 0; aliaslink = LibAliasRedirectPort (mla, localAddr, htons(localPort + i), remoteAddr, htons(remotePortCopy), publicAddr, htons(publicPort + i), proto); } /* * Setup LSNAT server pool. */ if (serverPool != NULL && aliaslink != NULL) { ptr = strtok(serverPool, ","); while (ptr != NULL) { if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0) errx(1, "redirect_port: invalid local port range"); localPort = GETLOPORT(portRange); if (GETNUMPORTS(portRange) != 1) errx(1, "redirect_port: local port must be single in this context"); LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort)); ptr = strtok(NULL, ","); } } free (buf); } void SetupProtoRedirect(const char* parms) { char *buf; char* ptr; struct in_addr localAddr; struct in_addr publicAddr; struct in_addr remoteAddr; int proto; char* protoName; struct protoent *protoent; buf = strdup (parms); if (!buf) errx (1, "redirect_port: strdup() failed"); /* * Extract protocol. */ protoName = strtok(buf, " \t"); if (!protoName) errx(1, "redirect_proto: missing protocol"); protoent = getprotobyname(protoName); if (protoent == NULL) errx(1, "redirect_proto: unknown protocol %s", protoName); else proto = protoent->p_proto; /* * Extract local address. */ ptr = strtok(NULL, " \t"); if (!ptr) errx(1, "redirect_proto: missing local address"); else StrToAddr(ptr, &localAddr); /* * Extract optional public address. */ ptr = strtok(NULL, " \t"); if (ptr) StrToAddr(ptr, &publicAddr); else publicAddr.s_addr = INADDR_ANY; /* * Extract optional remote address. */ ptr = strtok(NULL, " \t"); if (ptr) StrToAddr(ptr, &remoteAddr); else remoteAddr.s_addr = INADDR_ANY; /* * Create aliasing link. */ (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr, proto); free (buf); } void SetupAddressRedirect (const char* parms) { char *buf; char* ptr; char* separator; struct in_addr localAddr; struct in_addr publicAddr; char* serverPool; struct alias_link *aliaslink; buf = strdup (parms); if (!buf) errx (1, "redirect_port: strdup() failed"); /* * Extract local address. */ ptr = strtok (buf, " \t"); if (!ptr) errx (1, "redirect_address: missing local address"); separator = strchr(ptr, ','); if (separator) { /* LSNAT redirection syntax. */ localAddr.s_addr = INADDR_NONE; serverPool = ptr; } else { StrToAddr (ptr, &localAddr); serverPool = NULL; } /* * Extract public address. */ ptr = strtok (NULL, " \t"); if (!ptr) errx (1, "redirect_address: missing public address"); StrToAddr (ptr, &publicAddr); aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr); /* * Setup LSNAT server pool. */ if (serverPool != NULL && aliaslink != NULL) { ptr = strtok(serverPool, ","); while (ptr != NULL) { StrToAddr(ptr, &localAddr); LibAliasAddServer(mla, aliaslink, localAddr, htons(~0)); ptr = strtok(NULL, ","); } } free (buf); } void StrToAddr (const char* str, struct in_addr* addr) { struct hostent* hp; if (inet_aton (str, addr)) return; hp = gethostbyname (str); if (!hp) errx (1, "unknown host %s", str); memcpy (addr, hp->h_addr, sizeof (struct in_addr)); } u_short StrToPort (const char* str, const char* proto) { u_short port; struct servent* sp; char* end; port = strtol (str, &end, 10); if (end != str) return htons (port); sp = getservbyname (str, proto); if (!sp) errx (1, "%s/%s: unknown service", str, proto); return sp->s_port; } int StrToPortRange (const char* str, const char* proto, port_range *portRange) { const char* sep; struct servent* sp; char* end; u_short loPort; u_short hiPort; /* First see if this is a service, return corresponding port if so. */ sp = getservbyname (str,proto); if (sp) { SETLOPORT(*portRange, ntohs(sp->s_port)); SETNUMPORTS(*portRange, 1); return 0; } /* Not a service, see if it's a single port or port range. */ sep = strchr (str, '-'); if (sep == NULL) { SETLOPORT(*portRange, strtol(str, &end, 10)); if (end != str) { /* Single port. */ SETNUMPORTS(*portRange, 1); return 0; } /* Error in port range field. */ errx (1, "%s/%s: unknown service", str, proto); } /* Port range, get the values and sanity check. */ sscanf (str, "%hu-%hu", &loPort, &hiPort); SETLOPORT(*portRange, loPort); SETNUMPORTS(*portRange, 0); /* Error by default */ if (loPort <= hiPort) SETNUMPORTS(*portRange, hiPort - loPort + 1); if (GETNUMPORTS(*portRange) == 0) errx (1, "invalid port range %s", str); return 0; } static int StrToProto (const char* str) { if (!strcmp (str, "tcp")) return IPPROTO_TCP; if (!strcmp (str, "udp")) return IPPROTO_UDP; errx (1, "unknown protocol %s. Expected tcp or udp", str); } static int StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange) { char* ptr; ptr = strchr (str, ':'); if (!ptr) errx (1, "%s is missing port number", str); *ptr = '\0'; ++ptr; StrToAddr (str, addr); return StrToPortRange (ptr, proto, portRange); } static void SetupPunchFW(const char *strValue) { unsigned int base, num; if (sscanf(strValue, "%u:%u", &base, &num) != 2) errx(1, "punch_fw: basenumber:count parameter required"); if (CheckIpfwRulenum(base + num - 1) == -1) errx(1, "punch_fw: basenumber:count parameter should fit " "the maximum allowed rule numbers"); LibAliasSetFWBase(mla, base, num); (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); } static void SetupSkinnyPort(const char *strValue) { unsigned int port; if (sscanf(strValue, "%u", &port) != 1) errx(1, "skinny_port: port parameter required"); LibAliasSetSkinnyPort(mla, port); } static void NewInstance(const char *name) { struct instance *ip; LIST_FOREACH(ip, &root, list) { if (!strcmp(ip->name, name)) { mla = ip->la; mip = ip; return; } } ninstance++; - ip = calloc(sizeof *ip, 1); + ip = calloc(1, sizeof(*ip)); ip->name = strdup(name); ip->la = LibAliasInit (ip->la); ip->assignAliasAddr = 0; ip->ifName = NULL; ip->logDropped = 0; ip->inPort = 0; ip->outPort = 0; ip->inOutPort = 0; ip->aliasAddr.s_addr = INADDR_NONE; ip->ifMTU = -1; ip->aliasOverhead = 12; LIST_INSERT_HEAD(&root, ip, list); mla = ip->la; mip = ip; } static int CheckIpfwRulenum(unsigned int rnum) { unsigned int default_rule; size_t len = sizeof(default_rule); if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len, NULL, 0) == -1) { warn("Failed to get the default ipfw rule number, using " "default historical value 65535. The reason was"); default_rule = 65535; } if (rnum >= default_rule) { return -1; } return 0; } Index: stable/11/usr.bin/calendar/io.c =================================================================== --- stable/11/usr.bin/calendar/io.c (revision 307696) +++ stable/11/usr.bin/calendar/io.c (revision 307697) @@ -1,503 +1,503 @@ /*- * Copyright (c) 1989, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif #if 0 #ifndef lint static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #define _WITH_GETLINE #include #include #include #include #include #include "pathnames.h" #include "calendar.h" enum { T_OK = 0, T_ERR, T_PROCESS, }; const char *calendarFile = "calendar"; /* default calendar file */ static const char *calendarHomes[] = {".calendar", _PATH_INCLUDE}; /* HOME */ static const char *calendarNoMail = "nomail";/* don't sent mail if file exist */ static char path[MAXPATHLEN]; struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon; struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice; static int cal_parse(FILE *in, FILE *out); static StringList *definitions = NULL; static struct event *events[MAXCOUNT]; static char *extradata[MAXCOUNT]; static void trimlr(char **buf) { char *walk = *buf; char *last; while (isspace(*walk)) walk++; if (*walk != '\0') { last = walk + strlen(walk) - 1; while (last > walk && isspace(*last)) last--; *(last+1) = 0; } *buf = walk; } static FILE * cal_fopen(const char *file) { FILE *fp; char *home = getenv("HOME"); unsigned int i; if (home == NULL || *home == '\0') { warnx("Cannot get home directory"); return (NULL); } if (chdir(home) != 0) { warnx("Cannot enter home directory"); return (NULL); } - for (i = 0; i < sizeof(calendarHomes)/sizeof(calendarHomes[0]) ; i++) { + for (i = 0; i < nitems(calendarHomes); i++) { if (chdir(calendarHomes[i]) != 0) continue; if ((fp = fopen(file, "r")) != NULL) return (fp); } warnx("can't open calendar file \"%s\"", file); return (NULL); } static int token(char *line, FILE *out, bool *skip) { char *walk, c, a; if (strncmp(line, "endif", 5) == 0) { *skip = false; return (T_OK); } if (*skip) return (T_OK); if (strncmp(line, "include", 7) == 0) { walk = line + 7; trimlr(&walk); if (*walk == '\0') { warnx("Expecting arguments after #include"); return (T_ERR); } if (*walk != '<' && *walk != '\"') { warnx("Excecting '<' or '\"' after #include"); return (T_ERR); } a = *walk; walk++; c = walk[strlen(walk) - 1]; switch(c) { case '>': if (a != '<') { warnx("Unterminated include expecting '\"'"); return (T_ERR); } break; case '\"': if (a != '\"') { warnx("Unterminated include expecting '>'"); return (T_ERR); } break; default: warnx("Unterminated include expecting '%c'", a == '<' ? '>' : '\"' ); return (T_ERR); } walk[strlen(walk) - 1] = '\0'; if (cal_parse(cal_fopen(walk), out)) return (T_ERR); return (T_OK); } if (strncmp(line, "define", 6) == 0) { if (definitions == NULL) definitions = sl_init(); walk = line + 6; trimlr(&walk); if (*walk == '\0') { warnx("Expecting arguments after #define"); return (T_ERR); } sl_add(definitions, strdup(walk)); return (T_OK); } if (strncmp(line, "ifndef", 6) == 0) { walk = line + 6; trimlr(&walk); if (*walk == '\0') { warnx("Expecting arguments after #ifndef"); return (T_ERR); } if (definitions != NULL && sl_find(definitions, walk) != NULL) *skip = true; return (T_OK); } return (T_PROCESS); } #define REPLACE(string, slen, struct_) \ if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \ if (struct_.name != NULL) \ free(struct_.name); \ if ((struct_.name = strdup(buf + (slen))) == NULL) \ errx(1, "cannot allocate memory"); \ struct_.len = strlen(buf + (slen)); \ continue; \ } static int cal_parse(FILE *in, FILE *out) { char *line = NULL; char *buf; size_t linecap = 0; ssize_t linelen; ssize_t l; static int d_first = -1; static int count = 0; int i; int month[MAXCOUNT]; int day[MAXCOUNT]; int year[MAXCOUNT]; bool skip = false; char dbuf[80]; char *pp, p; struct tm tm; int flags; /* Unused */ tm.tm_sec = 0; tm.tm_min = 0; tm.tm_hour = 0; tm.tm_wday = 0; if (in == NULL) return (1); while ((linelen = getline(&line, &linecap, in)) > 0) { if (*line == '#') { switch (token(line+1, out, &skip)) { case T_ERR: free(line); return (1); case T_OK: continue; case T_PROCESS: break; default: break; } } if (skip) continue; buf = line; for (l = linelen; l > 0 && isspace((unsigned char)buf[l - 1]); l--) ; buf[l] = '\0'; if (buf[0] == '\0') continue; /* Parse special definitions: LANG, Easter, Paskha etc */ if (strncmp(buf, "LANG=", 5) == 0) { (void)setlocale(LC_ALL, buf + 5); d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); setnnames(); continue; } REPLACE("Easter=", 7, neaster); REPLACE("Paskha=", 7, npaskha); REPLACE("ChineseNewYear=", 15, ncny); REPLACE("NewMoon=", 8, nnewmoon); REPLACE("FullMoon=", 9, nfullmoon); REPLACE("MarEquinox=", 11, nmarequinox); REPLACE("SepEquinox=", 11, nsepequinox); REPLACE("JunSolstice=", 12, njunsolstice); REPLACE("DecSolstice=", 12, ndecsolstice); if (strncmp(buf, "SEQUENCE=", 9) == 0) { setnsequences(buf + 9); continue; } /* * If the line starts with a tab, the data has to be * added to the previous line */ if (buf[0] == '\t') { for (i = 0; i < count; i++) event_continue(events[i], buf); continue; } /* Get rid of leading spaces (non-standard) */ while (isspace((unsigned char)buf[0])) memcpy(buf, buf + 1, strlen(buf)); /* No tab in the line, then not a valid line */ if ((pp = strchr(buf, '\t')) == NULL) continue; /* Trim spaces in front of the tab */ while (isspace((unsigned char)pp[-1])) pp--; p = *pp; *pp = '\0'; if ((count = parsedaymonth(buf, year, month, day, &flags, extradata)) == 0) continue; *pp = p; if (count < 0) { /* Show error status based on return value */ if (debug) fprintf(stderr, "Ignored: %s\n", buf); if (count == -1) continue; count = -count + 1; } /* Find the last tab */ while (pp[1] == '\t') pp++; if (d_first < 0) d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); for (i = 0; i < count; i++) { tm.tm_mon = month[i] - 1; tm.tm_mday = day[i]; tm.tm_year = year[i] - 1900; (void)strftime(dbuf, sizeof(dbuf), d_first ? "%e %b" : "%b %e", &tm); if (debug) fprintf(stderr, "got %s\n", pp); events[i] = event_add(year[i], month[i], day[i], dbuf, ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp, extradata[i]); } } free(line); fclose(in); return (0); } void cal(void) { FILE *fpin; FILE *fpout; int i; for (i = 0; i < MAXCOUNT; i++) extradata[i] = (char *)calloc(1, 20); if ((fpin = opencalin()) == NULL) return; if ((fpout = opencalout()) == NULL) { fclose(fpin); return; } if (cal_parse(fpin, fpout)) return; event_print_all(fpout); closecal(fpout); } FILE * opencalin(void) { struct stat sbuf; FILE *fpin; /* open up calendar file */ if ((fpin = fopen(calendarFile, "r")) == NULL) { if (doall) { if (chdir(calendarHomes[0]) != 0) return (NULL); if (stat(calendarNoMail, &sbuf) == 0) return (NULL); if ((fpin = fopen(calendarFile, "r")) == NULL) return (NULL); } else { fpin = cal_fopen(calendarFile); } } return (fpin); } FILE * opencalout(void) { int fd; /* not reading all calendar files, just set output to stdout */ if (!doall) return (stdout); /* set output to a temporary file, so if no output don't send mail */ snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP); if ((fd = mkstemp(path)) < 0) return (NULL); return (fdopen(fd, "w+")); } void closecal(FILE *fp) { uid_t uid; struct stat sbuf; int nread, pdes[2], status; char buf[1024]; if (!doall) return; rewind(fp); if (fstat(fileno(fp), &sbuf) || !sbuf.st_size) goto done; if (pipe(pdes) < 0) goto done; switch (fork()) { case -1: /* error */ (void)close(pdes[0]); (void)close(pdes[1]); goto done; case 0: /* child -- set stdin to pipe output */ if (pdes[0] != STDIN_FILENO) { (void)dup2(pdes[0], STDIN_FILENO); (void)close(pdes[0]); } (void)close(pdes[1]); uid = geteuid(); if (setuid(getuid()) < 0) { warnx("setuid failed"); _exit(1); } if (setgid(getegid()) < 0) { warnx("setgid failed"); _exit(1); } if (setuid(uid) < 0) { warnx("setuid failed"); _exit(1); } execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", "\"Reminder Service\"", (char *)NULL); warn(_PATH_SENDMAIL); _exit(1); } /* parent -- write to pipe input */ (void)close(pdes[0]); write(pdes[1], "From: \"Reminder Service\" <", 26); write(pdes[1], pw->pw_name, strlen(pw->pw_name)); write(pdes[1], ">\nTo: <", 7); write(pdes[1], pw->pw_name, strlen(pw->pw_name)); write(pdes[1], ">\nSubject: ", 11); write(pdes[1], dayname, strlen(dayname)); write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30); while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) (void)write(pdes[1], buf, nread); (void)close(pdes[1]); done: (void)fclose(fp); (void)unlink(path); while (wait(&status) >= 0); } Index: stable/11/usr.bin/gzip/gzip.c =================================================================== --- stable/11/usr.bin/gzip/gzip.c (revision 307696) +++ stable/11/usr.bin/gzip/gzip.c (revision 307697) @@ -1,2174 +1,2174 @@ /* $NetBSD: gzip.c,v 1.109 2015/10/27 07:36:18 mrg Exp $ */ /*- * Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green * 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. * * 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 #ifndef lint __COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004, 2006\ Matthew R. Green. All rights reserved."); __FBSDID("$FreeBSD$"); #endif /* not lint */ /* * gzip.c -- GPL free gzip using zlib. * * RFC 1950 covers the zlib format * RFC 1951 covers the deflate format * RFC 1952 covers the gzip format * * TODO: * - use mmap where possible * - make bzip2/compress -v/-t/-l support work as well as possible */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* what type of file are we dealing with */ enum filetype { FT_GZIP, #ifndef NO_BZIP2_SUPPORT FT_BZIP2, #endif #ifndef NO_COMPRESS_SUPPORT FT_Z, #endif #ifndef NO_PACK_SUPPORT FT_PACK, #endif #ifndef NO_XZ_SUPPORT FT_XZ, #endif FT_LAST, FT_UNKNOWN }; #ifndef NO_BZIP2_SUPPORT #include #define BZ2_SUFFIX ".bz2" #define BZIP2_MAGIC "\102\132\150" #endif #ifndef NO_COMPRESS_SUPPORT #define Z_SUFFIX ".Z" #define Z_MAGIC "\037\235" #endif #ifndef NO_PACK_SUPPORT #define PACK_MAGIC "\037\036" #endif #ifndef NO_XZ_SUPPORT #include #define XZ_SUFFIX ".xz" #define XZ_MAGIC "\3757zXZ" #endif #define GZ_SUFFIX ".gz" #define BUFLEN (64 * 1024) #define GZIP_MAGIC0 0x1F #define GZIP_MAGIC1 0x8B #define GZIP_OMAGIC1 0x9E #define GZIP_TIMESTAMP (off_t)4 #define GZIP_ORIGNAME (off_t)10 #define HEAD_CRC 0x02 #define EXTRA_FIELD 0x04 #define ORIG_NAME 0x08 #define COMMENT 0x10 #define OS_CODE 3 /* Unix */ typedef struct { const char *zipped; int ziplen; const char *normal; /* for unzip - must not be longer than zipped */ } suffixes_t; static suffixes_t suffixes[] = { #define SUFFIX(Z, N) {Z, sizeof Z - 1, N} SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */ #ifndef SMALL SUFFIX(GZ_SUFFIX, ""), SUFFIX(".z", ""), SUFFIX("-gz", ""), SUFFIX("-z", ""), SUFFIX("_z", ""), SUFFIX(".taz", ".tar"), SUFFIX(".tgz", ".tar"), #ifndef NO_BZIP2_SUPPORT SUFFIX(BZ2_SUFFIX, ""), SUFFIX(".tbz", ".tar"), SUFFIX(".tbz2", ".tar"), #endif #ifndef NO_COMPRESS_SUPPORT SUFFIX(Z_SUFFIX, ""), #endif #ifndef NO_XZ_SUPPORT SUFFIX(XZ_SUFFIX, ""), #endif SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */ #endif /* SMALL */ #undef SUFFIX }; -#define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0]) +#define NUM_SUFFIXES (nitems(suffixes)) #define SUFFIX_MAXLEN 30 static const char gzip_version[] = "FreeBSD gzip 20150413"; #ifndef SMALL static const char gzip_copyright[] = \ " Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green\n" " All rights reserved.\n" "\n" " Redistribution and use in source and binary forms, with or without\n" " modification, are permitted provided that the following conditions\n" " are met:\n" " 1. Redistributions of source code must retain the above copyright\n" " notice, this list of conditions and the following disclaimer.\n" " 2. Redistributions in binary form must reproduce the above copyright\n" " notice, this list of conditions and the following disclaimer in the\n" " documentation and/or other materials provided with the distribution.\n" "\n" " THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" " IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" " OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" " IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" " INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n" " BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" " LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n" " AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n" " OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n" " SUCH DAMAGE."; #endif static int cflag; /* stdout mode */ static int dflag; /* decompress mode */ static int lflag; /* list mode */ static int numflag = 6; /* gzip -1..-9 value */ #ifndef SMALL static int fflag; /* force mode */ static int kflag; /* don't delete input files */ static int nflag; /* don't save name/timestamp */ static int Nflag; /* don't restore name/timestamp */ static int qflag; /* quiet mode */ static int rflag; /* recursive mode */ static int tflag; /* test */ static int vflag; /* verbose mode */ static const char *remove_file = NULL; /* file to be removed upon SIGINT */ #else #define qflag 0 #define tflag 0 #endif static int exit_value = 0; /* exit value */ static char *infile; /* name of file coming in */ static void maybe_err(const char *fmt, ...) __printflike(1, 2) __dead2; #if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ !defined(NO_XZ_SUPPORT) static void maybe_errx(const char *fmt, ...) __printflike(1, 2) __dead2; #endif static void maybe_warn(const char *fmt, ...) __printflike(1, 2); static void maybe_warnx(const char *fmt, ...) __printflike(1, 2); static enum filetype file_gettype(u_char *); #ifdef SMALL #define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz) #endif static off_t gz_compress(int, int, off_t *, const char *, uint32_t); static off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *); static off_t file_compress(char *, char *, size_t); static off_t file_uncompress(char *, char *, size_t); static void handle_pathname(char *); static void handle_file(char *, struct stat *); static void handle_stdin(void); static void handle_stdout(void); static void print_ratio(off_t, off_t, FILE *); static void print_list(int fd, off_t, const char *, time_t); static void usage(void) __dead2; static void display_version(void) __dead2; #ifndef SMALL static void display_license(void); static void sigint_handler(int); #endif static const suffixes_t *check_suffix(char *, int); static ssize_t read_retry(int, void *, size_t); #ifdef SMALL #define unlink_input(f, sb) unlink(f) #else static off_t cat_fd(unsigned char *, size_t, off_t *, int fd); static void prepend_gzip(char *, int *, char ***); static void handle_dir(char *); static void print_verbage(const char *, const char *, off_t, off_t); static void print_test(const char *, int); static void copymodes(int fd, const struct stat *, const char *file); static int check_outfile(const char *outfile); #endif #ifndef NO_BZIP2_SUPPORT static off_t unbzip2(int, int, char *, size_t, off_t *); #endif #ifndef NO_COMPRESS_SUPPORT static FILE *zdopen(int); static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); #endif #ifndef NO_PACK_SUPPORT static off_t unpack(int, int, char *, size_t, off_t *); #endif #ifndef NO_XZ_SUPPORT static off_t unxz(int, int, char *, size_t, off_t *); #endif #ifdef SMALL #define getopt_long(a,b,c,d,e) getopt(a,b,c) #else static const struct option longopts[] = { { "stdout", no_argument, 0, 'c' }, { "to-stdout", no_argument, 0, 'c' }, { "decompress", no_argument, 0, 'd' }, { "uncompress", no_argument, 0, 'd' }, { "force", no_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "keep", no_argument, 0, 'k' }, { "list", no_argument, 0, 'l' }, { "no-name", no_argument, 0, 'n' }, { "name", no_argument, 0, 'N' }, { "quiet", no_argument, 0, 'q' }, { "recursive", no_argument, 0, 'r' }, { "suffix", required_argument, 0, 'S' }, { "test", no_argument, 0, 't' }, { "verbose", no_argument, 0, 'v' }, { "version", no_argument, 0, 'V' }, { "fast", no_argument, 0, '1' }, { "best", no_argument, 0, '9' }, { "ascii", no_argument, 0, 'a' }, { "license", no_argument, 0, 'L' }, { NULL, no_argument, 0, 0 }, }; #endif int main(int argc, char **argv) { const char *progname = getprogname(); #ifndef SMALL char *gzip; int len; #endif int ch; #ifndef SMALL if ((gzip = getenv("GZIP")) != NULL) prepend_gzip(gzip, &argc, &argv); signal(SIGINT, sigint_handler); #endif /* * XXX * handle being called `gunzip', `zcat' and `gzcat' */ if (strcmp(progname, "gunzip") == 0) dflag = 1; else if (strcmp(progname, "zcat") == 0 || strcmp(progname, "gzcat") == 0) dflag = cflag = 1; #ifdef SMALL #define OPT_LIST "123456789cdhlV" #else #define OPT_LIST "123456789acdfhklLNnqrS:tVv" #endif while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) { switch (ch) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': numflag = ch - '0'; break; case 'c': cflag = 1; break; case 'd': dflag = 1; break; case 'l': lflag = 1; dflag = 1; break; case 'V': display_version(); /* NOTREACHED */ #ifndef SMALL case 'a': fprintf(stderr, "%s: option --ascii ignored on this system\n", progname); break; case 'f': fflag = 1; break; case 'k': kflag = 1; break; case 'L': display_license(); /* NOT REACHED */ case 'N': nflag = 0; Nflag = 1; break; case 'n': nflag = 1; Nflag = 0; break; case 'q': qflag = 1; break; case 'r': rflag = 1; break; case 'S': len = strlen(optarg); if (len != 0) { if (len > SUFFIX_MAXLEN) errx(1, "incorrect suffix: '%s': too long", optarg); suffixes[0].zipped = optarg; suffixes[0].ziplen = len; } else { suffixes[NUM_SUFFIXES - 1].zipped = ""; suffixes[NUM_SUFFIXES - 1].ziplen = 0; } break; case 't': cflag = 1; tflag = 1; dflag = 1; break; case 'v': vflag = 1; break; #endif default: usage(); /* NOTREACHED */ } } argv += optind; argc -= optind; if (argc == 0) { if (dflag) /* stdin mode */ handle_stdin(); else /* stdout mode */ handle_stdout(); } else { do { handle_pathname(argv[0]); } while (*++argv); } #ifndef SMALL if (qflag == 0 && lflag && argc > 1) print_list(-1, 0, "(totals)", 0); #endif exit(exit_value); } /* maybe print a warning */ void maybe_warn(const char *fmt, ...) { va_list ap; if (qflag == 0) { va_start(ap, fmt); vwarn(fmt, ap); va_end(ap); } if (exit_value == 0) exit_value = 1; } /* ... without an errno. */ void maybe_warnx(const char *fmt, ...) { va_list ap; if (qflag == 0) { va_start(ap, fmt); vwarnx(fmt, ap); va_end(ap); } if (exit_value == 0) exit_value = 1; } /* maybe print an error */ void maybe_err(const char *fmt, ...) { va_list ap; if (qflag == 0) { va_start(ap, fmt); vwarn(fmt, ap); va_end(ap); } exit(2); } #if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \ !defined(NO_XZ_SUPPORT) /* ... without an errno. */ void maybe_errx(const char *fmt, ...) { va_list ap; if (qflag == 0) { va_start(ap, fmt); vwarnx(fmt, ap); va_end(ap); } exit(2); } #endif #ifndef SMALL /* split up $GZIP and prepend it to the argument list */ static void prepend_gzip(char *gzip, int *argc, char ***argv) { char *s, **nargv, **ac; int nenvarg = 0, i; /* scan how many arguments there are */ for (s = gzip;;) { while (*s == ' ' || *s == '\t') s++; if (*s == 0) goto count_done; nenvarg++; while (*s != ' ' && *s != '\t') if (*s++ == 0) goto count_done; } count_done: /* punt early */ if (nenvarg == 0) return; *argc += nenvarg; ac = *argv; nargv = (char **)malloc((*argc + 1) * sizeof(char *)); if (nargv == NULL) maybe_err("malloc"); /* stash this away */ *argv = nargv; /* copy the program name first */ i = 0; nargv[i++] = *(ac++); /* take a copy of $GZIP and add it to the array */ s = strdup(gzip); if (s == NULL) maybe_err("strdup"); for (;;) { /* Skip whitespaces. */ while (*s == ' ' || *s == '\t') s++; if (*s == 0) goto copy_done; nargv[i++] = s; /* Find the end of this argument. */ while (*s != ' ' && *s != '\t') if (*s++ == 0) /* Argument followed by NUL. */ goto copy_done; /* Terminate by overwriting ' ' or '\t' with NUL. */ *s++ = 0; } copy_done: /* copy the original arguments and a NULL */ while (*ac) nargv[i++] = *(ac++); nargv[i] = NULL; } #endif /* compress input to output. Return bytes read, -1 on error */ static off_t gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime) { z_stream z; char *outbufp, *inbufp; off_t in_tot = 0, out_tot = 0; ssize_t in_size; int i, error; uLong crc; #ifdef SMALL static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0, 0, 0, 0, 0, 0, OS_CODE }; #endif outbufp = malloc(BUFLEN); inbufp = malloc(BUFLEN); if (outbufp == NULL || inbufp == NULL) { maybe_err("malloc failed"); goto out; } memset(&z, 0, sizeof z); z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = 0; #ifdef SMALL memcpy(outbufp, header, sizeof header); i = sizeof header; #else if (nflag != 0) { mtime = 0; origname = ""; } i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s", GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, *origname ? ORIG_NAME : 0, mtime & 0xff, (mtime >> 8) & 0xff, (mtime >> 16) & 0xff, (mtime >> 24) & 0xff, numflag == 1 ? 4 : numflag == 9 ? 2 : 0, OS_CODE, origname); if (i >= BUFLEN) /* this need PATH_MAX > BUFLEN ... */ maybe_err("snprintf"); if (*origname) i++; #endif z.next_out = (unsigned char *)outbufp + i; z.avail_out = BUFLEN - i; error = deflateInit2(&z, numflag, Z_DEFLATED, (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY); if (error != Z_OK) { maybe_warnx("deflateInit2 failed"); in_tot = -1; goto out; } crc = crc32(0L, Z_NULL, 0); for (;;) { if (z.avail_out == 0) { if (write(out, outbufp, BUFLEN) != BUFLEN) { maybe_warn("write"); out_tot = -1; goto out; } out_tot += BUFLEN; z.next_out = (unsigned char *)outbufp; z.avail_out = BUFLEN; } if (z.avail_in == 0) { in_size = read(in, inbufp, BUFLEN); if (in_size < 0) { maybe_warn("read"); in_tot = -1; goto out; } if (in_size == 0) break; crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size); in_tot += in_size; z.next_in = (unsigned char *)inbufp; z.avail_in = in_size; } error = deflate(&z, Z_NO_FLUSH); if (error != Z_OK && error != Z_STREAM_END) { maybe_warnx("deflate failed"); in_tot = -1; goto out; } } /* clean up */ for (;;) { size_t len; ssize_t w; error = deflate(&z, Z_FINISH); if (error != Z_OK && error != Z_STREAM_END) { maybe_warnx("deflate failed"); in_tot = -1; goto out; } len = (char *)z.next_out - outbufp; w = write(out, outbufp, len); if (w == -1 || (size_t)w != len) { maybe_warn("write"); out_tot = -1; goto out; } out_tot += len; z.next_out = (unsigned char *)outbufp; z.avail_out = BUFLEN; if (error == Z_STREAM_END) break; } if (deflateEnd(&z) != Z_OK) { maybe_warnx("deflateEnd failed"); in_tot = -1; goto out; } i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c", (int)crc & 0xff, (int)(crc >> 8) & 0xff, (int)(crc >> 16) & 0xff, (int)(crc >> 24) & 0xff, (int)in_tot & 0xff, (int)(in_tot >> 8) & 0xff, (int)(in_tot >> 16) & 0xff, (int)(in_tot >> 24) & 0xff); if (i != 8) maybe_err("snprintf"); if (write(out, outbufp, i) != i) { maybe_warn("write"); in_tot = -1; } else out_tot += i; out: if (inbufp != NULL) free(inbufp); if (outbufp != NULL) free(outbufp); if (gsizep) *gsizep = out_tot; return in_tot; } /* * uncompress input to output then close the input. return the * uncompressed size written, and put the compressed sized read * into `*gsizep'. */ static off_t gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep, const char *filename) { z_stream z; char *outbufp, *inbufp; off_t out_tot = -1, in_tot = 0; uint32_t out_sub_tot = 0; enum { GZSTATE_MAGIC0, GZSTATE_MAGIC1, GZSTATE_METHOD, GZSTATE_FLAGS, GZSTATE_SKIPPING, GZSTATE_EXTRA, GZSTATE_EXTRA2, GZSTATE_EXTRA3, GZSTATE_ORIGNAME, GZSTATE_COMMENT, GZSTATE_HEAD_CRC1, GZSTATE_HEAD_CRC2, GZSTATE_INIT, GZSTATE_READ, GZSTATE_CRC, GZSTATE_LEN, } state = GZSTATE_MAGIC0; int flags = 0, skip_count = 0; int error = Z_STREAM_ERROR, done_reading = 0; uLong crc = 0; ssize_t wr; int needmore = 0; #define ADVANCE() { z.next_in++; z.avail_in--; } if ((outbufp = malloc(BUFLEN)) == NULL) { maybe_err("malloc failed"); goto out2; } if ((inbufp = malloc(BUFLEN)) == NULL) { maybe_err("malloc failed"); goto out1; } memset(&z, 0, sizeof z); z.avail_in = prelen; z.next_in = (unsigned char *)pre; z.avail_out = BUFLEN; z.next_out = (unsigned char *)outbufp; z.zalloc = NULL; z.zfree = NULL; z.opaque = 0; in_tot = prelen; out_tot = 0; for (;;) { if ((z.avail_in == 0 || needmore) && done_reading == 0) { ssize_t in_size; if (z.avail_in > 0) { memmove(inbufp, z.next_in, z.avail_in); } z.next_in = (unsigned char *)inbufp; in_size = read(in, z.next_in + z.avail_in, BUFLEN - z.avail_in); if (in_size == -1) { maybe_warn("failed to read stdin"); goto stop_and_fail; } else if (in_size == 0) { done_reading = 1; } z.avail_in += in_size; needmore = 0; in_tot += in_size; } if (z.avail_in == 0) { if (done_reading && state != GZSTATE_MAGIC0) { maybe_warnx("%s: unexpected end of file", filename); goto stop_and_fail; } goto stop; } switch (state) { case GZSTATE_MAGIC0: if (*z.next_in != GZIP_MAGIC0) { if (in_tot > 0) { maybe_warnx("%s: trailing garbage " "ignored", filename); exit_value = 2; goto stop; } maybe_warnx("input not gziped (MAGIC0)"); goto stop_and_fail; } ADVANCE(); state++; out_sub_tot = 0; crc = crc32(0L, Z_NULL, 0); break; case GZSTATE_MAGIC1: if (*z.next_in != GZIP_MAGIC1 && *z.next_in != GZIP_OMAGIC1) { maybe_warnx("input not gziped (MAGIC1)"); goto stop_and_fail; } ADVANCE(); state++; break; case GZSTATE_METHOD: if (*z.next_in != Z_DEFLATED) { maybe_warnx("unknown compression method"); goto stop_and_fail; } ADVANCE(); state++; break; case GZSTATE_FLAGS: flags = *z.next_in; ADVANCE(); skip_count = 6; state++; break; case GZSTATE_SKIPPING: if (skip_count > 0) { skip_count--; ADVANCE(); } else state++; break; case GZSTATE_EXTRA: if ((flags & EXTRA_FIELD) == 0) { state = GZSTATE_ORIGNAME; break; } skip_count = *z.next_in; ADVANCE(); state++; break; case GZSTATE_EXTRA2: skip_count |= ((*z.next_in) << 8); ADVANCE(); state++; break; case GZSTATE_EXTRA3: if (skip_count > 0) { skip_count--; ADVANCE(); } else state++; break; case GZSTATE_ORIGNAME: if ((flags & ORIG_NAME) == 0) { state++; break; } if (*z.next_in == 0) state++; ADVANCE(); break; case GZSTATE_COMMENT: if ((flags & COMMENT) == 0) { state++; break; } if (*z.next_in == 0) state++; ADVANCE(); break; case GZSTATE_HEAD_CRC1: if (flags & HEAD_CRC) skip_count = 2; else skip_count = 0; state++; break; case GZSTATE_HEAD_CRC2: if (skip_count > 0) { skip_count--; ADVANCE(); } else state++; break; case GZSTATE_INIT: if (inflateInit2(&z, -MAX_WBITS) != Z_OK) { maybe_warnx("failed to inflateInit"); goto stop_and_fail; } state++; break; case GZSTATE_READ: error = inflate(&z, Z_FINISH); switch (error) { /* Z_BUF_ERROR goes with Z_FINISH... */ case Z_BUF_ERROR: if (z.avail_out > 0 && !done_reading) continue; case Z_STREAM_END: case Z_OK: break; case Z_NEED_DICT: maybe_warnx("Z_NEED_DICT error"); goto stop_and_fail; case Z_DATA_ERROR: maybe_warnx("data stream error"); goto stop_and_fail; case Z_STREAM_ERROR: maybe_warnx("internal stream error"); goto stop_and_fail; case Z_MEM_ERROR: maybe_warnx("memory allocation error"); goto stop_and_fail; default: maybe_warn("unknown error from inflate(): %d", error); } wr = BUFLEN - z.avail_out; if (wr != 0) { crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); if ( #ifndef SMALL /* don't write anything with -t */ tflag == 0 && #endif write(out, outbufp, wr) != wr) { maybe_warn("error writing to output"); goto stop_and_fail; } out_tot += wr; out_sub_tot += wr; } if (error == Z_STREAM_END) { inflateEnd(&z); state++; } z.next_out = (unsigned char *)outbufp; z.avail_out = BUFLEN; break; case GZSTATE_CRC: { uLong origcrc; if (z.avail_in < 4) { if (!done_reading) { needmore = 1; continue; } maybe_warnx("truncated input"); goto stop_and_fail; } origcrc = ((unsigned)z.next_in[0] & 0xff) | ((unsigned)z.next_in[1] & 0xff) << 8 | ((unsigned)z.next_in[2] & 0xff) << 16 | ((unsigned)z.next_in[3] & 0xff) << 24; if (origcrc != crc) { maybe_warnx("invalid compressed" " data--crc error"); goto stop_and_fail; } } z.avail_in -= 4; z.next_in += 4; if (!z.avail_in && done_reading) { goto stop; } state++; break; case GZSTATE_LEN: { uLong origlen; if (z.avail_in < 4) { if (!done_reading) { needmore = 1; continue; } maybe_warnx("truncated input"); goto stop_and_fail; } origlen = ((unsigned)z.next_in[0] & 0xff) | ((unsigned)z.next_in[1] & 0xff) << 8 | ((unsigned)z.next_in[2] & 0xff) << 16 | ((unsigned)z.next_in[3] & 0xff) << 24; if (origlen != out_sub_tot) { maybe_warnx("invalid compressed" " data--length error"); goto stop_and_fail; } } z.avail_in -= 4; z.next_in += 4; if (error < 0) { maybe_warnx("decompression error"); goto stop_and_fail; } state = GZSTATE_MAGIC0; break; } continue; stop_and_fail: out_tot = -1; stop: break; } if (state > GZSTATE_INIT) inflateEnd(&z); free(inbufp); out1: free(outbufp); out2: if (gsizep) *gsizep = in_tot; return (out_tot); } #ifndef SMALL /* * set the owner, mode, flags & utimes using the given file descriptor. * file is only used in possible warning messages. */ static void copymodes(int fd, const struct stat *sbp, const char *file) { struct timespec times[2]; struct stat sb; /* * If we have no info on the input, give this file some * default values and return.. */ if (sbp == NULL) { mode_t mask = umask(022); (void)fchmod(fd, DEFFILEMODE & ~mask); (void)umask(mask); return; } sb = *sbp; /* if the chown fails, remove set-id bits as-per compress(1) */ if (fchown(fd, sb.st_uid, sb.st_gid) < 0) { if (errno != EPERM) maybe_warn("couldn't fchown: %s", file); sb.st_mode &= ~(S_ISUID|S_ISGID); } /* we only allow set-id and the 9 normal permission bits */ sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; if (fchmod(fd, sb.st_mode) < 0) maybe_warn("couldn't fchmod: %s", file); times[0] = sb.st_atim; times[1] = sb.st_mtim; if (futimens(fd, times) < 0) maybe_warn("couldn't futimens: %s", file); /* only try flags if they exist already */ if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0) maybe_warn("couldn't fchflags: %s", file); } #endif /* what sort of file is this? */ static enum filetype file_gettype(u_char *buf) { if (buf[0] == GZIP_MAGIC0 && (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1)) return FT_GZIP; else #ifndef NO_BZIP2_SUPPORT if (memcmp(buf, BZIP2_MAGIC, 3) == 0 && buf[3] >= '0' && buf[3] <= '9') return FT_BZIP2; else #endif #ifndef NO_COMPRESS_SUPPORT if (memcmp(buf, Z_MAGIC, 2) == 0) return FT_Z; else #endif #ifndef NO_PACK_SUPPORT if (memcmp(buf, PACK_MAGIC, 2) == 0) return FT_PACK; else #endif #ifndef NO_XZ_SUPPORT if (memcmp(buf, XZ_MAGIC, 4) == 0) /* XXX: We only have 4 bytes */ return FT_XZ; else #endif return FT_UNKNOWN; } #ifndef SMALL /* check the outfile is OK. */ static int check_outfile(const char *outfile) { struct stat sb; int ok = 1; if (lflag == 0 && stat(outfile, &sb) == 0) { if (fflag) unlink(outfile); else if (isatty(STDIN_FILENO)) { char ans[10] = { 'n', '\0' }; /* default */ fprintf(stderr, "%s already exists -- do you wish to " "overwrite (y or n)? " , outfile); (void)fgets(ans, sizeof(ans) - 1, stdin); if (ans[0] != 'y' && ans[0] != 'Y') { fprintf(stderr, "\tnot overwriting\n"); ok = 0; } else unlink(outfile); } else { maybe_warnx("%s already exists -- skipping", outfile); ok = 0; } } return ok; } static void unlink_input(const char *file, const struct stat *sb) { struct stat nsb; if (kflag) return; if (stat(file, &nsb) != 0) /* Must be gone already */ return; if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino) /* Definitely a different file */ return; unlink(file); } static void sigint_handler(int signo __unused) { if (remove_file != NULL) unlink(remove_file); _exit(2); } #endif static const suffixes_t * check_suffix(char *file, int xlate) { const suffixes_t *s; int len = strlen(file); char *sp; for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) { /* if it doesn't fit in "a.suf", don't bother */ if (s->ziplen >= len) continue; sp = file + len - s->ziplen; if (strcmp(s->zipped, sp) != 0) continue; if (xlate) strcpy(sp, s->normal); return s; } return NULL; } /* * compress the given file: create a corresponding .gz file and remove the * original. */ static off_t file_compress(char *file, char *outfile, size_t outsize) { int in; int out; off_t size, insize; #ifndef SMALL struct stat isb, osb; const suffixes_t *suff; #endif in = open(file, O_RDONLY); if (in == -1) { maybe_warn("can't open %s", file); return (-1); } #ifndef SMALL if (fstat(in, &isb) != 0) { maybe_warn("couldn't stat: %s", file); close(in); return (-1); } #endif if (cflag == 0) { #ifndef SMALL if (isb.st_nlink > 1 && fflag == 0) { maybe_warnx("%s has %d other link%s -- skipping", file, isb.st_nlink - 1, (isb.st_nlink - 1) == 1 ? "" : "s"); close(in); return (-1); } if (fflag == 0 && (suff = check_suffix(file, 0)) && suff->zipped[0] != 0) { maybe_warnx("%s already has %s suffix -- unchanged", file, suff->zipped); close(in); return (-1); } #endif /* Add (usually) .gz to filename */ if ((size_t)snprintf(outfile, outsize, "%s%s", file, suffixes[0].zipped) >= outsize) memcpy(outfile + outsize - suffixes[0].ziplen - 1, suffixes[0].zipped, suffixes[0].ziplen + 1); #ifndef SMALL if (check_outfile(outfile) == 0) { close(in); return (-1); } #endif } if (cflag == 0) { out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600); if (out == -1) { maybe_warn("could not create output: %s", outfile); fclose(stdin); return (-1); } #ifndef SMALL remove_file = outfile; #endif } else out = STDOUT_FILENO; insize = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime); (void)close(in); /* * If there was an error, insize will be -1. * If we compressed to stdout, just return the size. * Otherwise stat the file and check it is the correct size. * We only blow away the file if we can stat the output and it * has the expected size. */ if (cflag != 0) return (insize == -1 ? -1 : size); #ifndef SMALL if (fstat(out, &osb) != 0) { maybe_warn("couldn't stat: %s", outfile); goto bad_outfile; } if (osb.st_size != size) { maybe_warnx("output file: %s wrong size (%ju != %ju), deleting", outfile, (uintmax_t)osb.st_size, (uintmax_t)size); goto bad_outfile; } copymodes(out, &isb, outfile); remove_file = NULL; #endif if (close(out) == -1) maybe_warn("couldn't close output"); /* output is good, ok to delete input */ unlink_input(file, &isb); return (size); #ifndef SMALL bad_outfile: if (close(out) == -1) maybe_warn("couldn't close output"); maybe_warnx("leaving original %s", file); unlink(outfile); return (size); #endif } /* uncompress the given file and remove the original */ static off_t file_uncompress(char *file, char *outfile, size_t outsize) { struct stat isb, osb; off_t size; ssize_t rbytes; unsigned char header1[4]; enum filetype method; int fd, ofd, zfd = -1; #ifndef SMALL ssize_t rv; time_t timestamp = 0; char name[PATH_MAX + 1]; #endif /* gather the old name info */ fd = open(file, O_RDONLY); if (fd < 0) { maybe_warn("can't open %s", file); goto lose; } strlcpy(outfile, file, outsize); if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) { maybe_warnx("%s: unknown suffix -- ignored", file); goto lose; } rbytes = read(fd, header1, sizeof header1); if (rbytes != sizeof header1) { /* we don't want to fail here. */ #ifndef SMALL if (fflag) goto lose; #endif if (rbytes == -1) maybe_warn("can't read %s", file); else goto unexpected_EOF; goto lose; } method = file_gettype(header1); #ifndef SMALL if (fflag == 0 && method == FT_UNKNOWN) { maybe_warnx("%s: not in gzip format", file); goto lose; } #endif #ifndef SMALL if (method == FT_GZIP && Nflag) { unsigned char ts[4]; /* timestamp */ rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP); if (rv >= 0 && rv < (ssize_t)(sizeof ts)) goto unexpected_EOF; if (rv == -1) { if (!fflag) maybe_warn("can't read %s", file); goto lose; } timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0]; if (header1[3] & ORIG_NAME) { rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME); if (rbytes < 0) { maybe_warn("can't read %s", file); goto lose; } if (name[0] != '\0') { char *dp, *nf; /* Make sure that name is NUL-terminated */ name[rbytes] = '\0'; /* strip saved directory name */ nf = strrchr(name, '/'); if (nf == NULL) nf = name; else nf++; /* preserve original directory name */ dp = strrchr(file, '/'); if (dp == NULL) dp = file; else dp++; snprintf(outfile, outsize, "%.*s%.*s", (int) (dp - file), file, (int) rbytes, nf); } } } #endif lseek(fd, 0, SEEK_SET); if (cflag == 0 || lflag) { if (fstat(fd, &isb) != 0) goto lose; #ifndef SMALL if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) { maybe_warnx("%s has %d other links -- skipping", file, isb.st_nlink - 1); goto lose; } if (nflag == 0 && timestamp) isb.st_mtime = timestamp; if (check_outfile(outfile) == 0) goto lose; #endif } if (cflag == 0 && lflag == 0) { zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); if (zfd == STDOUT_FILENO) { /* We won't close STDOUT_FILENO later... */ zfd = dup(zfd); close(STDOUT_FILENO); } if (zfd == -1) { maybe_warn("can't open %s", outfile); goto lose; } #ifndef SMALL remove_file = outfile; #endif } else zfd = STDOUT_FILENO; switch (method) { #ifndef NO_BZIP2_SUPPORT case FT_BZIP2: /* XXX */ if (lflag) { maybe_warnx("no -l with bzip2 files"); goto lose; } size = unbzip2(fd, zfd, NULL, 0, NULL); break; #endif #ifndef NO_COMPRESS_SUPPORT case FT_Z: { FILE *in, *out; /* XXX */ if (lflag) { maybe_warnx("no -l with Lempel-Ziv files"); goto lose; } if ((in = zdopen(fd)) == NULL) { maybe_warn("zdopen for read: %s", file); goto lose; } out = fdopen(dup(zfd), "w"); if (out == NULL) { maybe_warn("fdopen for write: %s", outfile); fclose(in); goto lose; } size = zuncompress(in, out, NULL, 0, NULL); /* need to fclose() if ferror() is true... */ if (ferror(in) | fclose(in)) { maybe_warn("failed infile fclose"); unlink(outfile); (void)fclose(out); } if (fclose(out) != 0) { maybe_warn("failed outfile fclose"); unlink(outfile); goto lose; } break; } #endif #ifndef NO_PACK_SUPPORT case FT_PACK: if (lflag) { maybe_warnx("no -l with packed files"); goto lose; } size = unpack(fd, zfd, NULL, 0, NULL); break; #endif #ifndef NO_XZ_SUPPORT case FT_XZ: if (lflag) { maybe_warnx("no -l with xz files"); goto lose; } size = unxz(fd, zfd, NULL, 0, NULL); break; #endif #ifndef SMALL case FT_UNKNOWN: if (lflag) { maybe_warnx("no -l for unknown filetypes"); goto lose; } size = cat_fd(NULL, 0, NULL, fd); break; #endif default: if (lflag) { print_list(fd, isb.st_size, outfile, isb.st_mtime); close(fd); return -1; /* XXX */ } size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); break; } if (close(fd) != 0) maybe_warn("couldn't close input"); if (zfd != STDOUT_FILENO && close(zfd) != 0) maybe_warn("couldn't close output"); if (size == -1) { if (cflag == 0) unlink(outfile); maybe_warnx("%s: uncompress failed", file); return -1; } /* if testing, or we uncompressed to stdout, this is all we need */ #ifndef SMALL if (tflag) return size; #endif /* if we are uncompressing to stdin, don't remove the file. */ if (cflag) return size; /* * if we create a file... */ /* * if we can't stat the file don't remove the file. */ ofd = open(outfile, O_RDWR, 0); if (ofd == -1) { maybe_warn("couldn't open (leaving original): %s", outfile); return -1; } if (fstat(ofd, &osb) != 0) { maybe_warn("couldn't stat (leaving original): %s", outfile); close(ofd); return -1; } if (osb.st_size != size) { maybe_warnx("stat gave different size: %ju != %ju (leaving original)", (uintmax_t)size, (uintmax_t)osb.st_size); close(ofd); unlink(outfile); return -1; } #ifndef SMALL copymodes(ofd, &isb, outfile); remove_file = NULL; #endif close(ofd); unlink_input(file, &isb); return size; unexpected_EOF: maybe_warnx("%s: unexpected end of file", file); lose: if (fd != -1) close(fd); if (zfd != -1 && zfd != STDOUT_FILENO) close(fd); return -1; } #ifndef SMALL static off_t cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd) { char buf[BUFLEN]; off_t in_tot; ssize_t w; in_tot = count; w = write(STDOUT_FILENO, prepend, count); if (w == -1 || (size_t)w != count) { maybe_warn("write to stdout"); return -1; } for (;;) { ssize_t rv; rv = read(fd, buf, sizeof buf); if (rv == 0) break; if (rv < 0) { maybe_warn("read from fd %d", fd); break; } if (write(STDOUT_FILENO, buf, rv) != rv) { maybe_warn("write to stdout"); break; } in_tot += rv; } if (gsizep) *gsizep = in_tot; return (in_tot); } #endif static void handle_stdin(void) { unsigned char header1[4]; off_t usize, gsize; enum filetype method; ssize_t bytes_read; #ifndef NO_COMPRESS_SUPPORT FILE *in; #endif #ifndef SMALL if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) { maybe_warnx("standard input is a terminal -- ignoring"); return; } #endif if (lflag) { struct stat isb; /* XXX could read the whole file, etc. */ if (fstat(STDIN_FILENO, &isb) < 0) { maybe_warn("fstat"); return; } print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime); return; } bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1); if (bytes_read == -1) { maybe_warn("can't read stdin"); return; } else if (bytes_read != sizeof(header1)) { maybe_warnx("(stdin): unexpected end of file"); return; } method = file_gettype(header1); switch (method) { default: #ifndef SMALL if (fflag == 0) { maybe_warnx("unknown compression format"); return; } usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO); break; #endif case FT_GZIP: usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO, (char *)header1, sizeof header1, &gsize, "(stdin)"); break; #ifndef NO_BZIP2_SUPPORT case FT_BZIP2: usize = unbzip2(STDIN_FILENO, STDOUT_FILENO, (char *)header1, sizeof header1, &gsize); break; #endif #ifndef NO_COMPRESS_SUPPORT case FT_Z: if ((in = zdopen(STDIN_FILENO)) == NULL) { maybe_warnx("zopen of stdin"); return; } usize = zuncompress(in, stdout, (char *)header1, sizeof header1, &gsize); fclose(in); break; #endif #ifndef NO_PACK_SUPPORT case FT_PACK: usize = unpack(STDIN_FILENO, STDOUT_FILENO, (char *)header1, sizeof header1, &gsize); break; #endif #ifndef NO_XZ_SUPPORT case FT_XZ: usize = unxz(STDIN_FILENO, STDOUT_FILENO, (char *)header1, sizeof header1, &gsize); break; #endif } #ifndef SMALL if (vflag && !tflag && usize != -1 && gsize != -1) print_verbage(NULL, NULL, usize, gsize); if (vflag && tflag) print_test("(stdin)", usize != -1); #endif } static void handle_stdout(void) { off_t gsize, usize; struct stat sb; time_t systime; uint32_t mtime; int ret; #ifndef SMALL if (fflag == 0 && isatty(STDOUT_FILENO)) { maybe_warnx("standard output is a terminal -- ignoring"); return; } #endif /* If stdin is a file use its mtime, otherwise use current time */ ret = fstat(STDIN_FILENO, &sb); #ifndef SMALL if (ret < 0) { maybe_warn("Can't stat stdin"); return; } #endif if (S_ISREG(sb.st_mode)) mtime = (uint32_t)sb.st_mtime; else { systime = time(NULL); #ifndef SMALL if (systime == -1) { maybe_warn("time"); return; } #endif mtime = (uint32_t)systime; } usize = gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime); #ifndef SMALL if (vflag && !tflag && usize != -1 && gsize != -1) print_verbage(NULL, NULL, usize, gsize); #endif } /* do what is asked for, for the path name */ static void handle_pathname(char *path) { char *opath = path, *s = NULL; ssize_t len; int slen; struct stat sb; /* check for stdout/stdin */ if (path[0] == '-' && path[1] == '\0') { if (dflag) handle_stdin(); else handle_stdout(); return; } retry: if (stat(path, &sb) != 0 || (fflag == 0 && cflag == 0 && lstat(path, &sb) != 0)) { /* lets try .gz if we're decompressing */ if (dflag && s == NULL && errno == ENOENT) { len = strlen(path); slen = suffixes[0].ziplen; s = malloc(len + slen + 1); if (s == NULL) maybe_err("malloc"); memcpy(s, path, len); memcpy(s + len, suffixes[0].zipped, slen + 1); path = s; goto retry; } maybe_warn("can't stat: %s", opath); goto out; } if (S_ISDIR(sb.st_mode)) { #ifndef SMALL if (rflag) handle_dir(path); else #endif maybe_warnx("%s is a directory", path); goto out; } if (S_ISREG(sb.st_mode)) handle_file(path, &sb); else maybe_warnx("%s is not a regular file", path); out: if (s) free(s); } /* compress/decompress a file */ static void handle_file(char *file, struct stat *sbp) { off_t usize, gsize; char outfile[PATH_MAX]; infile = file; if (dflag) { usize = file_uncompress(file, outfile, sizeof(outfile)); #ifndef SMALL if (vflag && tflag) print_test(file, usize != -1); #endif if (usize == -1) return; gsize = sbp->st_size; } else { gsize = file_compress(file, outfile, sizeof(outfile)); if (gsize == -1) return; usize = sbp->st_size; } #ifndef SMALL if (vflag && !tflag) print_verbage(file, (cflag) ? NULL : outfile, usize, gsize); #endif } #ifndef SMALL /* this is used with -r to recursively descend directories */ static void handle_dir(char *dir) { char *path_argv[2]; FTS *fts; FTSENT *entry; path_argv[0] = dir; path_argv[1] = 0; fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL); if (fts == NULL) { warn("couldn't fts_open %s", dir); return; } while ((entry = fts_read(fts))) { switch(entry->fts_info) { case FTS_D: case FTS_DP: continue; case FTS_DNR: case FTS_ERR: case FTS_NS: maybe_warn("%s", entry->fts_path); continue; case FTS_F: handle_file(entry->fts_path, entry->fts_statp); } } (void)fts_close(fts); } #endif /* print a ratio - size reduction as a fraction of uncompressed size */ static void print_ratio(off_t in, off_t out, FILE *where) { int percent10; /* 10 * percent */ off_t diff; char buff[8]; int len; diff = in - out/2; if (diff <= 0) /* * Output is more than double size of input! print -99.9% * Quite possibly we've failed to get the original size. */ percent10 = -999; else { /* * We only need 12 bits of result from the final division, * so reduce the values until a 32bit division will suffice. */ while (in > 0x100000) { diff >>= 1; in >>= 1; } if (in != 0) percent10 = ((u_int)diff * 2000) / (u_int)in - 1000; else percent10 = 0; } len = snprintf(buff, sizeof buff, "%2.2d.", percent10); /* Move the '.' to before the last digit */ buff[len - 1] = buff[len - 2]; buff[len - 2] = '.'; fprintf(where, "%5s%%", buff); } #ifndef SMALL /* print compression statistics, and the new name (if there is one!) */ static void print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize) { if (file) fprintf(stderr, "%s:%s ", file, strlen(file) < 7 ? "\t\t" : "\t"); print_ratio(usize, gsize, stderr); if (nfile) fprintf(stderr, " -- replaced with %s", nfile); fprintf(stderr, "\n"); fflush(stderr); } /* print test results */ static void print_test(const char *file, int ok) { if (exit_value == 0 && ok == 0) exit_value = 1; fprintf(stderr, "%s:%s %s\n", file, strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK"); fflush(stderr); } #endif /* print a file's info ala --list */ /* eg: compressed uncompressed ratio uncompressed_name 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar */ static void print_list(int fd, off_t out, const char *outfile, time_t ts) { static int first = 1; #ifndef SMALL static off_t in_tot, out_tot; uint32_t crc = 0; #endif off_t in = 0, rv; if (first) { #ifndef SMALL if (vflag) printf("method crc date time "); #endif if (qflag == 0) printf(" compressed uncompressed " "ratio uncompressed_name\n"); } first = 0; /* print totals? */ #ifndef SMALL if (fd == -1) { in = in_tot; out = out_tot; } else #endif { /* read the last 4 bytes - this is the uncompressed size */ rv = lseek(fd, (off_t)(-8), SEEK_END); if (rv != -1) { unsigned char buf[8]; uint32_t usize; rv = read(fd, (char *)buf, sizeof(buf)); if (rv == -1) maybe_warn("read of uncompressed size"); else if (rv != sizeof(buf)) maybe_warnx("read of uncompressed size"); else { usize = buf[4] | buf[5] << 8 | buf[6] << 16 | buf[7] << 24; in = (off_t)usize; #ifndef SMALL crc = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24; #endif } } } #ifndef SMALL if (vflag && fd == -1) printf(" "); else if (vflag) { char *date = ctime(&ts); /* skip the day, 1/100th second, and year */ date += 4; date[12] = 0; printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date); } in_tot += in; out_tot += out; #else (void)&ts; /* XXX */ #endif printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in); print_ratio(in, out, stdout); printf(" %s\n", outfile); } /* display the usage of NetBSD gzip */ static void usage(void) { fprintf(stderr, "%s\n", gzip_version); fprintf(stderr, #ifdef SMALL "usage: %s [-" OPT_LIST "] [ [ ...]]\n", #else "usage: %s [-123456789acdfhklLNnqrtVv] [-S .suffix] [ [ ...]]\n" " -1 --fast fastest (worst) compression\n" " -2 .. -8 set compression level\n" " -9 --best best (slowest) compression\n" " -c --stdout write to stdout, keep original files\n" " --to-stdout\n" " -d --decompress uncompress files\n" " --uncompress\n" " -f --force force overwriting & compress links\n" " -h --help display this help\n" " -k --keep don't delete input files during operation\n" " -l --list list compressed file contents\n" " -N --name save or restore original file name and time stamp\n" " -n --no-name don't save original file name or time stamp\n" " -q --quiet output no warnings\n" " -r --recursive recursively compress files in directories\n" " -S .suf use suffix .suf instead of .gz\n" " --suffix .suf\n" " -t --test test compressed file\n" " -V --version display program version\n" " -v --verbose print extra statistics\n", #endif getprogname()); exit(0); } #ifndef SMALL /* display the license information of FreeBSD gzip */ static void display_license(void) { fprintf(stderr, "%s (based on NetBSD gzip 20150113)\n", gzip_version); fprintf(stderr, "%s\n", gzip_copyright); exit(0); } #endif /* display the version of NetBSD gzip */ static void display_version(void) { fprintf(stderr, "%s\n", gzip_version); exit(0); } #ifndef NO_BZIP2_SUPPORT #include "unbzip2.c" #endif #ifndef NO_COMPRESS_SUPPORT #include "zuncompress.c" #endif #ifndef NO_PACK_SUPPORT #include "unpack.c" #endif #ifndef NO_XZ_SUPPORT #include "unxz.c" #endif static ssize_t read_retry(int fd, void *buf, size_t sz) { char *cp = buf; size_t left = MIN(sz, (size_t) SSIZE_MAX); while (left > 0) { ssize_t ret; ret = read(fd, cp, left); if (ret == -1) { return ret; } else if (ret == 0) { break; /* EOF */ } cp += ret; left -= ret; } return sz - left; } Index: stable/11/usr.bin/indent/indent.c =================================================================== --- stable/11/usr.bin/indent/indent.c (revision 307696) +++ stable/11/usr.bin/indent/indent.c (revision 307697) @@ -1,1234 +1,1234 @@ /* * Copyright (c) 1985 Sun Microsystems, Inc. * Copyright (c) 1976 Board of Trustees of the University of Illinois. * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\ @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\ @(#) Copyright (c) 1980, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)indent.c 5.17 (Berkeley) 6/7/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "indent_globs.h" #include "indent_codes.h" #include "indent.h" static void bakcopy(void); const char *in_name = "Standard Input"; /* will always point to name of input * file */ const char *out_name = "Standard Output"; /* will always point to name * of output file */ char bakfile[MAXPATHLEN] = ""; int main(int argc, char **argv) { int dec_ind; /* current indentation for declarations */ int di_stack[20]; /* a stack of structure indentation levels */ int flushed_nl; /* used when buffering up comments to remember * that a newline was passed over */ int force_nl; /* when true, code must be broken */ int hd_type = 0; /* used to store type of stmt for if (...), * for (...), etc */ int i; /* local loop counter */ int scase; /* set to true when we see a case, so we will * know what to do with the following colon */ int sp_sw; /* when true, we are in the expression of * if(...), while(...), etc. */ int squest; /* when this is positive, we have seen a ? * without the matching : in a ?: * construct */ const char *t_ptr; /* used for copying tokens */ int tabs_to_var; /* true if using tabs to indent to var name */ int type_code; /* the type of token, returned by lexi */ int last_else = 0; /* true iff last keyword was an else */ /*-----------------------------------------------*\ | INITIALIZATION | \*-----------------------------------------------*/ found_err = 0; ps.p_stack[0] = stmt; /* this is the parser's stack */ ps.last_nl = true; /* this is true if the last thing scanned was * a newline */ ps.last_token = semicolon; combuf = (char *) malloc(bufsize); if (combuf == NULL) err(1, NULL); labbuf = (char *) malloc(bufsize); if (labbuf == NULL) err(1, NULL); codebuf = (char *) malloc(bufsize); if (codebuf == NULL) err(1, NULL); tokenbuf = (char *) malloc(bufsize); if (tokenbuf == NULL) err(1, NULL); l_com = combuf + bufsize - 5; l_lab = labbuf + bufsize - 5; l_code = codebuf + bufsize - 5; l_token = tokenbuf + bufsize - 5; combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and * comment buffers */ combuf[1] = codebuf[1] = labbuf[1] = '\0'; ps.else_if = 1; /* Default else-if special processing to on */ s_lab = e_lab = labbuf + 1; s_code = e_code = codebuf + 1; s_com = e_com = combuf + 1; s_token = e_token = tokenbuf + 1; in_buffer = (char *) malloc(10); if (in_buffer == NULL) err(1, NULL); in_buffer_limit = in_buffer + 8; buf_ptr = buf_end = in_buffer; line_no = 1; had_eof = ps.in_decl = ps.decl_on_line = break_comma = false; sp_sw = force_nl = false; ps.in_or_st = false; ps.bl_line = true; dec_ind = 0; di_stack[ps.dec_nest = 0] = 0; ps.want_blank = ps.in_stmt = ps.ind_stmt = false; scase = ps.pcase = false; squest = 0; sc_end = 0; bp_save = 0; be_save = 0; output = 0; tabs_to_var = 0; /*--------------------------------------------------*\ | COMMAND LINE SCAN | \*--------------------------------------------------*/ #ifdef undef max_col = 78; /* -l78 */ lineup_to_parens = 1; /* -lp */ ps.ljust_decl = 0; /* -ndj */ ps.com_ind = 33; /* -c33 */ star_comment_cont = 1; /* -sc */ ps.ind_size = 8; /* -i8 */ verbose = 0; ps.decl_indent = 16; /* -di16 */ ps.local_decl_indent = -1; /* if this is not set to some nonnegative value * by an arg, we will set this equal to * ps.decl_ind */ ps.indent_parameters = 1; /* -ip */ ps.decl_com_ind = 0; /* if this is not set to some positive value * by an arg, we will set this equal to * ps.com_ind */ btype_2 = 1; /* -br */ cuddle_else = 1; /* -ce */ ps.unindent_displace = 0; /* -d0 */ ps.case_indent = 0; /* -cli0 */ format_block_comments = 1; /* -fcb */ format_col1_comments = 1; /* -fc1 */ procnames_start_line = 1; /* -psl */ proc_calls_space = 0; /* -npcs */ comment_delimiter_on_blankline = 1; /* -cdb */ ps.leave_comma = 1; /* -nbc */ #endif for (i = 1; i < argc; ++i) if (strcmp(argv[i], "-npro") == 0) break; set_defaults(); if (i >= argc) set_profile(); for (i = 1; i < argc; ++i) { /* * look thru args (if any) for changes to defaults */ if (argv[i][0] != '-') {/* no flag on parameter */ if (input == NULL) { /* we must have the input file */ in_name = argv[i]; /* remember name of input file */ input = fopen(in_name, "r"); if (input == NULL) /* check for open error */ err(1, "%s", in_name); continue; } else if (output == NULL) { /* we have the output file */ out_name = argv[i]; /* remember name of output file */ if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite * the file */ errx(1, "input and output files must be different"); } output = fopen(out_name, "w"); if (output == NULL) /* check for create error */ err(1, "%s", out_name); continue; } errx(1, "unknown parameter: %s", argv[i]); } else set_option(argv[i]); } /* end of for */ if (input == NULL) input = stdin; if (output == NULL) { if (troff || input == stdin) output = stdout; else { out_name = in_name; bakcopy(); } } if (ps.com_ind <= 1) ps.com_ind = 2; /* dont put normal comments before column 2 */ if (troff) { if (bodyf.font[0] == 0) parsefont(&bodyf, "R"); if (scomf.font[0] == 0) parsefont(&scomf, "I"); if (blkcomf.font[0] == 0) blkcomf = scomf, blkcomf.size += 2; if (boxcomf.font[0] == 0) boxcomf = blkcomf; if (stringf.font[0] == 0) parsefont(&stringf, "L"); if (keywordf.font[0] == 0) parsefont(&keywordf, "B"); writefdef(&bodyf, 'B'); writefdef(&scomf, 'C'); writefdef(&blkcomf, 'L'); writefdef(&boxcomf, 'X'); writefdef(&stringf, 'S'); writefdef(&keywordf, 'K'); } if (block_comment_max_col <= 0) block_comment_max_col = max_col; if (ps.local_decl_indent < 0) /* if not specified by user, set this */ ps.local_decl_indent = ps.decl_indent; if (ps.decl_com_ind <= 0) /* if not specified by user, set this */ ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind; if (continuation_indent == 0) continuation_indent = ps.ind_size; fill_buffer(); /* get first batch of stuff into input buffer */ parse(semicolon); { char *p = buf_ptr; int col = 1; while (1) { if (*p == ' ') col++; else if (*p == '\t') col = ((col - 1) & ~7) + 9; else break; p++; } if (col > ps.ind_size) ps.ind_level = ps.i_l_follow = col / ps.ind_size; } if (troff) { const char *p = in_name, *beg = in_name; while (*p) if (*p++ == '/') beg = p; fprintf(output, ".Fn \"%s\"\n", beg); } /* * START OF MAIN LOOP */ while (1) { /* this is the main loop. it will go until we * reach eof */ int is_procname; type_code = lexi(); /* lexi reads one token. The actual * characters read are stored in "token". lexi * returns a code indicating the type of token */ is_procname = ps.procname[0]; /* * The following code moves everything following an if (), while (), * else, etc. up to the start of the following stmt to a buffer. This * allows proper handling of both kinds of brace placement. */ flushed_nl = false; while (ps.search_brace) { /* if we scanned an if(), while(), * etc., we might need to copy stuff * into a buffer we must loop, copying * stuff into save_com, until we find * the start of the stmt which follows * the if, or whatever */ switch (type_code) { case newline: ++line_no; flushed_nl = true; case form_feed: break; /* form feeds and newlines found here will be * ignored */ case lbrace: /* this is a brace that starts the compound * stmt */ if (sc_end == 0) { /* ignore buffering if a comment wasn't * stored up */ ps.search_brace = false; goto check_type; } if (btype_2) { save_com[0] = '{'; /* we either want to put the brace * right after the if */ goto sw_buffer; /* go to common code to get out of * this loop */ } case comment: /* we have a comment, so we must copy it into * the buffer */ if (!flushed_nl || sc_end != 0) { if (sc_end == 0) { /* if this is the first comment, we * must set up the buffer */ save_com[0] = save_com[1] = ' '; sc_end = &(save_com[2]); } else { *sc_end++ = '\n'; /* add newline between * comments */ *sc_end++ = ' '; --line_no; } *sc_end++ = '/'; /* copy in start of comment */ *sc_end++ = '*'; for (;;) { /* loop until we get to the end of the comment */ *sc_end = *buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); if (*sc_end++ == '*' && *buf_ptr == '/') break; /* we are at end of comment */ if (sc_end >= &(save_com[sc_size])) { /* check for temp buffer * overflow */ diag2(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever"); fflush(output); exit(1); } } *sc_end++ = '/'; /* add ending slash */ if (++buf_ptr >= buf_end) /* get past / in buffer */ fill_buffer(); break; } default: /* it is the start of a normal statement */ if (flushed_nl) /* if we flushed a newline, make sure it is * put back */ force_nl = true; if ((type_code == sp_paren && *token == 'i' && last_else && ps.else_if) || (type_code == sp_nparen && *token == 'e' && e_code != s_code && e_code[-1] == '}')) force_nl = false; if (sc_end == 0) { /* ignore buffering if comment wasn't * saved up */ ps.search_brace = false; goto check_type; } if (force_nl) { /* if we should insert a nl here, put it into * the buffer */ force_nl = false; --line_no; /* this will be re-increased when the nl is * read from the buffer */ *sc_end++ = '\n'; *sc_end++ = ' '; if (verbose && !flushed_nl) /* print error msg if the line * was not already broken */ diag2(0, "Line broken"); flushed_nl = false; } for (t_ptr = token; *t_ptr; ++t_ptr) *sc_end++ = *t_ptr; /* copy token into temp buffer */ ps.procname[0] = 0; sw_buffer: ps.search_brace = false; /* stop looking for start of * stmt */ bp_save = buf_ptr; /* save current input buffer */ be_save = buf_end; buf_ptr = save_com; /* fix so that subsequent calls to * lexi will take tokens out of * save_com */ *sc_end++ = ' ';/* add trailing blank, just in case */ buf_end = sc_end; sc_end = 0; break; } /* end of switch */ if (type_code != 0) /* we must make this check, just in case there * was an unexpected EOF */ type_code = lexi(); /* read another token */ /* if (ps.search_brace) ps.procname[0] = 0; */ if ((is_procname = ps.procname[0]) && flushed_nl && !procnames_start_line && ps.in_decl && type_code == ident) flushed_nl = 0; } /* end of while (search_brace) */ last_else = 0; check_type: if (type_code == 0) { /* we got eof */ if (s_lab != e_lab || s_code != e_code || s_com != e_com) /* must dump end of line */ dump_line(); if (ps.tos > 1) /* check for balanced braces */ diag2(1, "Stuff missing from end of file"); if (verbose) { printf("There were %d output lines and %d comments\n", ps.out_lines, ps.out_coms); printf("(Lines with comments)/(Lines with code): %6.3f\n", (1.0 * ps.com_lines) / code_lines); } fflush(output); exit(found_err); } if ( (type_code != comment) && (type_code != newline) && (type_code != preesc) && (type_code != form_feed)) { if (force_nl && (type_code != semicolon) && (type_code != lbrace || !btype_2)) { /* we should force a broken line here */ if (verbose && !flushed_nl) diag2(0, "Line broken"); flushed_nl = false; dump_line(); ps.want_blank = false; /* dont insert blank at line start */ force_nl = false; } ps.in_stmt = true; /* turn on flag which causes an extra level of * indentation. this is turned off by a ; or * '}' */ if (s_com != e_com) { /* the turkey has embedded a comment * in a line. fix it */ *e_code++ = ' '; for (t_ptr = s_com; *t_ptr; ++t_ptr) { CHECK_SIZE_CODE; *e_code++ = *t_ptr; } *e_code++ = ' '; *e_code = '\0'; /* null terminate code sect */ ps.want_blank = false; e_com = s_com; } } else if (type_code != comment) /* preserve force_nl thru a comment */ force_nl = false; /* cancel forced newline after newline, form * feed, etc */ /*-----------------------------------------------------*\ | do switch on type of token scanned | \*-----------------------------------------------------*/ CHECK_SIZE_CODE; switch (type_code) { /* now, decide what to do with the token */ case form_feed: /* found a form feed in line */ ps.use_ff = true; /* a form feed is treated much like a newline */ dump_line(); ps.want_blank = false; break; case newline: if (ps.last_token != comma || ps.p_l_follow > 0 || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) { dump_line(); ps.want_blank = false; } ++line_no; /* keep track of input line number */ break; case lparen: /* got a '(' or '[' */ ++ps.p_l_follow; /* count parens to make Healy happy */ if (ps.want_blank && *token != '[' && (ps.last_token != ident || proc_calls_space || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon)))) *e_code++ = ' '; if (ps.in_decl && !ps.block_init) if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl) { ps.dumped_decl_indent = 1; sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token); e_code += strlen(e_code); } else { while ((e_code - s_code) < dec_ind) { CHECK_SIZE_CODE; *e_code++ = ' '; } *e_code++ = token[0]; } else *e_code++ = token[0]; ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code; if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent && ps.paren_indents[0] < 2 * ps.ind_size) ps.paren_indents[0] = 2 * ps.ind_size; ps.want_blank = false; if (ps.in_or_st && *token == '(' && ps.tos <= 2) { /* * this is a kluge to make sure that declarations will be * aligned right if proc decl has an explicit type on it, i.e. * "int a(x) {..." */ parse(semicolon); /* I said this was a kluge... */ ps.in_or_st = false; /* turn off flag for structure decl or * initialization */ } if (ps.sizeof_keyword) ps.sizeof_mask |= 1 << ps.p_l_follow; break; case rparen: /* got a ')' or ']' */ rparen_count--; if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) { ps.last_u_d = true; ps.cast_mask &= (1 << ps.p_l_follow) - 1; ps.want_blank = false; } else ps.want_blank = true; ps.sizeof_mask &= (1 << ps.p_l_follow) - 1; if (--ps.p_l_follow < 0) { ps.p_l_follow = 0; diag3(0, "Extra %c", *token); } if (e_code == s_code) /* if the paren starts the line */ ps.paren_level = ps.p_l_follow; /* then indent it */ *e_code++ = token[0]; if (sp_sw && (ps.p_l_follow == 0)) { /* check for end of if * (...), or some such */ sp_sw = false; force_nl = true;/* must force newline after if */ ps.last_u_d = true; /* inform lexi that a following * operator is unary */ ps.in_stmt = false; /* dont use stmt continuation * indentation */ parse(hd_type); /* let parser worry about if, or whatever */ } ps.search_brace = btype_2; /* this should insure that constructs * such as main(){...} and int[]{...} * have their braces put in the right * place */ break; case unary_op: /* this could be any unary operation */ if (ps.want_blank) *e_code++ = ' '; if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname) { sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token); ps.dumped_decl_indent = 1; e_code += strlen(e_code); } else { const char *res = token; if (ps.in_decl && !ps.block_init) { /* if this is a unary op * in a declaration, we * should indent this * token */ for (i = 0; token[i]; ++i); /* find length of token */ while ((e_code - s_code) < (dec_ind - i)) { CHECK_SIZE_CODE; *e_code++ = ' '; /* pad it */ } } if (troff && token[0] == '-' && token[1] == '>') res = "\\(->"; for (t_ptr = res; *t_ptr; ++t_ptr) { CHECK_SIZE_CODE; *e_code++ = *t_ptr; } } ps.want_blank = false; break; case binary_op: /* any binary operation */ if (ps.want_blank) *e_code++ = ' '; { const char *res = token; if (troff) switch (token[0]) { case '<': if (token[1] == '=') res = "\\(<="; break; case '>': if (token[1] == '=') res = "\\(>="; break; case '!': if (token[1] == '=') res = "\\(!="; break; case '|': if (token[1] == '|') res = "\\(br\\(br"; else if (token[1] == 0) res = "\\(br"; break; } for (t_ptr = res; *t_ptr; ++t_ptr) { CHECK_SIZE_CODE; *e_code++ = *t_ptr; /* move the operator */ } } ps.want_blank = true; break; case postop: /* got a trailing ++ or -- */ *e_code++ = token[0]; *e_code++ = token[1]; ps.want_blank = true; break; case question: /* got a ? */ squest++; /* this will be used when a later colon * appears so we can distinguish the * ?: construct */ if (ps.want_blank) *e_code++ = ' '; *e_code++ = '?'; ps.want_blank = true; break; case casestmt: /* got word 'case' or 'default' */ scase = true; /* so we can process the later colon properly */ goto copy_id; case colon: /* got a ':' */ if (squest > 0) { /* it is part of the ?: construct */ --squest; if (ps.want_blank) *e_code++ = ' '; *e_code++ = ':'; ps.want_blank = true; break; } if (ps.in_or_st) { *e_code++ = ':'; ps.want_blank = false; break; } ps.in_stmt = false; /* seeing a label does not imply we are in a * stmt */ for (t_ptr = s_code; *t_ptr; ++t_ptr) *e_lab++ = *t_ptr; /* turn everything so far into a label */ e_code = s_code; *e_lab++ = ':'; *e_lab++ = ' '; *e_lab = '\0'; force_nl = ps.pcase = scase; /* ps.pcase will be used by * dump_line to decide how to * indent the label. force_nl * will force a case n: to be * on a line by itself */ scase = false; ps.want_blank = false; break; case semicolon: /* got a ';' */ ps.in_or_st = false;/* we are not in an initialization or * structure declaration */ scase = false; /* these will only need resetting in an error */ squest = 0; if (ps.last_token == rparen && rparen_count == 0) ps.in_parameter_declaration = 0; ps.cast_mask = 0; ps.sizeof_mask = 0; ps.block_init = 0; ps.block_init_level = 0; ps.just_saw_decl--; if (ps.in_decl && s_code == e_code && !ps.block_init) while ((e_code - s_code) < (dec_ind - 1)) { CHECK_SIZE_CODE; *e_code++ = ' '; } ps.in_decl = (ps.dec_nest > 0); /* if we were in a first level * structure declaration, we * arent any more */ if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) { /* * This should be true iff there were unbalanced parens in the * stmt. It is a bit complicated, because the semicolon might * be in a for stmt */ diag2(1, "Unbalanced parens"); ps.p_l_follow = 0; if (sp_sw) { /* this is a check for an if, while, etc. with * unbalanced parens */ sp_sw = false; parse(hd_type); /* dont lose the if, or whatever */ } } *e_code++ = ';'; ps.want_blank = true; ps.in_stmt = (ps.p_l_follow > 0); /* we are no longer in the * middle of a stmt */ if (!sp_sw) { /* if not if for (;;) */ parse(semicolon); /* let parser know about end of stmt */ force_nl = true;/* force newline after an end of stmt */ } break; case lbrace: /* got a '{' */ ps.in_stmt = false; /* dont indent the {} */ if (!ps.block_init) force_nl = true;/* force other stuff on same line as '{' onto * new line */ else if (ps.block_init_level <= 0) ps.block_init_level = 1; else ps.block_init_level++; if (s_code != e_code && !ps.block_init) { if (!btype_2) { dump_line(); ps.want_blank = false; } else if (ps.in_parameter_declaration && !ps.in_or_st) { ps.i_l_follow = 0; if (function_brace_split) { /* dump the line prior to the * brace ... */ dump_line(); ps.want_blank = false; } else /* add a space between the decl and brace */ ps.want_blank = true; } } if (ps.in_parameter_declaration) prefix_blankline_requested = 0; if (ps.p_l_follow > 0) { /* check for preceding unbalanced * parens */ diag2(1, "Unbalanced parens"); ps.p_l_follow = 0; if (sp_sw) { /* check for unclosed if, for, etc. */ sp_sw = false; parse(hd_type); ps.ind_level = ps.i_l_follow; } } if (s_code == e_code) ps.ind_stmt = false; /* dont put extra indentation on line * with '{' */ if (ps.in_decl && ps.in_or_st) { /* this is either a structure * declaration or an init */ di_stack[ps.dec_nest++] = dec_ind; /* ? dec_ind = 0; */ } else { ps.decl_on_line = false; /* we can't be in the middle of * a declaration, so don't do * special indentation of * comments */ if (blanklines_after_declarations_at_proctop && ps.in_parameter_declaration) postfix_blankline_requested = 1; ps.in_parameter_declaration = 0; } dec_ind = 0; parse(lbrace); /* let parser know about this */ if (ps.want_blank) /* put a blank before '{' if '{' is not at * start of line */ *e_code++ = ' '; ps.want_blank = false; *e_code++ = '{'; ps.just_saw_decl = 0; break; case rbrace: /* got a '}' */ if (ps.p_stack[ps.tos] == decl && !ps.block_init) /* semicolons can be * omitted in * declarations */ parse(semicolon); if (ps.p_l_follow) {/* check for unclosed if, for, else. */ diag2(1, "Unbalanced parens"); ps.p_l_follow = 0; sp_sw = false; } ps.just_saw_decl = 0; ps.block_init_level--; if (s_code != e_code && !ps.block_init) { /* '}' must be first on * line */ if (verbose) diag2(0, "Line broken"); dump_line(); } *e_code++ = '}'; ps.want_blank = true; ps.in_stmt = ps.ind_stmt = false; if (ps.dec_nest > 0) { /* we are in multi-level structure * declaration */ dec_ind = di_stack[--ps.dec_nest]; if (ps.dec_nest == 0 && !ps.in_parameter_declaration) ps.just_saw_decl = 2; ps.in_decl = true; } prefix_blankline_requested = 0; parse(rbrace); /* let parser know about this */ ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead && ps.il[ps.tos] >= ps.ind_level; if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0) postfix_blankline_requested = 1; break; case swstmt: /* got keyword "switch" */ sp_sw = true; hd_type = swstmt; /* keep this for when we have seen the * expression */ goto copy_id; /* go move the token into buffer */ case sp_paren: /* token is if, while, for */ sp_sw = true; /* the interesting stuff is done after the * expression is scanned */ hd_type = (*token == 'i' ? ifstmt : (*token == 'w' ? whilestmt : forstmt)); /* * remember the type of header for later use by parser */ goto copy_id; /* copy the token into line */ case sp_nparen: /* got else, do */ ps.in_stmt = false; if (*token == 'e') { if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) { if (verbose) diag2(0, "Line broken"); dump_line();/* make sure this starts a line */ ps.want_blank = false; } force_nl = true;/* also, following stuff must go onto new line */ last_else = 1; parse(elselit); } else { if (e_code != s_code) { /* make sure this starts a line */ if (verbose) diag2(0, "Line broken"); dump_line(); ps.want_blank = false; } force_nl = true;/* also, following stuff must go onto new line */ last_else = 0; parse(dolit); } goto copy_id; /* move the token into line */ case decl: /* we have a declaration type (int, register, * etc.) */ parse(decl); /* let parser worry about indentation */ if (ps.last_token == rparen && ps.tos <= 1) { ps.in_parameter_declaration = 1; if (s_code != e_code) { dump_line(); ps.want_blank = 0; } } if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) { ps.ind_level = ps.i_l_follow = 1; ps.ind_stmt = 0; } ps.in_or_st = true; /* this might be a structure or initialization * declaration */ ps.in_decl = ps.decl_on_line = true; if ( /* !ps.in_or_st && */ ps.dec_nest <= 0) ps.just_saw_decl = 2; prefix_blankline_requested = 0; for (i = 0; token[i++];); /* get length of token */ if (ps.ind_level == 0 || ps.dec_nest > 0) { /* global variable or struct member in local variable */ dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i; tabs_to_var = (use_tabs ? ps.decl_indent > 0 : 0); } else { /* local variable */ dec_ind = ps.local_decl_indent > 0 ? ps.local_decl_indent : i; tabs_to_var = (use_tabs ? ps.local_decl_indent > 0 : 0); } goto copy_id; case ident: /* got an identifier or constant */ if (ps.in_decl) { /* if we are in a declaration, we must indent * identifier */ if (is_procname == 0 || !procnames_start_line) { if (!ps.block_init) { if (troff && !ps.dumped_decl_indent) { if (ps.want_blank) *e_code++ = ' '; ps.want_blank = false; sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7); ps.dumped_decl_indent = 1; e_code += strlen(e_code); } else { int cur_dec_ind; int pos, startpos; /* * in order to get the tab math right for * indentations that are not multiples of 8 we * need to modify both startpos and dec_ind * (cur_dec_ind) here by eight minus the * remainder of the current starting column * divided by eight. This seems to be a * properly working fix */ startpos = e_code - s_code; cur_dec_ind = dec_ind; pos = startpos; if ((ps.ind_level * ps.ind_size) % 8 != 0) { pos += (ps.ind_level * ps.ind_size) % 8; cur_dec_ind += (ps.ind_level * ps.ind_size) % 8; } if (tabs_to_var) { while ((pos & ~7) + 8 <= cur_dec_ind) { CHECK_SIZE_CODE; *e_code++ = '\t'; pos = (pos & ~7) + 8; } } while (pos < cur_dec_ind) { CHECK_SIZE_CODE; *e_code++ = ' '; pos++; } if (ps.want_blank && e_code - s_code == startpos) *e_code++ = ' '; ps.want_blank = false; } } } else { if (ps.want_blank) *e_code++ = ' '; ps.want_blank = false; if (dec_ind && s_code != e_code) dump_line(); dec_ind = 0; } } else if (sp_sw && ps.p_l_follow == 0) { sp_sw = false; force_nl = true; ps.last_u_d = true; ps.in_stmt = false; parse(hd_type); } copy_id: if (ps.want_blank) *e_code++ = ' '; if (troff && ps.its_a_keyword) { e_code = chfont(&bodyf, &keywordf, e_code); for (t_ptr = token; *t_ptr; ++t_ptr) { CHECK_SIZE_CODE; *e_code++ = keywordf.allcaps && islower(*t_ptr) ? toupper(*t_ptr) : *t_ptr; } e_code = chfont(&keywordf, &bodyf, e_code); } else for (t_ptr = token; *t_ptr; ++t_ptr) { CHECK_SIZE_CODE; *e_code++ = *t_ptr; } ps.want_blank = true; break; case period: /* treat a period kind of like a binary * operation */ *e_code++ = '.'; /* move the period into line */ ps.want_blank = false; /* dont put a blank after a period */ break; case comma: ps.want_blank = (s_code != e_code); /* only put blank after comma * if comma does not start the * line */ if (ps.in_decl && is_procname == 0 && !ps.block_init) while ((e_code - s_code) < (dec_ind - 1)) { CHECK_SIZE_CODE; *e_code++ = ' '; } *e_code++ = ','; if (ps.p_l_follow == 0) { if (ps.block_init_level <= 0) ps.block_init = 0; if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8)) force_nl = true; } break; case preesc: /* got the character '#' */ if ((s_com != e_com) || (s_lab != e_lab) || (s_code != e_code)) dump_line(); *e_lab++ = '#'; /* move whole line to 'label' buffer */ { int in_comment = 0; int com_start = 0; char quote = 0; int com_end = 0; while (*buf_ptr == ' ' || *buf_ptr == '\t') { buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); } while (*buf_ptr != '\n' || (in_comment && !had_eof)) { CHECK_SIZE_LAB; *e_lab = *buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); switch (*e_lab++) { case BACKSLASH: if (troff) *e_lab++ = BACKSLASH; if (!in_comment) { *e_lab++ = *buf_ptr++; if (buf_ptr >= buf_end) fill_buffer(); } break; case '/': if (*buf_ptr == '*' && !in_comment && !quote) { in_comment = 1; *e_lab++ = *buf_ptr++; com_start = e_lab - s_lab - 2; } break; case '"': if (quote == '"') quote = 0; break; case '\'': if (quote == '\'') quote = 0; break; case '*': if (*buf_ptr == '/' && in_comment) { in_comment = 0; *e_lab++ = *buf_ptr++; com_end = e_lab - s_lab; } break; } } while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) e_lab--; if (e_lab - s_lab == com_end && bp_save == 0) { /* comment on * preprocessor line */ if (sc_end == 0) /* if this is the first comment, we * must set up the buffer */ sc_end = &(save_com[0]); else { *sc_end++ = '\n'; /* add newline between * comments */ *sc_end++ = ' '; --line_no; } bcopy(s_lab + com_start, sc_end, com_end - com_start); sc_end += com_end - com_start; if (sc_end >= &save_com[sc_size]) abort(); e_lab = s_lab + com_start; while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) e_lab--; bp_save = buf_ptr; /* save current input buffer */ be_save = buf_end; buf_ptr = save_com; /* fix so that subsequent calls to * lexi will take tokens out of * save_com */ *sc_end++ = ' '; /* add trailing blank, just in case */ buf_end = sc_end; sc_end = 0; } *e_lab = '\0'; /* null terminate line */ ps.pcase = false; } if (strncmp(s_lab, "#if", 3) == 0) { if (blanklines_around_conditional_compilation) { int c; prefix_blankline_requested++; while ((c = getc(input)) == '\n'); ungetc(c, input); } - if ((size_t)ifdef_level < sizeof(state_stack)/sizeof(state_stack[0])) { + if ((size_t)ifdef_level < nitems(state_stack)) { match_state[ifdef_level].tos = -1; state_stack[ifdef_level++] = ps; } else diag2(1, "#if stack overflow"); } else if (strncmp(s_lab, "#else", 5) == 0) if (ifdef_level <= 0) diag2(1, "Unmatched #else"); else { match_state[ifdef_level - 1] = ps; ps = state_stack[ifdef_level - 1]; } else if (strncmp(s_lab, "#endif", 6) == 0) { if (ifdef_level <= 0) diag2(1, "Unmatched #endif"); else { ifdef_level--; #ifdef undef /* * This match needs to be more intelligent before the * message is useful */ if (match_state[ifdef_level].tos >= 0 && bcmp(&ps, &match_state[ifdef_level], sizeof ps)) diag2(0, "Syntactically inconsistent #ifdef alternatives"); #endif } if (blanklines_around_conditional_compilation) { postfix_blankline_requested++; n_real_blanklines = 0; } } break; /* subsequent processing of the newline * character will cause the line to be printed */ case comment: /* we have gotten a / followed by * this is a biggie */ if (flushed_nl) { /* we should force a broken line here */ flushed_nl = false; dump_line(); ps.want_blank = false; /* dont insert blank at line start */ force_nl = false; } pr_comment(); break; } /* end of big switch stmt */ *e_code = '\0'; /* make sure code section is null terminated */ if (type_code != comment && type_code != newline && type_code != preesc) ps.last_token = type_code; } /* end of main while (1) loop */ } /* * copy input file to backup file if in_name is /blah/blah/blah/file, then * backup file will be ".Bfile" then make the backup file the input and * original input file the output */ static void bakcopy(void) { int n, bakchn; char buff[8 * 1024]; const char *p; /* construct file name .Bfile */ for (p = in_name; *p; p++); /* skip to end of string */ while (p > in_name && *p != '/') /* find last '/' */ p--; if (*p == '/') p++; sprintf(bakfile, "%s.BAK", p); /* copy in_name to backup file */ bakchn = creat(bakfile, 0600); if (bakchn < 0) err(1, "%s", bakfile); while ((n = read(fileno(input), buff, sizeof buff)) != 0) if (write(bakchn, buff, n) != n) err(1, "%s", bakfile); if (n < 0) err(1, "%s", in_name); close(bakchn); fclose(input); /* re-open backup file as the input file */ input = fopen(bakfile, "r"); if (input == NULL) err(1, "%s", bakfile); /* now the original input file will be the output */ output = fopen(in_name, "w"); if (output == NULL) { unlink(bakfile); err(1, "%s", in_name); } } Index: stable/11/usr.bin/locale/locale.c =================================================================== --- stable/11/usr.bin/locale/locale.c (revision 307696) +++ stable/11/usr.bin/locale/locale.c (revision 307697) @@ -1,690 +1,690 @@ /*- * Copyright (c) 2002, 2003 Alexey Zelkin * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * XXX: implement missing era_* (LC_TIME) keywords (require libc & * nl_langinfo(3) extensions) * * XXX: correctly handle reserved 'charmap' keyword and '-m' option (require * localedef(1) implementation). Currently it's handled via * nl_langinfo(CODESET). */ #include #include #include #include #include #include #include #include #include #include #include #include "setlocale.h" /* Local prototypes */ void init_locales_list(void); void list_charmaps(void); void list_locales(void); const char *lookup_localecat(int); char *kwval_lconv(int); int kwval_lookup(char *, char **, int *, int *); void showdetails(char *); void showkeywordslist(char *substring); void showlocale(void); void usage(void); /* Global variables */ static StringList *locales = NULL; int all_locales = 0; int all_charmaps = 0; int prt_categories = 0; int prt_keywords = 0; int more_params = 0; struct _lcinfo { const char *name; int id; } lcinfo [] = { { "LC_CTYPE", LC_CTYPE }, { "LC_COLLATE", LC_COLLATE }, { "LC_TIME", LC_TIME }, { "LC_NUMERIC", LC_NUMERIC }, { "LC_MONETARY", LC_MONETARY }, { "LC_MESSAGES", LC_MESSAGES } }; #define NLCINFO nitems(lcinfo) /* ids for values not referenced by nl_langinfo() */ #define KW_ZERO 10000 #define KW_GROUPING (KW_ZERO+1) #define KW_INT_CURR_SYMBOL (KW_ZERO+2) #define KW_CURRENCY_SYMBOL (KW_ZERO+3) #define KW_MON_DECIMAL_POINT (KW_ZERO+4) #define KW_MON_THOUSANDS_SEP (KW_ZERO+5) #define KW_MON_GROUPING (KW_ZERO+6) #define KW_POSITIVE_SIGN (KW_ZERO+7) #define KW_NEGATIVE_SIGN (KW_ZERO+8) #define KW_INT_FRAC_DIGITS (KW_ZERO+9) #define KW_FRAC_DIGITS (KW_ZERO+10) #define KW_P_CS_PRECEDES (KW_ZERO+11) #define KW_P_SEP_BY_SPACE (KW_ZERO+12) #define KW_N_CS_PRECEDES (KW_ZERO+13) #define KW_N_SEP_BY_SPACE (KW_ZERO+14) #define KW_P_SIGN_POSN (KW_ZERO+15) #define KW_N_SIGN_POSN (KW_ZERO+16) #define KW_INT_P_CS_PRECEDES (KW_ZERO+17) #define KW_INT_P_SEP_BY_SPACE (KW_ZERO+18) #define KW_INT_N_CS_PRECEDES (KW_ZERO+19) #define KW_INT_N_SEP_BY_SPACE (KW_ZERO+20) #define KW_INT_P_SIGN_POSN (KW_ZERO+21) #define KW_INT_N_SIGN_POSN (KW_ZERO+22) struct _kwinfo { const char *name; int isstr; /* true - string, false - number */ int catid; /* LC_* */ int value_ref; const char *comment; } kwinfo [] = { { "charmap", 1, LC_CTYPE, CODESET, "" }, /* hack */ { "decimal_point", 1, LC_NUMERIC, RADIXCHAR, "" }, { "thousands_sep", 1, LC_NUMERIC, THOUSEP, "" }, { "grouping", 1, LC_NUMERIC, KW_GROUPING, "" }, { "radixchar", 1, LC_NUMERIC, RADIXCHAR, "Same as decimal_point (FreeBSD only)" }, /* compat */ { "thousep", 1, LC_NUMERIC, THOUSEP, "Same as thousands_sep (FreeBSD only)" }, /* compat */ { "int_curr_symbol", 1, LC_MONETARY, KW_INT_CURR_SYMBOL, "" }, { "currency_symbol", 1, LC_MONETARY, KW_CURRENCY_SYMBOL, "" }, { "mon_decimal_point", 1, LC_MONETARY, KW_MON_DECIMAL_POINT, "" }, { "mon_thousands_sep", 1, LC_MONETARY, KW_MON_THOUSANDS_SEP, "" }, { "mon_grouping", 1, LC_MONETARY, KW_MON_GROUPING, "" }, { "positive_sign", 1, LC_MONETARY, KW_POSITIVE_SIGN, "" }, { "negative_sign", 1, LC_MONETARY, KW_NEGATIVE_SIGN, "" }, { "int_frac_digits", 0, LC_MONETARY, KW_INT_FRAC_DIGITS, "" }, { "frac_digits", 0, LC_MONETARY, KW_FRAC_DIGITS, "" }, { "p_cs_precedes", 0, LC_MONETARY, KW_P_CS_PRECEDES, "" }, { "p_sep_by_space", 0, LC_MONETARY, KW_P_SEP_BY_SPACE, "" }, { "n_cs_precedes", 0, LC_MONETARY, KW_N_CS_PRECEDES, "" }, { "n_sep_by_space", 0, LC_MONETARY, KW_N_SEP_BY_SPACE, "" }, { "p_sign_posn", 0, LC_MONETARY, KW_P_SIGN_POSN, "" }, { "n_sign_posn", 0, LC_MONETARY, KW_N_SIGN_POSN, "" }, { "int_p_cs_precedes", 0, LC_MONETARY, KW_INT_P_CS_PRECEDES, "" }, { "int_p_sep_by_space", 0, LC_MONETARY, KW_INT_P_SEP_BY_SPACE, "" }, { "int_n_cs_precedes", 0, LC_MONETARY, KW_INT_N_CS_PRECEDES, "" }, { "int_n_sep_by_space", 0, LC_MONETARY, KW_INT_N_SEP_BY_SPACE, "" }, { "int_p_sign_posn", 0, LC_MONETARY, KW_INT_P_SIGN_POSN, "" }, { "int_n_sign_posn", 0, LC_MONETARY, KW_INT_N_SIGN_POSN, "" }, { "d_t_fmt", 1, LC_TIME, D_T_FMT, "" }, { "d_fmt", 1, LC_TIME, D_FMT, "" }, { "t_fmt", 1, LC_TIME, T_FMT, "" }, { "am_str", 1, LC_TIME, AM_STR, "" }, { "pm_str", 1, LC_TIME, PM_STR, "" }, { "t_fmt_ampm", 1, LC_TIME, T_FMT_AMPM, "" }, { "day_1", 1, LC_TIME, DAY_1, "" }, { "day_2", 1, LC_TIME, DAY_2, "" }, { "day_3", 1, LC_TIME, DAY_3, "" }, { "day_4", 1, LC_TIME, DAY_4, "" }, { "day_5", 1, LC_TIME, DAY_5, "" }, { "day_6", 1, LC_TIME, DAY_6, "" }, { "day_7", 1, LC_TIME, DAY_7, "" }, { "abday_1", 1, LC_TIME, ABDAY_1, "" }, { "abday_2", 1, LC_TIME, ABDAY_2, "" }, { "abday_3", 1, LC_TIME, ABDAY_3, "" }, { "abday_4", 1, LC_TIME, ABDAY_4, "" }, { "abday_5", 1, LC_TIME, ABDAY_5, "" }, { "abday_6", 1, LC_TIME, ABDAY_6, "" }, { "abday_7", 1, LC_TIME, ABDAY_7, "" }, { "mon_1", 1, LC_TIME, MON_1, "" }, { "mon_2", 1, LC_TIME, MON_2, "" }, { "mon_3", 1, LC_TIME, MON_3, "" }, { "mon_4", 1, LC_TIME, MON_4, "" }, { "mon_5", 1, LC_TIME, MON_5, "" }, { "mon_6", 1, LC_TIME, MON_6, "" }, { "mon_7", 1, LC_TIME, MON_7, "" }, { "mon_8", 1, LC_TIME, MON_8, "" }, { "mon_9", 1, LC_TIME, MON_9, "" }, { "mon_10", 1, LC_TIME, MON_10, "" }, { "mon_11", 1, LC_TIME, MON_11, "" }, { "mon_12", 1, LC_TIME, MON_12, "" }, { "abmon_1", 1, LC_TIME, ABMON_1, "" }, { "abmon_2", 1, LC_TIME, ABMON_2, "" }, { "abmon_3", 1, LC_TIME, ABMON_3, "" }, { "abmon_4", 1, LC_TIME, ABMON_4, "" }, { "abmon_5", 1, LC_TIME, ABMON_5, "" }, { "abmon_6", 1, LC_TIME, ABMON_6, "" }, { "abmon_7", 1, LC_TIME, ABMON_7, "" }, { "abmon_8", 1, LC_TIME, ABMON_8, "" }, { "abmon_9", 1, LC_TIME, ABMON_9, "" }, { "abmon_10", 1, LC_TIME, ABMON_10, "" }, { "abmon_11", 1, LC_TIME, ABMON_11, "" }, { "abmon_12", 1, LC_TIME, ABMON_12, "" }, { "altmon_1", 1, LC_TIME, ALTMON_1, "(FreeBSD only)" }, { "altmon_2", 1, LC_TIME, ALTMON_2, "(FreeBSD only)" }, { "altmon_3", 1, LC_TIME, ALTMON_3, "(FreeBSD only)" }, { "altmon_4", 1, LC_TIME, ALTMON_4, "(FreeBSD only)" }, { "altmon_5", 1, LC_TIME, ALTMON_5, "(FreeBSD only)" }, { "altmon_6", 1, LC_TIME, ALTMON_6, "(FreeBSD only)" }, { "altmon_7", 1, LC_TIME, ALTMON_7, "(FreeBSD only)" }, { "altmon_8", 1, LC_TIME, ALTMON_8, "(FreeBSD only)" }, { "altmon_9", 1, LC_TIME, ALTMON_9, "(FreeBSD only)" }, { "altmon_10", 1, LC_TIME, ALTMON_10, "(FreeBSD only)" }, { "altmon_11", 1, LC_TIME, ALTMON_11, "(FreeBSD only)" }, { "altmon_12", 1, LC_TIME, ALTMON_12, "(FreeBSD only)" }, { "era", 1, LC_TIME, ERA, "(unavailable)" }, { "era_d_fmt", 1, LC_TIME, ERA_D_FMT, "(unavailable)" }, { "era_d_t_fmt", 1, LC_TIME, ERA_D_T_FMT, "(unavailable)" }, { "era_t_fmt", 1, LC_TIME, ERA_T_FMT, "(unavailable)" }, { "alt_digits", 1, LC_TIME, ALT_DIGITS, "" }, { "d_md_order", 1, LC_TIME, D_MD_ORDER, "(FreeBSD only)" }, /* local */ { "yesexpr", 1, LC_MESSAGES, YESEXPR, "" }, { "noexpr", 1, LC_MESSAGES, NOEXPR, "" }, { "yesstr", 1, LC_MESSAGES, YESSTR, "(POSIX legacy)" }, /* compat */ { "nostr", 1, LC_MESSAGES, NOSTR, "(POSIX legacy)" } /* compat */ }; -#define NKWINFO (sizeof(kwinfo)/sizeof(kwinfo[0])) +#define NKWINFO (nitems(kwinfo)) const char *boguslocales[] = { "UTF-8" }; -#define NBOGUS (sizeof(boguslocales)/sizeof(boguslocales[0])) +#define NBOGUS (nitems(boguslocales)) int main(int argc, char *argv[]) { int ch; int tmp; while ((ch = getopt(argc, argv, "ackms:")) != -1) { switch (ch) { case 'a': all_locales = 1; break; case 'c': prt_categories = 1; break; case 'k': prt_keywords = 1; break; case 'm': all_charmaps = 1; break; default: usage(); } } argc -= optind; argv += optind; /* validate arguments */ if (all_locales && all_charmaps) usage(); if ((all_locales || all_charmaps) && argc > 0) usage(); if ((all_locales || all_charmaps) && (prt_categories || prt_keywords)) usage(); /* process '-a' */ if (all_locales) { list_locales(); exit(0); } /* process '-m' */ if (all_charmaps) { list_charmaps(); exit(0); } /* check for special case '-k list' */ tmp = 0; if (prt_keywords && argc > 0) while (tmp < argc) if (strcasecmp(argv[tmp++], "list") == 0) { showkeywordslist(argv[tmp]); exit(0); } /* process '-c', '-k', or command line arguments. */ if (prt_categories || prt_keywords || argc > 0) { if (argc > 0) { setlocale(LC_ALL, ""); while (argc > 0) { showdetails(*argv); argv++; argc--; } } else { uint i; for (i = 0; i < nitems(kwinfo); i++) showdetails ((char *)kwinfo [i].name); } exit(0); } /* no arguments, show current locale state */ showlocale(); return (0); } void usage(void) { printf("Usage: locale [ -a | -m ]\n" " locale -k list [prefix]\n" " locale [ -ck ] [keyword ...]\n"); exit(1); } /* * Output information about all available locales * * XXX actually output of this function does not guarantee that locale * is really available to application, since it can be broken or * inconsistent thus setlocale() will fail. Maybe add '-V' function to * also validate these locales? */ void list_locales(void) { size_t i; init_locales_list(); for (i = 0; i < locales->sl_cur; i++) { printf("%s\n", locales->sl_str[i]); } } /* * qsort() helper function */ static int scmp(const void *s1, const void *s2) { return strcmp(*(const char **)s1, *(const char **)s2); } /* * Output information about all available charmaps * * XXX this function is doing a task in hackish way, i.e. by scaning * list of locales, spliting their codeset part and building list of * them. */ void list_charmaps(void) { size_t i; char *s, *cs; StringList *charmaps; /* initialize StringList */ charmaps = sl_init(); if (charmaps == NULL) err(1, "could not allocate memory"); /* fetch locales list */ init_locales_list(); /* split codesets and build their list */ for (i = 0; i < locales->sl_cur; i++) { s = locales->sl_str[i]; if ((cs = strchr(s, '.')) != NULL) { cs++; if (sl_find(charmaps, cs) == NULL) sl_add(charmaps, cs); } } /* add US-ASCII, if not yet added */ if (sl_find(charmaps, "US-ASCII") == NULL) sl_add(charmaps, "US-ASCII"); /* sort the list */ qsort(charmaps->sl_str, charmaps->sl_cur, sizeof(char *), scmp); /* print results */ for (i = 0; i < charmaps->sl_cur; i++) { printf("%s\n", charmaps->sl_str[i]); } } /* * Retrieve sorted list of system locales (or user locales, if PATH_LOCALE * environment variable is set) */ void init_locales_list(void) { DIR *dirp; struct dirent *dp; size_t i; int bogus; /* why call this function twice ? */ if (locales != NULL) return; /* initialize StringList */ locales = sl_init(); if (locales == NULL) err(1, "could not allocate memory"); /* get actual locales directory name */ if (__detect_path_locale() != 0) err(1, "unable to find locales storage"); /* open locales directory */ dirp = opendir(_PathLocale); if (dirp == NULL) err(1, "could not open directory '%s'", _PathLocale); /* scan directory and store its contents except "." and ".." */ while ((dp = readdir(dirp)) != NULL) { if (*(dp->d_name) == '.') continue; /* exclude "." and ".." */ for (bogus = i = 0; i < NBOGUS; i++) if (strncmp(dp->d_name, boguslocales[i], strlen(boguslocales[i])) == 0) bogus = 1; if (!bogus) sl_add(locales, strdup(dp->d_name)); } closedir(dirp); /* make sure that 'POSIX' and 'C' locales are present in the list. * POSIX 1003.1-2001 requires presence of 'POSIX' name only here, but * we also list 'C' for constistency */ if (sl_find(locales, "POSIX") == NULL) sl_add(locales, "POSIX"); if (sl_find(locales, "C") == NULL) sl_add(locales, "C"); /* make output nicer, sort the list */ qsort(locales->sl_str, locales->sl_cur, sizeof(char *), scmp); } /* * Show current locale status, depending on environment variables */ void showlocale(void) { size_t i; const char *lang, *vval, *eval; setlocale(LC_ALL, ""); lang = getenv("LANG"); if (lang == NULL) { lang = ""; } printf("LANG=%s\n", lang); /* XXX: if LANG is null, then set it to "C" to get implied values? */ for (i = 0; i < NLCINFO; i++) { vval = setlocale(lcinfo[i].id, NULL); eval = getenv(lcinfo[i].name); if (eval != NULL && !strcmp(eval, vval) && strcmp(lang, vval)) { /* * Appropriate environment variable set, its value * is valid and not overridden by LC_ALL * * XXX: possible side effect: if both LANG and * overridden environment variable are set into same * value, then it'll be assumed as 'implied' */ printf("%s=%s\n", lcinfo[i].name, vval); } else { printf("%s=\"%s\"\n", lcinfo[i].name, vval); } } vval = getenv("LC_ALL"); if (vval == NULL) { vval = ""; } printf("LC_ALL=%s\n", vval); } /* * keyword value lookup helper (via localeconv()) */ char * kwval_lconv(int id) { struct lconv *lc; char *rval; rval = NULL; lc = localeconv(); switch (id) { case KW_GROUPING: rval = lc->grouping; break; case KW_INT_CURR_SYMBOL: rval = lc->int_curr_symbol; break; case KW_CURRENCY_SYMBOL: rval = lc->currency_symbol; break; case KW_MON_DECIMAL_POINT: rval = lc->mon_decimal_point; break; case KW_MON_THOUSANDS_SEP: rval = lc->mon_thousands_sep; break; case KW_MON_GROUPING: rval = lc->mon_grouping; break; case KW_POSITIVE_SIGN: rval = lc->positive_sign; break; case KW_NEGATIVE_SIGN: rval = lc->negative_sign; break; case KW_INT_FRAC_DIGITS: rval = &(lc->int_frac_digits); break; case KW_FRAC_DIGITS: rval = &(lc->frac_digits); break; case KW_P_CS_PRECEDES: rval = &(lc->p_cs_precedes); break; case KW_P_SEP_BY_SPACE: rval = &(lc->p_sep_by_space); break; case KW_N_CS_PRECEDES: rval = &(lc->n_cs_precedes); break; case KW_N_SEP_BY_SPACE: rval = &(lc->n_sep_by_space); break; case KW_P_SIGN_POSN: rval = &(lc->p_sign_posn); break; case KW_N_SIGN_POSN: rval = &(lc->n_sign_posn); break; case KW_INT_P_CS_PRECEDES: rval = &(lc->int_p_cs_precedes); break; case KW_INT_P_SEP_BY_SPACE: rval = &(lc->int_p_sep_by_space); break; case KW_INT_N_CS_PRECEDES: rval = &(lc->int_n_cs_precedes); break; case KW_INT_N_SEP_BY_SPACE: rval = &(lc->int_n_sep_by_space); break; case KW_INT_P_SIGN_POSN: rval = &(lc->int_p_sign_posn); break; case KW_INT_N_SIGN_POSN: rval = &(lc->int_n_sign_posn); break; default: break; } return (rval); } /* * keyword value and properties lookup */ int kwval_lookup(char *kwname, char **kwval, int *cat, int *isstr) { int rval; size_t i; rval = 0; for (i = 0; i < NKWINFO; i++) { if (strcasecmp(kwname, kwinfo[i].name) == 0) { rval = 1; *cat = kwinfo[i].catid; *isstr = kwinfo[i].isstr; if (kwinfo[i].value_ref < KW_ZERO) { *kwval = nl_langinfo(kwinfo[i].value_ref); } else { *kwval = kwval_lconv(kwinfo[i].value_ref); } break; } } return (rval); } /* * Show details about requested keyword according to '-k' and/or '-c' * command line options specified. */ void showdetails(char *kw) { int isstr, cat, tmpval; char *kwval; if (kwval_lookup(kw, &kwval, &cat, &isstr) == 0) { /* * invalid keyword specified. * XXX: any actions? */ fprintf(stderr, "Unknown keyword: `%s'\n", kw); return; } if (prt_categories) { if (prt_keywords) printf("%-20s ", lookup_localecat(cat)); else printf("%-20s\t%s\n", kw, lookup_localecat(cat)); } if (prt_keywords) { if (isstr) { printf("%s=\"%s\"\n", kw, kwval); } else { tmpval = (char) *kwval; printf("%s=%d\n", kw, tmpval); } } if (!prt_categories && !prt_keywords) { if (isstr) { printf("%s\n", kwval); } else { tmpval = (char) *kwval; printf("%d\n", tmpval); } } } /* * Convert locale category id into string */ const char * lookup_localecat(int cat) { size_t i; for (i = 0; i < NLCINFO; i++) if (lcinfo[i].id == cat) { return (lcinfo[i].name); } return ("UNKNOWN"); } /* * Show list of keywords */ void showkeywordslist(char *substring) { size_t i; #define FMT "%-20s %-12s %-7s %-20s\n" if (substring == NULL) printf("List of available keywords\n\n"); else printf("List of available keywords starting with '%s'\n\n", substring); printf(FMT, "Keyword", "Category", "Type", "Comment"); printf("-------------------- ------------ ------- --------------------\n"); for (i = 0; i < NKWINFO; i++) { if (substring != NULL) { if (strncmp(kwinfo[i].name, substring, strlen(substring)) != 0) continue; } printf(FMT, kwinfo[i].name, lookup_localecat(kwinfo[i].catid), (kwinfo[i].isstr == 0) ? "number" : "string", kwinfo[i].comment); } } Index: stable/11/usr.bin/localedef/collate.c =================================================================== --- stable/11/usr.bin/localedef/collate.c (revision 307696) +++ stable/11/usr.bin/localedef/collate.c (revision 307697) @@ -1,1313 +1,1313 @@ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. * Copyright 2015 John Marino * * This source code is derived from the illumos localedef command, and * provided under BSD-style license terms by Nexenta Systems, Inc. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ /* * LC_COLLATE database generation routines for localedef. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "localedef.h" #include "parser.h" #include "collate.h" /* * Design notes. * * It will be extremely helpful to the reader if they have access to * the localedef and locale file format specifications available. * Latest versions of these are available from www.opengroup.org. * * The design for the collation code is a bit complex. The goal is a * single collation database as described in collate.h (in * libc/port/locale). However, there are some other tidbits: * * a) The substitution entries are now a directly indexable array. A * priority elsewhere in the table is taken as an index into the * substitution table if it has a high bit (COLLATE_SUBST_PRIORITY) * set. (The bit is cleared and the result is the index into the * table. * * b) We eliminate duplicate entries into the substitution table. * This saves a lot of space. * * c) The priorities for each level are "compressed", so that each * sorting level has consecutively numbered priorities starting at 1. * (O is reserved for the ignore priority.) This means sort levels * which only have a few distinct priorities can represent the * priority level in fewer bits, which makes the strxfrm output * smaller. * * d) We record the total number of priorities so that strxfrm can * figure out how many bytes to expand a numeric priority into. * * e) For the UNDEFINED pass (the last pass), we record the maximum * number of bits needed to uniquely prioritize these entries, so that * the last pass can also use smaller strxfrm output when possible. * * f) Priorities with the sign bit set are verboten. This works out * because no active character set needs that bit to carry significant * information once the character is in wide form. * * To process the entire data to make the database, we actually run * multiple passes over the data. * * The first pass, which is done at parse time, identifies elements, * substitutions, and such, and records them in priority order. As * some priorities can refer to other priorities, using forward * references, we use a table of references indicating whether the * priority's value has been resolved, or whether it is still a * reference. * * The second pass walks over all the items in priority order, noting * that they are used directly, and not just an indirect reference. * This is done by creating a "weight" structure for the item. The * weights are stashed in an RB tree sorted by relative "priority". * * The third pass walks over all the weight structures, in priority * order, and assigns a new monotonically increasing (per sort level) * weight value to them. These are the values that will actually be * written to the file. * * The fourth pass just writes the data out. */ /* * In order to resolve the priorities, we create a table of priorities. * Entries in the table can be in one of three states. * * UNKNOWN is for newly allocated entries, and indicates that nothing * is known about the priority. (For example, when new entries are created * for collating-symbols, this is the value assigned for them until the * collating symbol's order has been determined. * * RESOLVED is used for an entry where the priority indicates the final * numeric weight. * * REFER is used for entries that reference other entries. Typically * this is used for forward references. A collating-symbol can never * have this value. * * The "pass" field is used during final resolution to aid in detection * of referencing loops. (For example depends on , but has its * priority dependent on .) */ typedef enum { UNKNOWN, /* priority is totally unknown */ RESOLVED, /* priority value fully resolved */ REFER /* priority is a reference (index) */ } res_t; typedef struct weight { int32_t pri; int opt; RB_ENTRY(weight) entry; } weight_t; typedef struct priority { res_t res; int32_t pri; int pass; int lineno; } collpri_t; #define NUM_WT collinfo.directive_count /* * These are the abstract collating symbols, which are just a symbolic * way to reference a priority. */ struct collsym { char *name; int32_t ref; RB_ENTRY(collsym) entry; }; /* * These are also abstract collating symbols, but we allow them to have * different priorities at different levels. */ typedef struct collundef { char *name; int32_t ref[COLL_WEIGHTS_MAX]; RB_ENTRY(collundef) entry; } collundef_t; /* * These are called "chains" in libc. This records the fact that two * more characters should be treated as a single collating entity when * they appear together. For example, in Spanish gets collated * as a character between and . */ struct collelem { char *symbol; wchar_t *expand; int32_t ref[COLL_WEIGHTS_MAX]; RB_ENTRY(collelem) rb_bysymbol; RB_ENTRY(collelem) rb_byexpand; }; /* * Individual characters have a sequence of weights as well. */ typedef struct collchar { wchar_t wc; int32_t ref[COLL_WEIGHTS_MAX]; RB_ENTRY(collchar) entry; } collchar_t; /* * Substitution entries. The key is itself a priority. Note that * when we create one of these, we *automatically* wind up with a * fully resolved priority for the key, because creation of * substitutions creates a resolved priority at the same time. */ typedef struct subst{ int32_t key; int32_t ref[COLLATE_STR_LEN]; RB_ENTRY(subst) entry; RB_ENTRY(subst) entry_ref; } subst_t; static RB_HEAD(collsyms, collsym) collsyms; static RB_HEAD(collundefs, collundef) collundefs; static RB_HEAD(elem_by_symbol, collelem) elem_by_symbol; static RB_HEAD(elem_by_expand, collelem) elem_by_expand; static RB_HEAD(collchars, collchar) collchars; static RB_HEAD(substs, subst) substs[COLL_WEIGHTS_MAX]; static RB_HEAD(substs_ref, subst) substs_ref[COLL_WEIGHTS_MAX]; static RB_HEAD(weights, weight) weights[COLL_WEIGHTS_MAX]; static int32_t nweight[COLL_WEIGHTS_MAX]; /* * This is state tracking for the ellipsis token. Note that we start * the initial values so that the ellipsis logic will think we got a * magic starting value of NUL. It starts at minus one because the * starting point is exclusive -- i.e. the starting point is not * itself handled by the ellipsis code. */ static int currorder = EOF; static int lastorder = EOF; static collelem_t *currelem; static collchar_t *currchar; static collundef_t *currundef; static wchar_t ellipsis_start = 0; static int32_t ellipsis_weights[COLL_WEIGHTS_MAX]; /* * We keep a running tally of weights. */ static int nextpri = 1; static int nextsubst[COLL_WEIGHTS_MAX] = { 0 }; /* * This array collects up the weights for each level. */ static int32_t order_weights[COLL_WEIGHTS_MAX]; static int curr_weight = 0; static int32_t subst_weights[COLLATE_STR_LEN]; static int curr_subst = 0; /* * Some initial priority values. */ static int32_t pri_undefined[COLL_WEIGHTS_MAX]; static int32_t pri_ignore; static collate_info_t collinfo; static collpri_t *prilist = NULL; static int numpri = 0; static int maxpri = 0; static void start_order(int); static int32_t new_pri(void) { int i; if (numpri >= maxpri) { maxpri = maxpri ? maxpri * 2 : 1024; prilist = realloc(prilist, sizeof (collpri_t) * maxpri); if (prilist == NULL) { fprintf(stderr,"out of memory"); return (-1); } for (i = numpri; i < maxpri; i++) { prilist[i].res = UNKNOWN; prilist[i].pri = 0; prilist[i].pass = 0; } } return (numpri++); } static collpri_t * get_pri(int32_t ref) { if ((ref < 0) || (ref > numpri)) { INTERR; return (NULL); } return (&prilist[ref]); } static void set_pri(int32_t ref, int32_t v, res_t res) { collpri_t *pri; pri = get_pri(ref); if ((res == REFER) && ((v < 0) || (v >= numpri))) { INTERR; } /* Resolve self references */ if ((res == REFER) && (ref == v)) { v = nextpri; res = RESOLVED; } if (pri->res != UNKNOWN) { warn("repeated item in order list (first on %d)", pri->lineno); return; } pri->lineno = lineno; pri->pri = v; pri->res = res; } static int32_t resolve_pri(int32_t ref) { collpri_t *pri; static int32_t pass = 0; pri = get_pri(ref); pass++; while (pri->res == REFER) { if (pri->pass == pass) { /* report a line with the circular symbol */ lineno = pri->lineno; fprintf(stderr,"circular reference in order list"); return (-1); } if ((pri->pri < 0) || (pri->pri >= numpri)) { INTERR; return (-1); } pri->pass = pass; pri = &prilist[pri->pri]; } if (pri->res == UNKNOWN) { return (-1); } if (pri->res != RESOLVED) INTERR; return (pri->pri); } static int weight_compare(const void *n1, const void *n2) { int32_t k1 = ((const weight_t *)n1)->pri; int32_t k2 = ((const weight_t *)n2)->pri; return (k1 < k2 ? -1 : k1 > k2 ? 1 : 0); } RB_GENERATE_STATIC(weights, weight, entry, weight_compare); static int collsym_compare(const void *n1, const void *n2) { const collsym_t *c1 = n1; const collsym_t *c2 = n2; int rv; rv = strcmp(c1->name, c2->name); return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); } RB_GENERATE_STATIC(collsyms, collsym, entry, collsym_compare); static int collundef_compare(const void *n1, const void *n2) { const collundef_t *c1 = n1; const collundef_t *c2 = n2; int rv; rv = strcmp(c1->name, c2->name); return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); } RB_GENERATE_STATIC(collundefs, collundef, entry, collundef_compare); static int element_compare_symbol(const void *n1, const void *n2) { const collelem_t *c1 = n1; const collelem_t *c2 = n2; int rv; rv = strcmp(c1->symbol, c2->symbol); return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); } RB_GENERATE_STATIC(elem_by_symbol, collelem, rb_bysymbol, element_compare_symbol); static int element_compare_expand(const void *n1, const void *n2) { const collelem_t *c1 = n1; const collelem_t *c2 = n2; int rv; rv = wcscmp(c1->expand, c2->expand); return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); } RB_GENERATE_STATIC(elem_by_expand, collelem, rb_byexpand, element_compare_expand); static int collchar_compare(const void *n1, const void *n2) { wchar_t k1 = ((const collchar_t *)n1)->wc; wchar_t k2 = ((const collchar_t *)n2)->wc; return (k1 < k2 ? -1 : k1 > k2 ? 1 : 0); } RB_GENERATE_STATIC(collchars, collchar, entry, collchar_compare); static int subst_compare(const void *n1, const void *n2) { int32_t k1 = ((const subst_t *)n1)->key; int32_t k2 = ((const subst_t *)n2)->key; return (k1 < k2 ? -1 : k1 > k2 ? 1 : 0); } RB_GENERATE_STATIC(substs, subst, entry, subst_compare); static int subst_compare_ref(const void *n1, const void *n2) { const wchar_t *c1 = ((const subst_t *)n1)->ref; const wchar_t *c2 = ((const subst_t *)n2)->ref; int rv; rv = wcscmp(c1, c2); return ((rv < 0) ? -1 : (rv > 0) ? 1 : 0); } RB_GENERATE_STATIC(substs_ref, subst, entry_ref, subst_compare_ref); void init_collate(void) { int i; RB_INIT(&collsyms); RB_INIT(&collundefs); RB_INIT(&elem_by_symbol); RB_INIT(&elem_by_expand); RB_INIT(&collchars); for (i = 0; i < COLL_WEIGHTS_MAX; i++) { RB_INIT(&substs[i]); RB_INIT(&substs_ref[i]); RB_INIT(&weights[i]); nweight[i] = 1; } (void) memset(&collinfo, 0, sizeof (collinfo)); /* allocate some initial priorities */ pri_ignore = new_pri(); set_pri(pri_ignore, 0, RESOLVED); for (i = 0; i < COLL_WEIGHTS_MAX; i++) { pri_undefined[i] = new_pri(); /* we will override this later */ set_pri(pri_undefined[i], COLLATE_MAX_PRIORITY, UNKNOWN); } } void define_collsym(char *name) { collsym_t *sym; - if ((sym = calloc(sizeof (*sym), 1)) == NULL) { + if ((sym = calloc(1, sizeof(*sym))) == NULL) { fprintf(stderr,"out of memory"); return; } sym->name = name; sym->ref = new_pri(); if (RB_FIND(collsyms, &collsyms, sym) != NULL) { /* * This should never happen because we are only called * for undefined symbols. */ free(sym); INTERR; return; } RB_INSERT(collsyms, &collsyms, sym); } collsym_t * lookup_collsym(char *name) { collsym_t srch; srch.name = name; return (RB_FIND(collsyms, &collsyms, &srch)); } collelem_t * lookup_collelem(char *symbol) { collelem_t srch; srch.symbol = symbol; return (RB_FIND(elem_by_symbol, &elem_by_symbol, &srch)); } static collundef_t * get_collundef(char *name) { collundef_t srch; collundef_t *ud; int i; srch.name = name; if ((ud = RB_FIND(collundefs, &collundefs, &srch)) == NULL) { - if (((ud = calloc(sizeof (*ud), 1)) == NULL) || + if (((ud = calloc(1, sizeof(*ud))) == NULL) || ((ud->name = strdup(name)) == NULL)) { fprintf(stderr,"out of memory"); free(ud); return (NULL); } for (i = 0; i < NUM_WT; i++) { ud->ref[i] = new_pri(); } RB_INSERT(collundefs, &collundefs, ud); } add_charmap_undefined(name); return (ud); } static collchar_t * get_collchar(wchar_t wc, int create) { collchar_t srch; collchar_t *cc; int i; srch.wc = wc; cc = RB_FIND(collchars, &collchars, &srch); if ((cc == NULL) && create) { - if ((cc = calloc(sizeof (*cc), 1)) == NULL) { + if ((cc = calloc(1, sizeof(*cc))) == NULL) { fprintf(stderr, "out of memory"); return (NULL); } for (i = 0; i < NUM_WT; i++) { cc->ref[i] = new_pri(); } cc->wc = wc; RB_INSERT(collchars, &collchars, cc); } return (cc); } void end_order_collsym(collsym_t *sym) { start_order(T_COLLSYM); /* update the weight */ set_pri(sym->ref, nextpri, RESOLVED); nextpri++; } void end_order(void) { int i; int32_t pri; int32_t ref; collpri_t *p; /* advance the priority/weight */ pri = nextpri; switch (currorder) { case T_CHAR: for (i = 0; i < NUM_WT; i++) { if (((ref = order_weights[i]) < 0) || ((p = get_pri(ref)) == NULL) || (p->pri == -1)) { /* unspecified weight is a self reference */ set_pri(currchar->ref[i], pri, RESOLVED); } else { set_pri(currchar->ref[i], ref, REFER); } order_weights[i] = -1; } /* leave a cookie trail in case next symbol is ellipsis */ ellipsis_start = currchar->wc + 1; currchar = NULL; break; case T_ELLIPSIS: /* save off the weights were we can find them */ for (i = 0; i < NUM_WT; i++) { ellipsis_weights[i] = order_weights[i]; order_weights[i] = -1; } break; case T_COLLELEM: if (currelem == NULL) { INTERR; } else { for (i = 0; i < NUM_WT; i++) { if (((ref = order_weights[i]) < 0) || ((p = get_pri(ref)) == NULL) || (p->pri == -1)) { set_pri(currelem->ref[i], pri, RESOLVED); } else { set_pri(currelem->ref[i], ref, REFER); } order_weights[i] = -1; } } break; case T_UNDEFINED: for (i = 0; i < NUM_WT; i++) { if (((ref = order_weights[i]) < 0) || ((p = get_pri(ref)) == NULL) || (p->pri == -1)) { set_pri(pri_undefined[i], -1, RESOLVED); } else { set_pri(pri_undefined[i], ref, REFER); } order_weights[i] = -1; } break; case T_SYMBOL: for (i = 0; i < NUM_WT; i++) { if (((ref = order_weights[i]) < 0) || ((p = get_pri(ref)) == NULL) || (p->pri == -1)) { set_pri(currundef->ref[i], pri, RESOLVED); } else { set_pri(currundef->ref[i], ref, REFER); } order_weights[i] = -1; } break; default: INTERR; } nextpri++; } static void start_order(int type) { int i; lastorder = currorder; currorder = type; /* this is used to protect ELLIPSIS processing */ if ((lastorder == T_ELLIPSIS) && (type != T_CHAR)) { fprintf(stderr, "character value expected"); } for (i = 0; i < COLL_WEIGHTS_MAX; i++) { order_weights[i] = -1; } curr_weight = 0; } void start_order_undefined(void) { start_order(T_UNDEFINED); } void start_order_symbol(char *name) { currundef = get_collundef(name); start_order(T_SYMBOL); } void start_order_char(wchar_t wc) { collchar_t *cc; int32_t ref; start_order(T_CHAR); /* * If we last saw an ellipsis, then we need to close the range. * Handle that here. Note that we have to be careful because the * items *inside* the range are treated exclusiveley to the items * outside of the range. The ends of the range can have quite * different weights than the range members. */ if (lastorder == T_ELLIPSIS) { int i; if (wc < ellipsis_start) { fprintf(stderr, "malformed range!"); return; } while (ellipsis_start < wc) { /* * pick all of the saved weights for the * ellipsis. note that -1 encodes for the * ellipsis itself, which means to take the * current relative priority. */ if ((cc = get_collchar(ellipsis_start, 1)) == NULL) { INTERR; return; } for (i = 0; i < NUM_WT; i++) { collpri_t *p; if (((ref = ellipsis_weights[i]) == -1) || ((p = get_pri(ref)) == NULL) || (p->pri == -1)) { set_pri(cc->ref[i], nextpri, RESOLVED); } else { set_pri(cc->ref[i], ref, REFER); } ellipsis_weights[i] = 0; } ellipsis_start++; nextpri++; } } currchar = get_collchar(wc, 1); } void start_order_collelem(collelem_t *e) { start_order(T_COLLELEM); currelem = e; } void start_order_ellipsis(void) { int i; start_order(T_ELLIPSIS); if (lastorder != T_CHAR) { fprintf(stderr, "illegal starting point for range"); return; } for (i = 0; i < NUM_WT; i++) { ellipsis_weights[i] = order_weights[i]; } } void define_collelem(char *name, wchar_t *wcs) { collelem_t *e; int i; if (wcslen(wcs) >= COLLATE_STR_LEN) { fprintf(stderr,"expanded collation element too long"); return; } - if ((e = calloc(sizeof (*e), 1)) == NULL) { + if ((e = calloc(1, sizeof(*e))) == NULL) { fprintf(stderr, "out of memory"); return; } e->expand = wcs; e->symbol = name; /* * This is executed before the order statement, so we don't * know how many priorities we *really* need. We allocate one * for each possible weight. Not a big deal, as collating-elements * prove to be quite rare. */ for (i = 0; i < COLL_WEIGHTS_MAX; i++) { e->ref[i] = new_pri(); } /* A character sequence can only reduce to one element. */ if ((RB_FIND(elem_by_symbol, &elem_by_symbol, e) != NULL) || (RB_FIND(elem_by_expand, &elem_by_expand, e) != NULL)) { fprintf(stderr, "duplicate collating element definition"); free(e); return; } RB_INSERT(elem_by_symbol, &elem_by_symbol, e); RB_INSERT(elem_by_expand, &elem_by_expand, e); } void add_order_bit(int kw) { uint8_t bit = DIRECTIVE_UNDEF; switch (kw) { case T_FORWARD: bit = DIRECTIVE_FORWARD; break; case T_BACKWARD: bit = DIRECTIVE_BACKWARD; break; case T_POSITION: bit = DIRECTIVE_POSITION; break; default: INTERR; break; } collinfo.directive[collinfo.directive_count] |= bit; } void add_order_directive(void) { if (collinfo.directive_count >= COLL_WEIGHTS_MAX) { fprintf(stderr,"too many directives (max %d)", COLL_WEIGHTS_MAX); } collinfo.directive_count++; } static void add_order_pri(int32_t ref) { if (curr_weight >= NUM_WT) { fprintf(stderr,"too many weights (max %d)", NUM_WT); return; } order_weights[curr_weight] = ref; curr_weight++; } void add_order_collsym(collsym_t *s) { add_order_pri(s->ref); } void add_order_char(wchar_t wc) { collchar_t *cc; if ((cc = get_collchar(wc, 1)) == NULL) { INTERR; return; } add_order_pri(cc->ref[curr_weight]); } void add_order_collelem(collelem_t *e) { add_order_pri(e->ref[curr_weight]); } void add_order_ignore(void) { add_order_pri(pri_ignore); } void add_order_symbol(char *sym) { collundef_t *c; if ((c = get_collundef(sym)) == NULL) { INTERR; return; } add_order_pri(c->ref[curr_weight]); } void add_order_ellipsis(void) { /* special NULL value indicates self reference */ add_order_pri(0); } void add_order_subst(void) { subst_t srch; subst_t *s; int i; (void) memset(&srch, 0, sizeof (srch)); for (i = 0; i < curr_subst; i++) { srch.ref[i] = subst_weights[i]; subst_weights[i] = 0; } s = RB_FIND(substs_ref, &substs_ref[curr_weight], &srch); if (s == NULL) { - if ((s = calloc(sizeof (*s), 1)) == NULL) { + if ((s = calloc(1, sizeof(*s))) == NULL) { fprintf(stderr,"out of memory"); return; } s->key = new_pri(); /* * We use a self reference for our key, but we set a * high bit to indicate that this is a substitution * reference. This will expedite table lookups later, * and prevent table lookups for situations that don't * require it. (In short, its a big win, because we * can skip a lot of binary searching.) */ set_pri(s->key, (nextsubst[curr_weight] | COLLATE_SUBST_PRIORITY), RESOLVED); nextsubst[curr_weight] += 1; for (i = 0; i < curr_subst; i++) { s->ref[i] = srch.ref[i]; } RB_INSERT(substs_ref, &substs_ref[curr_weight], s); if (RB_FIND(substs, &substs[curr_weight], s) != NULL) { INTERR; return; } RB_INSERT(substs, &substs[curr_weight], s); } curr_subst = 0; /* * We are using the current (unique) priority as a search key * in the substitution table. */ add_order_pri(s->key); } static void add_subst_pri(int32_t ref) { if (curr_subst >= COLLATE_STR_LEN) { fprintf(stderr,"substitution string is too long"); return; } subst_weights[curr_subst] = ref; curr_subst++; } void add_subst_char(wchar_t wc) { collchar_t *cc; if (((cc = get_collchar(wc, 1)) == NULL) || (cc->wc != wc)) { INTERR; return; } /* we take the weight for the character at that position */ add_subst_pri(cc->ref[curr_weight]); } void add_subst_collelem(collelem_t *e) { add_subst_pri(e->ref[curr_weight]); } void add_subst_collsym(collsym_t *s) { add_subst_pri(s->ref); } void add_subst_symbol(char *ptr) { collundef_t *cu; if ((cu = get_collundef(ptr)) != NULL) { add_subst_pri(cu->ref[curr_weight]); } } void add_weight(int32_t ref, int pass) { weight_t srch; weight_t *w; srch.pri = resolve_pri(ref); /* No translation of ignores */ if (srch.pri == 0) return; /* Substitution priorities are not weights */ if (srch.pri & COLLATE_SUBST_PRIORITY) return; if (RB_FIND(weights, &weights[pass], &srch) != NULL) return; - if ((w = calloc(sizeof (*w), 1)) == NULL) { + if ((w = calloc(1, sizeof(*w))) == NULL) { fprintf(stderr, "out of memory"); return; } w->pri = srch.pri; RB_INSERT(weights, &weights[pass], w); } void add_weights(int32_t *refs) { int i; for (i = 0; i < NUM_WT; i++) { add_weight(refs[i], i); } } int32_t get_weight(int32_t ref, int pass) { weight_t srch; weight_t *w; int32_t pri; pri = resolve_pri(ref); if (pri & COLLATE_SUBST_PRIORITY) { return (pri); } if (pri <= 0) { return (pri); } srch.pri = pri; if ((w = RB_FIND(weights, &weights[pass], &srch)) == NULL) { INTERR; return (-1); } return (w->opt); } wchar_t * wsncpy(wchar_t *s1, const wchar_t *s2, size_t n) { wchar_t *os1 = s1; n++; while (--n > 0 && (*s1++ = *s2++) != 0) continue; if (n > 0) while (--n > 0) *s1++ = 0; return (os1); } #define RB_COUNT(x, name, head, cnt) do { \ (cnt) = 0; \ RB_FOREACH(x, name, (head)) { \ (cnt)++; \ } \ } while (0) #define RB_NUMNODES(type, name, head, cnt) do { \ type *t; \ cnt = 0; \ RB_FOREACH(t, name, head) { \ cnt++; \ } \ } while (0) void dump_collate(void) { FILE *f; int i, j, n; size_t sz; int32_t pri; collelem_t *ce; collchar_t *cc; subst_t *sb; char vers[COLLATE_STR_LEN]; collate_char_t chars[UCHAR_MAX + 1]; collate_large_t *large; collate_subst_t *subst[COLL_WEIGHTS_MAX]; collate_chain_t *chain; /* * We have to run through a preliminary pass to identify all the * weights that we use for each sorting level. */ for (i = 0; i < NUM_WT; i++) { add_weight(pri_ignore, i); } for (i = 0; i < NUM_WT; i++) { RB_FOREACH(sb, substs, &substs[i]) { for (j = 0; sb->ref[j]; j++) { add_weight(sb->ref[j], i); } } } RB_FOREACH(ce, elem_by_expand, &elem_by_expand) { add_weights(ce->ref); } RB_FOREACH(cc, collchars, &collchars) { add_weights(cc->ref); } /* * Now we walk the entire set of weights, removing the gaps * in the weights. This gives us optimum usage. The walk * occurs in priority. */ for (i = 0; i < NUM_WT; i++) { weight_t *w; RB_FOREACH(w, weights, &weights[i]) { w->opt = nweight[i]; nweight[i] += 1; } } (void) memset(&chars, 0, sizeof (chars)); (void) memset(vers, 0, COLLATE_STR_LEN); (void) strlcpy(vers, COLLATE_VERSION, sizeof (vers)); /* * We need to make sure we arrange for the UNDEFINED field * to show up. Also, set the total weight counts. */ for (i = 0; i < NUM_WT; i++) { if (resolve_pri(pri_undefined[i]) == -1) { set_pri(pri_undefined[i], -1, RESOLVED); /* they collate at the end of everything else */ collinfo.undef_pri[i] = COLLATE_MAX_PRIORITY; } collinfo.pri_count[i] = nweight[i]; } collinfo.pri_count[NUM_WT] = max_wide(); collinfo.undef_pri[NUM_WT] = COLLATE_MAX_PRIORITY; collinfo.directive[NUM_WT] = DIRECTIVE_UNDEFINED; /* * Ordinary character priorities */ for (i = 0; i <= UCHAR_MAX; i++) { if ((cc = get_collchar(i, 0)) != NULL) { for (j = 0; j < NUM_WT; j++) { chars[i].pri[j] = get_weight(cc->ref[j], j); } } else { for (j = 0; j < NUM_WT; j++) { chars[i].pri[j] = get_weight(pri_undefined[j], j); } /* * Per POSIX, for undefined characters, we * also have to add a last item, which is the * character code. */ chars[i].pri[NUM_WT] = i; } } /* * Substitution tables */ for (i = 0; i < NUM_WT; i++) { collate_subst_t *st = NULL; subst_t *temp; RB_COUNT(temp, substs, &substs[i], n); collinfo.subst_count[i] = n; if ((st = calloc(n, sizeof(collate_subst_t))) == NULL) { fprintf(stderr, "out of memory"); return; } n = 0; RB_FOREACH(sb, substs, &substs[i]) { if ((st[n].key = resolve_pri(sb->key)) < 0) { /* by definition these resolve! */ INTERR; } if (st[n].key != (n | COLLATE_SUBST_PRIORITY)) { INTERR; } for (j = 0; sb->ref[j]; j++) { st[n].pri[j] = get_weight(sb->ref[j], i); } n++; } if (n != collinfo.subst_count[i]) INTERR; subst[i] = st; } /* * Chains, i.e. collating elements */ RB_NUMNODES(collelem_t, elem_by_expand, &elem_by_expand, collinfo.chain_count); chain = calloc(collinfo.chain_count, sizeof(collate_chain_t)); if (chain == NULL) { fprintf(stderr, "out of memory"); return; } n = 0; RB_FOREACH(ce, elem_by_expand, &elem_by_expand) { (void) wsncpy(chain[n].str, ce->expand, COLLATE_STR_LEN); for (i = 0; i < NUM_WT; i++) { chain[n].pri[i] = get_weight(ce->ref[i], i); } n++; } if (n != collinfo.chain_count) INTERR; /* * Large (> UCHAR_MAX) character priorities */ RB_NUMNODES(collchar_t, collchars, &collchars, n); large = calloc(n, sizeof(collate_large_t)); if (large == NULL) { fprintf(stderr, "out of memory"); return; } i = 0; RB_FOREACH(cc, collchars, &collchars) { int undef = 0; /* we already gathered those */ if (cc->wc <= UCHAR_MAX) continue; for (j = 0; j < NUM_WT; j++) { if ((pri = get_weight(cc->ref[j], j)) < 0) { undef = 1; } if (undef && (pri >= 0)) { /* if undefined, then all priorities are */ INTERR; } else { large[i].pri.pri[j] = pri; } } if (!undef) { large[i].val = cc->wc; collinfo.large_count = i++; } } if ((f = open_category()) == NULL) { return; } /* Time to write the entire data set out */ if ((wr_category(vers, COLLATE_STR_LEN, f) < 0) || (wr_category(&collinfo, sizeof (collinfo), f) < 0) || (wr_category(&chars, sizeof (chars), f) < 0)) { return; } for (i = 0; i < NUM_WT; i++) { sz = sizeof (collate_subst_t) * collinfo.subst_count[i]; if (wr_category(subst[i], sz, f) < 0) { return; } } sz = sizeof (collate_chain_t) * collinfo.chain_count; if (wr_category(chain, sz, f) < 0) { return; } sz = sizeof (collate_large_t) * collinfo.large_count; if (wr_category(large, sz, f) < 0) { return; } close_category(f); } Index: stable/11/usr.bin/netstat/pfkey.c =================================================================== --- stable/11/usr.bin/netstat/pfkey.c (revision 307696) +++ stable/11/usr.bin/netstat/pfkey.c (revision 307697) @@ -1,208 +1,207 @@ /* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */ /* $KAME: ipsec.c,v 1.25 2001/03/12 09:04:39 itojun Exp $ */ /*- * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * 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 project 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 PROJECT 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 PROJECT 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. */ /*- * Copyright (c) 1983, 1988, 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. * 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. */ #if 0 #ifndef lint static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #ifdef IPSEC #include #endif #include #include #include #include #include #include #include "netstat.h" #ifdef IPSEC static const char *pfkey_msgtypenames[] = { "reserved", "getspi", "update", "add", "delete", "get", "acquire", "register", "expire", "flush", "dump", "x_promisc", "x_pchange", "x_spdupdate", "x_spdadd", "x_spddelete", "x_spdget", "x_spdacquire", "x_spddump", "x_spdflush", "x_spdsetidx", "x_spdexpire", "x_spddelete2" }; static const char *pfkey_msgtype_names (int); static const char * pfkey_msgtype_names(int x) { - const int max = - sizeof(pfkey_msgtypenames)/sizeof(pfkey_msgtypenames[0]); + const int max = nitems(pfkey_msgtypenames); static char buf[20]; if (x < max && pfkey_msgtypenames[x]) return pfkey_msgtypenames[x]; snprintf(buf, sizeof(buf), "#%d", x); return buf; } void pfkey_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct pfkeystat pfkeystat; unsigned first, type; if (off == 0) return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); kread_counters(off, (char *)&pfkeystat, sizeof(pfkeystat)); #define p(f, m) if (pfkeystat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)pfkeystat.f, plural(pfkeystat.f)) /* userland -> kernel */ p(out_total, "\t{:sent-requests/%ju} " "{N:/request%s sent from userland}\n"); p(out_bytes, "\t{:sent-bytes/%ju} " "{N:/byte%s sent from userland}\n"); for (first = 1, type = 0; type userland */ p(in_total, "\t{:received-requests/%ju} " "{N:/request%s sent to userland}\n"); p(in_bytes, "\t{:received-bytes/%ju} " "{N:/byte%s sent to userland}\n"); for (first = 1, type = 0; type < sizeof(pfkeystat.in_msgtype)/sizeof(pfkeystat.in_msgtype[0]); type++) { if (pfkeystat.in_msgtype[type] <= 0) continue; if (first) { xo_open_list("input-histogram"); xo_emit("\t{T:histogram by message type}:\n"); first = 0; } xo_open_instance("input-histogram"); xo_emit("\t\t{k:type/%s}: {:count/%ju}\n", pfkey_msgtype_names(type), (uintmax_t)pfkeystat.in_msgtype[type]); xo_close_instance("input-histogram"); } if (!first) xo_close_list("input-histogram"); p(in_msgtarget[KEY_SENDUP_ONE], "\t{:received-one-socket/%ju} " "{N:/message%s toward single socket}\n"); p(in_msgtarget[KEY_SENDUP_ALL], "\t{:received-all-sockets/%ju} " "{N:/message%s toward all sockets}\n"); p(in_msgtarget[KEY_SENDUP_REGISTERED], "\t{:received-registered-sockets/%ju} " "{N:/message%s toward registered sockets}\n"); p(in_nomem, "\t{:discarded-no-memory/%ju} " "{N:/message%s with memory allocation failure}\n"); #undef p xo_close_container(name); } #endif /* IPSEC */ Index: stable/11/usr.bin/procstat/procstat_files.c =================================================================== --- stable/11/usr.bin/procstat/procstat_files.c (revision 307696) +++ stable/11/usr.bin/procstat/procstat_files.c (revision 307697) @@ -1,576 +1,575 @@ /*- * Copyright (c) 2007-2011 Robert N. M. Watson * Copyright (c) 2015 Allan Jude * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "procstat.h" static const char * protocol_to_string(int domain, int type, int protocol) { switch (domain) { case AF_INET: case AF_INET6: switch (protocol) { case IPPROTO_TCP: return ("TCP"); case IPPROTO_UDP: return ("UDP"); case IPPROTO_ICMP: return ("ICM"); case IPPROTO_RAW: return ("RAW"); case IPPROTO_SCTP: return ("SCT"); case IPPROTO_DIVERT: return ("IPD"); default: return ("IP?"); } case AF_LOCAL: switch (type) { case SOCK_STREAM: return ("UDS"); case SOCK_DGRAM: return ("UDD"); default: return ("UD?"); } default: return ("?"); } } static void addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen) { char buffer2[INET6_ADDRSTRLEN]; struct sockaddr_in6 *sin6; struct sockaddr_in *sin; struct sockaddr_un *sun; switch (ss->ss_family) { case AF_LOCAL: sun = (struct sockaddr_un *)ss; if (strlen(sun->sun_path) == 0) strlcpy(buffer, "-", buflen); else strlcpy(buffer, sun->sun_path, buflen); break; case AF_INET: sin = (struct sockaddr_in *)ss; snprintf(buffer, buflen, "%s:%d", inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)ss; if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2, sizeof(buffer2)) != NULL) snprintf(buffer, buflen, "%s.%d", buffer2, ntohs(sin6->sin6_port)); else strlcpy(buffer, "-", buflen); break; default: strlcpy(buffer, "", buflen); break; } } static struct cap_desc { uint64_t cd_right; const char *cd_desc; } cap_desc[] = { /* General file I/O. */ { CAP_READ, "rd" }, { CAP_WRITE, "wr" }, { CAP_SEEK, "se" }, { CAP_MMAP, "mm" }, { CAP_CREATE, "cr" }, { CAP_FEXECVE, "fe" }, { CAP_FSYNC, "fy" }, { CAP_FTRUNCATE, "ft" }, /* VFS methods. */ { CAP_FCHDIR, "cd" }, { CAP_FCHFLAGS, "cf" }, { CAP_FCHMOD, "cm" }, { CAP_FCHOWN, "cn" }, { CAP_FCNTL, "fc" }, { CAP_FLOCK, "fl" }, { CAP_FPATHCONF, "fp" }, { CAP_FSCK, "fk" }, { CAP_FSTAT, "fs" }, { CAP_FSTATFS, "sf" }, { CAP_FUTIMES, "fu" }, { CAP_LINKAT_SOURCE, "ls" }, { CAP_LINKAT_TARGET, "lt" }, { CAP_MKDIRAT, "md" }, { CAP_MKFIFOAT, "mf" }, { CAP_MKNODAT, "mn" }, { CAP_RENAMEAT_SOURCE, "rs" }, { CAP_RENAMEAT_TARGET, "rt" }, { CAP_SYMLINKAT, "sl" }, { CAP_UNLINKAT, "un" }, /* Lookups - used to constrain *at() calls. */ { CAP_LOOKUP, "lo" }, /* Extended attributes. */ { CAP_EXTATTR_GET, "eg" }, { CAP_EXTATTR_SET, "es" }, { CAP_EXTATTR_DELETE, "ed" }, { CAP_EXTATTR_LIST, "el" }, /* Access Control Lists. */ { CAP_ACL_GET, "ag" }, { CAP_ACL_SET, "as" }, { CAP_ACL_DELETE, "ad" }, { CAP_ACL_CHECK, "ac" }, /* Socket operations. */ { CAP_ACCEPT, "at" }, { CAP_BIND, "bd" }, { CAP_CONNECT, "co" }, { CAP_GETPEERNAME, "pn" }, { CAP_GETSOCKNAME, "sn" }, { CAP_GETSOCKOPT, "gs" }, { CAP_LISTEN, "ln" }, { CAP_PEELOFF, "pf" }, { CAP_SETSOCKOPT, "ss" }, { CAP_SHUTDOWN, "sh" }, /* Mandatory Access Control. */ { CAP_MAC_GET, "mg" }, { CAP_MAC_SET, "ms" }, /* Methods on semaphores. */ { CAP_SEM_GETVALUE, "sg" }, { CAP_SEM_POST, "sp" }, { CAP_SEM_WAIT, "sw" }, /* Event monitoring and posting. */ { CAP_EVENT, "ev" }, { CAP_KQUEUE_EVENT, "ke" }, { CAP_KQUEUE_CHANGE, "kc" }, /* Strange and powerful rights that should not be given lightly. */ { CAP_IOCTL, "io" }, { CAP_TTYHOOK, "ty" }, /* Process management via process descriptors. */ { CAP_PDGETPID, "pg" }, { CAP_PDWAIT, "pw" }, { CAP_PDKILL, "pk" }, /* * Rights that allow to use bindat(2) and connectat(2) syscalls on a * directory descriptor. */ { CAP_BINDAT, "ba" }, { CAP_CONNECTAT, "ca" }, /* Aliases and defines that combine multiple rights. */ { CAP_PREAD, "prd" }, { CAP_PWRITE, "pwr" }, { CAP_MMAP_R, "mmr" }, { CAP_MMAP_W, "mmw" }, { CAP_MMAP_X, "mmx" }, { CAP_MMAP_RW, "mrw" }, { CAP_MMAP_RX, "mrx" }, { CAP_MMAP_WX, "mwx" }, { CAP_MMAP_RWX, "mma" }, { CAP_RECV, "re" }, { CAP_SEND, "sd" }, { CAP_SOCK_CLIENT, "scl" }, { CAP_SOCK_SERVER, "ssr" }, }; -static const u_int cap_desc_count = sizeof(cap_desc) / - sizeof(cap_desc[0]); +static const u_int cap_desc_count = nitems(cap_desc); static u_int width_capability(cap_rights_t *rightsp) { u_int count, i, width; count = 0; width = 0; for (i = 0; i < cap_desc_count; i++) { if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) { width += strlen(cap_desc[i].cd_desc); if (count) width++; count++; } } return (width); } static void print_capability(cap_rights_t *rightsp, u_int capwidth) { u_int count, i, width; count = 0; width = 0; for (i = width_capability(rightsp); i < capwidth; i++) { if (i != 0) xo_emit(" "); else xo_emit("-"); } xo_open_list("capabilities"); for (i = 0; i < cap_desc_count; i++) { if (cap_rights_is_set(rightsp, cap_desc[i].cd_right)) { xo_emit("{D:/%s}{l:capabilities/%s}", count ? "," : "", cap_desc[i].cd_desc); width += strlen(cap_desc[i].cd_desc); if (count) width++; count++; } } xo_close_list("capabilities"); } void procstat_files(struct procstat *procstat, struct kinfo_proc *kipp) { struct sockstat sock; struct filestat_list *head; struct filestat *fst; const char *str; struct vnstat vn; u_int capwidth, width; int error; char src_addr[PATH_MAX]; char dst_addr[PATH_MAX]; /* * To print the header in capability mode, we need to know the width * of the widest capability string. Even if we get no processes * back, we will print the header, so we defer aborting due to a lack * of processes until after the header logic. */ capwidth = 0; head = procstat_getfiles(procstat, kipp, 0); if (head != NULL && Cflag) { STAILQ_FOREACH(fst, head, next) { width = width_capability(&fst->fs_cap_rights); if (width > capwidth) capwidth = width; } if (capwidth < strlen("CAPABILITIES")) capwidth = strlen("CAPABILITIES"); } if (!hflag) { if (Cflag) xo_emit("{T:/%5s %-16s %5s %1s %-8s %-*s " "%-3s %-12s}\n", "PID", "COMM", "FD", "T", "FLAGS", capwidth, "CAPABILITIES", "PRO", "NAME"); else xo_emit("{T:/%5s %-16s %5s %1s %1s %-8s " "%3s %7s %-3s %-12s}\n", "PID", "COMM", "FD", "T", "V", "FLAGS", "REF", "OFFSET", "PRO", "NAME"); } if (head == NULL) return; xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid); xo_emit("{e:command/%-16s/%s}", kipp->ki_comm); xo_open_list("files"); STAILQ_FOREACH(fst, head, next) { xo_open_instance("files"); xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); if (fst->fs_uflags & PS_FST_UFLAG_CTTY) xo_emit("{P: }{:fd/%s} ", "ctty"); else if (fst->fs_uflags & PS_FST_UFLAG_CDIR) xo_emit("{P: }{:fd/%s} ", "cwd"); else if (fst->fs_uflags & PS_FST_UFLAG_JAIL) xo_emit("{P: }{:fd/%s} ", "jail"); else if (fst->fs_uflags & PS_FST_UFLAG_RDIR) xo_emit("{P: }{:fd/%s} ", "root"); else if (fst->fs_uflags & PS_FST_UFLAG_TEXT) xo_emit("{P: }{:fd/%s} ", "text"); else if (fst->fs_uflags & PS_FST_UFLAG_TRACE) xo_emit("{:fd/%s} ", "trace"); else xo_emit("{:fd/%5d} ", fst->fs_fd); switch (fst->fs_type) { case PS_FST_TYPE_VNODE: str = "v"; xo_emit("{eq:fd_type/vnode}"); break; case PS_FST_TYPE_SOCKET: str = "s"; xo_emit("{eq:fd_type/socket}"); break; case PS_FST_TYPE_PIPE: str = "p"; xo_emit("{eq:fd_type/pipe}"); break; case PS_FST_TYPE_FIFO: str = "f"; xo_emit("{eq:fd_type/fifo}"); break; case PS_FST_TYPE_KQUEUE: str = "k"; xo_emit("{eq:fd_type/kqueue}"); break; case PS_FST_TYPE_CRYPTO: str = "c"; xo_emit("{eq:fd_type/crypto}"); break; case PS_FST_TYPE_MQUEUE: str = "m"; xo_emit("{eq:fd_type/mqueue}"); break; case PS_FST_TYPE_SHM: str = "h"; xo_emit("{eq:fd_type/shm}"); break; case PS_FST_TYPE_PTS: str = "t"; xo_emit("{eq:fd_type/pts}"); break; case PS_FST_TYPE_SEM: str = "e"; xo_emit("{eq:fd_type/sem}"); break; case PS_FST_TYPE_NONE: str = "?"; xo_emit("{eq:fd_type/none}"); break; case PS_FST_TYPE_UNKNOWN: default: str = "?"; xo_emit("{eq:fd_type/unknown}"); break; } xo_emit("{d:fd_type/%1s/%s} ", str); if (!Cflag) { str = "-"; if (fst->fs_type == PS_FST_TYPE_VNODE) { error = procstat_get_vnode_info(procstat, fst, &vn, NULL); switch (vn.vn_type) { case PS_FST_VTYPE_VREG: str = "r"; xo_emit("{eq:vode_type/regular}"); break; case PS_FST_VTYPE_VDIR: str = "d"; xo_emit("{eq:vode_type/directory}"); break; case PS_FST_VTYPE_VBLK: str = "b"; xo_emit("{eq:vode_type/block}"); break; case PS_FST_VTYPE_VCHR: str = "c"; xo_emit("{eq:vode_type/character}"); break; case PS_FST_VTYPE_VLNK: str = "l"; xo_emit("{eq:vode_type/link}"); break; case PS_FST_VTYPE_VSOCK: str = "s"; xo_emit("{eq:vode_type/socket}"); break; case PS_FST_VTYPE_VFIFO: str = "f"; xo_emit("{eq:vode_type/fifo}"); break; case PS_FST_VTYPE_VBAD: str = "x"; xo_emit("{eq:vode_type/revoked_device}"); break; case PS_FST_VTYPE_VNON: str = "?"; xo_emit("{eq:vode_type/non}"); break; case PS_FST_VTYPE_UNKNOWN: default: str = "?"; xo_emit("{eq:vode_type/unknown}"); break; } } xo_emit("{d:vnode_type/%1s/%s} ", str); } xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_READ ? "r" : "-"); xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_WRITE ? "w" : "-"); xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_APPEND ? "a" : "-"); xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_ASYNC ? "s" : "-"); xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_SYNC ? "f" : "-"); xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_NONBLOCK ? "n" : "-"); xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_DIRECT ? "d" : "-"); xo_emit("{d:/%s}", fst->fs_fflags & PS_FST_FFLAG_HASLOCK ? "l" : "-"); xo_emit(" "); xo_open_list("fd_flags"); if (fst->fs_fflags & PS_FST_FFLAG_READ) xo_emit("{elq:fd_flags/read}"); if (fst->fs_fflags & PS_FST_FFLAG_WRITE) xo_emit("{elq:fd_flags/write}"); if (fst->fs_fflags & PS_FST_FFLAG_APPEND) xo_emit("{elq:fd_flags/append}"); if (fst->fs_fflags & PS_FST_FFLAG_ASYNC) xo_emit("{elq:fd_flags/async}"); if (fst->fs_fflags & PS_FST_FFLAG_SYNC) xo_emit("{elq:fd_flags/fsync}"); if (fst->fs_fflags & PS_FST_FFLAG_NONBLOCK) xo_emit("{elq:fd_flags/nonblocking}"); if (fst->fs_fflags & PS_FST_FFLAG_DIRECT) xo_emit("{elq:fd_flags/direct_io}"); if (fst->fs_fflags & PS_FST_FFLAG_HASLOCK) xo_emit("{elq:fd_flags/lock_held}"); xo_close_list("fd_flags"); if (!Cflag) { if (fst->fs_ref_count > -1) xo_emit("{:ref_count/%3d/%d} ", fst->fs_ref_count); else xo_emit("{q:ref_count/%3c/%c} ", '-'); if (fst->fs_offset > -1) xo_emit("{:offset/%7jd/%jd} ", (intmax_t)fst->fs_offset); else xo_emit("{q:offset/%7c/%c} ", '-'); } if (Cflag) { print_capability(&fst->fs_cap_rights, capwidth); xo_emit(" "); } switch (fst->fs_type) { case PS_FST_TYPE_SOCKET: error = procstat_get_socket_info(procstat, fst, &sock, NULL); if (error != 0) break; xo_emit("{:protocol/%-3s/%s} ", protocol_to_string(sock.dom_family, sock.type, sock.proto)); /* * While generally we like to print two addresses, * local and peer, for sockets, it turns out to be * more useful to print the first non-nul address for * local sockets, as typically they aren't bound and * connected, and the path strings can get long. */ if (sock.dom_family == AF_LOCAL) { struct sockaddr_un *sun = (struct sockaddr_un *)&sock.sa_local; if (sun->sun_path[0] != 0) addr_to_string(&sock.sa_local, src_addr, sizeof(src_addr)); else addr_to_string(&sock.sa_peer, src_addr, sizeof(src_addr)); xo_emit("{:path/%s}", src_addr); } else { addr_to_string(&sock.sa_local, src_addr, sizeof(src_addr)); addr_to_string(&sock.sa_peer, dst_addr, sizeof(dst_addr)); xo_emit("{:path/%s %s}", src_addr, dst_addr); } break; default: xo_emit("{:protocol/%-3s/%s} ", "-"); xo_emit("{:path/%-18s/%s}", fst->fs_path != NULL ? fst->fs_path : "-"); } xo_emit("\n"); xo_close_instance("files"); } xo_close_list("files"); procstat_freefiles(procstat, head); } Index: stable/11/usr.bin/rpcgen/rpc_main.c =================================================================== --- stable/11/usr.bin/rpcgen/rpc_main.c (revision 307696) +++ stable/11/usr.bin/rpcgen/rpc_main.c (revision 307697) @@ -1,1267 +1,1267 @@ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #if 0 #ifndef lint #ident "@(#)rpc_main.c 1.21 94/04/25 SMI" static char sccsid[] = "@(#)rpc_main.c 1.30 89/03/30 (C) 1987 SMI"; #endif #endif #include __FBSDID("$FreeBSD$"); /* * rpc_main.c, Top level of the RPC protocol compiler. * Copyright (C) 1987, Sun Microsystems, Inc. */ #include #include #include #include #include #include #include #include #include #include "rpc_parse.h" #include "rpc_scan.h" #include "rpc_util.h" static void c_output(const char *, const char *, int, const char *); static void h_output(const char *, const char *, int, const char *, int); static void l_output(const char *, const char *, int, const char *); static void t_output(const char *, const char *, int, const char *); static void clnt_output(const char *, const char *, int, const char * ); static char *generate_guard(const char *); static void c_initialize(void); static void usage(void); static void options_usage(void); static int do_registers(int, const char **); static int parseargs(int, const char **, struct commandline *); static void svc_output(const char *, const char *, int, const char *); static void mkfile_output(struct commandline *); static void s_output(int, const char **, const char *, const char *, int, const char *, int, int); #define EXTEND 1 /* alias for TRUE */ #define DONT_EXTEND 0 /* alias for FALSE */ static const char *svcclosetime = "120"; static const char *CPP = NULL; static const char CPPFLAGS[] = "-C"; static char pathbuf[MAXPATHLEN + 1]; static const char *allv[] = { "rpcgen", "-s", "udp", "-s", "tcp", }; -static int allc = sizeof (allv)/sizeof (allv[0]); +static int allc = nitems(allv); static const char *allnv[] = { "rpcgen", "-s", "netpath", }; -static int allnc = sizeof (allnv)/sizeof (allnv[0]); +static int allnc = nitems(allnv); /* * machinations for handling expanding argument list */ static void addarg(const char *); /* add another argument to the list */ static void insarg(int, const char *); /* insert arg at specified location */ static void clear_args(void); /* clear argument list */ static void checkfiles(const char *, const char *); /* check if out file already exists */ #define ARGLISTLEN 20 #define FIXEDARGS 0 static char *arglist[ARGLISTLEN]; static int argcount = FIXEDARGS; int nonfatalerrors; /* errors */ int inetdflag = 0; /* Support for inetd is disabled by default, use -I */ int pmflag = 0; /* Support for port monitors is disabled by default */ int tirpc_socket = 1; /* TI-RPC on socket, no TLI library */ int logflag; /* Use syslog instead of fprintf for errors */ int tblflag; /* Support for dispatch table file */ int mtflag = 0; /* Support for MT */ #define INLINE 0 /* length at which to start doing an inline */ int inline_size = INLINE; /* * Length at which to start doing an inline. INLINE = default * if 0, no xdr_inline code */ int indefinitewait; /* If started by port monitors, hang till it wants */ int exitnow; /* If started by port monitors, exit after the call */ int timerflag; /* TRUE if !indefinite && !exitnow */ int newstyle; /* newstyle of passing arguments (by value) */ int CCflag = 0; /* C++ files */ static int allfiles; /* generate all files */ int tirpcflag = 1; /* generating code for tirpc, by default */ xdrfunc *xdrfunc_head = NULL; /* xdr function list */ xdrfunc *xdrfunc_tail = NULL; /* xdr function list */ pid_t childpid; int main(int argc, const char *argv[]) { struct commandline cmd; (void) memset((char *)&cmd, 0, sizeof (struct commandline)); clear_args(); if (!parseargs(argc, argv, &cmd)) usage(); /* * Only the client and server side stubs are likely to be customized, * so in that case only, check if the outfile exists, and if so, * print an error message and exit. */ if (cmd.Ssflag || cmd.Scflag || cmd.makefileflag) { checkfiles(cmd.infile, cmd.outfile); } else checkfiles(cmd.infile, NULL); if (cmd.cflag) { c_output(cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile); } else if (cmd.hflag) { h_output(cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile, cmd.hflag); } else if (cmd.lflag) { l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile); } else if (cmd.sflag || cmd.mflag || (cmd.nflag)) { s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND, cmd.outfile, cmd.mflag, cmd.nflag); } else if (cmd.tflag) { t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile); } else if (cmd.Ssflag) { svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND, cmd.outfile); } else if (cmd.Scflag) { clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND, cmd.outfile); } else if (cmd.makefileflag) { mkfile_output(&cmd); } else { /* the rescans are required, since cpp may effect input */ c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c"); reinitialize(); h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h", cmd.hflag); reinitialize(); l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c"); reinitialize(); if (inetdflag || !tirpcflag) s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND, "_svc.c", cmd.mflag, cmd.nflag); else s_output(allnc, allnv, cmd.infile, "-DRPC_SVC", EXTEND, "_svc.c", cmd.mflag, cmd.nflag); if (tblflag) { reinitialize(); t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i"); } if (allfiles) { reinitialize(); svc_output(cmd.infile, "-DRPC_SERVER", EXTEND, "_server.c"); reinitialize(); clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND, "_client.c"); } if (allfiles || (cmd.makefileflag == 1)){ reinitialize(); mkfile_output(&cmd); } } exit(nonfatalerrors); /* NOTREACHED */ } /* * add extension to filename */ static char * extendfile(const char *path, const char *ext) { char *res; const char *p; const char *file; if ((file = strrchr(path, '/')) == NULL) file = path; else file++; res = xmalloc(strlen(file) + strlen(ext) + 1); p = strrchr(file, '.'); if (p == NULL) { p = file + strlen(file); } (void) strcpy(res, file); (void) strcpy(res + (p - file), ext); return (res); } /* * Open output file with given extension */ static void open_output(const char *infile, const char *outfile) { if (outfile == NULL) { fout = stdout; return; } if (infile != NULL && streq(outfile, infile)) { warnx("%s already exists. No output generated", infile); crash(); } fout = fopen(outfile, "w"); if (fout == NULL) { warn("unable to open %s", outfile); crash(); } record_open(outfile); return; } static void add_warning(void) { f_print(fout, "/*\n"); f_print(fout, " * Please do not edit this file.\n"); f_print(fout, " * It was generated using rpcgen.\n"); f_print(fout, " */\n\n"); } /* clear list of arguments */ static void clear_args(void) { int i; for (i = FIXEDARGS; i < ARGLISTLEN; i++) arglist[i] = NULL; argcount = FIXEDARGS; } /* prepend C-preprocessor and flags before arguments */ static void prepend_cpp(void) { int idx = 1; const char *var; char *dupvar, *s, *t; if (CPP != NULL) insarg(0, CPP); else if ((var = getenv("RPCGEN_CPP")) == NULL) insarg(0, "/usr/bin/cpp"); else { /* Parse command line in a rudimentary way */ dupvar = xstrdup(var); for (s = dupvar, idx = 0; (t = strsep(&s, " \t")) != NULL; ) { if (t[0]) insarg(idx++, t); } free(dupvar); } insarg(idx, CPPFLAGS); } /* * Open input file with given define for C-preprocessor */ static void open_input(const char *infile, const char *define) { int pd[2]; infilename = (infile == NULL) ? "" : infile; (void) pipe(pd); switch (childpid = fork()) { case 0: prepend_cpp(); addarg(define); if (infile) addarg(infile); addarg((char *)NULL); (void) close(1); (void) dup2(pd[1], 1); (void) close(pd[0]); execvp(arglist[0], arglist); err(1, "execvp %s", arglist[0]); case -1: err(1, "fork"); } (void) close(pd[1]); fin = fdopen(pd[0], "r"); if (fin == NULL) { warn("%s", infilename); crash(); } } /* valid tirpc nettypes */ static const char *valid_ti_nettypes[] = { "netpath", "visible", "circuit_v", "datagram_v", "circuit_n", "datagram_n", "udp", "tcp", "raw", NULL }; /* valid inetd nettypes */ static const char *valid_i_nettypes[] = { "udp", "tcp", NULL }; static int check_nettype(const char *name, const char *list_to_check[]) { int i; for (i = 0; list_to_check[i] != NULL; i++) { if (strcmp(name, list_to_check[i]) == 0) { return (1); } } warnx("illegal nettype :\'%s\'", name); return (0); } static const char * file_name(const char *file, const char *ext) { char *temp; temp = extendfile(file, ext); if (access(temp, F_OK) != -1) return (temp); else return (" "); } static void c_output(const char *infile, const char *define, int extend, const char *outfile) { definition *def; char *include; const char *outfilename; long tell; c_initialize(); open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); /* .h file already contains rpc/rpc.h */ } else f_print(fout, "#include \n"); tell = ftell(fout); while ( (def = get_definition()) ) { emit(def); } if (extend && tell == ftell(fout)) { (void) unlink(outfilename); } } void c_initialize(void) { /* add all the starting basic types */ add_type(1, "int"); add_type(1, "long"); add_type(1, "short"); add_type(1, "bool"); add_type(1, "u_int"); add_type(1, "u_long"); add_type(1, "u_short"); } static const char rpcgen_table_dcl[] = "struct rpcgen_table {\n\ char *(*proc)(); \n\ xdrproc_t xdr_arg; \n\ unsigned len_arg; \n\ xdrproc_t xdr_res; \n\ unsigned len_res; \n\ }; \n"; char * generate_guard(const char *pathname) { const char *filename; char *guard, *tmp, *stopat; filename = strrchr(pathname, '/'); /* find last component */ filename = ((filename == NULL) ? pathname : filename+1); guard = xstrdup(filename); stopat = strrchr(guard, '.'); /* * Convert to a valid C macro name and make it upper case. * Map macro unfriendly characterss to '_'. */ for (tmp = guard; *tmp != '\000'; ++tmp) { if (islower(*tmp)) *tmp = toupper(*tmp); else if (isupper(*tmp) || *tmp == '_') /* OK for C */; else if (tmp == guard) *tmp = '_'; else if (isdigit(*tmp)) /* OK for all but first character */; else if (tmp == stopat) { *tmp = '\0'; break; } else *tmp = '_'; } /* * Can't have a '_' in front, because it'll end up being "__". * "__" macros shoudln't be used. So, remove all of the * '_' characters from the front. */ if (*guard == '_') { for (tmp = guard; *tmp == '_'; ++tmp) ; strcpy(guard, tmp); } guard = extendfile(guard, "_H_RPCGEN"); return (guard); } /* * Compile into an XDR header file */ static void h_output(const char *infile, const char *define, int extend, const char *outfile, int headeronly) { definition *def; const char *outfilename; long tell; const char *guard; list *l; xdrfunc *xdrfuncp; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); if (outfilename || infile){ guard = generate_guard(outfilename ? outfilename: infile); } else guard = "STDIN_"; f_print(fout, "#ifndef _%s\n#define _%s\n\n", guard, guard); f_print(fout, "#include \n"); if (mtflag) f_print(fout, "#include \n"); /* put the C++ support */ if (!CCflag) { f_print(fout, "\n#ifdef __cplusplus\n"); f_print(fout, "extern \"C\" {\n"); f_print(fout, "#endif\n\n"); } /* put in a typedef for quadprecision. Only with Cflag */ tell = ftell(fout); /* print data definitions */ while ( (def = get_definition()) ) { print_datadef(def, headeronly); } /* * print function declarations. * Do this after data definitions because they might be used as * arguments for functions */ for (l = defined; l != NULL; l = l->next) { print_funcdef(l->val, headeronly); } /* Now print all xdr func declarations */ if (xdrfunc_head != NULL){ f_print(fout, "\n/* the xdr functions */\n"); if (CCflag){ f_print(fout, "\n#ifdef __cplusplus\n"); f_print(fout, "extern \"C\" {\n"); f_print(fout, "#endif\n"); } xdrfuncp = xdrfunc_head; while (xdrfuncp != NULL){ print_xdr_func_def(xdrfuncp->name, xdrfuncp->pointerp); xdrfuncp = xdrfuncp->next; } } if (extend && tell == ftell(fout)) { (void) unlink(outfilename); } else if (tblflag) { f_print(fout, rpcgen_table_dcl); } f_print(fout, "\n#ifdef __cplusplus\n"); f_print(fout, "}\n"); f_print(fout, "#endif\n"); f_print(fout, "\n#endif /* !_%s */\n", guard); } /* * Compile into an RPC service */ static void s_output(int argc, const char *argv[], const char *infile, const char *define, int extend, const char *outfile, int nomain, int netflag) { char *include; definition *def; int foundprogram = 0; const char *outfilename; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); } else f_print(fout, "#include \n"); f_print(fout, "#include \n"); f_print(fout, "#include /* getenv, exit */\n"); f_print (fout, "#include /* for pmap_unset */\n"); f_print (fout, "#include /* strcmp */\n"); if (tirpcflag) f_print(fout, "#include \n"); if (strcmp(svcclosetime, "-1") == 0) indefinitewait = 1; else if (strcmp(svcclosetime, "0") == 0) exitnow = 1; else if (inetdflag || pmflag) { f_print(fout, "#include \n"); timerflag = 1; } if (!tirpcflag && inetdflag) f_print(fout, "#include /* TIOCNOTTY */\n"); if (inetdflag || pmflag) { f_print(fout, "#ifdef __cplusplus\n"); f_print(fout, "#include /* getdtablesize, open */\n"); f_print(fout, "#endif /* __cplusplus */\n"); } if (tirpcflag) { f_print(fout, "#include /* open */\n"); f_print(fout, "#include /* fork / setsid */\n"); f_print(fout, "#include \n"); } f_print(fout, "#include \n"); if (inetdflag || !tirpcflag) { f_print(fout, "#include \n"); f_print(fout, "#include \n"); } if ((netflag || pmflag) && tirpcflag && !nomain) { f_print(fout, "#include \n"); } if (tirpcflag) f_print(fout, "#include /* rlimit */\n"); if (logflag || inetdflag || pmflag || tirpcflag) f_print(fout, "#include \n"); f_print(fout, "\n#ifdef DEBUG\n#define RPC_SVC_FG\n#endif\n"); if (timerflag) f_print(fout, "\n#define _RPCSVC_CLOSEDOWN %s\n", svcclosetime); while ( (def = get_definition()) ) { foundprogram |= (def->def_kind == DEF_PROGRAM); } if (extend && !foundprogram) { (void) unlink(outfilename); return; } write_most(infile, netflag, nomain); if (!nomain) { if (!do_registers(argc, argv)) { if (outfilename) (void) unlink(outfilename); usage(); } write_rest(); } } /* * generate client side stubs */ static void l_output(const char *infile, const char *define, int extend, const char *outfile) { char *include; definition *def; int foundprogram = 0; const char *outfilename; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); f_print (fout, "#include /* for memset */\n"); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); } else f_print(fout, "#include \n"); while ( (def = get_definition()) ) { foundprogram |= (def->def_kind == DEF_PROGRAM); } if (extend && !foundprogram) { (void) unlink(outfilename); return; } write_stubs(); } /* * generate the dispatch table */ static void t_output(const char *infile, const char *define, int extend, const char *outfile) { definition *def; int foundprogram = 0; const char *outfilename; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; open_output(infile, outfilename); add_warning(); while ( (def = get_definition()) ) { foundprogram |= (def->def_kind == DEF_PROGRAM); } if (extend && !foundprogram) { (void) unlink(outfilename); return; } write_tables(); } /* sample routine for the server template */ static void svc_output(const char *infile, const char *define, int extend, const char *outfile) { definition *def; char *include; const char *outfilename; long tell; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; checkfiles(infile, outfilename); /* * Check if outfile already exists. * if so, print an error message and exit */ open_output(infile, outfilename); add_sample_msg(); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); } else f_print(fout, "#include \n"); tell = ftell(fout); while ( (def = get_definition()) ) { write_sample_svc(def); } if (extend && tell == ftell(fout)) { (void) unlink(outfilename); } } /* sample main routine for client */ static void clnt_output(const char *infile, const char *define, int extend, const char *outfile) { definition *def; char *include; const char *outfilename; long tell; int has_program = 0; open_input(infile, define); outfilename = extend ? extendfile(infile, outfile) : outfile; checkfiles(infile, outfilename); /* * Check if outfile already exists. * if so, print an error message and exit */ open_output(infile, outfilename); add_sample_msg(); if (infile && (include = extendfile(infile, ".h"))) { f_print(fout, "#include \"%s\"\n", include); free(include); } else f_print(fout, "#include \n"); f_print(fout, "#include \n"); f_print(fout, "#include \n"); tell = ftell(fout); while ( (def = get_definition()) ) { has_program += write_sample_clnt(def); } if (has_program) write_sample_clnt_main(); if (extend && tell == ftell(fout)) { (void) unlink(outfilename); } } static void mkfile_output(struct commandline *cmd) { const char *mkfilename, *clientname, *clntname, *xdrname, *hdrname; const char *servername, *svcname, *servprogname, *clntprogname; char *temp, *mkftemp; svcname = file_name(cmd->infile, "_svc.c"); clntname = file_name(cmd->infile, "_clnt.c"); xdrname = file_name(cmd->infile, "_xdr.c"); hdrname = file_name(cmd->infile, ".h"); if (allfiles){ servername = extendfile(cmd->infile, "_server.c"); clientname = extendfile(cmd->infile, "_client.c"); }else{ servername = " "; clientname = " "; } servprogname = extendfile(cmd->infile, "_server"); clntprogname = extendfile(cmd->infile, "_client"); if (allfiles){ mkftemp = xmalloc(strlen("makefile.") + strlen(cmd->infile) + 1); temp = strrchr(cmd->infile, '.'); strcpy(mkftemp, "makefile."); (void) strncat(mkftemp, cmd->infile, (temp - cmd->infile)); mkfilename = mkftemp; } else mkfilename = cmd->outfile; checkfiles(NULL, mkfilename); open_output(NULL, mkfilename); f_print(fout, "\n# This is a template makefile generated\ by rpcgen \n"); f_print(fout, "\n# Parameters \n\n"); f_print(fout, "CLIENT = %s\nSERVER = %s\n\n", clntprogname, servprogname); f_print(fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n"); f_print(fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n"); f_print(fout, "SOURCES.x = %s\n\n", cmd->infile); f_print(fout, "TARGETS_SVC.c = %s %s %s \n", svcname, servername, xdrname); f_print(fout, "TARGETS_CLNT.c = %s %s %s \n", clntname, clientname, xdrname); f_print(fout, "TARGETS = %s %s %s %s %s %s\n\n", hdrname, xdrname, clntname, svcname, clientname, servername); f_print(fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) \ $(TARGETS_CLNT.c:%%.c=%%.o) "); f_print(fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) \ $(TARGETS_SVC.c:%%.c=%%.o) "); f_print(fout, "\n# Compiler flags \n"); if (mtflag) f_print(fout, "\nCFLAGS += -D_REENTRANT -D_THEAD_SAFE \nLDLIBS += -pthread\n"); f_print(fout, "RPCGENFLAGS = \n"); f_print(fout, "\n# Targets \n\n"); f_print(fout, "all : $(CLIENT) $(SERVER)\n\n"); f_print(fout, "$(TARGETS) : $(SOURCES.x) \n"); f_print(fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n"); if (allfiles) { f_print(fout, "\trpcgen -Sc $(RPCGENFLAGS) $(SOURCES.x) -o %s\n\n", clientname); f_print(fout, "\trpcgen -Ss $(RPCGENFLAGS) $(SOURCES.x) -o %s\n\n", servername); } f_print(fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) \ $(TARGETS_CLNT.c) \n\n"); f_print(fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) \ $(TARGETS_SVC.c) \n\n"); f_print(fout, "$(CLIENT) : $(OBJECTS_CLNT) \n"); f_print(fout, "\t$(CC) -o $(CLIENT) $(OBJECTS_CLNT) \ $(LDLIBS) \n\n"); f_print(fout, "$(SERVER) : $(OBJECTS_SVC) \n"); f_print(fout, "\t$(CC) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n"); f_print(fout, "clean:\n\t rm -f core $(TARGETS) $(OBJECTS_CLNT) \ $(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n"); } /* * Perform registrations for service output * Return 0 if failed; 1 otherwise. */ static int do_registers(int argc, const char *argv[]) { int i; if (inetdflag || !tirpcflag) { for (i = 1; i < argc; i++) { if (streq(argv[i], "-s")) { if (!check_nettype(argv[i + 1], valid_i_nettypes)) return (0); write_inetd_register(argv[i + 1]); i++; } } } else { for (i = 1; i < argc; i++) if (streq(argv[i], "-s")) { if (!check_nettype(argv[i + 1], valid_ti_nettypes)) return (0); write_nettype_register(argv[i + 1]); i++; } else if (streq(argv[i], "-n")) { write_netid_register(argv[i + 1]); i++; } } return (1); } /* * Add another argument to the arg list */ static void addarg(const char *cp) { if (argcount >= ARGLISTLEN) { warnx("too many defines"); crash(); /*NOTREACHED*/ } if (cp != NULL) arglist[argcount++] = xstrdup(cp); else arglist[argcount++] = NULL; } /* * Insert an argument at the specified location */ static void insarg(int place, const char *cp) { int i; if (argcount >= ARGLISTLEN) { warnx("too many defines"); crash(); /*NOTREACHED*/ } /* Move up existing arguments */ for (i = argcount - 1; i >= place; i--) arglist[i + 1] = arglist[i]; arglist[place] = xstrdup(cp); argcount++; } /* * if input file is stdin and an output file is specified then complain * if the file already exists. Otherwise the file may get overwritten * If input file does not exist, exit with an error */ static void checkfiles(const char *infile, const char *outfile) { struct stat buf; if (infile) /* infile ! = NULL */ if (stat(infile, &buf) < 0) { warn("%s", infile); crash(); } if (outfile) { if (stat(outfile, &buf) < 0) return; /* file does not exist */ else { warnx("file '%s' already exists and may be overwritten", outfile); crash(); } } } /* * Parse command line arguments */ static int parseargs(int argc, const char *argv[], struct commandline *cmd) { int i; int j; char c, ch; char flag[(1 << 8 * sizeof (char))]; int nflags; cmd->infile = cmd->outfile = NULL; if (argc < 2) { return (0); } allfiles = 0; flag['c'] = 0; flag['h'] = 0; flag['l'] = 0; flag['m'] = 0; flag['o'] = 0; flag['s'] = 0; flag['n'] = 0; flag['t'] = 0; flag['S'] = 0; flag['C'] = 0; flag['M'] = 0; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { if (cmd->infile) { warnx("cannot specify more than one input file"); return (0); } cmd->infile = argv[i]; } else { for (j = 1; argv[i][j] != 0; j++) { c = argv[i][j]; switch (c) { case 'a': allfiles = 1; break; case 'c': case 'h': case 'l': case 'm': case 't': if (flag[(int)c]) { return (0); } flag[(int)c] = 1; break; case 'S': /* * sample flag: Ss or Sc. * Ss means set flag['S']; * Sc means set flag['C']; * Sm means set flag['M']; */ ch = argv[i][++j]; /* get next char */ if (ch == 's') ch = 'S'; else if (ch == 'c') ch = 'C'; else if (ch == 'm') ch = 'M'; else return (0); if (flag[(int)ch]) { return (0); } flag[(int)ch] = 1; break; case 'C': /* ANSI C syntax */ ch = argv[i][j+1]; /* get next char */ if (ch != 'C') break; CCflag = 1; break; case 'b': /* * Turn TIRPC flag off for * generating backward compatible * code */ tirpcflag = 0; break; case 'I': inetdflag = 1; break; case 'N': newstyle = 1; break; case 'L': logflag = 1; break; case 'P': pmflag = 1; break; case 'K': if (++i == argc) { return (0); } svcclosetime = argv[i]; goto nextarg; case 'T': tblflag = 1; break; case 'M': mtflag = 1; break; case 'i' : if (++i == argc) { return (0); } inline_size = atoi(argv[i]); goto nextarg; case 'n': case 'o': case 's': if (argv[i][j - 1] != '-' || argv[i][j + 1] != 0) { return (0); } flag[(int)c] = 1; if (++i == argc) { return (0); } if (c == 'o') { if (cmd->outfile) { return (0); } cmd->outfile = argv[i]; } goto nextarg; case 'D': if (argv[i][j - 1] != '-') { return (0); } (void) addarg(argv[i]); goto nextarg; case 'Y': if (++i == argc) { return (0); } if (strlcpy(pathbuf, argv[i], sizeof(pathbuf)) >= sizeof(pathbuf) || strlcat(pathbuf, "/cpp", sizeof(pathbuf)) >= sizeof(pathbuf)) { warnx("argument too long"); return (0); } CPP = pathbuf; goto nextarg; default: return (0); } } nextarg: ; } } cmd->cflag = flag['c']; cmd->hflag = flag['h']; cmd->lflag = flag['l']; cmd->mflag = flag['m']; cmd->nflag = flag['n']; cmd->sflag = flag['s']; cmd->tflag = flag['t']; cmd->Ssflag = flag['S']; cmd->Scflag = flag['C']; cmd->makefileflag = flag['M']; if (tirpcflag) { if (inetdflag) pmflag = 0; if ((inetdflag && cmd->nflag)) { /* netid not allowed with inetdflag */ warnx("cannot use netid flag with inetd flag"); return (0); } } else { /* 4.1 mode */ pmflag = 0; /* set pmflag only in tirpcmode */ if (cmd->nflag) { /* netid needs TIRPC */ warnx("cannot use netid flag without TIRPC"); return (0); } } if (newstyle && (tblflag || cmd->tflag)) { warnx("cannot use table flags with newstyle"); return (0); } /* check no conflicts with file generation flags */ nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag + cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag + cmd->makefileflag; if (nflags == 0) { if (cmd->outfile != NULL || cmd->infile == NULL) { return (0); } } else if (cmd->infile == NULL && (cmd->Ssflag || cmd->Scflag || cmd->makefileflag)) { warnx("\"infile\" is required for template generation flags"); return (0); } if (nflags > 1) { warnx("cannot have more than one file generation flag"); return (0); } return (1); } static void usage(void) { f_print(stderr, "%s\n%s\n%s\n%s\n%s\n", "usage: rpcgen infile", " rpcgen [-abCLNTM] [-Dname[=value]] [-i size]\ [-I -P [-K seconds]] [-Y path] infile", " rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm]\ [-o outfile] [infile]", " rpcgen [-s nettype]* [-o outfile] [infile]", " rpcgen [-n netid]* [-o outfile] [infile]"); options_usage(); exit(1); } static void options_usage(void) { f_print(stderr, "options:\n"); f_print(stderr, "-a\t\tgenerate all files, including samples\n"); f_print(stderr, "-b\t\tbackward compatibility mode (generates code \ for FreeBSD 4.X)\n"); f_print(stderr, "-c\t\tgenerate XDR routines\n"); f_print(stderr, "-C\t\tANSI C mode\n"); f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n"); f_print(stderr, "-h\t\tgenerate header file\n"); f_print(stderr, "-i size\t\tsize at which to start generating\ inline code\n"); f_print(stderr, "-I\t\tgenerate code for inetd support in server\n"); f_print(stderr, "-K seconds\tserver exits after K seconds of\ inactivity\n"); f_print(stderr, "-l\t\tgenerate client side stubs\n"); f_print(stderr, "-L\t\tserver errors will be printed to syslog\n"); f_print(stderr, "-m\t\tgenerate server side stubs\n"); f_print(stderr, "-M\t\tgenerate MT-safe code\n"); f_print(stderr, "-n netid\tgenerate server code that supports\ named netid\n"); f_print(stderr, "-N\t\tsupports multiple arguments and\ call-by-value\n"); f_print(stderr, "-o outfile\tname of the output file\n"); f_print(stderr, "-P\t\tgenerate code for port monitoring support in server\n"); f_print(stderr, "-s nettype\tgenerate server code that supports named\ nettype\n"); f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote\ procedures\n"); f_print(stderr, "-Ss\t\tgenerate sample server code that defines\ remote procedures\n"); f_print(stderr, "-Sm \t\tgenerate makefile template \n"); f_print(stderr, "-t\t\tgenerate RPC dispatch table\n"); f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n"); f_print(stderr, "-Y path\t\tpath where cpp is found\n"); exit(1); } Index: stable/11/usr.bin/systat/main.c =================================================================== --- stable/11/usr.bin/systat/main.c (revision 307696) +++ stable/11/usr.bin/systat/main.c (revision 307697) @@ -1,380 +1,380 @@ /*- * Copyright (c) 1980, 1992, 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. * 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. */ #include __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; #endif #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1992, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "systat.h" #include "extern.h" static int dellave; kvm_t *kd; sig_t sigtstpdfl; double avenrun[3]; int col; unsigned int delay = 5000000; /* in microseconds */ int verbose = 1; /* to report kvm read errs */ struct clockinfo clkinfo; double hertz; char c; char *namp; char hostname[MAXHOSTNAMELEN]; WINDOW *wnd; int CMDLINE; int use_kvm = 1; static WINDOW *wload; /* one line window for load average */ struct cmdentry { SLIST_ENTRY(cmdentry) link; char *cmd; /* Command name */ char *argv; /* Arguments vector for a command */ }; SLIST_HEAD(, cmdentry) commands; static void parse_cmd_args (int argc, char **argv) { int in_command = 0; struct cmdentry *cmd = NULL; double t; while (argc) { if (argv[0][0] == '-') { if (in_command) SLIST_INSERT_HEAD(&commands, cmd, link); if (memcmp(argv[0], "--", 3) == 0) { in_command = 0; /*-- ends a command explicitly*/ argc --, argv ++; continue; } cmd = calloc(1, sizeof(struct cmdentry)); if (cmd == NULL) errx(1, "memory allocating failure"); cmd->cmd = strdup(&argv[0][1]); if (cmd->cmd == NULL) errx(1, "memory allocating failure"); in_command = 1; } else if (!in_command) { t = strtod(argv[0], NULL) * 1000000.0; if (t > 0 && t < (double)UINT_MAX) delay = (unsigned int)t; } else if (cmd != NULL) { cmd->argv = strdup(argv[0]); if (cmd->argv == NULL) errx(1, "memory allocating failure"); in_command = 0; SLIST_INSERT_HEAD(&commands, cmd, link); } else errx(1, "invalid arguments list"); argc--, argv++; } if (in_command && cmd != NULL) SLIST_INSERT_HEAD(&commands, cmd, link); } int main(int argc, char **argv) { char errbuf[_POSIX2_LINE_MAX], dummy; size_t size; struct cmdentry *cmd = NULL; (void) setlocale(LC_ALL, ""); SLIST_INIT(&commands); argc--, argv++; if (argc > 0) { if (argv[0][0] == '-') { struct cmdtab *p; p = lookup(&argv[0][1]); if (p == (struct cmdtab *)-1) errx(1, "%s: ambiguous request", &argv[0][1]); if (p == (struct cmdtab *)0) errx(1, "%s: unknown request", &argv[0][1]); curcmd = p; argc--, argv++; } parse_cmd_args (argc, argv); } kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); if (kd != NULL) { /* * Try to actually read something, we may be in a jail, and * have /dev/null opened as /dev/mem. */ if (kvm_nlist(kd, namelist) != 0 || namelist[0].n_value == 0 || kvm_read(kd, namelist[0].n_value, &dummy, sizeof(dummy)) != sizeof(dummy)) { kvm_close(kd); kd = NULL; } } if (kd == NULL) { /* * Maybe we are lacking permissions? Retry, this time with bogus * devices. We can now use sysctl only. */ use_kvm = 0; kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, O_RDONLY, errbuf); if (kd == NULL) { error("%s", errbuf); exit(1); } } signal(SIGHUP, die); signal(SIGINT, die); signal(SIGQUIT, die); signal(SIGTERM, die); /* * Initialize display. Load average appears in a one line * window of its own. Current command's display appears in * an overlapping sub-window of stdscr configured by the display * routines to minimize update work by curses. */ initscr(); CMDLINE = LINES - 1; wnd = (*curcmd->c_open)(); if (wnd == NULL) { warnx("couldn't initialize display"); die(0); } wload = newwin(1, 0, 1, 20); if (wload == NULL) { warnx("couldn't set up load average window"); die(0); } gethostname(hostname, sizeof (hostname)); size = sizeof(clkinfo); if (sysctlbyname("kern.clockrate", &clkinfo, &size, NULL, 0) || size != sizeof(clkinfo)) { error("kern.clockrate"); die(0); } hertz = clkinfo.stathz; (*curcmd->c_init)(); curcmd->c_flags |= CF_INIT; labels(); if (curcmd->c_cmd != NULL) SLIST_FOREACH (cmd, &commands, link) if (!curcmd->c_cmd(cmd->cmd, cmd->argv)) warnx("command is not understood"); dellave = 0.0; display(); noecho(); crmode(); keyboard(); /*NOTREACHED*/ return EXIT_SUCCESS; } void labels(void) { if (curcmd->c_flags & CF_LOADAV) { mvaddstr(0, 20, "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); mvaddstr(1, 5, "Load Average"); } if (curcmd->c_flags & CF_ZFSARC) { mvaddstr(0, 20, " Total MFU MRU Anon Hdr L2Hdr Other"); mvaddstr(1, 5, "ZFS ARC "); } (*curcmd->c_label)(); #ifdef notdef mvprintw(21, 25, "CPU usage on %s", hostname); #endif refresh(); } void display(void) { int i, j; /* Get the load average over the last minute. */ - (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); + (void) getloadavg(avenrun, nitems(avenrun)); (*curcmd->c_fetch)(); if (curcmd->c_flags & CF_LOADAV) { j = 5.0*avenrun[0] + 0.5; dellave -= avenrun[0]; if (dellave >= 0.0) c = '<'; else { c = '>'; dellave = -dellave; } if (dellave < 0.1) c = '|'; dellave = avenrun[0]; wmove(wload, 0, 0); wclrtoeol(wload); for (i = MIN(j, 50); i > 0; i--) waddch(wload, c); if (j > 50) wprintw(wload, " %4.1f", avenrun[0]); } if (curcmd->c_flags & CF_ZFSARC) { uint64_t arc[7] = {}; size_t size = sizeof(arc[0]); if (sysctlbyname("kstat.zfs.misc.arcstats.size", &arc[0], &size, NULL, 0) == 0 ) { GETSYSCTL("vfs.zfs.mfu_size", arc[1]); GETSYSCTL("vfs.zfs.mru_size", arc[2]); GETSYSCTL("vfs.zfs.anon_size", arc[3]); GETSYSCTL("kstat.zfs.misc.arcstats.hdr_size", arc[4]); GETSYSCTL("kstat.zfs.misc.arcstats.l2_hdr_size", arc[5]); GETSYSCTL("kstat.zfs.misc.arcstats.other_size", arc[6]); wmove(wload, 0, 0); wclrtoeol(wload); - for (i = 0 ; i < sizeof(arc) / sizeof(arc[0]) ; i++) { + for (i = 0 ; i < nitems(arc); i++) { if (arc[i] > 10llu * 1024 * 1024 * 1024 ) { wprintw(wload, "%7lluG", arc[i] >> 30); } else if (arc[i] > 10 * 1024 * 1024 ) { wprintw(wload, "%7lluM", arc[i] >> 20); } else { wprintw(wload, "%7lluK", arc[i] >> 10); } } } } (*curcmd->c_refresh)(); if (curcmd->c_flags & (CF_LOADAV |CF_ZFSARC)) wrefresh(wload); wrefresh(wnd); move(CMDLINE, col); refresh(); } void load(void) { - (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); + (void) getloadavg(avenrun, nitems(avenrun)); mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", avenrun[0], avenrun[1], avenrun[2]); clrtoeol(); } void die(int signo __unused) { move(CMDLINE, 0); clrtoeol(); refresh(); endwin(); exit(0); } #include void error(const char *fmt, ...) { va_list ap; char buf[255]; int oy, ox; va_start(ap, fmt); if (wnd) { getyx(stdscr, oy, ox); (void) vsnprintf(buf, sizeof(buf), fmt, ap); clrtoeol(); standout(); mvaddstr(CMDLINE, 0, buf); standend(); move(oy, ox); refresh(); } else { (void) vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } va_end(ap); } void nlisterr(struct nlist n_list[]) { int i, n; n = 0; clear(); mvprintw(2, 10, "systat: nlist: can't find following symbols:"); for (i = 0; n_list[i].n_name != NULL && *n_list[i].n_name != '\0'; i++) if (n_list[i].n_value == 0) mvprintw(2 + ++n, 10, "%s", n_list[i].n_name); move(CMDLINE, 0); clrtoeol(); refresh(); endwin(); exit(1); } Index: stable/11/usr.sbin/ctld/chap.c =================================================================== --- stable/11/usr.sbin/ctld/chap.c (revision 307696) +++ stable/11/usr.sbin/ctld/chap.c (revision 307697) @@ -1,422 +1,422 @@ /*- * Copyright (c) 2014 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "ctld.h" static void chap_compute_md5(const char id, const char *secret, const void *challenge, size_t challenge_len, void *response, size_t response_len) { MD5_CTX ctx; assert(response_len == CHAP_DIGEST_LEN); MD5Init(&ctx); MD5Update(&ctx, &id, sizeof(id)); MD5Update(&ctx, secret, strlen(secret)); MD5Update(&ctx, challenge, challenge_len); MD5Final(response, &ctx); } static int chap_hex2int(const char hex) { switch (hex) { case '0': return (0x00); case '1': return (0x01); case '2': return (0x02); case '3': return (0x03); case '4': return (0x04); case '5': return (0x05); case '6': return (0x06); case '7': return (0x07); case '8': return (0x08); case '9': return (0x09); case 'a': case 'A': return (0x0a); case 'b': case 'B': return (0x0b); case 'c': case 'C': return (0x0c); case 'd': case 'D': return (0x0d); case 'e': case 'E': return (0x0e); case 'f': case 'F': return (0x0f); default: return (-1); } } static int chap_b642bin(const char *b64, void **binp, size_t *bin_lenp) { char *bin; int b64_len, bin_len; b64_len = strlen(b64); bin_len = (b64_len + 3) / 4 * 3; bin = calloc(bin_len, 1); if (bin == NULL) log_err(1, "calloc"); bin_len = b64_pton(b64, bin, bin_len); if (bin_len < 0) { log_warnx("malformed base64 variable"); free(bin); return (-1); } *binp = bin; *bin_lenp = bin_len; return (0); } /* * XXX: Review this _carefully_. */ static int chap_hex2bin(const char *hex, void **binp, size_t *bin_lenp) { int i, hex_len, nibble; bool lo = true; /* As opposed to 'hi'. */ char *bin; size_t bin_off, bin_len; if (strncasecmp(hex, "0b", strlen("0b")) == 0) return (chap_b642bin(hex + 2, binp, bin_lenp)); if (strncasecmp(hex, "0x", strlen("0x")) != 0) { log_warnx("malformed variable, should start with \"0x\"" " or \"0b\""); return (-1); } hex += strlen("0x"); hex_len = strlen(hex); if (hex_len < 1) { log_warnx("malformed variable; doesn't contain anything " "but \"0x\""); return (-1); } bin_len = hex_len / 2 + hex_len % 2; bin = calloc(bin_len, 1); if (bin == NULL) log_err(1, "calloc"); bin_off = bin_len - 1; for (i = hex_len - 1; i >= 0; i--) { nibble = chap_hex2int(hex[i]); if (nibble < 0) { log_warnx("malformed variable, invalid char \"%c\"", hex[i]); free(bin); return (-1); } assert(bin_off < bin_len); if (lo) { bin[bin_off] = nibble; lo = false; } else { bin[bin_off] |= nibble << 4; bin_off--; lo = true; } } *binp = bin; *bin_lenp = bin_len; return (0); } #ifdef USE_BASE64 static char * chap_bin2hex(const char *bin, size_t bin_len) { unsigned char *b64, *tmp; size_t b64_len; b64_len = (bin_len + 2) / 3 * 4 + 3; /* +2 for "0b", +1 for '\0'. */ b64 = malloc(b64_len); if (b64 == NULL) log_err(1, "malloc"); tmp = b64; tmp += sprintf(tmp, "0b"); b64_ntop(bin, bin_len, tmp, b64_len - 2); return (b64); } #else static char * chap_bin2hex(const char *bin, size_t bin_len) { unsigned char *hex, *tmp, ch; size_t hex_len; size_t i; hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */ hex = malloc(hex_len); if (hex == NULL) log_err(1, "malloc"); tmp = hex; tmp += sprintf(tmp, "0x"); for (i = 0; i < bin_len; i++) { ch = bin[i]; tmp += sprintf(tmp, "%02x", ch); } return (hex); } #endif /* !USE_BASE64 */ struct chap * chap_new(void) { struct chap *chap; - chap = calloc(sizeof(*chap), 1); + chap = calloc(1, sizeof(*chap)); if (chap == NULL) log_err(1, "calloc"); /* * Generate the challenge. */ arc4random_buf(chap->chap_challenge, sizeof(chap->chap_challenge)); arc4random_buf(&chap->chap_id, sizeof(chap->chap_id)); return (chap); } char * chap_get_id(const struct chap *chap) { char *chap_i; int ret; ret = asprintf(&chap_i, "%d", chap->chap_id); if (ret < 0) log_err(1, "asprintf"); return (chap_i); } char * chap_get_challenge(const struct chap *chap) { char *chap_c; chap_c = chap_bin2hex(chap->chap_challenge, sizeof(chap->chap_challenge)); return (chap_c); } static int chap_receive_bin(struct chap *chap, void *response, size_t response_len) { if (response_len != sizeof(chap->chap_response)) { log_debugx("got CHAP response with invalid length; " "got %zd, should be %zd", response_len, sizeof(chap->chap_response)); return (1); } memcpy(chap->chap_response, response, response_len); return (0); } int chap_receive(struct chap *chap, const char *response) { void *response_bin; size_t response_bin_len; int error; error = chap_hex2bin(response, &response_bin, &response_bin_len); if (error != 0) { log_debugx("got incorrectly encoded CHAP response \"%s\"", response); return (1); } error = chap_receive_bin(chap, response_bin, response_bin_len); free(response_bin); return (error); } int chap_authenticate(struct chap *chap, const char *secret) { char expected_response[CHAP_DIGEST_LEN]; chap_compute_md5(chap->chap_id, secret, chap->chap_challenge, sizeof(chap->chap_challenge), expected_response, sizeof(expected_response)); if (memcmp(chap->chap_response, expected_response, sizeof(expected_response)) != 0) { return (-1); } return (0); } void chap_delete(struct chap *chap) { free(chap); } struct rchap * rchap_new(const char *secret) { struct rchap *rchap; - rchap = calloc(sizeof(*rchap), 1); + rchap = calloc(1, sizeof(*rchap)); if (rchap == NULL) log_err(1, "calloc"); rchap->rchap_secret = checked_strdup(secret); return (rchap); } static void rchap_receive_bin(struct rchap *rchap, const unsigned char id, const void *challenge, size_t challenge_len) { rchap->rchap_id = id; rchap->rchap_challenge = calloc(challenge_len, 1); if (rchap->rchap_challenge == NULL) log_err(1, "calloc"); memcpy(rchap->rchap_challenge, challenge, challenge_len); rchap->rchap_challenge_len = challenge_len; } int rchap_receive(struct rchap *rchap, const char *id, const char *challenge) { unsigned char id_bin; void *challenge_bin; size_t challenge_bin_len; int error; id_bin = strtoul(id, NULL, 10); error = chap_hex2bin(challenge, &challenge_bin, &challenge_bin_len); if (error != 0) { log_debugx("got incorrectly encoded CHAP challenge \"%s\"", challenge); return (1); } rchap_receive_bin(rchap, id_bin, challenge_bin, challenge_bin_len); free(challenge_bin); return (0); } static void rchap_get_response_bin(struct rchap *rchap, void **responsep, size_t *response_lenp) { void *response_bin; size_t response_bin_len = CHAP_DIGEST_LEN; response_bin = calloc(response_bin_len, 1); if (response_bin == NULL) log_err(1, "calloc"); chap_compute_md5(rchap->rchap_id, rchap->rchap_secret, rchap->rchap_challenge, rchap->rchap_challenge_len, response_bin, response_bin_len); *responsep = response_bin; *response_lenp = response_bin_len; } char * rchap_get_response(struct rchap *rchap) { void *response; size_t response_len; char *chap_r; rchap_get_response_bin(rchap, &response, &response_len); chap_r = chap_bin2hex(response, response_len); free(response); return (chap_r); } void rchap_delete(struct rchap *rchap) { free(rchap->rchap_secret); free(rchap->rchap_challenge); free(rchap); } Index: stable/11/usr.sbin/ctld/keys.c =================================================================== --- stable/11/usr.sbin/ctld/keys.c (revision 307696) +++ stable/11/usr.sbin/ctld/keys.c (revision 307697) @@ -1,198 +1,198 @@ /*- * Copyright (c) 2012 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include "ctld.h" struct keys * keys_new(void) { struct keys *keys; - keys = calloc(sizeof(*keys), 1); + keys = calloc(1, sizeof(*keys)); if (keys == NULL) log_err(1, "calloc"); return (keys); } void keys_delete(struct keys *keys) { free(keys->keys_data); free(keys); } void keys_load(struct keys *keys, const struct pdu *pdu) { int i; char *pair; size_t pair_len; if (pdu->pdu_data_len == 0) return; if (pdu->pdu_data[pdu->pdu_data_len - 1] != '\0') log_errx(1, "protocol error: key not NULL-terminated\n"); assert(keys->keys_data == NULL); keys->keys_data_len = pdu->pdu_data_len; keys->keys_data = malloc(keys->keys_data_len); if (keys->keys_data == NULL) log_err(1, "malloc"); memcpy(keys->keys_data, pdu->pdu_data, keys->keys_data_len); /* * XXX: Review this carefully. */ pair = keys->keys_data; for (i = 0;; i++) { if (i >= KEYS_MAX) log_errx(1, "too many keys received"); pair_len = strlen(pair); keys->keys_values[i] = pair; keys->keys_names[i] = strsep(&keys->keys_values[i], "="); if (keys->keys_names[i] == NULL || keys->keys_values[i] == NULL) log_errx(1, "malformed keys"); log_debugx("key received: \"%s=%s\"", keys->keys_names[i], keys->keys_values[i]); pair += pair_len + 1; /* +1 to skip the terminating '\0'. */ if (pair == keys->keys_data + keys->keys_data_len) break; assert(pair < keys->keys_data + keys->keys_data_len); } } void keys_save(struct keys *keys, struct pdu *pdu) { char *data; size_t len; int i; /* * XXX: Not particularly efficient. */ len = 0; for (i = 0; i < KEYS_MAX; i++) { if (keys->keys_names[i] == NULL) break; /* * +1 for '=', +1 for '\0'. */ len += strlen(keys->keys_names[i]) + strlen(keys->keys_values[i]) + 2; } if (len == 0) return; data = malloc(len); if (data == NULL) log_err(1, "malloc"); pdu->pdu_data = data; pdu->pdu_data_len = len; for (i = 0; i < KEYS_MAX; i++) { if (keys->keys_names[i] == NULL) break; data += sprintf(data, "%s=%s", keys->keys_names[i], keys->keys_values[i]); data += 1; /* for '\0'. */ } } const char * keys_find(struct keys *keys, const char *name) { int i; /* * Note that we don't handle duplicated key names here, * as they are not supposed to happen in requests, and if they do, * it's an initiator error. */ for (i = 0; i < KEYS_MAX; i++) { if (keys->keys_names[i] == NULL) return (NULL); if (strcmp(keys->keys_names[i], name) == 0) return (keys->keys_values[i]); } return (NULL); } void keys_add(struct keys *keys, const char *name, const char *value) { int i; log_debugx("key to send: \"%s=%s\"", name, value); /* * Note that we don't check for duplicates here, as they are perfectly * fine in responses, e.g. the "TargetName" keys in discovery sesion * response. */ for (i = 0; i < KEYS_MAX; i++) { if (keys->keys_names[i] == NULL) { keys->keys_names[i] = checked_strdup(name); keys->keys_values[i] = checked_strdup(value); return; } } log_errx(1, "too many keys"); } void keys_add_int(struct keys *keys, const char *name, int value) { char *str; int ret; ret = asprintf(&str, "%d", value); if (ret <= 0) log_err(1, "asprintf"); keys_add(keys, name, str); free(str); } Index: stable/11/usr.sbin/ctld/pdu.c =================================================================== --- stable/11/usr.sbin/ctld/pdu.c (revision 307696) +++ stable/11/usr.sbin/ctld/pdu.c (revision 307697) @@ -1,264 +1,264 @@ /*- * Copyright (c) 2012 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "ctld.h" #include "iscsi_proto.h" #ifdef ICL_KERNEL_PROXY #include #endif extern bool proxy_mode; static int pdu_ahs_length(const struct pdu *pdu) { return (pdu->pdu_bhs->bhs_total_ahs_len * 4); } static int pdu_data_segment_length(const struct pdu *pdu) { uint32_t len = 0; len += pdu->pdu_bhs->bhs_data_segment_len[0]; len <<= 8; len += pdu->pdu_bhs->bhs_data_segment_len[1]; len <<= 8; len += pdu->pdu_bhs->bhs_data_segment_len[2]; return (len); } static void pdu_set_data_segment_length(struct pdu *pdu, uint32_t len) { pdu->pdu_bhs->bhs_data_segment_len[2] = len; pdu->pdu_bhs->bhs_data_segment_len[1] = len >> 8; pdu->pdu_bhs->bhs_data_segment_len[0] = len >> 16; } struct pdu * pdu_new(struct connection *conn) { struct pdu *pdu; - pdu = calloc(sizeof(*pdu), 1); + pdu = calloc(1, sizeof(*pdu)); if (pdu == NULL) log_err(1, "calloc"); - pdu->pdu_bhs = calloc(sizeof(*pdu->pdu_bhs), 1); + pdu->pdu_bhs = calloc(1, sizeof(*pdu->pdu_bhs)); if (pdu->pdu_bhs == NULL) log_err(1, "calloc"); pdu->pdu_connection = conn; return (pdu); } struct pdu * pdu_new_response(struct pdu *request) { return (pdu_new(request->pdu_connection)); } #ifdef ICL_KERNEL_PROXY static void pdu_receive_proxy(struct pdu *pdu) { size_t len; assert(proxy_mode); kernel_receive(pdu); len = pdu_ahs_length(pdu); if (len > 0) log_errx(1, "protocol error: non-empty AHS"); len = pdu_data_segment_length(pdu); assert(len <= MAX_DATA_SEGMENT_LENGTH); pdu->pdu_data_len = len; } static void pdu_send_proxy(struct pdu *pdu) { assert(proxy_mode); pdu_set_data_segment_length(pdu, pdu->pdu_data_len); kernel_send(pdu); } #endif /* ICL_KERNEL_PROXY */ static size_t pdu_padding(const struct pdu *pdu) { if ((pdu->pdu_data_len % 4) != 0) return (4 - (pdu->pdu_data_len % 4)); return (0); } static void pdu_read(int fd, char *data, size_t len) { ssize_t ret; while (len > 0) { ret = read(fd, data, len); if (ret < 0) { if (timed_out()) log_errx(1, "exiting due to timeout"); log_err(1, "read"); } else if (ret == 0) log_errx(1, "read: connection lost"); len -= ret; data += ret; } } void pdu_receive(struct pdu *pdu) { size_t len, padding; char dummy[4]; #ifdef ICL_KERNEL_PROXY if (proxy_mode) return (pdu_receive_proxy(pdu)); #endif assert(proxy_mode == false); pdu_read(pdu->pdu_connection->conn_socket, (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs)); len = pdu_ahs_length(pdu); if (len > 0) log_errx(1, "protocol error: non-empty AHS"); len = pdu_data_segment_length(pdu); if (len > 0) { if (len > MAX_DATA_SEGMENT_LENGTH) { log_errx(1, "protocol error: received PDU " "with DataSegmentLength exceeding %d", MAX_DATA_SEGMENT_LENGTH); } pdu->pdu_data_len = len; pdu->pdu_data = malloc(len); if (pdu->pdu_data == NULL) log_err(1, "malloc"); pdu_read(pdu->pdu_connection->conn_socket, (char *)pdu->pdu_data, pdu->pdu_data_len); padding = pdu_padding(pdu); if (padding != 0) { assert(padding < sizeof(dummy)); pdu_read(pdu->pdu_connection->conn_socket, (char *)dummy, padding); } } } void pdu_send(struct pdu *pdu) { ssize_t ret, total_len; size_t padding; uint32_t zero = 0; struct iovec iov[3]; int iovcnt; #ifdef ICL_KERNEL_PROXY if (proxy_mode) return (pdu_send_proxy(pdu)); #endif assert(proxy_mode == false); pdu_set_data_segment_length(pdu, pdu->pdu_data_len); iov[0].iov_base = pdu->pdu_bhs; iov[0].iov_len = sizeof(*pdu->pdu_bhs); total_len = iov[0].iov_len; iovcnt = 1; if (pdu->pdu_data_len > 0) { iov[1].iov_base = pdu->pdu_data; iov[1].iov_len = pdu->pdu_data_len; total_len += iov[1].iov_len; iovcnt = 2; padding = pdu_padding(pdu); if (padding > 0) { assert(padding < sizeof(zero)); iov[2].iov_base = &zero; iov[2].iov_len = padding; total_len += iov[2].iov_len; iovcnt = 3; } } ret = writev(pdu->pdu_connection->conn_socket, iov, iovcnt); if (ret < 0) { if (timed_out()) log_errx(1, "exiting due to timeout"); log_err(1, "writev"); } if (ret != total_len) log_errx(1, "short write"); } void pdu_delete(struct pdu *pdu) { free(pdu->pdu_data); free(pdu->pdu_bhs); free(pdu); } Index: stable/11/usr.sbin/fifolog/lib/fifolog_int.c =================================================================== --- stable/11/usr.sbin/fifolog/lib/fifolog_int.c (revision 307696) +++ stable/11/usr.sbin/fifolog/lib/fifolog_int.c (revision 307697) @@ -1,256 +1,256 @@ /*- * Copyright (c) 2005-2008 Poul-Henning Kamp * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include "miniobj.h" #include "fifolog.h" #include "libfifolog_int.h" /* * Open a fifolog file or partition for reading or writing. * * Return value is NULL for success or a error description string to * be augmented by errno if non-zero. * * The second function is just an error-handling wrapper around the * first which, does the actual work. */ static const char * fifolog_int_open_i(struct fifolog_file *f, const char *fname, int mode) { struct stat st; ssize_t u; int i; f->fd = open(fname, mode ? O_RDWR : O_RDONLY); if (f->fd < 0) return ("Cannot open"); /* Determine initial record size guesstimate */ i = ioctl(f->fd, DIOCGSECTORSIZE, &f->recsize); if (i != 0 && errno != ENOTTY) return ("ioctl(DIOCGSECTORSIZE) failed"); if (i != 0) { i = fstat(f->fd, &st); assert(i == 0); if (!S_ISREG(st.st_mode)) return ("Neither disk nor regular file"); f->recsize = 512; f->logsize = st.st_size; } else if (f->recsize < 64) { return ("Disk device sectorsize smaller than 64"); } else { i = ioctl(f->fd, DIOCGMEDIASIZE, &f->logsize); if (i < 0 && errno != ENOTTY) return ("ioctl(DIOCGMEDIASIZE) failed"); } /* Allocate a record buffer */ f->recbuf = malloc(f->recsize); if (f->recbuf == NULL) return ("Cannot malloc"); /* Read and validate the label sector */ i = pread(f->fd, f->recbuf, f->recsize, 0); if (i < 0 || i < (int)f->recsize) return ("Read error, first sector"); errno = 0; if (memcmp(f->recbuf, FIFOLOG_FMT_MAGIC, strlen(FIFOLOG_FMT_MAGIC) + 1)) return ("Wrong or missing magic string"); u = be32dec(f->recbuf + FIFOLOG_OFF_BS); if (u < 64) return ("Wrong record size in header (<64)"); if ((off_t)u >= f->logsize) return ("Record size in header bigger than fifolog"); f->recsize = u; /* Reallocate the buffer to correct size if necessary */ if (u != f->recsize) { free(f->recbuf); f->recbuf = NULL; f->recsize = u; f->recbuf = malloc(f->recsize); if (f->recbuf == NULL) return ("Cannot malloc"); } /* Calculate number of records in fifolog */ f->logsize /= u; if (f->logsize < 10) return ("less than 10 records in fifolog"); f->logsize--; /* the label record */ /* Initialize zlib handling */ - f->zs = calloc(sizeof *f->zs, 1); + f->zs = calloc(1, sizeof(*f->zs)); if (f->zs == NULL) return ("cannot malloc"); return (NULL); } const char * fifolog_int_open(struct fifolog_file **ff, const char *fname, int mode) { struct fifolog_file fs, *f; const char *retval; int e; f = &fs; memset(f, 0, sizeof *f); f->fd = -1; retval = fifolog_int_open_i(f, fname, mode); e = errno; if (retval == NULL) { *ff = malloc(sizeof *f); if (*ff != NULL) { memcpy(*ff, f, sizeof *f); (*ff)->magic = FIFOLOG_FILE_MAGIC; return (retval); } } fifolog_int_close(&f); errno = e; return (retval); } void fifolog_int_close(struct fifolog_file **ff) { struct fifolog_file *f; f = *ff; *ff = NULL; if (f == NULL) return; if (f->fd >= 0) (void)close(f->fd); if (f->zs != NULL) free(f->zs); if (f->recbuf != NULL) free(f->recbuf); } static void fifolog_int_file_assert(const struct fifolog_file *ff) { CHECK_OBJ_NOTNULL(ff, FIFOLOG_FILE_MAGIC); assert(ff->fd >= 0); assert(ff->recbuf != NULL); } /* * Read a record. * * Return zero on success */ int fifolog_int_read(const struct fifolog_file *ff, off_t recno) { int i; fifolog_int_file_assert(ff); if (recno >= ff->logsize) return (-1); recno++; /* label sector */ i = pread(ff->fd, ff->recbuf, ff->recsize, recno * ff->recsize); if (i < 0) return (-2); if (i != (int)ff->recsize) return (-3); return (0); } /* * Find the last written record in the fifolog. * * Return is error string or NULL on success */ const char * fifolog_int_findend(const struct fifolog_file *ff, off_t *last) { off_t o, s; int e; unsigned seq0, seq; fifolog_int_file_assert(ff); o = 0; e = fifolog_int_read(ff, o); if (e) return("Read error, first record"); seq0 = be32dec(ff->recbuf); /* If the first records sequence is zero, the fifolog is empty */ if (seq0 == 0) { *last = o; return (NULL); } /* Do a binary search for a discontinuity in the sequence numbers */ s = ff->logsize / 2; do { e = fifolog_int_read(ff, o + s); if (e) return ("Read error while searching"); seq = be32dec(ff->recbuf); if (seq == seq0 + s) { o += s; seq0 = seq; } s /= 2; assert(o < ff->logsize); } while (s > 0); *last = o; return (NULL); } Index: stable/11/usr.sbin/fifolog/lib/fifolog_reader.c =================================================================== --- stable/11/usr.sbin/fifolog/lib/fifolog_reader.c (revision 307696) +++ stable/11/usr.sbin/fifolog/lib/fifolog_reader.c (revision 307697) @@ -1,322 +1,322 @@ /*- * Copyright (c) 2005-2008 Poul-Henning Kamp * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include "fifolog.h" #include "libfifolog.h" #include "libfifolog_int.h" #include "miniobj.h" /*--------------------------------------------------------------------*/ struct fifolog_reader { unsigned magic; #define FIFOLOG_READER_MAGIC 0x1036d139 struct fifolog_file *ff; unsigned olen; unsigned char *obuf; time_t now; }; struct fifolog_reader * fifolog_reader_open(const char *fname) { const char *retval; struct fifolog_reader *fr; int i; - fr = calloc(sizeof *fr, 1); + fr = calloc(1, sizeof(*fr)); if (fr == NULL) err(1, "Cannot malloc"); retval = fifolog_int_open(&fr->ff, fname, 0); if (retval != NULL) err(1, "%s", retval); fr->obuf = calloc(16, fr->ff->recsize); if (fr->obuf == NULL) err(1, "Cannot malloc"); fr->olen = fr->ff->recsize * 16; i = inflateInit(fr->ff->zs); assert(i == Z_OK); fr->magic = FIFOLOG_READER_MAGIC; return (fr); } /* * Find the next SYNC block * * Return: * 0 - empty fifolog * 1 - found sync block * 2 - would have wrapped around * 3 - End of written log. */ static int fifolog_reader_findsync(const struct fifolog_file *ff, off_t *o) { int e; unsigned seq, seqs; assert(*o < ff->logsize); e = fifolog_int_read(ff, *o); if (e) err(1, "Read error (%d) while looking for SYNC", e); seq = be32dec(ff->recbuf); if (*o == 0 && seq == 0) return (0); if (ff->recbuf[4] & FIFOLOG_FLG_SYNC) return (1); /* That was easy... */ while(1) { assert(*o < ff->logsize); (*o)++; seq++; if (*o == ff->logsize) return (2); /* wraparound */ e = fifolog_int_read(ff, *o); if (e) err(1, "Read error (%d) while looking for SYNC", e); seqs = be32dec(ff->recbuf); if (seqs != seq) return (3); /* End of log */ if (ff->recbuf[4] & FIFOLOG_FLG_SYNC) return (1); /* Bingo! */ } } /* * Seek out a given timestamp */ off_t fifolog_reader_seek(const struct fifolog_reader *fr, time_t t0) { off_t o, s, st; time_t t, tt; unsigned seq, seqs; const char *retval; int e; CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC); /* * First, find the first SYNC block */ o = 0; e = fifolog_reader_findsync(fr->ff, &o); if (e == 0) return (0); /* empty fifolog */ assert(e == 1); assert(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC); seq = be32dec(fr->ff->recbuf); t = be32dec(fr->ff->recbuf + 5); if (t > t0) { /* Check if there is a second older part we can use */ retval = fifolog_int_findend(fr->ff, &s); if (retval != NULL) err(1, "%s", retval); s++; e = fifolog_reader_findsync(fr->ff, &s); if (e == 0) return (0); /* empty fifolog */ if (e == 1) { o = s; seq = be32dec(fr->ff->recbuf); t = be32dec(fr->ff->recbuf + 5); } } /* Now do a binary search to find the sync block right before t0 */ s = st = (fr->ff->logsize - o) / 2; while (s > 1) { /* We know we shouldn't wrap */ if (o + st > fr->ff->logsize + 1) { s = st = s / 2; continue; } e = fifolog_int_read(fr->ff, o + st); if (e) { s = st = s / 2; continue; } /* If not in same part, sequence won't match */ seqs = be32dec(fr->ff->recbuf); if (seqs != seq + st) { s = st = s / 2; continue; } /* If not sync block, try next */ if (!(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC)) { st++; continue; } /* Check timestamp */ tt = be32dec(fr->ff->recbuf + 5); if (tt >= t0) { s = st = s / 2; continue; } o += st; seq = seqs; } fprintf(stderr, "Read from %jx\n", o * fr->ff->recsize); return (o); } static unsigned char * fifolog_reader_chop(struct fifolog_reader *fr, fifolog_reader_render_t *func, void *priv) { u_char *p, *q; uint32_t v, w, u; p = fr->obuf; q = fr->obuf + (fr->olen - fr->ff->zs->avail_out); while (1) { /* Make sure we have a complete header */ if (p + 5 >= q) return (p); w = 4; u = be32dec(p); if (u & FIFOLOG_TIMESTAMP) { fr->now = be32dec(p + 4); w += 4; } if (u & FIFOLOG_LENGTH) { v = p[w]; w++; if (p + w + v >= q) return (p); } else { for (v = 0; p + v + w < q && p[v + w] != '\0'; v++) continue; if (p + v + w >= q) return (p); v++; } func(priv, fr->now, u, p + w, v); p += w + v; } } /* * Process fifolog until end of written log or provided timestamp */ void fifolog_reader_process(struct fifolog_reader *fr, off_t from, fifolog_reader_render_t *func, void *priv, time_t end) { uint32_t seq, lseq; off_t o = from; int i, e; time_t t; u_char *p, *q; z_stream *zs; CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC); zs = fr->ff->zs; lseq = 0; while (1) { e = fifolog_int_read(fr->ff, o); if (e) err(1, "Read error (%d)", e); if (++o >= fr->ff->logsize) o = 0; seq = be32dec(fr->ff->recbuf); if (lseq != 0 && seq != lseq + 1) break; lseq = seq; zs->avail_in = fr->ff->recsize - 5; zs->next_in = fr->ff->recbuf + 5; if (fr->ff->recbuf[4] & FIFOLOG_FLG_1BYTE) zs->avail_in -= fr->ff->recbuf[fr->ff->recsize - 1]; if (fr->ff->recbuf[4] & FIFOLOG_FLG_4BYTE) zs->avail_in -= be32dec(fr->ff->recbuf + fr->ff->recsize - 4); if (fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC) { i = inflateReset(zs); assert(i == Z_OK); zs->next_out = fr->obuf; zs->avail_out = fr->olen; t = be32dec(fr->ff->recbuf + 5); if (t > end) break; zs->next_in += 4; zs->avail_in -= 4; } while(zs->avail_in > 0) { i = inflate(zs, 0); if (i == Z_BUF_ERROR) { #if 1 fprintf(stderr, "Z_BUF_ERROR [%d,%d] [%d,%d,%d]\n", (int)(zs->next_in - fr->ff->recbuf), zs->avail_in, (int)(zs->next_out - fr->obuf), zs->avail_out, fr->olen); exit (250); #else i = Z_OK; #endif } if (i == Z_STREAM_END) { i = inflateReset(zs); } if (i != Z_OK) { fprintf(stderr, "inflate = %d\n", i); exit (250); } assert(i == Z_OK); if (zs->avail_out != fr->olen) { q = fr->obuf + (fr->olen - zs->avail_out); p = fifolog_reader_chop(fr, func, priv); if (p < q) (void)memmove(fr->obuf, p, q - p); zs->avail_out = fr->olen - (q - p); zs->next_out = fr->obuf + (q - p); } } } } Index: stable/11/usr.sbin/iscsid/chap.c =================================================================== --- stable/11/usr.sbin/iscsid/chap.c (revision 307696) +++ stable/11/usr.sbin/iscsid/chap.c (revision 307697) @@ -1,422 +1,422 @@ /*- * Copyright (c) 2014 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "iscsid.h" static void chap_compute_md5(const char id, const char *secret, const void *challenge, size_t challenge_len, void *response, size_t response_len) { MD5_CTX ctx; assert(response_len == CHAP_DIGEST_LEN); MD5Init(&ctx); MD5Update(&ctx, &id, sizeof(id)); MD5Update(&ctx, secret, strlen(secret)); MD5Update(&ctx, challenge, challenge_len); MD5Final(response, &ctx); } static int chap_hex2int(const char hex) { switch (hex) { case '0': return (0x00); case '1': return (0x01); case '2': return (0x02); case '3': return (0x03); case '4': return (0x04); case '5': return (0x05); case '6': return (0x06); case '7': return (0x07); case '8': return (0x08); case '9': return (0x09); case 'a': case 'A': return (0x0a); case 'b': case 'B': return (0x0b); case 'c': case 'C': return (0x0c); case 'd': case 'D': return (0x0d); case 'e': case 'E': return (0x0e); case 'f': case 'F': return (0x0f); default: return (-1); } } static int chap_b642bin(const char *b64, void **binp, size_t *bin_lenp) { char *bin; int b64_len, bin_len; b64_len = strlen(b64); bin_len = (b64_len + 3) / 4 * 3; bin = calloc(bin_len, 1); if (bin == NULL) log_err(1, "calloc"); bin_len = b64_pton(b64, bin, bin_len); if (bin_len < 0) { log_warnx("malformed base64 variable"); free(bin); return (-1); } *binp = bin; *bin_lenp = bin_len; return (0); } /* * XXX: Review this _carefully_. */ static int chap_hex2bin(const char *hex, void **binp, size_t *bin_lenp) { int i, hex_len, nibble; bool lo = true; /* As opposed to 'hi'. */ char *bin; size_t bin_off, bin_len; if (strncasecmp(hex, "0b", strlen("0b")) == 0) return (chap_b642bin(hex + 2, binp, bin_lenp)); if (strncasecmp(hex, "0x", strlen("0x")) != 0) { log_warnx("malformed variable, should start with \"0x\"" " or \"0b\""); return (-1); } hex += strlen("0x"); hex_len = strlen(hex); if (hex_len < 1) { log_warnx("malformed variable; doesn't contain anything " "but \"0x\""); return (-1); } bin_len = hex_len / 2 + hex_len % 2; bin = calloc(bin_len, 1); if (bin == NULL) log_err(1, "calloc"); bin_off = bin_len - 1; for (i = hex_len - 1; i >= 0; i--) { nibble = chap_hex2int(hex[i]); if (nibble < 0) { log_warnx("malformed variable, invalid char \"%c\"", hex[i]); free(bin); return (-1); } assert(bin_off < bin_len); if (lo) { bin[bin_off] = nibble; lo = false; } else { bin[bin_off] |= nibble << 4; bin_off--; lo = true; } } *binp = bin; *bin_lenp = bin_len; return (0); } #ifdef USE_BASE64 static char * chap_bin2hex(const char *bin, size_t bin_len) { unsigned char *b64, *tmp; size_t b64_len; b64_len = (bin_len + 2) / 3 * 4 + 3; /* +2 for "0b", +1 for '\0'. */ b64 = malloc(b64_len); if (b64 == NULL) log_err(1, "malloc"); tmp = b64; tmp += sprintf(tmp, "0b"); b64_ntop(bin, bin_len, tmp, b64_len - 2); return (b64); } #else static char * chap_bin2hex(const char *bin, size_t bin_len) { unsigned char *hex, *tmp, ch; size_t hex_len; size_t i; hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */ hex = malloc(hex_len); if (hex == NULL) log_err(1, "malloc"); tmp = hex; tmp += sprintf(tmp, "0x"); for (i = 0; i < bin_len; i++) { ch = bin[i]; tmp += sprintf(tmp, "%02x", ch); } return (hex); } #endif /* !USE_BASE64 */ struct chap * chap_new(void) { struct chap *chap; - chap = calloc(sizeof(*chap), 1); + chap = calloc(1, sizeof(*chap)); if (chap == NULL) log_err(1, "calloc"); /* * Generate the challenge. */ arc4random_buf(chap->chap_challenge, sizeof(chap->chap_challenge)); arc4random_buf(&chap->chap_id, sizeof(chap->chap_id)); return (chap); } char * chap_get_id(const struct chap *chap) { char *chap_i; int ret; ret = asprintf(&chap_i, "%d", chap->chap_id); if (ret < 0) log_err(1, "asprintf"); return (chap_i); } char * chap_get_challenge(const struct chap *chap) { char *chap_c; chap_c = chap_bin2hex(chap->chap_challenge, sizeof(chap->chap_challenge)); return (chap_c); } static int chap_receive_bin(struct chap *chap, void *response, size_t response_len) { if (response_len != sizeof(chap->chap_response)) { log_debugx("got CHAP response with invalid length; " "got %zd, should be %zd", response_len, sizeof(chap->chap_response)); return (1); } memcpy(chap->chap_response, response, response_len); return (0); } int chap_receive(struct chap *chap, const char *response) { void *response_bin; size_t response_bin_len; int error; error = chap_hex2bin(response, &response_bin, &response_bin_len); if (error != 0) { log_debugx("got incorrectly encoded CHAP response \"%s\"", response); return (1); } error = chap_receive_bin(chap, response_bin, response_bin_len); free(response_bin); return (error); } int chap_authenticate(struct chap *chap, const char *secret) { char expected_response[CHAP_DIGEST_LEN]; chap_compute_md5(chap->chap_id, secret, chap->chap_challenge, sizeof(chap->chap_challenge), expected_response, sizeof(expected_response)); if (memcmp(chap->chap_response, expected_response, sizeof(expected_response)) != 0) { return (-1); } return (0); } void chap_delete(struct chap *chap) { free(chap); } struct rchap * rchap_new(const char *secret) { struct rchap *rchap; - rchap = calloc(sizeof(*rchap), 1); + rchap = calloc(1, sizeof(*rchap)); if (rchap == NULL) log_err(1, "calloc"); rchap->rchap_secret = checked_strdup(secret); return (rchap); } static void rchap_receive_bin(struct rchap *rchap, const unsigned char id, const void *challenge, size_t challenge_len) { rchap->rchap_id = id; rchap->rchap_challenge = calloc(challenge_len, 1); if (rchap->rchap_challenge == NULL) log_err(1, "calloc"); memcpy(rchap->rchap_challenge, challenge, challenge_len); rchap->rchap_challenge_len = challenge_len; } int rchap_receive(struct rchap *rchap, const char *id, const char *challenge) { unsigned char id_bin; void *challenge_bin; size_t challenge_bin_len; int error; id_bin = strtoul(id, NULL, 10); error = chap_hex2bin(challenge, &challenge_bin, &challenge_bin_len); if (error != 0) { log_debugx("got incorrectly encoded CHAP challenge \"%s\"", challenge); return (1); } rchap_receive_bin(rchap, id_bin, challenge_bin, challenge_bin_len); free(challenge_bin); return (0); } static void rchap_get_response_bin(struct rchap *rchap, void **responsep, size_t *response_lenp) { void *response_bin; size_t response_bin_len = CHAP_DIGEST_LEN; response_bin = calloc(response_bin_len, 1); if (response_bin == NULL) log_err(1, "calloc"); chap_compute_md5(rchap->rchap_id, rchap->rchap_secret, rchap->rchap_challenge, rchap->rchap_challenge_len, response_bin, response_bin_len); *responsep = response_bin; *response_lenp = response_bin_len; } char * rchap_get_response(struct rchap *rchap) { void *response; size_t response_len; char *chap_r; rchap_get_response_bin(rchap, &response, &response_len); chap_r = chap_bin2hex(response, response_len); free(response); return (chap_r); } void rchap_delete(struct rchap *rchap) { free(rchap->rchap_secret); free(rchap->rchap_challenge); free(rchap); } Index: stable/11/usr.sbin/iscsid/keys.c =================================================================== --- stable/11/usr.sbin/iscsid/keys.c (revision 307696) +++ stable/11/usr.sbin/iscsid/keys.c (revision 307697) @@ -1,198 +1,198 @@ /*- * Copyright (c) 2012 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include "iscsid.h" struct keys * keys_new(void) { struct keys *keys; - keys = calloc(sizeof(*keys), 1); + keys = calloc(1, sizeof(*keys)); if (keys == NULL) log_err(1, "calloc"); return (keys); } void keys_delete(struct keys *keys) { free(keys->keys_data); free(keys); } void keys_load(struct keys *keys, const struct pdu *pdu) { int i; char *pair; size_t pair_len; if (pdu->pdu_data_len == 0) return; if (pdu->pdu_data[pdu->pdu_data_len - 1] != '\0') log_errx(1, "protocol error: key not NULL-terminated\n"); assert(keys->keys_data == NULL); keys->keys_data_len = pdu->pdu_data_len; keys->keys_data = malloc(keys->keys_data_len); if (keys->keys_data == NULL) log_err(1, "malloc"); memcpy(keys->keys_data, pdu->pdu_data, keys->keys_data_len); /* * XXX: Review this carefully. */ pair = keys->keys_data; for (i = 0;; i++) { if (i >= KEYS_MAX) log_errx(1, "too many keys received"); pair_len = strlen(pair); keys->keys_values[i] = pair; keys->keys_names[i] = strsep(&keys->keys_values[i], "="); if (keys->keys_names[i] == NULL || keys->keys_values[i] == NULL) log_errx(1, "malformed keys"); log_debugx("key received: \"%s=%s\"", keys->keys_names[i], keys->keys_values[i]); pair += pair_len + 1; /* +1 to skip the terminating '\0'. */ if (pair == keys->keys_data + keys->keys_data_len) break; assert(pair < keys->keys_data + keys->keys_data_len); } } void keys_save(struct keys *keys, struct pdu *pdu) { char *data; size_t len; int i; /* * XXX: Not particularly efficient. */ len = 0; for (i = 0; i < KEYS_MAX; i++) { if (keys->keys_names[i] == NULL) break; /* * +1 for '=', +1 for '\0'. */ len += strlen(keys->keys_names[i]) + strlen(keys->keys_values[i]) + 2; } if (len == 0) return; data = malloc(len); if (data == NULL) log_err(1, "malloc"); pdu->pdu_data = data; pdu->pdu_data_len = len; for (i = 0; i < KEYS_MAX; i++) { if (keys->keys_names[i] == NULL) break; data += sprintf(data, "%s=%s", keys->keys_names[i], keys->keys_values[i]); data += 1; /* for '\0'. */ } } const char * keys_find(struct keys *keys, const char *name) { int i; /* * Note that we don't handle duplicated key names here, * as they are not supposed to happen in requests, and if they do, * it's an initiator error. */ for (i = 0; i < KEYS_MAX; i++) { if (keys->keys_names[i] == NULL) return (NULL); if (strcmp(keys->keys_names[i], name) == 0) return (keys->keys_values[i]); } return (NULL); } void keys_add(struct keys *keys, const char *name, const char *value) { int i; log_debugx("key to send: \"%s=%s\"", name, value); /* * Note that we don't check for duplicates here, as they are perfectly * fine in responses, e.g. the "TargetName" keys in discovery sesion * response. */ for (i = 0; i < KEYS_MAX; i++) { if (keys->keys_names[i] == NULL) { keys->keys_names[i] = checked_strdup(name); keys->keys_values[i] = checked_strdup(value); return; } } log_errx(1, "too many keys"); } void keys_add_int(struct keys *keys, const char *name, int value) { char *str; int ret; ret = asprintf(&str, "%d", value); if (ret <= 0) log_err(1, "asprintf"); keys_add(keys, name, str); free(str); } Index: stable/11/usr.sbin/iscsid/pdu.c =================================================================== --- stable/11/usr.sbin/iscsid/pdu.c (revision 307696) +++ stable/11/usr.sbin/iscsid/pdu.c (revision 307697) @@ -1,304 +1,304 @@ /*- * Copyright (c) 2012 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "iscsid.h" #include "iscsi_proto.h" #ifdef ICL_KERNEL_PROXY #include #endif static int pdu_ahs_length(const struct pdu *pdu) { return (pdu->pdu_bhs->bhs_total_ahs_len * 4); } static int pdu_data_segment_length(const struct pdu *pdu) { uint32_t len = 0; len += pdu->pdu_bhs->bhs_data_segment_len[0]; len <<= 8; len += pdu->pdu_bhs->bhs_data_segment_len[1]; len <<= 8; len += pdu->pdu_bhs->bhs_data_segment_len[2]; return (len); } static void pdu_set_data_segment_length(struct pdu *pdu, uint32_t len) { pdu->pdu_bhs->bhs_data_segment_len[2] = len; pdu->pdu_bhs->bhs_data_segment_len[1] = len >> 8; pdu->pdu_bhs->bhs_data_segment_len[0] = len >> 16; } struct pdu * pdu_new(struct connection *conn) { struct pdu *pdu; - pdu = calloc(sizeof(*pdu), 1); + pdu = calloc(1, sizeof(*pdu)); if (pdu == NULL) log_err(1, "calloc"); - pdu->pdu_bhs = calloc(sizeof(*pdu->pdu_bhs), 1); + pdu->pdu_bhs = calloc(1, sizeof(*pdu->pdu_bhs)); if (pdu->pdu_bhs == NULL) log_err(1, "calloc"); pdu->pdu_connection = conn; return (pdu); } struct pdu * pdu_new_response(struct pdu *request) { return (pdu_new(request->pdu_connection)); } #ifdef ICL_KERNEL_PROXY static void pdu_receive_proxy(struct pdu *pdu) { struct iscsi_daemon_receive *idr; size_t len; int error; assert(pdu->pdu_connection->conn_conf.isc_iser != 0); pdu->pdu_data = malloc(ISCSI_MAX_DATA_SEGMENT_LENGTH); if (pdu->pdu_data == NULL) log_err(1, "malloc"); idr = calloc(1, sizeof(*idr)); if (idr == NULL) log_err(1, "calloc"); idr->idr_session_id = pdu->pdu_connection->conn_session_id; idr->idr_bhs = pdu->pdu_bhs; idr->idr_data_segment_len = ISCSI_MAX_DATA_SEGMENT_LENGTH; idr->idr_data_segment = pdu->pdu_data; error = ioctl(pdu->pdu_connection->conn_iscsi_fd, ISCSIDRECEIVE, idr); if (error != 0) log_err(1, "ISCSIDRECEIVE"); len = pdu_ahs_length(pdu); if (len > 0) log_errx(1, "protocol error: non-empty AHS"); len = pdu_data_segment_length(pdu); assert(len <= ISCSI_MAX_DATA_SEGMENT_LENGTH); pdu->pdu_data_len = len; free(idr); } static void pdu_send_proxy(struct pdu *pdu) { struct iscsi_daemon_send *ids; int error; assert(pdu->pdu_connection->conn_conf.isc_iser != 0); pdu_set_data_segment_length(pdu, pdu->pdu_data_len); ids = calloc(1, sizeof(*ids)); if (ids == NULL) log_err(1, "calloc"); ids->ids_session_id = pdu->pdu_connection->conn_session_id; ids->ids_bhs = pdu->pdu_bhs; ids->ids_data_segment_len = pdu->pdu_data_len; ids->ids_data_segment = pdu->pdu_data; error = ioctl(pdu->pdu_connection->conn_iscsi_fd, ISCSIDSEND, ids); if (error != 0) log_err(1, "ISCSIDSEND"); free(ids); } #endif /* ICL_KERNEL_PROXY */ static size_t pdu_padding(const struct pdu *pdu) { if ((pdu->pdu_data_len % 4) != 0) return (4 - (pdu->pdu_data_len % 4)); return (0); } static void pdu_read(const struct connection *conn, char *data, size_t len) { ssize_t ret; while (len > 0) { ret = read(conn->conn_socket, data, len); if (ret < 0) { if (timed_out()) { fail(conn, "Login Phase timeout"); log_errx(1, "exiting due to timeout"); } fail(conn, strerror(errno)); log_err(1, "read"); } else if (ret == 0) { fail(conn, "connection lost"); log_errx(1, "read: connection lost"); } len -= ret; data += ret; } } void pdu_receive(struct pdu *pdu) { size_t len, padding; char dummy[4]; #ifdef ICL_KERNEL_PROXY if (pdu->pdu_connection->conn_conf.isc_iser != 0) return (pdu_receive_proxy(pdu)); #endif assert(pdu->pdu_connection->conn_conf.isc_iser == 0); pdu_read(pdu->pdu_connection, (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs)); len = pdu_ahs_length(pdu); if (len > 0) log_errx(1, "protocol error: non-empty AHS"); len = pdu_data_segment_length(pdu); if (len > 0) { if (len > ISCSI_MAX_DATA_SEGMENT_LENGTH) { log_errx(1, "protocol error: received PDU " "with DataSegmentLength exceeding %d", ISCSI_MAX_DATA_SEGMENT_LENGTH); } pdu->pdu_data_len = len; pdu->pdu_data = malloc(len); if (pdu->pdu_data == NULL) log_err(1, "malloc"); pdu_read(pdu->pdu_connection, (char *)pdu->pdu_data, pdu->pdu_data_len); padding = pdu_padding(pdu); if (padding != 0) { assert(padding < sizeof(dummy)); pdu_read(pdu->pdu_connection, (char *)dummy, padding); } } } void pdu_send(struct pdu *pdu) { ssize_t ret, total_len; size_t padding; uint32_t zero = 0; struct iovec iov[3]; int iovcnt; #ifdef ICL_KERNEL_PROXY if (pdu->pdu_connection->conn_conf.isc_iser != 0) return (pdu_send_proxy(pdu)); #endif assert(pdu->pdu_connection->conn_conf.isc_iser == 0); pdu_set_data_segment_length(pdu, pdu->pdu_data_len); iov[0].iov_base = pdu->pdu_bhs; iov[0].iov_len = sizeof(*pdu->pdu_bhs); total_len = iov[0].iov_len; iovcnt = 1; if (pdu->pdu_data_len > 0) { iov[1].iov_base = pdu->pdu_data; iov[1].iov_len = pdu->pdu_data_len; total_len += iov[1].iov_len; iovcnt = 2; padding = pdu_padding(pdu); if (padding > 0) { assert(padding < sizeof(zero)); iov[2].iov_base = &zero; iov[2].iov_len = padding; total_len += iov[2].iov_len; iovcnt = 3; } } ret = writev(pdu->pdu_connection->conn_socket, iov, iovcnt); if (ret < 0) { if (timed_out()) log_errx(1, "exiting due to timeout"); log_err(1, "writev"); } if (ret != total_len) log_errx(1, "short write"); } void pdu_delete(struct pdu *pdu) { free(pdu->pdu_data); free(pdu->pdu_bhs); free(pdu); } Index: stable/11 =================================================================== --- stable/11 (revision 307696) +++ stable/11 (revision 307697) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r303541-303543,303545-303547,304225-304226,304605,304676,305212,305863