diff --git a/usr.sbin/accton/accton.c b/usr.sbin/accton/accton.c index 80823ecabbc5..91b775928389 100644 --- a/usr.sbin/accton/accton.c +++ b/usr.sbin/accton/accton.c @@ -1,89 +1,89 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)accton.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include -static void usage(void); +static void usage(void) __dead2; int main(int argc, char *argv[]) { int ch; while ((ch = getopt(argc, argv, "")) != -1) switch(ch) { case '?': default: usage(); } argc -= optind; argv += optind; switch(argc) { case 0: if (acct(NULL)) err(1, NULL); break; case 1: if (acct(*argv)) err(1, "%s", *argv); break; default: usage(); } exit(0); } static void usage(void) { (void)fprintf(stderr, "usage: accton [file]\n"); exit(1); } diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c index 5a6c58e99e78..8b82d73aab08 100644 --- a/usr.sbin/arp/arp.c +++ b/usr.sbin/arp/arp.c @@ -1,908 +1,908 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1984, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Sun Microsystems, 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1984, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char const sccsid[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); /* * arp - display, set, and delete arp table entries */ #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 #include "arp.h" typedef void (action_fn)(struct sockaddr_dl *sdl, struct sockaddr_in *s_in, struct rt_msghdr *rtm); static void nuke_entries(uint32_t ifindex, struct in_addr addr); static int print_entries(uint32_t ifindex, struct in_addr addr); static int delete(char *host); -static void usage(void); +static void usage(void) __dead2; static int set(int argc, char **argv); static int get(char *host); static int file(char *name); static struct rt_msghdr *rtmsg(int cmd, struct sockaddr_in *dst, struct sockaddr_dl *sdl); static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr); static int set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m, char *host); static char *rifname; struct if_nameindex *ifnameindex; struct arp_opts opts = {}; /* which function we're supposed to do */ #define F_GET 1 #define F_SET 2 #define F_FILESET 3 #define F_REPLACE 4 #define F_DELETE 5 #define SETFUNC(f) { if (func) usage(); func = (f); } #define ARP_XO_VERSION "1" int main(int argc, char *argv[]) { int ch, func = 0; int rtn = 0; argc = xo_parse_args(argc, argv); if (argc < 0) exit(1); while ((ch = getopt(argc, argv, "andfsSi:")) != -1) switch(ch) { case 'a': opts.aflag = true; break; case 'd': SETFUNC(F_DELETE); break; case 'n': opts.nflag = true; break; case 'S': SETFUNC(F_REPLACE); break; case 's': SETFUNC(F_SET); break; case 'f' : SETFUNC(F_FILESET); break; case 'i': rifname = optarg; break; case '?': default: usage(); } argc -= optind; argv += optind; if (!func) func = F_GET; if (rifname) { if (func != F_GET && !(func == F_DELETE && opts.aflag)) xo_errx(1, "-i not applicable to this operation"); if (if_nametoindex(rifname) == 0) { if (errno == ENXIO) xo_errx(1, "interface %s does not exist", rifname); else xo_err(1, "if_nametoindex(%s)", rifname); } } switch (func) { case F_GET: if (opts.aflag) { if (argc != 0) usage(); xo_set_version(ARP_XO_VERSION); xo_open_container("arp"); xo_open_list("arp-cache"); struct in_addr all_addrs = {}; print_entries(0, all_addrs); xo_close_list("arp-cache"); xo_close_container("arp"); xo_finish(); } else { if (argc != 1) usage(); rtn = get(argv[0]); } break; case F_SET: case F_REPLACE: if (argc < 2 || argc > 6) usage(); if (func == F_REPLACE) (void)delete(argv[0]); rtn = set(argc, argv) ? 1 : 0; break; case F_DELETE: if (opts.aflag) { if (argc != 0) usage(); struct in_addr all_addrs = {}; nuke_entries(0, all_addrs); } else { if (argc != 1) usage(); rtn = delete(argv[0]); } break; case F_FILESET: if (argc != 1) usage(); rtn = file(argv[0]); break; } if (ifnameindex != NULL) if_freenameindex(ifnameindex); return (rtn); } /* * Process a file to set standard arp entries */ static int file(char *name) { FILE *fp; int i, retval; char line[100], arg[5][50], *args[5], *p; if ((fp = fopen(name, "r")) == NULL) xo_err(1, "cannot open %s", name); args[0] = &arg[0][0]; args[1] = &arg[1][0]; args[2] = &arg[2][0]; args[3] = &arg[3][0]; args[4] = &arg[4][0]; retval = 0; while(fgets(line, sizeof(line), fp) != NULL) { if ((p = strchr(line, '#')) != NULL) *p = '\0'; for (p = line; isblank(*p); p++); if (*p == '\n' || *p == '\0') continue; i = sscanf(p, "%49s %49s %49s %49s %49s", arg[0], arg[1], arg[2], arg[3], arg[4]); if (i < 2) { xo_warnx("bad line: %s", line); retval = 1; continue; } if (set(i, args)) retval = 1; } fclose(fp); return (retval); } /* * Given a hostname, fills up a (static) struct sockaddr_in with * the address of the host and returns a pointer to the * structure. */ struct sockaddr_in * getaddr(char *host) { struct hostent *hp; static struct sockaddr_in reply; bzero(&reply, sizeof(reply)); reply.sin_len = sizeof(reply); reply.sin_family = AF_INET; reply.sin_addr.s_addr = inet_addr(host); if (reply.sin_addr.s_addr == INADDR_NONE) { if (!(hp = gethostbyname(host))) { xo_warnx("%s: %s", host, hstrerror(h_errno)); return (NULL); } bcopy((char *)hp->h_addr, (char *)&reply.sin_addr, sizeof reply.sin_addr); } return (&reply); } int valid_type(int type); /* * Returns true if the type is a valid one for ARP. */ int valid_type(int type) { switch (type) { case IFT_ETHER: case IFT_FDDI: case IFT_IEEE1394: case IFT_INFINIBAND: case IFT_ISO88023: case IFT_ISO88024: case IFT_L2VLAN: case IFT_BRIDGE: return (1); default: return (0); } } /* * Set an individual arp entry */ static int set(int argc, char **argv) { struct sockaddr_in *dst; /* what are we looking for */ struct ether_addr *ea; char *host = argv[0], *eaddr = argv[1]; struct sockaddr_dl sdl_m; argc -= 2; argv += 2; bzero(&sdl_m, sizeof(sdl_m)); sdl_m.sdl_len = sizeof(sdl_m); sdl_m.sdl_family = AF_LINK; dst = getaddr(host); if (dst == NULL) return (1); while (argc-- > 0) { if (strcmp(argv[0], "temp") == 0) { int max_age; size_t len = sizeof(max_age); if (sysctlbyname("net.link.ether.inet.max_age", &max_age, &len, NULL, 0) != 0) xo_err(1, "sysctlbyname"); opts.expire_time = max_age; } else if (strcmp(argv[0], "pub") == 0) { opts.flags |= RTF_ANNOUNCE; if (argc && strcmp(argv[1], "only") == 0) { /* * Compatibility: in pre FreeBSD 8 times * the "only" keyword used to mean that * an ARP entry should be announced, but * not installed into routing table. */ argc--; argv++; } } else if (strcmp(argv[0], "blackhole") == 0) { if (opts.flags & RTF_REJECT) { xo_errx(1, "Choose one of blackhole or reject, " "not both."); } opts.flags |= RTF_BLACKHOLE; } else if (strcmp(argv[0], "reject") == 0) { if (opts.flags & RTF_BLACKHOLE) { xo_errx(1, "Choose one of blackhole or reject, " "not both."); } opts.flags |= RTF_REJECT; } else { xo_warnx("Invalid parameter '%s'", argv[0]); usage(); } argv++; } ea = (struct ether_addr *)LLADDR(&sdl_m); if ((opts.flags & RTF_ANNOUNCE) && !strcmp(eaddr, "auto")) { if (!get_ether_addr(dst->sin_addr.s_addr, ea)) { xo_warnx("no interface found for %s", inet_ntoa(dst->sin_addr)); return (1); } sdl_m.sdl_alen = ETHER_ADDR_LEN; } else { struct ether_addr *ea1 = ether_aton(eaddr); if (ea1 == NULL) { xo_warnx("invalid Ethernet address '%s'", eaddr); return (1); } else { *ea = *ea1; sdl_m.sdl_alen = ETHER_ADDR_LEN; } } #ifndef WITHOUT_NETLINK return (set_nl(0, dst, &sdl_m, host)); #else return (set_rtsock(dst, &sdl_m, host)); #endif } #ifdef WITHOUT_NETLINK static int set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m, char *host) { struct sockaddr_in *addr; struct sockaddr_dl *sdl; struct rt_msghdr *rtm; /* * In the case a proxy-arp entry is being added for * a remote end point, the RTF_ANNOUNCE flag in the * RTM_GET command is an indication to the kernel * routing code that the interface associated with * the prefix route covering the local end of the * PPP link should be returned, on which ARP applies. */ rtm = rtmsg(RTM_GET, dst, NULL); if (rtm == NULL) { xo_warn("%s", host); return (1); } addr = (struct sockaddr_in *)(rtm + 1); sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); if ((sdl->sdl_family != AF_LINK) || (rtm->rtm_flags & RTF_GATEWAY) || !valid_type(sdl->sdl_type)) { xo_warnx("cannot intuit interface index and type for %s", host); return (1); } sdl_m->sdl_type = sdl->sdl_type; sdl_m->sdl_index = sdl->sdl_index; return (rtmsg(RTM_ADD, dst, sdl_m) == NULL); } #endif /* * Display an individual arp entry */ static int get(char *host) { struct sockaddr_in *addr; int found; addr = getaddr(host); if (addr == NULL) return (1); xo_set_version(ARP_XO_VERSION); xo_open_container("arp"); xo_open_list("arp-cache"); found = print_entries(0, addr->sin_addr); if (found == 0) { xo_emit("{d:hostname/%s} ({d:ip-address/%s}) -- no entry", host, inet_ntoa(addr->sin_addr)); if (rifname) xo_emit(" on {d:interface/%s}", rifname); xo_emit("\n"); } xo_close_list("arp-cache"); xo_close_container("arp"); xo_finish(); return (found == 0); } /* * Delete an arp entry */ #ifdef WITHOUT_NETLINK static int delete_rtsock(char *host) { struct sockaddr_in *addr, *dst; struct rt_msghdr *rtm; struct sockaddr_dl *sdl; dst = getaddr(host); if (dst == NULL) return (1); /* * Perform a regular entry delete first. */ opts.flags &= ~RTF_ANNOUNCE; for (;;) { /* try twice */ rtm = rtmsg(RTM_GET, dst, NULL); if (rtm == NULL) { xo_warn("%s", host); return (1); } addr = (struct sockaddr_in *)(rtm + 1); sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); /* * With the new L2/L3 restructure, the route * returned is a prefix route. The important * piece of information from the previous * RTM_GET is the interface index. In the * case of ECMP, the kernel will traverse * the route group for the given entry. */ if (sdl->sdl_family == AF_LINK && !(rtm->rtm_flags & RTF_GATEWAY) && valid_type(sdl->sdl_type) ) { addr->sin_addr.s_addr = dst->sin_addr.s_addr; break; } /* * Regular entry delete failed, now check if there * is a proxy-arp entry to remove. */ if (opts.flags & RTF_ANNOUNCE) { xo_warnx("delete: cannot locate %s", host); return (1); } opts.flags |= RTF_ANNOUNCE; } rtm->rtm_flags |= RTF_LLDATA; if (rtmsg(RTM_DELETE, dst, NULL) != NULL) { printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr)); return (0); } return (1); } #endif static int delete(char *host) { #ifdef WITHOUT_NETLINK return (delete_rtsock(host)); #else return (delete_nl(0, host)); #endif } /* * Search the arp table and do some action on matching entries */ static int search(u_long addr, action_fn *action) { int mib[6]; size_t needed; char *lim, *buf, *next; struct rt_msghdr *rtm; struct sockaddr_in *sin2; struct sockaddr_dl *sdl; char ifname[IF_NAMESIZE]; int st, found_entry = 0; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_FLAGS; #ifdef RTF_LLINFO mib[5] = RTF_LLINFO; #else mib[5] = 0; #endif if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) xo_err(1, "route-sysctl-estimate"); if (needed == 0) /* empty table */ return 0; buf = NULL; for (;;) { buf = reallocf(buf, needed); if (buf == NULL) xo_errx(1, "could not reallocate memory"); st = sysctl(mib, 6, buf, &needed, NULL, 0); if (st == 0 || errno != ENOMEM) break; needed += needed / 8; } if (st == -1) xo_err(1, "actual retrieval of routing table"); lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sin2 = (struct sockaddr_in *)(rtm + 1); sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2)); if (rifname && if_indextoname(sdl->sdl_index, ifname) && strcmp(ifname, rifname)) continue; if (addr) { if (addr != sin2->sin_addr.s_addr) continue; found_entry = 1; } (*action)(sdl, sin2, rtm); } free(buf); return (found_entry); } /* * Display an arp entry */ static void print_entry(struct sockaddr_dl *sdl, struct sockaddr_in *addr, struct rt_msghdr *rtm) { const char *host; struct hostent *hp; struct if_nameindex *p; if (ifnameindex == NULL) if ((ifnameindex = if_nameindex()) == NULL) xo_err(1, "cannot retrieve interface names"); xo_open_instance("arp-cache"); if (!opts.nflag) hp = gethostbyaddr((caddr_t)&(addr->sin_addr), sizeof addr->sin_addr, AF_INET); else hp = 0; if (hp) host = hp->h_name; else { host = "?"; if (h_errno == TRY_AGAIN) opts.nflag = true; } xo_emit("{:hostname/%s} ({:ip-address/%s}) at ", host, inet_ntoa(addr->sin_addr)); if (sdl->sdl_alen) { if ((sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_L2VLAN || sdl->sdl_type == IFT_BRIDGE) && sdl->sdl_alen == ETHER_ADDR_LEN) xo_emit("{:mac-address/%s}", ether_ntoa((struct ether_addr *)LLADDR(sdl))); else { int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; xo_emit("{:mac-address/%s}", link_ntoa(sdl) + n); } } else xo_emit("{d:/(incomplete)}{en:incomplete/true}"); for (p = ifnameindex; p && p->if_index && p->if_name; p++) { if (p->if_index == sdl->sdl_index) { xo_emit(" on {:interface/%s}", p->if_name); break; } } if (rtm->rtm_rmx.rmx_expire == 0) xo_emit("{d:/ permanent}{en:permanent/true}"); else { static struct timespec tp; time_t expire_time = 0; if (tp.tv_sec == 0) clock_gettime(CLOCK_MONOTONIC, &tp); if ((expire_time = rtm->rtm_rmx.rmx_expire - tp.tv_sec) > 0) xo_emit(" expires in {:expires/%d} seconds", (int)expire_time); else xo_emit("{d:/ expired}{en:expired/true}"); } if (rtm->rtm_flags & RTF_ANNOUNCE) xo_emit("{d:/ published}{en:published/true}"); switch(sdl->sdl_type) { case IFT_ETHER: xo_emit(" [{:type/ethernet}]"); break; case IFT_FDDI: xo_emit(" [{:type/fddi}]"); break; case IFT_ATM: xo_emit(" [{:type/atm}]"); break; case IFT_L2VLAN: xo_emit(" [{:type/vlan}]"); break; case IFT_IEEE1394: xo_emit(" [{:type/firewire}]"); break; case IFT_BRIDGE: xo_emit(" [{:type/bridge}]"); break; case IFT_INFINIBAND: xo_emit(" [{:type/infiniband}]"); break; default: break; } xo_emit("\n"); xo_close_instance("arp-cache"); } static int print_entries(uint32_t ifindex, struct in_addr addr) { #ifndef WITHOUT_NETLINK return (print_entries_nl(ifindex, addr)); #else return (search(addr.s_addr, print_entry)); #endif } /* * Nuke an arp entry */ static void nuke_entry(struct sockaddr_dl *sdl __unused, struct sockaddr_in *addr, struct rt_msghdr *rtm) { char ip[20]; if (rtm->rtm_flags & RTF_PINNED) return; snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr)); delete(ip); } static void nuke_entries(uint32_t ifindex, struct in_addr addr) { search(addr.s_addr, nuke_entry); } static void usage(void) { fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: arp [-n] [-i interface] hostname", " arp [-n] [-i interface] -a", " arp -d hostname [pub]", " arp -d [-i interface] -a", " arp -s hostname ether_addr [temp] [reject | blackhole] [pub [only]]", " arp -S hostname ether_addr [temp] [reject | blackhole] [pub [only]]", " arp -f filename"); exit(1); } static struct rt_msghdr * rtmsg(int cmd, struct sockaddr_in *dst, struct sockaddr_dl *sdl) { static int seq; int rlen; int l; static int s = -1; static pid_t pid; static struct { struct rt_msghdr m_rtm; char m_space[512]; } m_rtmsg; struct rt_msghdr *rtm = &m_rtmsg.m_rtm; char *cp = m_rtmsg.m_space; if (s < 0) { /* first time: open socket, get pid */ s = socket(PF_ROUTE, SOCK_RAW, 0); if (s < 0) xo_err(1, "socket"); pid = getpid(); } errno = 0; /* * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer * appropriately. */ if (cmd == RTM_DELETE) goto doit; bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); rtm->rtm_flags = opts.flags; rtm->rtm_version = RTM_VERSION; switch (cmd) { default: xo_errx(1, "internal wrong cmd"); case RTM_ADD: rtm->rtm_addrs |= RTA_GATEWAY; if (opts.expire_time != 0) { struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); rtm->rtm_rmx.rmx_expire = opts.expire_time + tp.tv_sec; } rtm->rtm_inits = RTV_EXPIRE; rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); /* FALLTHROUGH */ case RTM_GET: rtm->rtm_addrs |= RTA_DST; } #define NEXTADDR(w, s) \ do { \ if ((s) != NULL && rtm->rtm_addrs & (w)) { \ bcopy((s), cp, sizeof(*(s))); \ cp += SA_SIZE(s); \ } \ } while (0) NEXTADDR(RTA_DST, dst); NEXTADDR(RTA_GATEWAY, sdl); rtm->rtm_msglen = cp - (char *)&m_rtmsg; doit: l = rtm->rtm_msglen; rtm->rtm_seq = ++seq; rtm->rtm_type = cmd; if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { if (errno != ESRCH || cmd != RTM_DELETE) { xo_warn("writing to routing socket"); return (NULL); } } do { l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); } while (l > 0 && (rtm->rtm_type != cmd || rtm->rtm_seq != seq || rtm->rtm_pid != pid)); if (l < 0) xo_warn("read from routing socket"); return (rtm); } /* * get_ether_addr - get the hardware address of an interface on the * the same subnet as ipaddr. */ static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr) { struct ifaddrs *ifa, *ifd, *ifas = NULL; in_addr_t ina, mask; struct sockaddr_dl *dla; int retval = 0; /* * Scan through looking for an interface with an Internet * address on the same subnet as `ipaddr'. */ if (getifaddrs(&ifas) < 0) { xo_warnx("getifaddrs"); goto done; } for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL) continue; if (ifa->ifa_addr->sa_family != AF_INET) continue; /* * Check that the interface is up, * and not point-to-point or loopback. */ if ((ifa->ifa_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) continue; /* Get its netmask and check that it's on the right subnet. */ mask = ((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr; ina = ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr; if ((ipaddr & mask) == (ina & mask)) break; /* ok, we got it! */ } if (ifa == NULL) goto done; /* * Now scan through again looking for a link-level address * for this interface. */ for (ifd = ifas; ifd != NULL; ifd = ifd->ifa_next) { if (ifd->ifa_addr == NULL) continue; if (strcmp(ifa->ifa_name, ifd->ifa_name) == 0 && ifd->ifa_addr->sa_family == AF_LINK) break; } if (ifd == NULL) goto done; /* * Found the link-level address - copy it out */ dla = (struct sockaddr_dl *)ifd->ifa_addr; memcpy(hwaddr, LLADDR(dla), dla->sdl_alen); printf("using interface %s for proxy with address %s\n", ifa->ifa_name, ether_ntoa(hwaddr)); retval = dla->sdl_alen; done: if (ifas != NULL) freeifaddrs(ifas); return (retval); } diff --git a/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c b/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c index deb890c573b0..c7d4369e5f6d 100644 --- a/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c +++ b/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c @@ -1,218 +1,218 @@ /*- * bthidcontrol.c * * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2004 Maksim Yevmenkin * 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. * * $Id: bthidcontrol.c,v 1.2 2004/02/13 21:44:41 max Exp $ * $FreeBSD$ */ #include #include #define L2CAP_SOCKET_CHECKED #include #include #include #include #include #include #include #include #include "bthid_config.h" #include "bthidcontrol.h" static int do_bthid_command(bdaddr_p bdaddr, int argc, char **argv); static struct bthid_command * find_bthid_command(char const *command, struct bthid_command *category); static void print_bthid_command(struct bthid_command *category); -static void usage(void); +static void usage(void) __dead2; int32_t hid_sdp_query(bdaddr_t const *local, bdaddr_t const *remote, int32_t *error); uint32_t verbose = 0; /* * bthidcontrol */ int main(int argc, char *argv[]) { bdaddr_t bdaddr; int opt; hid_init(NULL); memcpy(&bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr)); while ((opt = getopt(argc, argv, "a:c:H:hv")) != -1) { switch (opt) { case 'a': /* bdaddr */ if (!bt_aton(optarg, &bdaddr)) { struct hostent *he = NULL; if ((he = bt_gethostbyname(optarg)) == NULL) errx(1, "%s: %s", optarg, hstrerror(h_errno)); memcpy(&bdaddr, he->h_addr, sizeof(bdaddr)); } break; case 'c': /* config file */ config_file = optarg; break; case 'H': /* HIDs file */ hids_file = optarg; break; case 'v': /* verbose */ verbose++; break; case 'h': default: usage(); /* NOT REACHED */ } } argc -= optind; argv += optind; if (*argv == NULL) usage(); return (do_bthid_command(&bdaddr, argc, argv)); } /* main */ /* Execute commands */ static int do_bthid_command(bdaddr_p bdaddr, int argc, char **argv) { char *cmd = argv[0]; struct bthid_command *c = NULL; int e, help; help = 0; if (strcasecmp(cmd, "help") == 0) { argc --; argv ++; if (argc <= 0) { fprintf(stdout, "Supported commands:\n"); print_bthid_command(sdp_commands); print_bthid_command(hid_commands); fprintf(stdout, "\nFor more information use " \ "'help command'\n"); return (OK); } help = 1; cmd = argv[0]; } c = find_bthid_command(cmd, sdp_commands); if (c == NULL) c = find_bthid_command(cmd, hid_commands); if (c == NULL) { fprintf(stdout, "Unknown command: \"%s\"\n", cmd); return (ERROR); } if (!help) e = (c->handler)(bdaddr, -- argc, ++ argv); else e = USAGE; switch (e) { case OK: case FAILED: break; case ERROR: fprintf(stdout, "Could not execute command \"%s\". %s\n", cmd, strerror(errno)); break; case USAGE: fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description); break; default: assert(0); break; } return (e); } /* do_bthid_command */ /* Try to find command in specified category */ static struct bthid_command * find_bthid_command(char const *command, struct bthid_command *category) { struct bthid_command *c = NULL; for (c = category; c->command != NULL; c++) { char *c_end = strchr(c->command, ' '); if (c_end != NULL) { int len = c_end - c->command; if (strncasecmp(command, c->command, len) == 0) return (c); } else if (strcasecmp(command, c->command) == 0) return (c); } return (NULL); } /* find_bthid_command */ /* Print commands in specified category */ static void print_bthid_command(struct bthid_command *category) { struct bthid_command *c = NULL; for (c = category; c->command != NULL; c++) fprintf(stdout, "\t%s\n", c->command); } /* print_bthid_command */ /* Usage */ static void usage(void) { fprintf(stderr, "Usage: bthidcontrol options command\n" \ "Where options are:\n" " -a bdaddr specify bdaddr\n" \ " -c file specify path to the bthidd config file\n" \ " -H file specify path to the bthidd HIDs file\n" \ " -h display usage and quit\n" \ " -v be verbose\n" \ " command one of the supported commands\n"); exit(255); } /* usage */ diff --git a/usr.sbin/bluetooth/btpand/btpand.c b/usr.sbin/bluetooth/btpand/btpand.c index 6e215fe32269..f226338edd15 100644 --- a/usr.sbin/bluetooth/btpand/btpand.c +++ b/usr.sbin/bluetooth/btpand/btpand.c @@ -1,296 +1,296 @@ /* $NetBSD: btpand.c,v 1.1 2008/08/17 13:20:57 plunky Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2008 Iain Hibbert * 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. */ /* $FreeBSD$ */ #include __COPYRIGHT("@(#) Copyright (c) 2008 Iain Hibbert. All rights reserved."); __RCSID("$NetBSD: btpand.c,v 1.1 2008/08/17 13:20:57 plunky Exp $"); #include #define L2CAP_SOCKET_CHECKED #include #include #include #include #include #include #include #include #include #include #include "btpand.h" /* global variables */ const char * control_path; /* -c */ const char * interface_name; /* -i */ const char * service_name; /* -s */ uint16_t service_class; bdaddr_t local_bdaddr; /* -d */ bdaddr_t remote_bdaddr; /* -a */ uint16_t l2cap_psm; /* -p */ int l2cap_mode; /* -m */ int server_limit; /* -n */ static const struct { const char * name; uint16_t class; const char * desc; } services[] = { { "PANU", SDP_SERVICE_CLASS_PANU, "Personal Area Networking User" }, { "NAP", SDP_SERVICE_CLASS_NAP, "Network Access Point" }, { "GN", SDP_SERVICE_CLASS_GN, "Group Network" }, }; -static void main_exit(int); +static void main_exit(int) __dead2; static void main_detach(void); -static void usage(void); +static void usage(void) __dead2; int main(int argc, char *argv[]) { unsigned long ul; char * ep; int ch, status; while ((ch = getopt(argc, argv, "a:c:d:i:l:m:p:S:s:")) != -1) { switch (ch) { case 'a': /* remote address */ if (!bt_aton(optarg, &remote_bdaddr)) { struct hostent *he; if ((he = bt_gethostbyname(optarg)) == NULL) errx(EXIT_FAILURE, "%s: %s", optarg, hstrerror(h_errno)); bdaddr_copy(&remote_bdaddr, (bdaddr_t *)he->h_addr); } break; case 'c': /* control socket path */ control_path = optarg; break; case 'd': /* local address */ if (!bt_devaddr(optarg, &local_bdaddr)) { struct hostent *he; if ((he = bt_gethostbyname(optarg)) == NULL) errx(EXIT_FAILURE, "%s: %s", optarg, hstrerror(h_errno)); bdaddr_copy(&local_bdaddr, (bdaddr_t *)he->h_addr); } break; case 'i': /* tap interface name */ if (strchr(optarg, '/') == NULL) { asprintf(&ep, "/dev/%s", optarg); interface_name = ep; } else interface_name = optarg; break; case 'l': /* limit server sessions */ ul = strtoul(optarg, &ep, 10); if (*optarg == '\0' || *ep != '\0' || ul == 0) errx(EXIT_FAILURE, "%s: invalid session limit", optarg); server_limit = ul; break; case 'm': /* link mode */ warnx("Setting link mode is not yet supported"); break; case 'p': /* protocol/service multiplexer */ ul = strtoul(optarg, &ep, 0); if (*optarg == '\0' || *ep != '\0' || ul > 0xffff || L2CAP_PSM_INVALID(ul)) errx(EXIT_FAILURE, "%s: invalid PSM", optarg); l2cap_psm = ul; break; case 's': /* service */ case 'S': /* service (no SDP) */ for (ul = 0; strcasecmp(optarg, services[ul].name); ul++) { if (ul == __arraycount(services)) errx(EXIT_FAILURE, "%s: unknown service", optarg); } if (ch == 's') service_name = services[ul].name; service_class = services[ul].class; break; default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; /* validate options */ if (bdaddr_any(&local_bdaddr) || service_class == 0) usage(); if (!bdaddr_any(&remote_bdaddr) && (server_limit != 0 || control_path != NULL || (service_name != NULL && l2cap_psm != 0))) usage(); /* default options */ if (interface_name == NULL) interface_name = "/dev/tap"; if (l2cap_psm == 0) l2cap_psm = L2CAP_PSM_BNEP; if (bdaddr_any(&remote_bdaddr) && server_limit == 0) { if (service_class == SDP_SERVICE_CLASS_PANU) server_limit = 1; else server_limit = 7; } #ifdef L2CAP_LM_MASTER if (server_limit > 1 && service_class != SDP_SERVICE_CLASS_PANU) l2cap_mode |= L2CAP_LM_MASTER; #endif /* * fork() now so that the setup can be done in the child process * (as kqueue is not inherited) but block in the parent until the * setup is finished so we can return an error if necessary. */ switch(fork()) { case -1: /* bad */ err(EXIT_FAILURE, "fork() failed"); case 0: /* child */ signal(SIGPIPE, SIG_IGN); openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON); channel_init(); server_init(); event_init(); client_init(); tap_init(); main_detach(); event_dispatch(); break; default: /* parent */ signal(SIGUSR1, main_exit); wait(&status); if (WIFEXITED(status)) exit(WEXITSTATUS(status)); break; } err(EXIT_FAILURE, "exiting"); } static void main_exit(int s) { /* child is all grown up */ _exit(EXIT_SUCCESS); } static void main_detach(void) { int fd; if (kill(getppid(), SIGUSR1) == -1) log_err("Could not signal main process: %m"); if (setsid() == -1) log_err("setsid() failed"); fd = open(_PATH_DEVNULL, O_RDWR, 0); if (fd == -1) { log_err("Could not open %s", _PATH_DEVNULL); } else { (void)dup2(fd, STDIN_FILENO); (void)dup2(fd, STDOUT_FILENO); (void)dup2(fd, STDERR_FILENO); close(fd); } } static void usage(void) { const char *p = getprogname(); int n = strlen(p); fprintf(stderr, "usage: %s [-i ifname] [-m mode] -a address -d device\n" " %*s {-s service | -S service [-p psm]}\n" " %s [-c path] [-i ifname] [-l limit] [-m mode] [-p psm] -d device\n" " %*s {-s service | -S service}\n" "\n" "Where:\n" "\t-a address remote bluetooth device\n" "\t-c path SDP server socket\n" "\t-d device local bluetooth device\n" "\t-i ifname tap interface\n" "\t-l limit limit server sessions\n" "\t-m mode L2CAP link mode (NOT YET SUPPORTED)\n" "\t-p psm L2CAP PSM\n" "\t-S service service name (no SDP)\n" "\t-s service service name\n" "\n" "Known services:\n" "", p, n, "", p, n, ""); for (n = 0; n < __arraycount(services); n++) fprintf(stderr, "\t%s\t%s\n", services[n].name, services[n].desc); exit(EXIT_FAILURE); } diff --git a/usr.sbin/boot0cfg/boot0cfg.c b/usr.sbin/boot0cfg/boot0cfg.c index bccab173e2fb..1b742dd6ef9c 100644 --- a/usr.sbin/boot0cfg/boot0cfg.c +++ b/usr.sbin/boot0cfg/boot0cfg.c @@ -1,602 +1,602 @@ /* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2008 Luigi Rizzo * Copyright (c) 1999 Robert Nordier * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #define MBRSIZE 512 /* master boot record size */ #define OFF_VERSION 0x1b0 /* offset: version number, only boot0version */ #define OFF_SERIAL 0x1b8 /* offset: volume serial number */ #define OFF_PTBL 0x1be /* offset: partition table */ #define OFF_MAGIC 0x1fe /* offset: magic number */ /* * Offsets to the parameters of the 512-byte boot block. * For historical reasons they are set as macros */ struct opt_offsets { int opt; int drive; int flags; int ticks; }; static struct opt_offsets b0_ofs[] = { { 0x0, 0x0, 0x0, 0x0 }, /* no boot block */ { 0x1b9, 0x1ba, 0x1bb, 0x1bc }, /* original block */ { 0x1b5, 0x1b6, 0x1b7, 0x1bc }, /* NT_SERIAL block */ }; static int b0_ver; /* boot block version set by boot0bs */ #define OFF_OPT (b0_ofs[b0_ver].opt) /* default boot option */ #define OFF_DRIVE (b0_ofs[b0_ver].drive) /* setdrv drive */ #define OFF_FLAGS (b0_ofs[b0_ver].flags) /* option flags */ #define OFF_TICKS (b0_ofs[b0_ver].ticks) /* clock ticks */ #define cv2(p) ((p)[0] | (p)[1] << 010) #define mk2(p, x) \ (p)[0] = (u_int8_t)(x), \ (p)[1] = (u_int8_t)((x) >> 010) static const struct { const char *tok; int def; } opttbl[] = { {"packet", 0}, {"update", 1}, {"setdrv", 0} }; static const int nopt = nitems(opttbl); static const char fmt0[] = "# flag start chs type" " end chs offset size\n"; static const char fmt1[] = "%d 0x%02x %4u:%3u:%2u 0x%02x" " %4u:%3u:%2u %10u %10u\n"; static int geom_class_available(const char *); static int read_mbr(const char *, u_int8_t **, int); static void write_mbr(const char *, int, u_int8_t *, int, int); static void display_mbr(u_int8_t *); static int boot0version(const u_int8_t *); static int boot0bs(const u_int8_t *); static void stropt(const char *, int *, int *); static int argtoi(const char *, int, int, int); static int set_bell(u_int8_t *, int, int); -static void usage(void); +static void usage(void) __dead2; static unsigned vol_id[5]; /* 4 plus 1 for flag */ static int v_flag; /* * Boot manager installation/configuration utility. */ int main(int argc, char *argv[]) { u_int8_t *mbr, *boot0; int boot0_size, mbr_size; const char *bpath, *fpath; char *disk; int B_flag, o_flag; int d_arg, m_arg, s_arg, t_arg; int o_and, o_or, o_e = -1; int up, c; bpath = "/boot/boot0"; fpath = NULL; B_flag = v_flag = o_flag = 0; d_arg = m_arg = s_arg = t_arg = -1; o_and = 0xff; o_or = 0; while ((c = getopt(argc, argv, "Bvb:d:e:f:i:m:o:s:t:")) != -1) switch (c) { case 'B': B_flag = 1; break; case 'v': v_flag = 1; break; case 'b': bpath = optarg; break; case 'd': d_arg = argtoi(optarg, 0, 0xff, 'd'); break; case 'e': if (optarg[0] == '0' && optarg[1] == 'x') sscanf(optarg, "0x%02x", &o_e); else o_e = optarg[0]; break; case 'f': fpath = optarg; break; case 'i': if (sscanf(optarg, "%02x%02x-%02x%02x", vol_id, vol_id+1, vol_id+2, vol_id+3) == 4) vol_id[4] = 1; else errx(1, "bad argument %s", optarg); break; case 'm': m_arg = argtoi(optarg, 0, 0xf, 'm'); break; case 'o': stropt(optarg, &o_and, &o_or); o_flag = 1; break; case 's': if (strcasecmp(optarg, "pxe") == 0) s_arg = 6; else s_arg = argtoi(optarg, 1, 6, 's'); break; case 't': t_arg = argtoi(optarg, 1, 0xffff, 't'); break; default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); disk = g_device_path(*argv); if (disk == NULL) errx(1, "Unable to get providername for %s\n", *argv); up = B_flag || d_arg != -1 || m_arg != -1 || o_flag || s_arg != -1 || t_arg != -1; /* open the disk and read in the existing mbr. Either here or * when reading the block from disk, we do check for the version * and abort if a suitable block is not found. */ mbr_size = read_mbr(disk, &mbr, !B_flag); /* save the existing MBR if we are asked to do so */ if (fpath) write_mbr(fpath, O_CREAT | O_TRUNC, mbr, mbr_size, 0); /* * If we are installing the boot loader, read it from disk and copy the * slice table over from the existing MBR. If not, then point boot0 * back at the MBR we just read in. After this, boot0 is the data to * write back to disk if we are going to do a write. */ if (B_flag) { boot0_size = read_mbr(bpath, &boot0, 1); memcpy(boot0 + OFF_PTBL, mbr + OFF_PTBL, sizeof(struct dos_partition) * NDOSPART); if (b0_ver == 2) /* volume serial number support */ memcpy(boot0 + OFF_SERIAL, mbr + OFF_SERIAL, 4); } else { boot0 = mbr; boot0_size = mbr_size; } /* set the drive */ if (d_arg != -1) boot0[OFF_DRIVE] = d_arg; /* set various flags */ if (m_arg != -1) { boot0[OFF_FLAGS] &= 0xf0; boot0[OFF_FLAGS] |= m_arg; } if (o_flag) { boot0[OFF_FLAGS] &= o_and; boot0[OFF_FLAGS] |= o_or; } /* set the default boot selection */ if (s_arg != -1) boot0[OFF_OPT] = s_arg - 1; /* set the timeout */ if (t_arg != -1) mk2(boot0 + OFF_TICKS, t_arg); /* set the bell char */ if (o_e != -1 && set_bell(boot0, o_e, 0) != -1) up = 1; if (vol_id[4]) { if (b0_ver != 2) errx(1, "incompatible boot block, cannot set volume ID"); boot0[OFF_SERIAL] = vol_id[0]; boot0[OFF_SERIAL+1] = vol_id[1]; boot0[OFF_SERIAL+2] = vol_id[2]; boot0[OFF_SERIAL+3] = vol_id[3]; up = 1; /* force update */ } /* write the MBR back to disk */ if (up) write_mbr(disk, 0, boot0, boot0_size, vol_id[4] || b0_ver == 1); /* display the MBR */ if (v_flag) display_mbr(boot0); /* clean up */ if (mbr != boot0) free(boot0); free(mbr); free(disk); return 0; } /* get or set the 'bell' character to be used in case of errors. * Lookup for a certain code sequence, return -1 if not found. */ static int set_bell(u_int8_t *mbr, int new_bell, int report) { /* lookup sequence: 0x100 means skip, 0x200 means done */ static unsigned seq[] = { 0xb0, 0x100, 0xe8, 0x100, 0x100, 0x30, 0xe4, 0x200 }; int ofs, i, c; for (ofs = 0x60; ofs < 0x180; ofs++) { /* search range */ if (mbr[ofs] != seq[0]) /* search initial pattern */ continue; for (i=0;; i++) { if (seq[i] == 0x200) { /* found */ c = mbr[ofs+1]; if (!report) mbr[ofs+1] = c = new_bell; else printf(" bell=%c (0x%x)", (c >= ' ' && c < 0x7f) ? c : ' ', c); return c; } if (seq[i] != 0x100 && seq[i] != mbr[ofs+i]) break; } } warn("bell not found"); return -1; } /* * Read in the MBR of the disk. If it is boot0, then use the version to * read in all of it if necessary. Use pointers to return a malloc'd * buffer containing the MBR and then return its size. */ static int read_mbr(const char *disk, u_int8_t **mbr, int check_version) { u_int8_t buf[MBRSIZE]; int mbr_size, fd; int ver; ssize_t n; if ((fd = open(disk, O_RDONLY)) == -1) err(1, "open %s", disk); if ((n = read(fd, buf, MBRSIZE)) == -1) err(1, "read %s", disk); if (n != MBRSIZE) errx(1, "%s: short read", disk); if (cv2(buf + OFF_MAGIC) != 0xaa55) errx(1, "%s: bad magic", disk); if (! (ver = boot0bs(buf))) { if (check_version) errx(1, "%s: unknown or incompatible boot code", disk); } else if (boot0version(buf) == 0x101) { mbr_size = 1024; if ((*mbr = malloc(mbr_size)) == NULL) errx(1, "%s: unable to allocate read buffer", disk); if (lseek(fd, 0, SEEK_SET) == -1 || (n = read(fd, *mbr, mbr_size)) == -1) err(1, "%s", disk); if (n != mbr_size) errx(1, "%s: short read", disk); close(fd); return (mbr_size); } if ((*mbr = malloc(sizeof(buf))) == NULL) errx(1, "%s: unable to allocate MBR buffer", disk); memcpy(*mbr, buf, sizeof(buf)); close(fd); return sizeof(buf); } static int geom_class_available(const char *name) { struct gclass *class; struct gmesh mesh; int error; error = geom_gettree(&mesh); if (error != 0) errc(1, error, "Cannot get GEOM tree"); LIST_FOREACH(class, &mesh.lg_class, lg_class) { if (strcmp(class->lg_name, name) == 0) { geom_deletetree(&mesh); return (1); } } geom_deletetree(&mesh); return (0); } /* * Write out the mbr to the specified file. */ static void write_mbr(const char *fname, int flags, u_int8_t *mbr, int mbr_size, int disable_dsn) { struct gctl_req *grq; const char *errmsg; char *pname; ssize_t n; int fd; fd = open(fname, O_WRONLY | flags, 0666); if (fd != -1) { n = write(fd, mbr, mbr_size); close(fd); if (n != mbr_size) errx(1, "%s: short write", fname); return; } /* * If we're called to write to a backup file, don't try to * write through GEOM. */ if (flags != 0) err(1, "can't open file %s to write backup", fname); /* Try open it read only. */ fd = open(fname, O_RDONLY); if (fd == -1) { warn("error opening %s", fname); return; } pname = g_providername(fd); if (pname == NULL) { warn("error getting providername for %s", fname); return; } /* First check that GEOM_PART is available */ if (geom_class_available("PART") != 0) { grq = gctl_get_handle(); gctl_ro_param(grq, "class", -1, "PART"); gctl_ro_param(grq, "arg0", -1, pname); gctl_ro_param(grq, "verb", -1, "bootcode"); gctl_ro_param(grq, "bootcode", mbr_size, mbr); gctl_ro_param(grq, "flags", -1, "C"); if (disable_dsn) gctl_ro_param(grq, "skip_dsn", sizeof(int), &disable_dsn); errmsg = gctl_issue(grq); if (errmsg != NULL && errmsg[0] != '\0') errx(1, "GEOM_PART: write bootcode to %s failed: %s", fname, errmsg); gctl_free(grq); } else errx(1, "can't write MBR to %s", fname); free(pname); } /* * Outputs an informative dump of the data in the MBR to stdout. */ static void display_mbr(u_int8_t *mbr) { struct dos_partition *part; int i, version; part = (struct dos_partition *)(mbr + DOSPARTOFF); printf(fmt0); for (i = 0; i < NDOSPART; i++) if (part[i].dp_typ) printf(fmt1, 1 + i, part[i].dp_flag, part[i].dp_scyl + ((part[i].dp_ssect & 0xc0) << 2), part[i].dp_shd, part[i].dp_ssect & 0x3f, part[i].dp_typ, part[i].dp_ecyl + ((part[i].dp_esect & 0xc0) << 2), part[i].dp_ehd, part[i].dp_esect & 0x3f, part[i].dp_start, part[i].dp_size); printf("\n"); version = boot0version(mbr); printf("version=%d.%d drive=0x%x mask=0x%x ticks=%u", version >> 8, version & 0xff, mbr[OFF_DRIVE], mbr[OFF_FLAGS] & 0xf, cv2(mbr + OFF_TICKS)); set_bell(mbr, 0, 1); printf("\noptions="); for (i = 0; i < nopt; i++) { if (i) printf(","); if (!(mbr[OFF_FLAGS] & 1 << (7 - i)) ^ opttbl[i].def) printf("no"); printf("%s", opttbl[i].tok); } printf("\n"); if (b0_ver == 2) printf("volume serial ID %02x%02x-%02x%02x\n", mbr[OFF_SERIAL], mbr[OFF_SERIAL+1], mbr[OFF_SERIAL+2], mbr[OFF_SERIAL+3]); printf("default_selection=F%d (", mbr[OFF_OPT] + 1); if (mbr[OFF_OPT] < 4) printf("Slice %d", mbr[OFF_OPT] + 1); else if (mbr[OFF_OPT] == 4) printf("Drive 1"); else printf("PXE"); printf(")\n"); } /* * Return the boot0 version with the minor revision in the low byte, and * the major revision in the next higher byte. */ static int boot0version(const u_int8_t *bs) { /* Check for old version, and return 0x100 if found. */ int v = boot0bs(bs); if (v != 0) return v << 8; /* We have a newer boot0, so extract the version number and return it. */ return *(const int *)(bs + OFF_VERSION) & 0xffff; } /* descriptor of a pattern to match. * Start from the first entry trying to match the chunk of bytes, * if you hit an entry with len=0 terminate the search and report * off as the version. Otherwise skip to the next block after len=0 * An entry with len=0, off=0 is the end marker. */ struct byte_pattern { unsigned off; unsigned len; u_int8_t *key; }; /* * Decide if we have valid boot0 boot code by looking for * characteristic byte sequences at fixed offsets. */ static int boot0bs(const u_int8_t *bs) { /* the initial code sequence */ static u_int8_t id0[] = {0xfc, 0x31, 0xc0, 0x8e, 0xc0, 0x8e, 0xd8, 0x8e, 0xd0, 0xbc, 0x00, 0x7c }; /* the drive id */ static u_int8_t id1[] = {'D', 'r', 'i', 'v', 'e', ' '}; static struct byte_pattern patterns[] = { {0x0, sizeof(id0), id0}, {0x1b2, sizeof(id1), id1}, {1, 0, NULL}, {0x0, sizeof(id0), id0}, /* version with NT support */ {0x1ae, sizeof(id1), id1}, {2, 0, NULL}, {0, 0, NULL}, }; struct byte_pattern *p = patterns; for (; p->off || p->len; p++) { if (p->len == 0) break; if (!memcmp(bs + p->off, p->key, p->len)) /* match */ continue; while (p->len) /* skip to next block */ p++; } b0_ver = p->off; /* XXX ugly side effect */ return p->off; } /* * Adjust "and" and "or" masks for a -o option argument. */ static void stropt(const char *arg, int *xa, int *xo) { const char *q; char *s, *s1; int inv, i, x; if (!(s = strdup(arg))) err(1, NULL); for (s1 = s; (q = strtok(s1, ",")); s1 = NULL) { if ((inv = !strncmp(q, "no", 2))) q += 2; for (i = 0; i < nopt; i++) if (!strcmp(q, opttbl[i].tok)) break; if (i == nopt) errx(1, "%s: Unknown -o option", q); if (opttbl[i].def) inv ^= 1; x = 1 << (7 - i); if (inv) *xa &= ~x; else *xo |= x; } free(s); } /* * Convert and check an option argument. */ static int argtoi(const char *arg, int lo, int hi, int opt) { char *s; long x; errno = 0; x = strtol(arg, &s, 0); if (errno || !*arg || *s || x < lo || x > hi) errx(1, "%s: Bad argument to -%c option", arg, opt); return x; } /* * Display usage information. */ static void usage(void) { fprintf(stderr, "%s\n%s\n", "usage: boot0cfg [-Bv] [-b boot0] [-d drive] [-f file] [-m mask]", " [-o options] [-s slice] [-t ticks] disk"); exit(1); } diff --git a/usr.sbin/bootparamd/bootparamd/main.c b/usr.sbin/bootparamd/bootparamd/main.c index 95b49f8f39a0..578bb2605be6 100644 --- a/usr.sbin/bootparamd/bootparamd/main.c +++ b/usr.sbin/bootparamd/bootparamd/main.c @@ -1,118 +1,118 @@ /* This code is not copyright, and is placed in the public domain. Feel free to use and modify. Please send modifications and/or suggestions + bug fixes to Klas Heggemann */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bootparam_prot.h" extern int debug, dolog; extern in_addr_t route_addr; extern const char *bootpfile; int debug = 0; int dolog = 0; in_addr_t route_addr = -1; const char *bootpfile = "/etc/bootparams"; static struct sockaddr_in my_addr; -static void usage(void); +static void usage(void) __dead2; int main(int argc, char **argv) { SVCXPRT *transp; struct hostent *he; struct stat buf; int c; while ((c = getopt(argc, argv,"dsr:f:")) != -1) switch (c) { case 'd': debug = 1; break; case 'r': if (isdigit((unsigned char)*optarg)) { route_addr = inet_addr(optarg); break; } else { he = gethostbyname(optarg); if (he) { bcopy(he->h_addr, (char *)&route_addr, sizeof(route_addr)); break; } else { errx(1, "no such host %s", optarg); } } case 'f': bootpfile = optarg; break; case 's': dolog = 1; #ifndef LOG_DAEMON openlog("bootparamd", 0 , 0); #else openlog("bootparamd", 0 , LOG_DAEMON); setlogmask(LOG_UPTO(LOG_NOTICE)); #endif break; default: usage(); } if ( stat(bootpfile, &buf ) ) err(1, "%s", bootpfile); if (route_addr == INADDR_NONE) { get_myaddress(&my_addr); bcopy(&my_addr.sin_addr.s_addr, &route_addr, sizeof (route_addr)); } if (!debug) { if (daemon(0,0)) err(1, "fork"); } (void)pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS); transp = svcudp_create(RPC_ANYSOCK); if (transp == NULL) errx(1, "cannot create udp service"); if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS, bootparamprog_1, IPPROTO_UDP)) errx(1, "unable to register (BOOTPARAMPROG, BOOTPARAMVERS, udp)"); svc_run(); errx(1, "svc_run returned"); } static void usage(void) { fprintf(stderr, "usage: bootparamd [-d] [-s] [-r router] [-f bootparmsfile]\n"); exit(1); } diff --git a/usr.sbin/bootparamd/callbootd/callbootd.c b/usr.sbin/bootparamd/callbootd/callbootd.c index ea1432c3140a..0a0980bd4aa0 100644 --- a/usr.sbin/bootparamd/callbootd/callbootd.c +++ b/usr.sbin/bootparamd/callbootd/callbootd.c @@ -1,193 +1,193 @@ /* This code is not copyright, and is placed in the public domain. Feel free to use and modify. Please send modifications and/or suggestions + bug fixes to Klas Heggemann */ #include __FBSDID("$FreeBSD$"); #include "bootparam_prot.h" #include #include #include #include #include #include #include #include /* #define bp_address_u bp_address */ #include #include static int broadcast; static char cln[MAX_MACHINE_NAME+1]; static char dmn[MAX_MACHINE_NAME+1]; static char path[MAX_PATH_LEN+1]; -static void usage(void); +static void usage(void) __dead2; int printgetfile(bp_getfile_res *); int printwhoami(bp_whoami_res *); static bool_t eachres_whoami(bp_whoami_res *resultp, struct sockaddr_in *raddr) { struct hostent *he; he = gethostbyaddr((char *)&raddr->sin_addr.s_addr,4,AF_INET); printf("%s answered:\n", he ? he->h_name : inet_ntoa(raddr->sin_addr)); printwhoami(resultp); printf("\n"); return(0); } static bool_t eachres_getfile(bp_getfile_res *resultp, struct sockaddr_in *raddr) { struct hostent *he; he = gethostbyaddr((char *)&raddr->sin_addr.s_addr,4,AF_INET); printf("%s answered:\n", he ? he->h_name : inet_ntoa(raddr->sin_addr)); printgetfile(resultp); printf("\n"); return(0); } int main(int argc, char **argv) { char *server; bp_whoami_arg whoami_arg; bp_whoami_res *whoami_res, stat_whoami_res; bp_getfile_arg getfile_arg; bp_getfile_res *getfile_res, stat_getfile_res; in_addr_t the_inet_addr; CLIENT *clnt = NULL; /* Silence warnings */ stat_whoami_res.client_name = cln; stat_whoami_res.domain_name = dmn; stat_getfile_res.server_name = cln; stat_getfile_res.server_path = path; if (argc < 3) usage(); server = argv[1]; if ( ! strcmp(server , "all") ) broadcast = 1; if ( ! broadcast ) { clnt = clnt_create(server,BOOTPARAMPROG, BOOTPARAMVERS, "udp"); if ( clnt == NULL ) errx(1, "could not contact bootparam server on host %s", server); } switch (argc) { case 3: whoami_arg.client_address.address_type = IP_ADDR_TYPE; the_inet_addr = inet_addr(argv[2]); if ( the_inet_addr == INADDR_NONE) errx(2, "bogus addr %s", argv[2]); bcopy(&the_inet_addr,&whoami_arg.client_address.bp_address_u.ip_addr,4); if (! broadcast ) { whoami_res = bootparamproc_whoami_1(&whoami_arg, clnt); printf("Whoami returning:\n"); if (printwhoami(whoami_res)) { errx(1, "bad answer returned from server %s", server); } else exit(0); } else { (void)clnt_broadcast(BOOTPARAMPROG, BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI, (xdrproc_t)xdr_bp_whoami_arg, (char *)&whoami_arg, (xdrproc_t)xdr_bp_whoami_res, (char *)&stat_whoami_res, (resultproc_t)eachres_whoami); exit(0); } case 4: getfile_arg.client_name = argv[2]; getfile_arg.file_id = argv[3]; if (! broadcast ) { getfile_res = bootparamproc_getfile_1(&getfile_arg,clnt); printf("getfile returning:\n"); if (printgetfile(getfile_res)) { errx(1, "bad answer returned from server %s", server); } else exit(0); } else { (void)clnt_broadcast(BOOTPARAMPROG, BOOTPARAMVERS, BOOTPARAMPROC_GETFILE, (xdrproc_t)xdr_bp_getfile_arg, (char *)&getfile_arg, (xdrproc_t)xdr_bp_getfile_res, (char *)&stat_getfile_res, (resultproc_t)eachres_getfile); exit(0); } default: usage(); } } static void usage(void) { fprintf(stderr, "usage: callbootd server procnum (IP-addr | host fileid)\n"); exit(1); } int printwhoami(bp_whoami_res *res) { if ( res) { printf("client_name:\t%s\ndomain_name:\t%s\n", res->client_name, res->domain_name); printf("router:\t%d.%d.%d.%d\n", 255 & res->router_address.bp_address_u.ip_addr.net, 255 & res->router_address.bp_address_u.ip_addr.host, 255 & res->router_address.bp_address_u.ip_addr.lh, 255 & res->router_address.bp_address_u.ip_addr.impno); return(0); } else { warnx("null answer!!!"); return(1); } } int printgetfile(bp_getfile_res *res) { if (res) { printf("server_name:\t%s\nserver_address:\t%s\npath:\t%s\n", res->server_name, inet_ntoa(*(struct in_addr *)&res->server_address.bp_address_u.ip_addr), res->server_path); return(0); } else { warnx("null answer!!!"); return(1); } } diff --git a/usr.sbin/btxld/btxld.c b/usr.sbin/btxld/btxld.c index 5ce24a42b216..e7211ad48fa4 100644 --- a/usr.sbin/btxld/btxld.c +++ b/usr.sbin/btxld/btxld.c @@ -1,576 +1,576 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 1998 Robert Nordier * 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. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include /* XXX make this work as an i386/amd64 cross-tool */ #include #undef __LDPGSZ #define __LDPGSZ 4096 #include #include #include #include #include #include #include #include #include #include #include "btx.h" #include "elfh.h" #define BTX_PATH "/sys/boot/i386/btx" #define I_LDR 0 /* BTX loader */ #define I_BTX 1 /* BTX kernel */ #define I_CLNT 2 /* Client program */ #define F_BIN 0 /* Binary */ #define F_AOUT 1 /* ZMAGIC a.out */ #define F_ELF 2 /* 32-bit ELF */ #define F_CNT 3 /* Number of formats */ #define IMPURE 1 /* Writable text */ #define MAXU32 0xffffffff /* Maximum unsigned 32-bit quantity */ struct hdr { uint32_t fmt; /* Format */ uint32_t flags; /* Bit flags */ uint32_t size; /* Size of file */ uint32_t text; /* Size of text segment */ uint32_t data; /* Size of data segment */ uint32_t bss; /* Size of bss segment */ uint32_t org; /* Program origin */ uint32_t entry; /* Program entry point */ }; static const char *const fmtlist[] = {"bin", "aout", "elf"}; static const char binfo[] = "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM " "pgctl=%x:%x\n"; static const char cinfo[] = "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n"; static const char oinfo[] = "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n"; static const char *lname = BTX_PATH "/btxldr/btxldr"; /* BTX loader */ static const char *bname = BTX_PATH "/btx/btx"; /* BTX kernel */ static const char *oname = "a.out"; /* Output filename */ static int ppage = -1; /* First page present */ static int wpage = -1; /* First page writable */ static unsigned int format; /* Output format */ static uint32_t centry; /* Client entry address */ static uint32_t lentry; /* Loader entry address */ static int Eflag; /* Client entry option */ static int quiet; /* Inhibit warnings */ static int verbose; /* Display information */ static const char *tname; /* Temporary output file */ static const char *fname; /* Current input file */ static void cleanup(void); static void btxld(const char *); static void getbtx(int, struct btx_hdr *); static void gethdr(int, struct hdr *); static void puthdr(int, struct hdr *); static void copy(int, int, size_t, off_t); static size_t readx(int, void *, size_t, off_t); static void writex(int, const void *, size_t); static void seekx(int, off_t); static unsigned int optfmt(const char *); static uint32_t optaddr(const char *); static int optpage(const char *, int); static void Warn(const char *, const char *, ...); -static void usage(void); +static void usage(void) __dead2; /* * A link editor for BTX clients. */ int main(int argc, char *argv[]) { int c; while ((c = getopt(argc, argv, "qvb:E:e:f:l:o:P:W:")) != -1) switch (c) { case 'q': quiet = 1; break; case 'v': verbose = 1; break; case 'b': bname = optarg; break; case 'E': centry = optaddr(optarg); Eflag = 1; break; case 'e': lentry = optaddr(optarg); break; case 'f': format = optfmt(optarg); break; case 'l': lname = optarg; break; case 'o': oname = optarg; break; case 'P': ppage = optpage(optarg, 1); break; case 'W': wpage = optpage(optarg, BTX_MAXCWR); break; default: usage(); } argc -= optind; argv += optind; if (argc != 1) usage(); atexit(cleanup); btxld(*argv); return 0; } /* * Clean up after errors. */ static void cleanup(void) { if (tname) (void)remove(tname); } /* * Read the input files; write the output file; display information. */ static void btxld(const char *iname) { char name[FILENAME_MAX]; struct btx_hdr btx, btxle; struct hdr ihdr, ohdr; unsigned int ldr_size, cwr; int fdi[3], fdo, i; ldr_size = 0; for (i = I_LDR; i <= I_CLNT; i++) { fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; if ((fdi[i] = open(fname, O_RDONLY)) == -1) err(2, "%s", fname); switch (i) { case I_LDR: gethdr(fdi[i], &ihdr); if (ihdr.fmt != F_BIN) Warn(fname, "Loader format is %s; processing as %s", fmtlist[ihdr.fmt], fmtlist[F_BIN]); ldr_size = ihdr.size; break; case I_BTX: getbtx(fdi[i], &btx); break; case I_CLNT: gethdr(fdi[i], &ihdr); if (ihdr.org && ihdr.org != BTX_PGSIZE) Warn(fname, "Client origin is 0x%x; expecting 0 or 0x%x", ihdr.org, BTX_PGSIZE); } } memset(&ohdr, 0, sizeof(ohdr)); ohdr.fmt = format; ohdr.text = ldr_size; ohdr.data = btx.btx_textsz + ihdr.size; ohdr.org = lentry; ohdr.entry = lentry; cwr = 0; if (wpage > 0 || (wpage == -1 && !(ihdr.flags & IMPURE))) { if (wpage > 0) cwr = wpage; else { cwr = howmany(ihdr.text, BTX_PGSIZE); if (cwr > BTX_MAXCWR) cwr = BTX_MAXCWR; } } if (ppage > 0 || (ppage && wpage && ihdr.org >= BTX_PGSIZE)) { btx.btx_flags |= BTX_MAPONE; if (!cwr) cwr++; } btx.btx_pgctl -= cwr; btx.btx_entry = Eflag ? centry : ihdr.entry; if ((size_t)snprintf(name, sizeof(name), "%s.tmp", oname) >= sizeof(name)) errx(2, "%s: Filename too long", oname); if ((fdo = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1) err(2, "%s", name); if (!(tname = strdup(name))) err(2, NULL); puthdr(fdo, &ohdr); for (i = I_LDR; i <= I_CLNT; i++) { fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; switch (i) { case I_LDR: copy(fdi[i], fdo, ldr_size, 0); seekx(fdo, ohdr.size += ohdr.text); break; case I_BTX: btxle = btx; btxle.btx_pgctl = htole16(btxle.btx_pgctl); btxle.btx_textsz = htole16(btxle.btx_textsz); btxle.btx_entry = htole32(btxle.btx_entry); writex(fdo, &btxle, sizeof(btxle)); copy(fdi[i], fdo, btx.btx_textsz - sizeof(btx), sizeof(btx)); break; case I_CLNT: copy(fdi[i], fdo, ihdr.size, 0); if (ftruncate(fdo, ohdr.size += ohdr.data)) err(2, "%s", tname); } if (close(fdi[i])) err(2, "%s", fname); } if (close(fdo)) err(2, "%s", tname); if (rename(tname, oname)) err(2, "%s: Can't rename to %s", tname, oname); free((void*)(intptr_t)tname); tname = NULL; if (verbose) { printf(binfo, btx.btx_majver, btx.btx_minver, btx.btx_textsz, BTX_ORIGIN(btx), BTX_ENTRY(btx), BTX_MAPPED(btx) * BTX_PGSIZE / 0x100000, !!(btx.btx_flags & BTX_MAPONE), BTX_MAPPED(btx) - btx.btx_pgctl - BTX_PGBASE / BTX_PGSIZE - BTX_MAPPED(btx) * 4 / BTX_PGSIZE); printf(cinfo, fmtlist[ihdr.fmt], ihdr.size, ihdr.text, ihdr.data, ihdr.bss, ihdr.entry); printf(oinfo, fmtlist[ohdr.fmt], ohdr.size, ohdr.text, ohdr.data, ohdr.org, ohdr.entry); } } /* * Read BTX file header. */ static void getbtx(int fd, struct btx_hdr * btx) { if (readx(fd, btx, sizeof(*btx), 0) != sizeof(*btx) || btx->btx_magic[0] != BTX_MAG0 || btx->btx_magic[1] != BTX_MAG1 || btx->btx_magic[2] != BTX_MAG2) errx(1, "%s: Not a BTX kernel", fname); btx->btx_pgctl = le16toh(btx->btx_pgctl); btx->btx_textsz = le16toh(btx->btx_textsz); btx->btx_entry = le32toh(btx->btx_entry); } /* * Get file size and read a.out or ELF header. */ static void gethdr(int fd, struct hdr *hdr) { struct stat sb; const struct exec *ex; const Elf32_Ehdr *ee; const Elf32_Phdr *ep; void *p; unsigned int fmt, x, n, i; memset(hdr, 0, sizeof(*hdr)); if (fstat(fd, &sb)) err(2, "%s", fname); if (sb.st_size > MAXU32) errx(1, "%s: Too big", fname); hdr->size = sb.st_size; if (!hdr->size) return; if ((p = mmap(NULL, hdr->size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) err(2, "%s", fname); for (fmt = F_CNT - 1; !hdr->fmt && fmt; fmt--) switch (fmt) { case F_AOUT: ex = p; if (hdr->size >= sizeof(struct exec) && !N_BADMAG(*ex)) { hdr->fmt = fmt; x = N_GETMAGIC(*ex); if (x == OMAGIC || x == NMAGIC) { if (x == NMAGIC) Warn(fname, "Treating %s NMAGIC as OMAGIC", fmtlist[fmt]); hdr->flags |= IMPURE; } hdr->text = le32toh(ex->a_text); hdr->data = le32toh(ex->a_data); hdr->bss = le32toh(ex->a_bss); hdr->entry = le32toh(ex->a_entry); if (le32toh(ex->a_entry) >= BTX_PGSIZE) hdr->org = BTX_PGSIZE; } break; case F_ELF: ee = p; if (hdr->size >= sizeof(Elf32_Ehdr) && IS_ELF(*ee)) { hdr->fmt = fmt; for (n = i = 0; i < le16toh(ee->e_phnum); i++) { ep = (void *)((uint8_t *)p + le32toh(ee->e_phoff) + le16toh(ee->e_phentsize) * i); if (le32toh(ep->p_type) == PT_LOAD) switch (n++) { case 0: hdr->text = le32toh(ep->p_filesz); hdr->org = le32toh(ep->p_paddr); if (le32toh(ep->p_flags) & PF_W) hdr->flags |= IMPURE; break; case 1: hdr->data = le32toh(ep->p_filesz); hdr->bss = le32toh(ep->p_memsz) - le32toh(ep->p_filesz); break; case 2: Warn(fname, "Ignoring extra %s PT_LOAD segments", fmtlist[fmt]); } } hdr->entry = le32toh(ee->e_entry); } } if (munmap(p, hdr->size)) err(2, "%s", fname); } /* * Write a.out or ELF header. */ static void puthdr(int fd, struct hdr *hdr) { struct exec ex; struct elfh eh; switch (hdr->fmt) { case F_AOUT: memset(&ex, 0, sizeof(ex)); N_SETMAGIC(ex, ZMAGIC, MID_I386, 0); hdr->text = N_ALIGN(ex, hdr->text); ex.a_text = htole32(hdr->text); hdr->data = N_ALIGN(ex, hdr->data); ex.a_data = htole32(hdr->data); ex.a_entry = htole32(hdr->entry); writex(fd, &ex, sizeof(ex)); hdr->size = N_ALIGN(ex, sizeof(ex)); seekx(fd, hdr->size); break; case F_ELF: eh = elfhdr; eh.e.e_entry = htole32(hdr->entry); eh.p[0].p_vaddr = eh.p[0].p_paddr = htole32(hdr->org); eh.p[0].p_filesz = eh.p[0].p_memsz = htole32(hdr->text); eh.p[1].p_offset = htole32(le32toh(eh.p[0].p_offset) + le32toh(eh.p[0].p_filesz)); eh.p[1].p_vaddr = eh.p[1].p_paddr = htole32(roundup2(le32toh(eh.p[0].p_paddr) + le32toh(eh.p[0].p_memsz), 4096)); eh.p[1].p_filesz = eh.p[1].p_memsz = htole32(hdr->data); eh.sh[2].sh_addr = eh.p[0].p_vaddr; eh.sh[2].sh_offset = eh.p[0].p_offset; eh.sh[2].sh_size = eh.p[0].p_filesz; eh.sh[3].sh_addr = eh.p[1].p_vaddr; eh.sh[3].sh_offset = eh.p[1].p_offset; eh.sh[3].sh_size = eh.p[1].p_filesz; writex(fd, &eh, sizeof(eh)); hdr->size = sizeof(eh); } } /* * Safe copy from input file to output file. */ static void copy(int fdi, int fdo, size_t nbyte, off_t offset) { char buf[8192]; size_t n; while (nbyte) { if ((n = sizeof(buf)) > nbyte) n = nbyte; if (readx(fdi, buf, n, offset) != n) errx(2, "%s: Short read", fname); writex(fdo, buf, n); nbyte -= n; offset = -1; } } /* * Safe read from input file. */ static size_t readx(int fd, void *buf, size_t nbyte, off_t offset) { ssize_t n; if (offset != -1 && lseek(fd, offset, SEEK_SET) != offset) err(2, "%s", fname); if ((n = read(fd, buf, nbyte)) == -1) err(2, "%s", fname); return n; } /* * Safe write to output file. */ static void writex(int fd, const void *buf, size_t nbyte) { ssize_t n; if ((n = write(fd, buf, nbyte)) == -1) err(2, "%s", tname); if ((size_t)n != nbyte) errx(2, "%s: Short write", tname); } /* * Safe seek in output file. */ static void seekx(int fd, off_t offset) { if (lseek(fd, offset, SEEK_SET) != offset) err(2, "%s", tname); } /* * Convert an option argument to a format code. */ static unsigned int optfmt(const char *arg) { unsigned int i; for (i = 0; i < F_CNT && strcmp(arg, fmtlist[i]); i++); if (i == F_CNT) errx(1, "%s: Unknown format", arg); return i; } /* * Convert an option argument to an address. */ static uint32_t optaddr(const char *arg) { char *s; unsigned long x; errno = 0; x = strtoul(arg, &s, 0); if (errno || !*arg || *s || x > MAXU32) errx(1, "%s: Illegal address", arg); return x; } /* * Convert an option argument to a page number. */ static int optpage(const char *arg, int hi) { char *s; long x; errno = 0; x = strtol(arg, &s, 0); if (errno || !*arg || *s || x < 0 || x > hi) errx(1, "%s: Illegal page number", arg); return x; } /* * Display a warning. */ static void Warn(const char *locus, const char *fmt, ...) { va_list ap; char *s; if (!quiet) { asprintf(&s, "%s: Warning: %s", locus, fmt); va_start(ap, fmt); vwarnx(s, ap); va_end(ap); free(s); } } /* * Display usage information. */ static void usage(void) { fprintf(stderr, "%s\n%s\n", "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]", " [-l file] [-o filename] [-P page] [-W page] file"); exit(1); } diff --git a/usr.sbin/chroot/chroot.c b/usr.sbin/chroot/chroot.c index b14e1cbf4597..59bf8f0791a2 100644 --- a/usr.sbin/chroot/chroot.c +++ b/usr.sbin/chroot/chroot.c @@ -1,198 +1,198 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 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. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)chroot.c 8.1 (Berkeley) 6/9/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include -static void usage(void); +static void usage(void) __dead2; int main(int argc, char *argv[]) { struct group *gp; struct passwd *pw; char *endp, *p, *user, *group, *grouplist; const char *shell; gid_t gid, *gidlist; uid_t uid; int arg, ch, error, gids; long ngroups_max; bool nonprivileged; gid = 0; uid = 0; user = group = grouplist = NULL; nonprivileged = false; while ((ch = getopt(argc, argv, "G:g:u:n")) != -1) { switch(ch) { case 'u': user = optarg; if (*user == '\0') usage(); break; case 'g': group = optarg; if (*group == '\0') usage(); break; case 'G': grouplist = optarg; if (*grouplist == '\0') usage(); break; case 'n': nonprivileged = true; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc < 1) usage(); if (group != NULL) { if (isdigit((unsigned char)*group)) { gid = (gid_t)strtoul(group, &endp, 0); if (*endp != '\0') goto getgroup; } else { getgroup: if ((gp = getgrnam(group)) != NULL) gid = gp->gr_gid; else errx(1, "no such group `%s'", group); } } ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; if ((gidlist = malloc(sizeof(gid_t) * ngroups_max)) == NULL) err(1, "malloc"); for (gids = 0; (p = strsep(&grouplist, ",")) != NULL && gids < ngroups_max; ) { if (*p == '\0') continue; if (isdigit((unsigned char)*p)) { gidlist[gids] = (gid_t)strtoul(p, &endp, 0); if (*endp != '\0') goto getglist; } else { getglist: if ((gp = getgrnam(p)) != NULL) gidlist[gids] = gp->gr_gid; else errx(1, "no such group `%s'", p); } gids++; } if (p != NULL && gids == ngroups_max) errx(1, "too many supplementary groups provided"); if (user != NULL) { if (isdigit((unsigned char)*user)) { uid = (uid_t)strtoul(user, &endp, 0); if (*endp != '\0') goto getuser; } else { getuser: if ((pw = getpwnam(user)) != NULL) uid = pw->pw_uid; else errx(1, "no such user `%s'", user); } } if (nonprivileged) { arg = PROC_NO_NEW_PRIVS_ENABLE; error = procctl(P_PID, getpid(), PROC_NO_NEW_PRIVS_CTL, &arg); if (error != 0) err(1, "procctl"); } if (chdir(argv[0]) == -1 || chroot(".") == -1) err(1, "%s", argv[0]); if (gids && setgroups(gids, gidlist) == -1) err(1, "setgroups"); if (group && setgid(gid) == -1) err(1, "setgid"); if (user && setuid(uid) == -1) err(1, "setuid"); if (argv[1]) { execvp(argv[1], &argv[1]); err(1, "%s", argv[1]); } if (!(shell = getenv("SHELL"))) shell = _PATH_BSHELL; execlp(shell, shell, "-i", (char *)NULL); err(1, "%s", shell); /* NOTREACHED */ } static void usage(void) { (void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] " "[-u user] [-n] newroot [command]\n"); exit(1); } diff --git a/usr.sbin/ckdist/ckdist.c b/usr.sbin/ckdist/ckdist.c index b64392dfb771..caee507f246b 100644 --- a/usr.sbin/ckdist/ckdist.c +++ b/usr.sbin/ckdist/ckdist.c @@ -1,447 +1,447 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 1997 Robert Nordier * 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(S) ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include extern int crc(int fd, uint32_t *cval, off_t *clen); #define DISTMD5 1 /* MD5 format */ #define DISTINF 2 /* .inf format */ #define DISTTYPES 2 /* types supported */ #define E_UNKNOWN 1 /* Unknown format */ #define E_BADMD5 2 /* Invalid MD5 format */ #define E_BADINF 3 /* Invalid .inf format */ #define E_NAME 4 /* Can't derive component name */ #define E_LENGTH 5 /* Length mismatch */ #define E_CHKSUM 6 /* Checksum mismatch */ #define E_ERRNO 7 /* sys_errlist[errno] */ #define isfatal(err) ((err) && (err) <= E_NAME) #define NAMESIZE 256 /* filename buffer size */ #define MDSUMLEN 32 /* length of MD5 message digest */ #define isstdin(path) ((path)[0] == '-' && !(path)[1]) static const char *opt_dir; /* where to look for components */ static const char *opt_name; /* name for accessing components */ static int opt_all; /* report on all components */ static int opt_ignore; /* ignore missing components */ static int opt_recurse; /* search directories recursively */ static int opt_silent; /* silent about inaccessible files */ static int opt_type; /* dist type: md5 or inf */ static int opt_exist; /* just verify existence */ static int ckdist(const char *path, int type); static int chkmd5(FILE * fp, const char *path); static int chkinf(FILE * fp, const char *path); static int report(const char *path, const char *name, int error); static const char *distname(const char *path, const char *name, const char *ext); static const char *stripath(const char *path); static int distfile(const char *path); static int disttype(const char *name); static int fail(const char *path, const char *msg); -static void usage(void); +static void usage(void) __dead2; int main(int argc, char *argv[]) { static char *arg[2]; struct stat sb; FTS *ftsp; FTSENT *f; int rval, c, type; while ((c = getopt(argc, argv, "ad:in:rst:x")) != -1) switch (c) { case 'a': opt_all = 1; break; case 'd': opt_dir = optarg; break; case 'i': opt_ignore = 1; break; case 'n': opt_name = optarg; break; case 'r': opt_recurse = 1; break; case 's': opt_silent = 1; break; case 't': if ((opt_type = disttype(optarg)) == 0) { warnx("illegal argument to -t option"); usage(); } break; case 'x': opt_exist = 1; break; default: usage(); } argc -= optind; argv += optind; if (argc < 1) usage(); if (opt_dir) { if (stat(opt_dir, &sb)) err(2, "%s", opt_dir); if (!S_ISDIR(sb.st_mode)) errx(2, "%s: not a directory", opt_dir); } rval = 0; do { if (isstdin(*argv)) rval |= ckdist(*argv, opt_type); else if (stat(*argv, &sb)) rval |= fail(*argv, NULL); else if (S_ISREG(sb.st_mode)) rval |= ckdist(*argv, opt_type); else { arg[0] = *argv; if ((ftsp = fts_open(arg, FTS_LOGICAL, NULL)) == NULL) err(2, "fts_open"); while (errno = 0, (f = fts_read(ftsp)) != NULL) switch (f->fts_info) { case FTS_DC: rval = fail(f->fts_path, "Directory causes a cycle"); break; case FTS_DNR: case FTS_ERR: case FTS_NS: rval = fail(f->fts_path, sys_errlist[f->fts_errno]); break; case FTS_D: if (!opt_recurse && f->fts_level > FTS_ROOTLEVEL && fts_set(ftsp, f, FTS_SKIP)) err(2, "fts_set"); break; case FTS_F: if ((type = distfile(f->fts_name)) != 0 && (!opt_type || type == opt_type)) rval |= ckdist(f->fts_path, type); break; default: ; } if (errno) err(2, "fts_read"); if (fts_close(ftsp)) err(2, "fts_close"); } } while (*++argv); return rval; } static int ckdist(const char *path, int type) { FILE *fp; int rval, c; if (isstdin(path)) { path = "(stdin)"; fp = stdin; } else if ((fp = fopen(path, "r")) == NULL) return fail(path, NULL); if (!type) { if (fp != stdin) type = distfile(path); if (!type) if ((c = fgetc(fp)) != EOF) { type = c == 'M' ? DISTMD5 : c == 'P' ? DISTINF : 0; (void)ungetc(c, fp); } } switch (type) { case DISTMD5: rval = chkmd5(fp, path); break; case DISTINF: rval = chkinf(fp, path); break; default: rval = report(path, NULL, E_UNKNOWN); } if (ferror(fp)) warn("%s", path); if (fp != stdin && fclose(fp)) err(2, "%s", path); return rval; } static int chkmd5(FILE * fp, const char *path) { char buf[298]; /* "MD5 (NAMESIZE = MDSUMLEN" */ char name[NAMESIZE + 1]; char sum[MDSUMLEN + 1], chk[MDSUMLEN + 1]; const char *dname; char *s; int rval, error, c, fd; char ch; rval = 0; while (fgets(buf, sizeof(buf), fp)) { dname = NULL; error = 0; if (((c = sscanf(buf, "MD5 (%256s = %32s%c", name, sum, &ch)) != 3 && (!feof(fp) || c != 2)) || (c == 3 && ch != '\n') || (s = strrchr(name, ')')) == NULL || strlen(sum) != MDSUMLEN) error = E_BADMD5; else { *s = 0; if ((dname = distname(path, name, NULL)) == NULL) error = E_NAME; else if (opt_exist) { if ((fd = open(dname, O_RDONLY)) == -1) error = E_ERRNO; else if (close(fd)) err(2, "%s", dname); } else if (!MD5File(dname, chk)) error = E_ERRNO; else if (strcmp(chk, sum)) error = E_CHKSUM; } if (opt_ignore && error == E_ERRNO && errno == ENOENT) continue; if (error || opt_all) rval |= report(path, dname, error); if (isfatal(error)) break; } return rval; } static int chkinf(FILE * fp, const char *path) { char buf[30]; /* "cksum.2 = 10 6" */ char ext[3]; struct stat sb; const char *dname; off_t len; u_long sum; intmax_t sumlen; uint32_t chk; int rval, error, c, pieces, cnt, fd; char ch; rval = 0; for (cnt = -1; fgets(buf, sizeof(buf), fp); cnt++) { fd = -1; dname = NULL; error = 0; if (cnt == -1) { if ((c = sscanf(buf, "Pieces = %d%c", &pieces, &ch)) != 2 || ch != '\n' || pieces < 1) error = E_BADINF; } else if (((c = sscanf(buf, "cksum.%2s = %lu %jd%c", ext, &sum, &sumlen, &ch)) != 4 && (!feof(fp) || c != 3)) || (c == 4 && ch != '\n') || ext[0] != 'a' + cnt / 26 || ext[1] != 'a' + cnt % 26) error = E_BADINF; else if ((dname = distname(fp == stdin ? NULL : path, NULL, ext)) == NULL) error = E_NAME; else if ((fd = open(dname, O_RDONLY)) == -1) error = E_ERRNO; else if (fstat(fd, &sb)) error = E_ERRNO; else if (sb.st_size != (off_t)sumlen) error = E_LENGTH; else if (!opt_exist) { if (crc(fd, &chk, &len)) error = E_ERRNO; else if (chk != sum) error = E_CHKSUM; } if (fd != -1 && close(fd)) err(2, "%s", dname); if (opt_ignore && error == E_ERRNO && errno == ENOENT) continue; if (error || (opt_all && cnt >= 0)) rval |= report(path, dname, error); if (isfatal(error)) break; } return rval; } static int report(const char *path, const char *name, int error) { if (name) name = stripath(name); switch (error) { case E_UNKNOWN: printf("%s: Unknown format\n", path); break; case E_BADMD5: printf("%s: Invalid MD5 format\n", path); break; case E_BADINF: printf("%s: Invalid .inf format\n", path); break; case E_NAME: printf("%s: Can't derive component name\n", path); break; case E_LENGTH: printf("%s: %s: Size mismatch\n", path, name); break; case E_CHKSUM: printf("%s: %s: Checksum mismatch\n", path, name); break; case E_ERRNO: printf("%s: %s: %s\n", path, name, sys_errlist[errno]); break; default: printf("%s: %s: OK\n", path, name); } return error != 0; } static const char * distname(const char *path, const char *name, const char *ext) { static char buf[NAMESIZE]; size_t plen, nlen; char *s; if (opt_name) name = opt_name; else if (!name) { if (!path) return NULL; name = stripath(path); } nlen = strlen(name); if (ext && nlen > 4 && name[nlen - 4] == '.' && disttype(name + nlen - 3) == DISTINF) nlen -= 4; if (opt_dir) { path = opt_dir; plen = strlen(path); } else plen = path && (s = strrchr(path, '/')) != NULL ? (size_t)(s - path) : 0; if (plen + (plen > 0) + nlen + (ext ? 3 : 0) >= sizeof(buf)) return NULL; s = buf; if (plen) { memcpy(s, path, plen); s += plen; *s++ = '/'; } memcpy(s, name, nlen); s += nlen; if (ext) { *s++ = '.'; memcpy(s, ext, 2); s += 2; } *s = 0; return buf; } static const char * stripath(const char *path) { const char *s; return ((s = strrchr(path, '/')) != NULL && s[1] ? s + 1 : path); } static int distfile(const char *path) { const char *s; int type; if ((type = disttype(path)) == DISTMD5 || ((s = strrchr(path, '.')) != NULL && s > path && (type = disttype(s + 1)) != 0)) return type; return 0; } static int disttype(const char *name) { static const char dname[DISTTYPES][4] = {"md5", "inf"}; int i; for (i = 0; i < DISTTYPES; i++) if (!strcmp(dname[i], name)) return 1 + i; return 0; } static int fail(const char *path, const char *msg) { if (opt_silent) return 0; warnx("%s: %s", path, msg ? msg : sys_errlist[errno]); return 2; } static void usage(void) { fprintf(stderr, "usage: ckdist [-airsx] [-d dir] [-n name] [-t type] file ...\n"); exit(2); } diff --git a/usr.sbin/crunch/crunchide/crunchide.c b/usr.sbin/crunch/crunchide/crunchide.c index bd663e1d57bd..94778e8c9d3e 100644 --- a/usr.sbin/crunch/crunchide/crunchide.c +++ b/usr.sbin/crunch/crunchide/crunchide.c @@ -1,264 +1,264 @@ /* $NetBSD: crunchide.c,v 1.8 1997/11/01 06:51:45 lukem Exp $ */ /* * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved. * Copyright (c) 1994 University of Maryland * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: James da Silva, Systems Design and Analysis Group * Computer Science Department * University of Maryland at College Park */ /* * crunchide.c - tiptoes through a symbol table, hiding all defined * global symbols. Allows the user to supply a "keep list" of symbols * that are not to be hidden. * * The point of all this is to allow multiple programs to be linked * together without getting multiple-defined errors. * * For example, consider a program "foo.c". It can be linked with a * small stub routine, called "foostub.c", eg: * int foo_main(int argc, char **argv){ return main(argc, argv); } * like so: * cc -c foo.c foostub.c * ld -r foo.o foostub.o -o foo.combined.o * crunchide -k _foo_main foo.combined.o * at this point, foo.combined.o can be linked with another program * and invoked with "foo_main(argc, argv)". foo's main() and any * other globals are hidden and will not conflict with other symbols. * * TODO: * - resolve the theoretical hanging reloc problem (see check_reloc() * below). I have yet to see this problem actually occur in any real * program. In what cases will gcc/gas generate code that needs a * relative reloc from a global symbol, other than PIC? The * solution is to not hide the symbol from the linker in this case, * but to generate some random name for it so that it doesn't link * with anything but holds the place for the reloc. * - arrange that all the BSS segments start at the same address, so * that the final crunched binary BSS size is the max of all the * component programs' BSS sizes, rather than their sum. */ #include #ifndef lint __RCSID("$NetBSD: crunchide.c,v 1.8 1997/11/01 06:51:45 lukem Exp $"); #endif __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "extern.h" static const char *pname = "crunchide"; -static void usage(void); +static void usage(void) __dead2; static void add_to_keep_list(char *symbol); static void add_file_to_keep_list(char *filename); static int hide_syms(const char *filename); static int verbose; int main(int, char *[]); int main(int argc, char **argv) { int ch, errors; if(argc > 0) pname = argv[0]; while ((ch = getopt(argc, argv, "k:f:v")) != -1) switch(ch) { case 'k': add_to_keep_list(optarg); break; case 'f': add_file_to_keep_list(optarg); break; case 'v': verbose = 1; break; default: usage(); } argc -= optind; argv += optind; if(argc == 0) usage(); errors = 0; while(argc) { if (hide_syms(*argv)) errors = 1; argc--, argv++; } return errors; } static void usage(void) { fprintf(stderr, "usage: %s [-k ] [-f ] ...\n", pname); exit(1); } /* ---------------------------- */ static struct keep { struct keep *next; char *sym; } *keep_list; static void add_to_keep_list(char *symbol) { struct keep *newp, *prevp, *curp; int cmp; cmp = 0; for(curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next) if((cmp = strcmp(symbol, curp->sym)) <= 0) break; if(curp && cmp == 0) return; /* already in table */ newp = (struct keep *) malloc(sizeof(struct keep)); if(newp) newp->sym = strdup(symbol); if(newp == NULL || newp->sym == NULL) { fprintf(stderr, "%s: out of memory for keep list\n", pname); exit(1); } newp->next = curp; if(prevp) prevp->next = newp; else keep_list = newp; } int in_keep_list(const char *symbol) { struct keep *curp; int cmp; cmp = 0; for(curp = keep_list; curp; curp = curp->next) if((cmp = strcmp(symbol, curp->sym)) <= 0) break; return curp && cmp == 0; } static void add_file_to_keep_list(char *filename) { FILE *keepf; char symbol[1024]; int len; if((keepf = fopen(filename, "r")) == NULL) { perror(filename); usage(); } while(fgets(symbol, sizeof(symbol), keepf)) { len = strlen(symbol); if(len && symbol[len-1] == '\n') symbol[len-1] = '\0'; add_to_keep_list(symbol); } fclose(keepf); } /* ---------------------------- */ static struct { const char *name; int (*check)(int, const char *); /* 1 if match, zero if not */ int (*hide)(int, const char *); /* non-zero if error */ } exec_formats[] = { #ifdef NLIST_ELF32 { "ELF32", check_elf32, hide_elf32, }, #endif #ifdef NLIST_ELF64 { "ELF64", check_elf64, hide_elf64, }, #endif }; static int hide_syms(const char *filename) { int fd, i, n, rv; fd = open(filename, O_RDWR, 0); if (fd == -1) { perror(filename); return 1; } rv = 0; n = sizeof exec_formats / sizeof exec_formats[0]; for (i = 0; i < n; i++) { if (lseek(fd, 0, SEEK_SET) != 0) { perror(filename); goto err; } if ((*exec_formats[i].check)(fd, filename) != 0) break; } if (i == n) { fprintf(stderr, "%s: unknown executable format\n", filename); goto err; } if (verbose) fprintf(stderr, "%s is an %s binary\n", filename, exec_formats[i].name); if (lseek(fd, 0, SEEK_SET) != 0) { perror(filename); goto err; } rv = (*exec_formats[i].hide)(fd, filename); out: close (fd); return (rv); err: rv = 1; goto out; } diff --git a/usr.sbin/edquota/edquota.c b/usr.sbin/edquota/edquota.c index de2083506864..036b3f699eae 100644 --- a/usr.sbin/edquota/edquota.c +++ b/usr.sbin/edquota/edquota.c @@ -1,961 +1,961 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Robert Elz at The University of Melbourne. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1990, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)edquota.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); /* * Disk quota editor. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" /* Let's be paranoid about block size */ #if 10 > DEV_BSHIFT #define dbtokb(db) \ ((off_t)(db) >> (10-DEV_BSHIFT)) #elif 10 < DEV_BSHIFT #define dbtokb(db) \ ((off_t)(db) << (DEV_BSHIFT-10)) #else #define dbtokb(db) (db) #endif static const char *qfextension[] = INITQFNAMES; static char tmpfil[] = _PATH_TMP; static int hflag; struct quotause { struct quotause *next; struct quotafile *qf; struct dqblk dqblk; int flags; char fsname[MAXPATHLEN + 1]; }; #define FOUND 0x01 int alldigits(const char *s); int cvtatos(uint64_t, char *, uint64_t *); char *cvtstoa(uint64_t); uint64_t cvtblkval(uint64_t, char, const char *); uint64_t cvtinoval(uint64_t, char, const char *); int editit(char *); char *fmthumanvalblks(int64_t); char *fmthumanvalinos(int64_t); void freeprivs(struct quotause *); int getentry(const char *, int); struct quotause *getprivs(long, int, char *); void putprivs(long, struct quotause *); int readprivs(struct quotause *, char *); int readtimes(struct quotause *, char *); -static void usage(void); +static void usage(void) __dead2; int writetimes(struct quotause *, int, int); int writeprivs(struct quotause *, int, char *, int); int main(int argc, char *argv[]) { struct quotause *qup, *protoprivs, *curprivs; long id, protoid; int i, quotatype, range, tmpfd; uid_t startuid, enduid; uint64_t lim; char *protoname, *cp, *endpt, *oldoptarg; int eflag = 0, tflag = 0, pflag = 0, ch; char *fspath = NULL; char buf[MAXLOGNAME]; if (argc < 2) usage(); if (getuid()) errx(1, "permission denied"); quotatype = USRQUOTA; protoprivs = NULL; curprivs = NULL; protoname = NULL; while ((ch = getopt(argc, argv, "ughtf:p:e:")) != -1) { switch(ch) { case 'f': fspath = optarg; break; case 'p': if (eflag) { warnx("cannot specify both -e and -p"); usage(); /* not reached */ } protoname = optarg; pflag++; break; case 'g': quotatype = GRPQUOTA; break; case 'h': hflag++; break; case 'u': quotatype = USRQUOTA; break; case 't': tflag++; break; case 'e': if (pflag) { warnx("cannot specify both -e and -p"); usage(); /* not reached */ } if ((qup = calloc(1, sizeof(*qup))) == NULL) errx(2, "out of memory"); oldoptarg = optarg; for (i = 0, cp = optarg; (cp = strsep(&optarg, ":")) != NULL; i++) { if (cp != oldoptarg) *(cp - 1) = ':'; if (i > 0 && !isdigit(*cp)) { warnx("incorrect quota specification: " "%s", oldoptarg); usage(); /* Not Reached */ } switch (i) { case 0: strlcpy(qup->fsname, cp, sizeof(qup->fsname)); break; case 1: lim = strtoll(cp, &endpt, 10); qup->dqblk.dqb_bsoftlimit = cvtblkval(lim, *endpt, "block soft limit"); continue; case 2: lim = strtoll(cp, &endpt, 10); qup->dqblk.dqb_bhardlimit = cvtblkval(lim, *endpt, "block hard limit"); continue; case 3: lim = strtoll(cp, &endpt, 10); qup->dqblk.dqb_isoftlimit = cvtinoval(lim, *endpt, "inode soft limit"); continue; case 4: lim = strtoll(cp, &endpt, 10); qup->dqblk.dqb_ihardlimit = cvtinoval(lim, *endpt, "inode hard limit"); continue; default: warnx("incorrect quota specification: " "%s", oldoptarg); usage(); /* Not Reached */ } } if (protoprivs == NULL) { protoprivs = curprivs = qup; } else { curprivs->next = qup; curprivs = qup; } eflag++; break; default: usage(); /* Not Reached */ } } argc -= optind; argv += optind; if (pflag || eflag) { if (pflag) { if ((protoid = getentry(protoname, quotatype)) == -1) exit(1); protoprivs = getprivs(protoid, quotatype, fspath); if (protoprivs == NULL) exit(0); for (qup = protoprivs; qup; qup = qup->next) { qup->dqblk.dqb_btime = 0; qup->dqblk.dqb_itime = 0; } } for (; argc-- > 0; argv++) { if (strspn(*argv, "0123456789-") == strlen(*argv) && (cp = strchr(*argv, '-')) != NULL) { *cp++ = '\0'; startuid = atoi(*argv); enduid = atoi(cp); if (enduid < startuid) errx(1, "ending uid (%d) must be >= starting uid (%d) when using uid ranges", enduid, startuid); range = 1; } else { startuid = enduid = 0; range = 0; } for ( ; startuid <= enduid; startuid++) { if (range) snprintf(buf, sizeof(buf), "%d", startuid); else snprintf(buf, sizeof(buf), "%s", *argv); if ((id = getentry(buf, quotatype)) < 0) continue; if (pflag) { putprivs(id, protoprivs); continue; } for (qup = protoprivs; qup; qup = qup->next) { curprivs = getprivs(id, quotatype, qup->fsname); if (curprivs == NULL) continue; curprivs->dqblk = qup->dqblk; putprivs(id, curprivs); freeprivs(curprivs); } } } if (pflag) freeprivs(protoprivs); exit(0); } tmpfd = mkostemp(tmpfil, O_CLOEXEC); fchown(tmpfd, getuid(), getgid()); if (tflag) { if ((protoprivs = getprivs(0, quotatype, fspath)) != NULL) { if (writetimes(protoprivs, tmpfd, quotatype) != 0 && editit(tmpfil) && readtimes(protoprivs, tmpfil)) putprivs(0L, protoprivs); freeprivs(protoprivs); } close(tmpfd); unlink(tmpfil); exit(0); } for ( ; argc > 0; argc--, argv++) { if ((id = getentry(*argv, quotatype)) == -1) continue; if ((curprivs = getprivs(id, quotatype, fspath)) == NULL) exit(1); if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0) continue; if (editit(tmpfil) && readprivs(curprivs, tmpfil)) putprivs(id, curprivs); freeprivs(curprivs); } close(tmpfd); unlink(tmpfil); exit(0); } static void usage(void) { fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: edquota [-uh] [-f fspath] [-p username] username ...", " edquota [-u] -e fspath[:bslim[:bhlim[:islim[:ihlim]]]] [-e ...]", " username ...", " edquota -g [-h] [-f fspath] [-p groupname] groupname ...", " edquota -g -e fspath[:bslim[:bhlim[:islim[:ihlim]]]] [-e ...]", " groupname ...", " edquota [-u] -t [-f fspath]", " edquota -g -t [-f fspath]"); exit(1); } /* * This routine converts a name for a particular quota type to * an identifier. This routine must agree with the kernel routine * getinoquota as to the interpretation of quota types. */ int getentry(const char *name, int quotatype) { struct passwd *pw; struct group *gr; if (alldigits(name)) return (atoi(name)); switch(quotatype) { case USRQUOTA: if ((pw = getpwnam(name))) return (pw->pw_uid); warnx("%s: no such user", name); sleep(3); break; case GRPQUOTA: if ((gr = getgrnam(name))) return (gr->gr_gid); warnx("%s: no such group", name); sleep(3); break; default: warnx("%d: unknown quota type", quotatype); sleep(3); break; } sleep(1); return (-1); } /* * Collect the requested quota information. */ struct quotause * getprivs(long id, int quotatype, char *fspath) { struct quotafile *qf; struct fstab *fs; struct quotause *qup, *quptail; struct quotause *quphead; setfsent(); quphead = quptail = NULL; while ((fs = getfsent())) { if (fspath && *fspath && strcmp(fspath, fs->fs_spec) && strcmp(fspath, fs->fs_file)) continue; if (strcmp(fs->fs_vfstype, "ufs")) continue; if ((qf = quota_open(fs, quotatype, O_CREAT|O_RDWR)) == NULL) { if (errno != EOPNOTSUPP) warn("cannot open quotas on %s", fs->fs_file); continue; } if ((qup = (struct quotause *)calloc(1, sizeof(*qup))) == NULL) errx(2, "out of memory"); qup->qf = qf; strlcpy(qup->fsname, fs->fs_file, sizeof(qup->fsname)); if (quota_read(qf, &qup->dqblk, id) == -1) { warn("cannot read quotas on %s", fs->fs_file); freeprivs(qup); continue; } if (quphead == NULL) quphead = qup; else quptail->next = qup; quptail = qup; qup->next = 0; } if (quphead == NULL) { warnx("No quotas on %s", fspath ? fspath : "any filesystems"); } endfsent(); return (quphead); } /* * Store the requested quota information. */ void putprivs(long id, struct quotause *quplist) { struct quotause *qup; for (qup = quplist; qup; qup = qup->next) if (quota_write_limits(qup->qf, &qup->dqblk, id) == -1) warn("%s", qup->fsname); } /* * Take a list of privileges and get it edited. */ int editit(char *tmpf) { long omask; int pid, status; omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); top: if ((pid = fork()) < 0) { if (errno == EPROCLIM) { warnx("you have too many processes"); return(0); } if (errno == EAGAIN) { sleep(1); goto top; } warn("fork"); return (0); } if (pid == 0) { const char *ed; sigsetmask(omask); if (setgid(getgid()) != 0) err(1, "setgid failed"); if (setuid(getuid()) != 0) err(1, "setuid failed"); if ((ed = getenv("EDITOR")) == (char *)0) ed = _PATH_VI; execlp(ed, ed, tmpf, (char *)0); err(1, "%s", ed); } waitpid(pid, &status, 0); sigsetmask(omask); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) return (0); return (1); } /* * Convert a quotause list to an ASCII file. */ int writeprivs(struct quotause *quplist, int outfd, char *name, int quotatype) { struct quotause *qup; FILE *fd; ftruncate(outfd, 0); lseek(outfd, 0, L_SET); if ((fd = fdopen(dup(outfd), "w")) == NULL) err(1, "%s", tmpfil); fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name); for (qup = quplist; qup; qup = qup->next) { fprintf(fd, "%s: in use: %s, ", qup->fsname, fmthumanvalblks(qup->dqblk.dqb_curblocks)); fprintf(fd, "limits (soft = %s, ", fmthumanvalblks(qup->dqblk.dqb_bsoftlimit)); fprintf(fd, "hard = %s)\n", fmthumanvalblks(qup->dqblk.dqb_bhardlimit)); fprintf(fd, "\tinodes in use: %s, ", fmthumanvalinos(qup->dqblk.dqb_curinodes)); fprintf(fd, "limits (soft = %s, ", fmthumanvalinos(qup->dqblk.dqb_isoftlimit)); fprintf(fd, "hard = %s)\n", fmthumanvalinos(qup->dqblk.dqb_ihardlimit)); } fclose(fd); return (1); } char * fmthumanvalblks(int64_t blocks) { static char numbuf[20]; if (hflag) { humanize_number(numbuf, blocks < 0 ? 7 : 6, dbtob(blocks), "", HN_AUTOSCALE, HN_NOSPACE); return (numbuf); } snprintf(numbuf, sizeof(numbuf), "%juk", (uintmax_t)dbtokb(blocks)); return(numbuf); } char * fmthumanvalinos(int64_t inos) { static char numbuf[20]; if (hflag) { humanize_number(numbuf, inos < 0 ? 7 : 6, inos, "", HN_AUTOSCALE, HN_NOSPACE | HN_DIVISOR_1000); return (numbuf); } snprintf(numbuf, sizeof(numbuf), "%ju", (uintmax_t)inos); return(numbuf); } /* * Merge changes to an ASCII file into a quotause list. */ int readprivs(struct quotause *quplist, char *inname) { struct quotause *qup; FILE *fd; uintmax_t hardlimit, softlimit, curitems; char hardunits, softunits, curitemunits; int cnt; char *cp; struct dqblk dqblk; char *fsp, line1[BUFSIZ], line2[BUFSIZ]; fd = fopen(inname, "r"); if (fd == NULL) { warnx("can't re-read temp file!!"); return (0); } /* * Discard title line, then read pairs of lines to process. */ (void) fgets(line1, sizeof (line1), fd); while (fgets(line1, sizeof (line1), fd) != NULL && fgets(line2, sizeof (line2), fd) != NULL) { if ((fsp = strtok(line1, " \t:")) == NULL) { warnx("%s: bad format", line1); return (0); } if ((cp = strtok((char *)0, "\n")) == NULL) { warnx("%s: %s: bad format", fsp, &fsp[strlen(fsp) + 1]); return (0); } cnt = sscanf(cp, " in use: %ju%c, limits (soft = %ju%c, hard = %ju%c)", &curitems, &curitemunits, &softlimit, &softunits, &hardlimit, &hardunits); /* * The next three check for old-style input formats. */ if (cnt != 6) cnt = sscanf(cp, " in use: %ju%c, limits (soft = %ju%c hard = %ju%c", &curitems, &curitemunits, &softlimit, &softunits, &hardlimit, &hardunits); if (cnt != 6) cnt = sscanf(cp, " in use: %ju%c, limits (soft = %ju%c hard = %ju%c)", &curitems, &curitemunits, &softlimit, &softunits, &hardlimit, &hardunits); if (cnt != 6) cnt = sscanf(cp, " in use: %ju%c, limits (soft = %ju%c, hard = %ju%c", &curitems, &curitemunits, &softlimit, &softunits, &hardlimit, &hardunits); if (cnt != 6) { warnx("%s:%s: bad format", fsp, cp); return (0); } dqblk.dqb_curblocks = cvtblkval(curitems, curitemunits, "current block count"); dqblk.dqb_bsoftlimit = cvtblkval(softlimit, softunits, "block soft limit"); dqblk.dqb_bhardlimit = cvtblkval(hardlimit, hardunits, "block hard limit"); if ((cp = strtok(line2, "\n")) == NULL) { warnx("%s: %s: bad format", fsp, line2); return (0); } cnt = sscanf(&cp[7], " in use: %ju%c limits (soft = %ju%c, hard = %ju%c)", &curitems, &curitemunits, &softlimit, &softunits, &hardlimit, &hardunits); /* * The next three check for old-style input formats. */ if (cnt != 6) cnt = sscanf(&cp[7], " in use: %ju%c limits (soft = %ju%c hard = %ju%c", &curitems, &curitemunits, &softlimit, &softunits, &hardlimit, &hardunits); if (cnt != 6) cnt = sscanf(&cp[7], " in use: %ju%c limits (soft = %ju%c hard = %ju%c)", &curitems, &curitemunits, &softlimit, &softunits, &hardlimit, &hardunits); if (cnt != 6) cnt = sscanf(&cp[7], " in use: %ju%c limits (soft = %ju%c, hard = %ju%c", &curitems, &curitemunits, &softlimit, &softunits, &hardlimit, &hardunits); if (cnt != 6) { warnx("%s: %s: bad format cnt %d", fsp, &cp[7], cnt); return (0); } dqblk.dqb_curinodes = cvtinoval(curitems, curitemunits, "current inode count"); dqblk.dqb_isoftlimit = cvtinoval(softlimit, softunits, "inode soft limit"); dqblk.dqb_ihardlimit = cvtinoval(hardlimit, hardunits, "inode hard limit"); for (qup = quplist; qup; qup = qup->next) { if (strcmp(fsp, qup->fsname)) continue; /* * Cause time limit to be reset when the quota * is next used if previously had no soft limit * or were under it, but now have a soft limit * and are over it. */ if (dqblk.dqb_bsoftlimit && qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit && (qup->dqblk.dqb_bsoftlimit == 0 || qup->dqblk.dqb_curblocks < qup->dqblk.dqb_bsoftlimit)) qup->dqblk.dqb_btime = 0; if (dqblk.dqb_isoftlimit && qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit && (qup->dqblk.dqb_isoftlimit == 0 || qup->dqblk.dqb_curinodes < qup->dqblk.dqb_isoftlimit)) qup->dqblk.dqb_itime = 0; qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit; qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit; qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit; qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit; qup->flags |= FOUND; /* Humanized input returns only approximate counts */ if (hflag || (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks && dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)) break; warnx("%s: cannot change current allocation", fsp); break; } } fclose(fd); /* * Disable quotas for any filesystems that have not been found. */ for (qup = quplist; qup; qup = qup->next) { if (qup->flags & FOUND) { qup->flags &= ~FOUND; continue; } qup->dqblk.dqb_bsoftlimit = 0; qup->dqblk.dqb_bhardlimit = 0; qup->dqblk.dqb_isoftlimit = 0; qup->dqblk.dqb_ihardlimit = 0; } return (1); } /* * Convert a quotause list to an ASCII file of grace times. */ int writetimes(struct quotause *quplist, int outfd, int quotatype) { struct quotause *qup; FILE *fd; ftruncate(outfd, 0); lseek(outfd, 0, L_SET); if ((fd = fdopen(dup(outfd), "w")) == NULL) err(1, "%s", tmpfil); fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n"); fprintf(fd, "Grace period before enforcing soft limits for %ss:\n", qfextension[quotatype]); for (qup = quplist; qup; qup = qup->next) { fprintf(fd, "%s: block grace period: %s, ", qup->fsname, cvtstoa(qup->dqblk.dqb_btime)); fprintf(fd, "file grace period: %s\n", cvtstoa(qup->dqblk.dqb_itime)); } fclose(fd); return (1); } /* * Merge changes of grace times in an ASCII file into a quotause list. */ int readtimes(struct quotause *quplist, char *inname) { struct quotause *qup; FILE *fd; int cnt; char *cp; uintmax_t itime, btime, iseconds, bseconds; char *fsp, bunits[10], iunits[10], line1[BUFSIZ]; fd = fopen(inname, "r"); if (fd == NULL) { warnx("can't re-read temp file!!"); return (0); } /* * Discard two title lines, then read lines to process. */ (void) fgets(line1, sizeof (line1), fd); (void) fgets(line1, sizeof (line1), fd); while (fgets(line1, sizeof (line1), fd) != NULL) { if ((fsp = strtok(line1, " \t:")) == NULL) { warnx("%s: bad format", line1); return (0); } if ((cp = strtok((char *)0, "\n")) == NULL) { warnx("%s: %s: bad format", fsp, &fsp[strlen(fsp) + 1]); return (0); } cnt = sscanf(cp, " block grace period: %ju %s file grace period: %ju %s", &btime, bunits, &itime, iunits); if (cnt != 4) { warnx("%s:%s: bad format", fsp, cp); return (0); } if (cvtatos(btime, bunits, &bseconds) == 0) return (0); if (cvtatos(itime, iunits, &iseconds) == 0) return (0); for (qup = quplist; qup; qup = qup->next) { if (strcmp(fsp, qup->fsname)) continue; qup->dqblk.dqb_btime = bseconds; qup->dqblk.dqb_itime = iseconds; qup->flags |= FOUND; break; } } fclose(fd); /* * reset default grace periods for any filesystems * that have not been found. */ for (qup = quplist; qup; qup = qup->next) { if (qup->flags & FOUND) { qup->flags &= ~FOUND; continue; } qup->dqblk.dqb_btime = 0; qup->dqblk.dqb_itime = 0; } return (1); } /* * Convert seconds to ASCII times. */ char * cvtstoa(uint64_t secs) { static char buf[20]; if (secs % (24 * 60 * 60) == 0) { secs /= 24 * 60 * 60; sprintf(buf, "%ju day%s", (uintmax_t)secs, secs == 1 ? "" : "s"); } else if (secs % (60 * 60) == 0) { secs /= 60 * 60; sprintf(buf, "%ju hour%s", (uintmax_t)secs, secs == 1 ? "" : "s"); } else if (secs % 60 == 0) { secs /= 60; sprintf(buf, "%ju minute%s", (uintmax_t)secs, secs == 1 ? "" : "s"); } else sprintf(buf, "%ju second%s", (uintmax_t)secs, secs == 1 ? "" : "s"); return (buf); } /* * Convert ASCII input times to seconds. */ int cvtatos(uint64_t period, char *units, uint64_t *seconds) { if (bcmp(units, "second", 6) == 0) *seconds = period; else if (bcmp(units, "minute", 6) == 0) *seconds = period * 60; else if (bcmp(units, "hour", 4) == 0) *seconds = period * 60 * 60; else if (bcmp(units, "day", 3) == 0) *seconds = period * 24 * 60 * 60; else { warnx("%s: bad units, specify %s\n", units, "days, hours, minutes, or seconds"); return (0); } return (1); } /* * Convert a limit to number of disk blocks. */ uint64_t cvtblkval(uint64_t limit, char units, const char *itemname) { switch(units) { case 'B': case 'b': limit = btodb(limit); break; case '\0': /* historic behavior */ case ',': /* historic behavior */ case ')': /* historic behavior */ case 'K': case 'k': limit *= btodb(1024); break; case 'M': case 'm': limit *= btodb(1048576); break; case 'G': case 'g': limit *= btodb(1073741824); break; case 'T': case 't': limit *= btodb(1099511627776); break; case 'P': case 'p': limit *= btodb(1125899906842624); break; case 'E': case 'e': limit *= btodb(1152921504606846976); break; case ' ': errx(2, "No space permitted between value and units for %s\n", itemname); break; default: errx(2, "%ju%c: unknown units for %s, specify " "none, K, M, G, T, P, or E\n", (uintmax_t)limit, units, itemname); break; } return (limit); } /* * Convert a limit to number of inodes. */ uint64_t cvtinoval(uint64_t limit, char units, const char *itemname) { switch(units) { case 'B': case 'b': case '\0': /* historic behavior */ case ',': /* historic behavior */ case ')': /* historic behavior */ break; case 'K': case 'k': limit *= 1000; break; case 'M': case 'm': limit *= 1000000; break; case 'G': case 'g': limit *= 1000000000; break; case 'T': case 't': limit *= 1000000000000; break; case 'P': case 'p': limit *= 1000000000000000; break; case 'E': case 'e': limit *= 1000000000000000000; break; case ' ': errx(2, "No space permitted between value and units for %s\n", itemname); break; default: errx(2, "%ju%c: unknown units for %s, specify " "none, K, M, G, T, P, or E\n", (uintmax_t)limit, units, itemname); break; } return (limit); } /* * Free a list of quotause structures. */ void freeprivs(struct quotause *quplist) { struct quotause *qup, *nextqup; for (qup = quplist; qup; qup = nextqup) { quota_close(qup->qf); nextqup = qup->next; free(qup); } } /* * Check whether a string is completely composed of digits. */ int alldigits(const char *s) { int c; c = *s++; do { if (!isdigit(c)) return (0); } while ((c = *s++)); return (1); } diff --git a/usr.sbin/efitable/efitable.c b/usr.sbin/efitable/efitable.c index 6bd4d96ffd2a..329c784611ae 100644 --- a/usr.sbin/efitable/efitable.c +++ b/usr.sbin/efitable/efitable.c @@ -1,239 +1,239 @@ /*- * Copyright (c) 2021 3mdeb Embedded Systems Consulting * * 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 #include #include #include #include #include #include #include #include #define TABLE_MAX_LEN 30 #define EFITABLE_XO_VERSION "1" static void efi_table_print_esrt(const void *data); static void efi_table_print_prop(const void *data); -static void usage(void); +static void usage(void) __dead2; struct efi_table_op { char name[TABLE_MAX_LEN]; void (*parse) (const void *); struct uuid uuid; }; static const struct efi_table_op efi_table_ops[] = { { .name = "esrt", .parse = efi_table_print_esrt, .uuid = EFI_TABLE_ESRT }, { .name = "prop", .parse = efi_table_print_prop, .uuid = EFI_PROPERTIES_TABLE } }; int main(int argc, char **argv) { struct efi_get_table_ioc table = { .buf = NULL, .buf_len = 0, .table_len = 0 }; int efi_fd, ch, rc = 1, efi_idx = -1; bool got_table = false; bool table_set = false; bool uuid_set = false; struct option longopts[] = { { "uuid", required_argument, NULL, 'u' }, { "table", required_argument, NULL, 't' }, { NULL, 0, NULL, 0 } }; argc = xo_parse_args(argc, argv); if (argc < 0) exit(EXIT_FAILURE); while ((ch = getopt_long(argc, argv, "u:t:", longopts, NULL)) != -1) { switch (ch) { case 'u': { char *uuid_str = optarg; struct uuid uuid; uint32_t status; uuid_set = 1; uuid_from_string(uuid_str, &uuid, &status); if (status != uuid_s_ok) xo_errx(EX_DATAERR, "invalid UUID"); for (size_t n = 0; n < nitems(efi_table_ops); n++) { if (!memcmp(&uuid, &efi_table_ops[n].uuid, sizeof(uuid))) { efi_idx = n; got_table = true; break; } } break; } case 't': { char *table_name = optarg; table_set = true; for (size_t n = 0; n < nitems(efi_table_ops); n++) { if (!strcmp(table_name, efi_table_ops[n].name)) { efi_idx = n; got_table = true; break; } } if (!got_table) xo_errx(EX_DATAERR, "unsupported efi table"); break; } default: usage(); } } if (!table_set && !uuid_set) xo_errx(EX_USAGE, "table is not set"); if (!got_table) xo_errx(EX_DATAERR, "unsupported table"); efi_fd = open("/dev/efi", O_RDWR); if (efi_fd < 0) xo_err(EX_OSFILE, "/dev/efi"); table.uuid = efi_table_ops[efi_idx].uuid; if (ioctl(efi_fd, EFIIOC_GET_TABLE, &table) == -1) xo_err(EX_OSERR, "EFIIOC_GET_TABLE (len == 0)"); table.buf = malloc(table.table_len); table.buf_len = table.table_len; if (ioctl(efi_fd, EFIIOC_GET_TABLE, &table) == -1) xo_err(EX_OSERR, "EFIIOC_GET_TABLE"); efi_table_ops[efi_idx].parse(table.buf); close(efi_fd); return (rc); } static void efi_table_print_esrt(const void *data) { const struct efi_esrt_entry_v1 *entries_v1; const struct efi_esrt_table *esrt; esrt = (const struct efi_esrt_table *)data; xo_set_version(EFITABLE_XO_VERSION); xo_open_container("esrt"); xo_emit("{Lwc:FwResourceCount}{:fw_resource_count/%u}\n", esrt->fw_resource_count); xo_emit("{Lwc:FwResourceCountMax}{:fw_resource_count_max/%u}\n", esrt->fw_resource_count_max); xo_emit("{Lwc:FwResourceVersion}{:fw_resource_version/%u}\n", esrt->fw_resource_version); xo_open_list("entries"); xo_emit("\nEntries:\n"); entries_v1 = (const void *) esrt->entries; for (uint32_t i = 0; i < esrt->fw_resource_count; i++) { const struct efi_esrt_entry_v1 *e = &entries_v1[i]; uint32_t status; char *uuid; uuid_to_string(&e->fw_class, &uuid, &status); if (status != uuid_s_ok) { xo_errx(EX_DATAERR, "uuid_to_string error"); } xo_open_instance("entries"); xo_emit("\n"); xo_emit("{P: }{Lwc:FwClass}{:fw_class/%s}\n", uuid); xo_emit("{P: }{Lwc:FwType}{:fw_type/%u}\n", e->fw_type); xo_emit("{P: }{Lwc:FwVersion}{:fw_version/%u}\n", e->fw_version); xo_emit("{P: }{Lwc:LowestSupportedFwVersion}" "{:lowest_supported_fw_version/%u}\n", e->lowest_supported_fw_version); xo_emit("{P: }{Lwc:CapsuleFlags}{:capsule_flags/%#x}\n", e->capsule_flags); xo_emit("{P: }{Lwc:LastAttemptVersion" "}{:last_attempt_version/%u}\n", e->last_attempt_version); xo_emit("{P: }{Lwc:LastAttemptStatus" "}{:last_attempt_status/%u}\n", e->last_attempt_status); xo_close_instance("entries"); } xo_close_list("entries"); xo_close_container("esrt"); xo_finish(); } static void efi_table_print_prop(const void *data) { const struct efi_prop_table *prop; prop = (const struct efi_prop_table *)data; xo_set_version(EFITABLE_XO_VERSION); xo_open_container("prop"); xo_emit("{Lwc:Version}{:version/%#x}\n", prop->version); xo_emit("{Lwc:Length}{:length/%u}\n", prop->length); xo_emit("{Lwc:MemoryProtectionAttribute}" "{:memory_protection_attribute/%#lx}\n", prop->memory_protection_attribute); xo_close_container("prop"); xo_finish(); } static void usage(void) { xo_error("usage: efitable [-d uuid | -t name] [--libxo]\n"); exit(EX_USAGE); }