diff --git a/usr.bin/elfctl/elfctl.c b/usr.bin/elfctl/elfctl.c index 41b45aee80b8..5c15ddd43528 100644 --- a/usr.bin/elfctl/elfctl.c +++ b/usr.bin/elfctl/elfctl.c @@ -1,469 +1,469 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 The FreeBSD Foundation. * * This software was developed by Bora Ozarslan under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_elftc.h" __FBSDID("$FreeBSD$"); static bool convert_to_feature_val(const char *, uint32_t *); static bool edit_file_features(Elf *, int, int, char *, bool); static bool get_file_features(Elf *, int, int, uint32_t *, uint64_t *, bool); static void print_features(void); static bool print_file_features(Elf *, int, int, char *, bool); -static void usage(void); +static void usage(void) __dead2; struct ControlFeatures { const char *alias; unsigned long value; const char *desc; }; static struct ControlFeatures featurelist[] = { { "noaslr", NT_FREEBSD_FCTL_ASLR_DISABLE, "Disable ASLR" }, { "noprotmax", NT_FREEBSD_FCTL_PROTMAX_DISABLE, "Disable implicit PROT_MAX" }, { "nostackgap", NT_FREEBSD_FCTL_STKGAP_DISABLE, "Disable stack gap" }, { "wxneeded", NT_FREEBSD_FCTL_WXNEEDED, "Requires W+X mappings" }, { "la48", NT_FREEBSD_FCTL_LA48, "amd64: Limit user VA to 48bit" }, }; static struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; #if BYTE_ORDER == LITTLE_ENDIAN #define HOST_ENDIAN ELFDATA2LSB #define SWAP_ENDIAN ELFDATA2MSB #else #define HOST_ENDIAN ELFDATA2MSB #define SWAP_ENDIAN ELFDATA2LSB #endif static bool iflag; int main(int argc, char **argv) { GElf_Ehdr ehdr; Elf *elf; Elf_Kind kind; int ch, fd, retval; char *features; bool editfeatures, lflag, endian_swap; lflag = 0; editfeatures = false; retval = 0; features = NULL; if (elf_version(EV_CURRENT) == EV_NONE) errx(EXIT_FAILURE, "elf_version error"); while ((ch = getopt_long(argc, argv, "hile:", long_opts, NULL)) != -1) { switch (ch) { case 'i': iflag = true; break; case 'l': print_features(); lflag = true; break; case 'e': if (features != NULL) errx(1, "-e may be specified only once"); features = optarg; editfeatures = true; break; case 'h': default: usage(); } } argc -= optind; argv += optind; if (argc == 0) { if (lflag) exit(0); else { warnx("no file(s) specified"); usage(); } } while (argc) { elf = NULL; if ((fd = open(argv[0], editfeatures ? O_RDWR : O_RDONLY, 0)) < 0) { warn("error opening file %s", argv[0]); retval = 1; goto fail; } if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warnx("elf_begin failed: %s", elf_errmsg(-1)); retval = 1; goto fail; } if ((kind = elf_kind(elf)) != ELF_K_ELF) { if (kind == ELF_K_AR) warnx("file '%s' is an archive", argv[0]); else warnx("file '%s' is not an ELF file", argv[0]); retval = 1; goto fail; } if (gelf_getehdr(elf, &ehdr) == NULL) { warnx("gelf_getehdr: %s", elf_errmsg(-1)); retval = 1; goto fail; } if (ehdr.e_ident[EI_DATA] == HOST_ENDIAN) { endian_swap = false; } else if (ehdr.e_ident[EI_DATA] == SWAP_ENDIAN) { endian_swap = true; } else { warnx("file endianness unknown"); retval = 1; goto fail; } if (!editfeatures) { if (!print_file_features(elf, ehdr.e_phnum, fd, argv[0], endian_swap)) { retval = 1; goto fail; } } else if (!edit_file_features(elf, ehdr.e_phnum, fd, features, endian_swap)) { retval = 1; goto fail; } fail: if (elf != NULL) elf_end(elf); if (fd >= 0) close(fd); argc--; argv++; } return (retval); } #define USAGE_MESSAGE \ "\ Usage: %s [options] file...\n\ Set or display the control features for an ELF object.\n\n\ Supported options are:\n\ -l List known control features.\n\ -i Ignore unknown features.\n\ -e [+-=]feature,list Edit features from a comma separated list.\n\ -h | --help Print a usage message and exit.\n" static void usage(void) { fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); exit(1); } static bool convert_to_feature_val(const char *feature_str, uint32_t *feature_val) { char *feature, *feature_tmp; int i, len; uint32_t input; char operation; input = 0; operation = *feature_str; feature_str++; if (operation != '+' && operation != '-' && operation != '=') errx(1, "'%c' not an operator - use '+', '-', '='", operation); if ((feature_tmp = strdup(feature_str)) == NULL) err(1, "strdup"); len = nitems(featurelist); while ((feature = strsep(&feature_tmp, ",")) != NULL) { for (i = 0; i < len; ++i) { if (strcmp(featurelist[i].alias, feature) == 0) { input |= featurelist[i].value; break; } /* XXX Backwards compatibility for "no"-prefix flags. */ if (strncmp(featurelist[i].alias, "no", 2) == 0 && strcmp(featurelist[i].alias + 2, feature) == 0) { input |= featurelist[i].value; warnx( "interpreting %s as %s; please specify %s", feature, featurelist[i].alias, featurelist[i].alias); break; } } if (i == len) { if (isdigit(feature[0])) { char *eptr; unsigned long long val; errno = 0; val = strtoll(feature, &eptr, 0); if (eptr == feature || *eptr != '\0') errno = EINVAL; else if (val > UINT32_MAX) errno = ERANGE; if (errno != 0) { warn("%s invalid", feature); free(feature_tmp); return (false); } input |= val; } else { warnx("%s is not a valid feature", feature); if (!iflag) { free(feature_tmp); return (false); } } } } if (operation == '+') { *feature_val |= input; } else if (operation == '=') { *feature_val = input; } else if (operation == '-') { *feature_val &= ~input; } free(feature_tmp); return (true); } static bool edit_file_features(Elf *elf, int phcount, int fd, char *val, bool endian_swap) { uint32_t features, prev_features; uint64_t off; if (!get_file_features(elf, phcount, fd, &features, &off, endian_swap)) { warnx("NT_FREEBSD_FEATURE_CTL note not found"); return (false); } prev_features = features; if (!convert_to_feature_val(val, &features)) return (false); /* Avoid touching file if no change. */ if (features == prev_features) return (true); if (endian_swap) features = bswap32(features); if (lseek(fd, off, SEEK_SET) == -1 || write(fd, &features, sizeof(features)) < (ssize_t)sizeof(features)) { warnx("error writing feature value"); return (false); } return (true); } static void print_features(void) { size_t i; printf("Known features are:\n"); for (i = 0; i < nitems(featurelist); ++i) printf("%-16s%s\n", featurelist[i].alias, featurelist[i].desc); } static bool print_file_features(Elf *elf, int phcount, int fd, char *filename, bool endian_swap) { uint32_t features; unsigned long i; if (!get_file_features(elf, phcount, fd, &features, NULL, endian_swap)) { return (false); } printf("File '%s' features:\n", filename); for (i = 0; i < nitems(featurelist); ++i) { printf("%-16s'%s' is ", featurelist[i].alias, featurelist[i].desc); if ((featurelist[i].value & features) == 0) printf("un"); printf("set.\n"); } return (true); } static bool get_file_features(Elf *elf, int phcount, int fd, uint32_t *features, uint64_t *off, bool endian_swap) { GElf_Phdr phdr; Elf_Note note; unsigned long read_total; int namesz, descsz, i; char *name; /* * Go through each program header to find one that is of type PT_NOTE * and has a note for feature control. */ for (i = 0; i < phcount; ++i) { if (gelf_getphdr(elf, i, &phdr) == NULL) { warnx("gelf_getphdr failed: %s", elf_errmsg(-1)); return (false); } if (phdr.p_type != PT_NOTE) continue; if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) { warn("lseek() failed:"); return (false); } read_total = 0; while (read_total < phdr.p_filesz) { if (read(fd, ¬e, sizeof(note)) < (ssize_t)sizeof(note)) { warnx("elf note header too short"); return (false); } read_total += sizeof(note); if (endian_swap) { note.n_namesz = bswap32(note.n_namesz); note.n_descsz = bswap32(note.n_descsz); note.n_type = bswap32(note.n_type); } /* * XXX: Name and descriptor are 4 byte aligned, however, * the size given doesn't include the padding. */ namesz = roundup2(note.n_namesz, 4); name = malloc(namesz); if (name == NULL) { warn("malloc() failed."); return (false); } descsz = roundup2(note.n_descsz, 4); if (read(fd, name, namesz) < namesz) { warnx("elf note name too short"); free(name); return (false); } read_total += namesz; if (note.n_namesz != 8 || strncmp("FreeBSD", name, 7) != 0 || note.n_type != NT_FREEBSD_FEATURE_CTL) { /* Not the right note. Skip the description */ if (lseek(fd, descsz, SEEK_CUR) < 0) { warn("lseek() failed."); free(name); return (false); } read_total += descsz; free(name); continue; } if (note.n_descsz < sizeof(uint32_t)) { warnx("Feature descriptor can't " "be less than 4 bytes"); free(name); return (false); } /* * XXX: For now we look at only 4 bytes of the * descriptor. This should respect descsz. */ if (note.n_descsz > sizeof(uint32_t)) warnx("Feature note is bigger than expected"); if (read(fd, features, sizeof(uint32_t)) < (ssize_t)sizeof(uint32_t)) { warnx("feature note data too short"); free(name); return (false); } if (endian_swap) *features = bswap32(*features); if (off != NULL) *off = phdr.p_offset + read_total; free(name); return (true); } } warnx("NT_FREEBSD_FEATURE_CTL note not found"); return (false); } diff --git a/usr.bin/elfdump/elfdump.c b/usr.bin/elfdump/elfdump.c index b7f60d0eb27b..0ab64534ac50 100644 --- a/usr.bin/elfdump/elfdump.c +++ b/usr.bin/elfdump/elfdump.c @@ -1,1290 +1,1290 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2003 David O'Brien. All rights reserved. * Copyright (c) 2001 Jake Burkholder * 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 #include #include #include #include #define ED_DYN (1<<0) #define ED_EHDR (1<<1) #define ED_GOT (1<<2) #define ED_HASH (1<<3) #define ED_INTERP (1<<4) #define ED_NOTE (1<<5) #define ED_PHDR (1<<6) #define ED_REL (1<<7) #define ED_SHDR (1<<8) #define ED_SYMTAB (1<<9) #define ED_ALL ((1<<10)-1) #define ED_IS_ELF (1<<10) /* Exclusive with other flags */ #define elf_get_addr elf_get_quad #define elf_get_off elf_get_quad #define elf_get_size elf_get_quad enum elf_member { D_TAG = 1, D_PTR, D_VAL, E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY, E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE, E_SHNUM, E_SHSTRNDX, N_NAMESZ, N_DESCSZ, N_TYPE, P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS, P_ALIGN, SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK, SH_INFO, SH_ADDRALIGN, SH_ENTSIZE, ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX, R_OFFSET, R_INFO, RA_OFFSET, RA_INFO, RA_ADDEND }; typedef enum elf_member elf_member_t; static int elf32_offsets[] = { 0, offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr), offsetof(Elf32_Dyn, d_un.d_val), offsetof(Elf32_Ehdr, e_ident[EI_CLASS]), offsetof(Elf32_Ehdr, e_ident[EI_DATA]), offsetof(Elf32_Ehdr, e_ident[EI_OSABI]), offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine), offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry), offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff), offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize), offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum), offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum), offsetof(Elf32_Ehdr, e_shstrndx), offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz), offsetof(Elf_Note, n_type), offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset), offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr), offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz), offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align), offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type), offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr), offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size), offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info), offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize), offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value), offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info), offsetof(Elf32_Sym, st_shndx), offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info), offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info), offsetof(Elf32_Rela, r_addend) }; static int elf64_offsets[] = { 0, offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr), offsetof(Elf64_Dyn, d_un.d_val), offsetof(Elf32_Ehdr, e_ident[EI_CLASS]), offsetof(Elf32_Ehdr, e_ident[EI_DATA]), offsetof(Elf32_Ehdr, e_ident[EI_OSABI]), offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine), offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry), offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff), offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize), offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum), offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum), offsetof(Elf64_Ehdr, e_shstrndx), offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz), offsetof(Elf_Note, n_type), offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset), offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr), offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz), offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align), offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type), offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr), offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size), offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info), offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize), offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value), offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info), offsetof(Elf64_Sym, st_shndx), offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info), offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info), offsetof(Elf64_Rela, r_addend) }; /* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */ static const char * d_tags(u_int64_t tag) { static char unknown_tag[48]; switch (tag) { case DT_NULL: return "DT_NULL"; case DT_NEEDED: return "DT_NEEDED"; case DT_PLTRELSZ: return "DT_PLTRELSZ"; case DT_PLTGOT: return "DT_PLTGOT"; case DT_HASH: return "DT_HASH"; case DT_STRTAB: return "DT_STRTAB"; case DT_SYMTAB: return "DT_SYMTAB"; case DT_RELA: return "DT_RELA"; case DT_RELASZ: return "DT_RELASZ"; case DT_RELAENT: return "DT_RELAENT"; case DT_STRSZ: return "DT_STRSZ"; case DT_SYMENT: return "DT_SYMENT"; case DT_INIT: return "DT_INIT"; case DT_FINI: return "DT_FINI"; case DT_SONAME: return "DT_SONAME"; case DT_RPATH: return "DT_RPATH"; case DT_SYMBOLIC: return "DT_SYMBOLIC"; case DT_REL: return "DT_REL"; case DT_RELSZ: return "DT_RELSZ"; case DT_RELENT: return "DT_RELENT"; case DT_PLTREL: return "DT_PLTREL"; case DT_DEBUG: return "DT_DEBUG"; case DT_TEXTREL: return "DT_TEXTREL"; case DT_JMPREL: return "DT_JMPREL"; case DT_BIND_NOW: return "DT_BIND_NOW"; case DT_INIT_ARRAY: return "DT_INIT_ARRAY"; case DT_FINI_ARRAY: return "DT_FINI_ARRAY"; case DT_INIT_ARRAYSZ: return "DT_INIT_ARRAYSZ"; case DT_FINI_ARRAYSZ: return "DT_FINI_ARRAYSZ"; case DT_RUNPATH: return "DT_RUNPATH"; case DT_FLAGS: return "DT_FLAGS"; case DT_PREINIT_ARRAY: return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */ case DT_PREINIT_ARRAYSZ:return "DT_PREINIT_ARRAYSZ"; /* 0x6000000D - 0x6ffff000 operating system-specific semantics */ case 0x6ffffdf5: return "DT_GNU_PRELINKED"; case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ"; case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ"; case 0x6ffffdf8: return "DT_SUNW_CHECKSUM"; case DT_PLTPADSZ: return "DT_PLTPADSZ"; case DT_MOVEENT: return "DT_MOVEENT"; case DT_MOVESZ: return "DT_MOVESZ"; case DT_FEATURE: return "DT_FEATURE"; case DT_POSFLAG_1: return "DT_POSFLAG_1"; case DT_SYMINSZ: return "DT_SYMINSZ"; case DT_SYMINENT : return "DT_SYMINENT (DT_VALRNGHI)"; case DT_ADDRRNGLO: return "DT_ADDRRNGLO"; case DT_GNU_HASH: return "DT_GNU_HASH"; case 0x6ffffef8: return "DT_GNU_CONFLICT"; case 0x6ffffef9: return "DT_GNU_LIBLIST"; case DT_CONFIG: return "DT_CONFIG"; case DT_DEPAUDIT: return "DT_DEPAUDIT"; case DT_AUDIT: return "DT_AUDIT"; case DT_PLTPAD: return "DT_PLTPAD"; case DT_MOVETAB: return "DT_MOVETAB"; case DT_SYMINFO : return "DT_SYMINFO (DT_ADDRRNGHI)"; case DT_RELACOUNT: return "DT_RELACOUNT"; case DT_RELCOUNT: return "DT_RELCOUNT"; case DT_FLAGS_1: return "DT_FLAGS_1"; case DT_VERDEF: return "DT_VERDEF"; case DT_VERDEFNUM: return "DT_VERDEFNUM"; case DT_VERNEED: return "DT_VERNEED"; case DT_VERNEEDNUM: return "DT_VERNEEDNUM"; case 0x6ffffff0: return "DT_GNU_VERSYM"; /* 0x70000000 - 0x7fffffff processor-specific semantics */ case 0x70000000: return "DT_IA_64_PLT_RESERVE"; case DT_AUXILIARY: return "DT_AUXILIARY"; case DT_USED: return "DT_USED"; case DT_FILTER: return "DT_FILTER"; } snprintf(unknown_tag, sizeof(unknown_tag), "ERROR: TAG NOT DEFINED -- tag 0x%jx", (uintmax_t)tag); return (unknown_tag); } static const char * e_machines(u_int mach) { static char machdesc[64]; switch (mach) { case EM_NONE: return "EM_NONE"; case EM_M32: return "EM_M32"; case EM_SPARC: return "EM_SPARC"; case EM_386: return "EM_386"; case EM_68K: return "EM_68K"; case EM_88K: return "EM_88K"; case EM_IAMCU: return "EM_IAMCU"; case EM_860: return "EM_860"; case EM_MIPS: return "EM_MIPS"; case EM_PPC: return "EM_PPC"; case EM_PPC64: return "EM_PPC64"; case EM_ARM: return "EM_ARM"; case EM_ALPHA: return "EM_ALPHA (legacy)"; case EM_SPARCV9:return "EM_SPARCV9"; case EM_IA_64: return "EM_IA_64"; case EM_X86_64: return "EM_X86_64"; case EM_AARCH64:return "EM_AARCH64"; case EM_RISCV: return "EM_RISCV"; } snprintf(machdesc, sizeof(machdesc), "(unknown machine) -- type 0x%x", mach); return (machdesc); } static const char *e_types[] = { "ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE" }; static const char *ei_versions[] = { "EV_NONE", "EV_CURRENT" }; static const char *ei_classes[] = { "ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64" }; static const char *ei_data[] = { "ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB" }; static const char *ei_abis[256] = { "ELFOSABI_NONE", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", "ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD", [255] = "ELFOSABI_STANDALONE" }; static const char *p_types[] = { "PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE", "PT_SHLIB", "PT_PHDR", "PT_TLS" }; static const char *p_flags[] = { "", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R", "PF_X|PF_W|PF_R" }; #define NT_ELEM(x) [x] = #x, static const char *nt_types[] = { "", NT_ELEM(NT_FREEBSD_ABI_TAG) NT_ELEM(NT_FREEBSD_NOINIT_TAG) NT_ELEM(NT_FREEBSD_ARCH_TAG) NT_ELEM(NT_FREEBSD_FEATURE_CTL) }; /* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */ static const char * sh_types(uint64_t machine, uint64_t sht) { static char unknown_buf[64]; if (sht < 0x60000000) { switch (sht) { case SHT_NULL: return "SHT_NULL"; case SHT_PROGBITS: return "SHT_PROGBITS"; case SHT_SYMTAB: return "SHT_SYMTAB"; case SHT_STRTAB: return "SHT_STRTAB"; case SHT_RELA: return "SHT_RELA"; case SHT_HASH: return "SHT_HASH"; case SHT_DYNAMIC: return "SHT_DYNAMIC"; case SHT_NOTE: return "SHT_NOTE"; case SHT_NOBITS: return "SHT_NOBITS"; case SHT_REL: return "SHT_REL"; case SHT_SHLIB: return "SHT_SHLIB"; case SHT_DYNSYM: return "SHT_DYNSYM"; case SHT_INIT_ARRAY: return "SHT_INIT_ARRAY"; case SHT_FINI_ARRAY: return "SHT_FINI_ARRAY"; case SHT_PREINIT_ARRAY: return "SHT_PREINIT_ARRAY"; case SHT_GROUP: return "SHT_GROUP"; case SHT_SYMTAB_SHNDX: return "SHT_SYMTAB_SHNDX"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: SHT %ju NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else if (sht < 0x70000000) { /* 0x60000000-0x6fffffff operating system-specific semantics */ switch (sht) { case 0x6ffffff0: return "XXX:VERSYM"; case SHT_SUNW_dof: return "SHT_SUNW_dof"; case SHT_GNU_HASH: return "SHT_GNU_HASH"; case 0x6ffffff7: return "SHT_GNU_LIBLIST"; case 0x6ffffffc: return "XXX:VERDEF"; case SHT_SUNW_verdef: return "SHT_SUNW(GNU)_verdef"; case SHT_SUNW_verneed: return "SHT_SUNW(GNU)_verneed"; case SHT_SUNW_versym: return "SHT_SUNW(GNU)_versym"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: OS-SPECIFIC SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else if (sht < 0x80000000) { /* 0x70000000-0x7fffffff processor-specific semantics */ switch (machine) { case EM_ARM: switch (sht) { case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX"; case SHT_ARM_PREEMPTMAP:return "SHT_ARM_PREEMPTMAP"; case SHT_ARM_ATTRIBUTES:return "SHT_ARM_ATTRIBUTES"; case SHT_ARM_DEBUGOVERLAY: return "SHT_ARM_DEBUGOVERLAY"; case SHT_ARM_OVERLAYSECTION: return "SHT_ARM_OVERLAYSECTION"; } break; case EM_IA_64: switch (sht) { case 0x70000000: return "SHT_IA_64_EXT"; case 0x70000001: return "SHT_IA_64_UNWIND"; } break; case EM_MIPS: switch (sht) { case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO"; case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS"; case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS"; } break; } switch (sht) { case 0x7ffffffd: return "XXX:AUXILIARY"; case 0x7fffffff: return "XXX:FILTER"; } snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: PROCESSOR-SPECIFIC SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } else { /* 0x80000000-0xffffffff application programs */ snprintf(unknown_buf, sizeof(unknown_buf), "ERROR: SHT 0x%jx NOT DEFINED", (uintmax_t)sht); return (unknown_buf); } } static const char *sh_flags[] = { "", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR", "SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR", "SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR" }; static const char * st_type(unsigned int mach, unsigned int type) { static char s_type[32]; switch (type) { case STT_NOTYPE: return "STT_NOTYPE"; case STT_OBJECT: return "STT_OBJECT"; case STT_FUNC: return "STT_FUNC"; case STT_SECTION: return "STT_SECTION"; case STT_FILE: return "STT_FILE"; case STT_COMMON: return "STT_COMMON"; case STT_TLS: return "STT_TLS"; case 13: if (mach == EM_SPARCV9) return "STT_SPARC_REGISTER"; break; } snprintf(s_type, sizeof(s_type), "", type); return (s_type); } static const char *st_bindings[] = { "STB_LOCAL", "STB_GLOBAL", "STB_WEAK" }; static char *dynstr; static char *shstrtab; static char *strtab; static FILE *out; static u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member); static u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member); #if 0 static u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member); #endif static u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member); static u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member); static void elf_print_ehdr(Elf32_Ehdr *e, void *sh); static void elf_print_phdr(Elf32_Ehdr *e, void *p); static void elf_print_shdr(Elf32_Ehdr *e, void *sh); static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str); static void elf_print_dynamic(Elf32_Ehdr *e, void *sh); static void elf_print_rel(Elf32_Ehdr *e, void *r); static void elf_print_rela(Elf32_Ehdr *e, void *ra); static void elf_print_interp(Elf32_Ehdr *e, void *p); static void elf_print_got(Elf32_Ehdr *e, void *sh); static void elf_print_hash(Elf32_Ehdr *e, void *sh); static void elf_print_note(Elf32_Ehdr *e, void *sh); -static void usage(void); +static void usage(void) __dead2; /* * Helpers for ELF files with shnum or shstrndx values that don't fit in the * ELF header. If the values are too large then an escape value is used to * indicate that the actual value is found in one of section 0's fields. */ static uint64_t elf_get_shnum(Elf32_Ehdr *e, void *sh) { uint64_t shnum; shnum = elf_get_quarter(e, e, E_SHNUM); if (shnum == 0) shnum = elf_get_word(e, (char *)sh, SH_SIZE); return shnum; } static uint64_t elf_get_shstrndx(Elf32_Ehdr *e, void *sh) { uint64_t shstrndx; shstrndx = elf_get_quarter(e, e, E_SHSTRNDX); if (shstrndx == SHN_XINDEX) shstrndx = elf_get_word(e, (char *)sh, SH_LINK); return shstrndx; } int main(int ac, char **av) { cap_rights_t rights; u_int64_t phoff; u_int64_t shoff; u_int64_t phentsize; u_int64_t phnum; u_int64_t shentsize; u_int64_t shnum; u_int64_t shstrndx; u_int64_t offset; u_int64_t name; u_int64_t type; struct stat sb; u_int flags; Elf32_Ehdr *e; void *p; void *sh; void *v; int fd; int ch; int i; out = stdout; flags = 0; while ((ch = getopt(ac, av, "acdEeiGhnprsw:")) != -1) switch (ch) { case 'a': flags = ED_ALL; break; case 'c': flags |= ED_SHDR; break; case 'd': flags |= ED_DYN; break; case 'E': flags = ED_IS_ELF; break; case 'e': flags |= ED_EHDR; break; case 'i': flags |= ED_INTERP; break; case 'G': flags |= ED_GOT; break; case 'h': flags |= ED_HASH; break; case 'n': flags |= ED_NOTE; break; case 'p': flags |= ED_PHDR; break; case 'r': flags |= ED_REL; break; case 's': flags |= ED_SYMTAB; break; case 'w': if ((out = fopen(optarg, "w")) == NULL) err(1, "%s", optarg); cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); if (caph_rights_limit(fileno(out), &rights) < 0) err(1, "unable to limit rights for %s", optarg); break; case '?': default: usage(); } ac -= optind; av += optind; if (ac == 0 || flags == 0 || ((flags & ED_IS_ELF) && (ac != 1 || (flags & ~ED_IS_ELF) || out != stdout))) usage(); if ((fd = open(*av, O_RDONLY)) < 0 || fstat(fd, &sb) < 0) err(1, "%s", *av); if ((size_t)sb.st_size < sizeof(Elf32_Ehdr)) { if (flags & ED_IS_ELF) exit(1); errx(1, "not an elf file"); } cap_rights_init(&rights, CAP_MMAP_R); if (caph_rights_limit(fd, &rights) < 0) err(1, "unable to limit rights for %s", *av); cap_rights_init(&rights); if (caph_rights_limit(STDIN_FILENO, &rights) < 0 || caph_limit_stdout() < 0 || caph_limit_stderr() < 0) { err(1, "unable to limit rights for stdio"); } if (caph_enter() < 0) err(1, "unable to enter capability mode"); e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (e == MAP_FAILED) err(1, NULL); if (!IS_ELF(*e)) { if (flags & ED_IS_ELF) exit(1); errx(1, "not an elf file"); } else if (flags & ED_IS_ELF) exit (0); phoff = elf_get_off(e, e, E_PHOFF); shoff = elf_get_off(e, e, E_SHOFF); phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); p = (char *)e + phoff; if (shoff > 0) { sh = (char *)e + shoff; shnum = elf_get_shnum(e, sh); shstrndx = elf_get_shstrndx(e, sh); offset = elf_get_off(e, (char *)sh + shstrndx * shentsize, SH_OFFSET); shstrtab = (char *)e + offset; } else { sh = NULL; shnum = 0; shstrndx = 0; shstrtab = NULL; } for (i = 0; (u_int64_t)i < shnum; i++) { name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME); offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET); if (strcmp(shstrtab + name, ".strtab") == 0) strtab = (char *)e + offset; if (strcmp(shstrtab + name, ".dynstr") == 0) dynstr = (char *)e + offset; } if (flags & ED_EHDR) elf_print_ehdr(e, sh); if (flags & ED_PHDR) elf_print_phdr(e, p); if (flags & ED_SHDR) elf_print_shdr(e, sh); for (i = 0; (u_int64_t)i < phnum; i++) { v = (char *)p + i * phentsize; type = elf_get_word(e, v, P_TYPE); switch (type) { case PT_INTERP: if (flags & ED_INTERP) elf_print_interp(e, v); break; case PT_NULL: case PT_LOAD: case PT_DYNAMIC: case PT_NOTE: case PT_SHLIB: case PT_PHDR: break; } } for (i = 0; (u_int64_t)i < shnum; i++) { v = (char *)sh + i * shentsize; type = elf_get_word(e, v, SH_TYPE); switch (type) { case SHT_SYMTAB: if (flags & ED_SYMTAB) elf_print_symtab(e, v, strtab); break; case SHT_DYNAMIC: if (flags & ED_DYN) elf_print_dynamic(e, v); break; case SHT_RELA: if (flags & ED_REL) elf_print_rela(e, v); break; case SHT_REL: if (flags & ED_REL) elf_print_rel(e, v); break; case SHT_NOTE: name = elf_get_word(e, v, SH_NAME); if (flags & ED_NOTE && strcmp(shstrtab + name, ".note.tag") == 0) elf_print_note(e, v); break; case SHT_DYNSYM: if (flags & ED_SYMTAB) elf_print_symtab(e, v, dynstr); break; case SHT_PROGBITS: name = elf_get_word(e, v, SH_NAME); if (flags & ED_GOT && strcmp(shstrtab + name, ".got") == 0) elf_print_got(e, v); break; case SHT_HASH: if (flags & ED_HASH) elf_print_hash(e, v); break; case SHT_NULL: case SHT_STRTAB: case SHT_NOBITS: case SHT_SHLIB: break; } } return 0; } static void elf_print_ehdr(Elf32_Ehdr *e, void *sh) { u_int64_t class; u_int64_t data; u_int64_t osabi; u_int64_t type; u_int64_t machine; u_int64_t version; u_int64_t entry; u_int64_t phoff; u_int64_t shoff; u_int64_t flags; u_int64_t ehsize; u_int64_t phentsize; u_int64_t phnum; u_int64_t shentsize; u_int64_t shnum; u_int64_t shstrndx; class = elf_get_byte(e, e, E_CLASS); data = elf_get_byte(e, e, E_DATA); osabi = elf_get_byte(e, e, E_OSABI); type = elf_get_quarter(e, e, E_TYPE); machine = elf_get_quarter(e, e, E_MACHINE); version = elf_get_word(e, e, E_VERSION); entry = elf_get_addr(e, e, E_ENTRY); phoff = elf_get_off(e, e, E_PHOFF); shoff = elf_get_off(e, e, E_SHOFF); flags = elf_get_word(e, e, E_FLAGS); ehsize = elf_get_quarter(e, e, E_EHSIZE); phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); fprintf(out, "\nelf header:\n"); fprintf(out, "\n"); fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data], ei_abis[osabi]); fprintf(out, "\te_type: %s\n", e_types[type]); fprintf(out, "\te_machine: %s\n", e_machines(machine)); fprintf(out, "\te_version: %s\n", ei_versions[version]); fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry); fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff); fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff); fprintf(out, "\te_flags: %jd\n", (intmax_t)flags); fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize); fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize); fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum); fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize); if (sh != NULL) { shnum = elf_get_shnum(e, sh); shstrndx = elf_get_shstrndx(e, sh); fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum); fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx); } } static void elf_print_phdr(Elf32_Ehdr *e, void *p) { u_int64_t phentsize; u_int64_t phnum; u_int64_t type; u_int64_t offset; u_int64_t vaddr; u_int64_t paddr; u_int64_t filesz; u_int64_t memsz; u_int64_t flags; u_int64_t align; void *v; int i; phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); fprintf(out, "\nprogram header:\n"); for (i = 0; (u_int64_t)i < phnum; i++) { v = (char *)p + i * phentsize; type = elf_get_word(e, v, P_TYPE); offset = elf_get_off(e, v, P_OFFSET); vaddr = elf_get_addr(e, v, P_VADDR); paddr = elf_get_addr(e, v, P_PADDR); filesz = elf_get_size(e, v, P_FILESZ); memsz = elf_get_size(e, v, P_MEMSZ); flags = elf_get_word(e, v, P_FLAGS); align = elf_get_size(e, v, P_ALIGN); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]); fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset); fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr); fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr); fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz); fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz); fprintf(out, "\tp_flags: %s\n", p_flags[flags]); fprintf(out, "\tp_align: %jd\n", (intmax_t)align); } } static void elf_print_shdr(Elf32_Ehdr *e, void *sh) { u_int64_t shentsize; u_int64_t shnum; u_int64_t name; u_int64_t type; u_int64_t flags; u_int64_t addr; u_int64_t offset; u_int64_t size; u_int64_t shlink; u_int64_t info; u_int64_t addralign; u_int64_t entsize; u_int64_t machine; void *v; int i; if (sh == NULL) { fprintf(out, "\nNo section headers\n"); return; } machine = elf_get_quarter(e, e, E_MACHINE); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); shnum = elf_get_shnum(e, sh); fprintf(out, "\nsection header:\n"); for (i = 0; (u_int64_t)i < shnum; i++) { v = (char *)sh + i * shentsize; name = elf_get_word(e, v, SH_NAME); type = elf_get_word(e, v, SH_TYPE); flags = elf_get_word(e, v, SH_FLAGS); addr = elf_get_addr(e, v, SH_ADDR); offset = elf_get_off(e, v, SH_OFFSET); size = elf_get_size(e, v, SH_SIZE); shlink = elf_get_word(e, v, SH_LINK); info = elf_get_word(e, v, SH_INFO); addralign = elf_get_size(e, v, SH_ADDRALIGN); entsize = elf_get_size(e, v, SH_ENTSIZE); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tsh_name: %s\n", shstrtab + name); fprintf(out, "\tsh_type: %s\n", sh_types(machine, type)); fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]); fprintf(out, "\tsh_addr: %#jx\n", addr); fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset); fprintf(out, "\tsh_size: %jd\n", (intmax_t)size); fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink); fprintf(out, "\tsh_info: %jd\n", (intmax_t)info); fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign); fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize); } } static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str) { u_int64_t machine; u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t value; u_int64_t info; u_int64_t shndx; void *st; int len; int i; machine = elf_get_quarter(e, e, E_MACHINE); offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); len = size / entsize; fprintf(out, "\nsymbol table (%s):\n", shstrtab + name); for (i = 0; i < len; i++) { st = (char *)e + offset + i * entsize; name = elf_get_word(e, st, ST_NAME); value = elf_get_addr(e, st, ST_VALUE); size = elf_get_size(e, st, ST_SIZE); info = elf_get_byte(e, st, ST_INFO); shndx = elf_get_quarter(e, st, ST_SHNDX); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tst_name: %s\n", str + name); fprintf(out, "\tst_value: %#jx\n", value); fprintf(out, "\tst_size: %jd\n", (intmax_t)size); fprintf(out, "\tst_info: %s %s\n", st_type(machine, ELF32_ST_TYPE(info)), st_bindings[ELF32_ST_BIND(info)]); fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx); } } static void elf_print_dynamic(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; int64_t tag; u_int64_t ptr; u_int64_t val; void *d; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); fprintf(out, "\ndynamic:\n"); for (i = 0; (u_int64_t)i < size / entsize; i++) { d = (char *)e + offset + i * entsize; tag = elf_get_size(e, d, D_TAG); ptr = elf_get_size(e, d, D_PTR); val = elf_get_addr(e, d, D_VAL); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\td_tag: %s\n", d_tags(tag)); switch (tag) { case DT_NEEDED: case DT_SONAME: case DT_RPATH: fprintf(out, "\td_val: %s\n", dynstr + val); break; case DT_PLTRELSZ: case DT_RELA: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: fprintf(out, "\td_val: %jd\n", (intmax_t)val); break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_INIT: case DT_FINI: case DT_REL: case DT_JMPREL: fprintf(out, "\td_ptr: %#jx\n", ptr); break; case DT_NULL: case DT_SYMBOLIC: case DT_DEBUG: case DT_TEXTREL: break; } } } static void elf_print_rela(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t info; int64_t addend; void *ra; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); v = (char *)e + offset; fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name); for (i = 0; (u_int64_t)i < size / entsize; i++) { ra = (char *)v + i * entsize; offset = elf_get_addr(e, ra, RA_OFFSET); info = elf_get_word(e, ra, RA_INFO); addend = elf_get_off(e, ra, RA_ADDEND); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tr_offset: %#jx\n", offset); fprintf(out, "\tr_info: %jd\n", (intmax_t)info); fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend); } } static void elf_print_rel(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t entsize; u_int64_t size; u_int64_t name; u_int64_t info; void *r; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); entsize = elf_get_size(e, sh, SH_ENTSIZE); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); v = (char *)e + offset; fprintf(out, "\nrelocation (%s):\n", shstrtab + name); for (i = 0; (u_int64_t)i < size / entsize; i++) { r = (char *)v + i * entsize; offset = elf_get_addr(e, r, R_OFFSET); info = elf_get_word(e, r, R_INFO); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\tr_offset: %#jx\n", offset); fprintf(out, "\tr_info: %jd\n", (intmax_t)info); } } static void elf_print_interp(Elf32_Ehdr *e, void *p) { u_int64_t offset; char *s; offset = elf_get_off(e, p, P_OFFSET); s = (char *)e + offset; fprintf(out, "\ninterp:\n"); fprintf(out, "\t%s\n", s); } static void elf_print_got(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t addralign; u_int64_t size; u_int64_t addr; void *v; int i; offset = elf_get_off(e, sh, SH_OFFSET); addralign = elf_get_size(e, sh, SH_ADDRALIGN); size = elf_get_size(e, sh, SH_SIZE); v = (char *)e + offset; fprintf(out, "\nglobal offset table:\n"); for (i = 0; (u_int64_t)i < size / addralign; i++) { addr = elf_get_addr(e, (char *)v + i * addralign, 0); fprintf(out, "\n"); fprintf(out, "entry: %d\n", i); fprintf(out, "\t%#jx\n", addr); } } static void elf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused) { } static void elf_print_note(Elf32_Ehdr *e, void *sh) { u_int64_t offset; u_int64_t size; u_int64_t name; u_int32_t namesz; u_int32_t descsz; u_int32_t desc; u_int32_t type; char *n, *s; const char *nt_type; offset = elf_get_off(e, sh, SH_OFFSET); size = elf_get_size(e, sh, SH_SIZE); name = elf_get_word(e, sh, SH_NAME); n = (char *)e + offset; fprintf(out, "\nnote (%s):\n", shstrtab + name); while (n < ((char *)e + offset + size)) { namesz = elf_get_word(e, n, N_NAMESZ); descsz = elf_get_word(e, n, N_DESCSZ); type = elf_get_word(e, n, N_TYPE); if (type < nitems(nt_types) && nt_types[type] != NULL) nt_type = nt_types[type]; else nt_type = "Unknown type"; s = n + sizeof(Elf_Note); desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0); fprintf(out, "\t%s %d (%s)\n", s, desc, nt_type); n += sizeof(Elf_Note) + namesz + descsz; } } static u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: val = ((uint8_t *)base)[elf32_offsets[member]]; break; case ELFCLASS64: val = ((uint8_t *)base)[elf64_offsets[member]]; break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } #if 0 static u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be16dec(base); break; case ELFDATA2LSB: val = le16dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } #endif static u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member) { u_int64_t val; val = 0; switch (e->e_ident[EI_CLASS]) { case ELFCLASS32: base = (char *)base + elf32_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be32dec(base); break; case ELFDATA2LSB: val = le32dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASS64: base = (char *)base + elf64_offsets[member]; switch (e->e_ident[EI_DATA]) { case ELFDATA2MSB: val = be64dec(base); break; case ELFDATA2LSB: val = le64dec(base); break; case ELFDATANONE: errx(1, "invalid data format"); } break; case ELFCLASSNONE: errx(1, "invalid class"); } return val; } static void usage(void) { fprintf(stderr, "usage: elfdump -a | -E | -cdeGhinprs [-w file] file\n"); exit(1); } diff --git a/usr.bin/env/env.c b/usr.bin/env/env.c index a0f55d665a9a..4c4e36d12075 100644 --- a/usr.bin/env/env.c +++ b/usr.bin/env/env.c @@ -1,230 +1,230 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)env.c 8.3 (Berkeley) 4/2/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "envopts.h" extern char **environ; int env_verbosity; -static void usage(void); +static void usage(void) __dead2; /* * Exit codes. */ #define EXIT_CANCELED 125 /* Internal error prior to exec attempt. */ #define EXIT_CANNOT_INVOKE 126 /* Program located, but not usable. */ #define EXIT_ENOENT 127 /* Could not find program to exec. */ int main(int argc, char **argv) { char *altpath, **ep, *p, **parg, term; char *cleanenv[1]; char *login_class, *login_name; struct passwd *pw; login_cap_t *lc; bool login_as_user; uid_t uid; int ch, want_clear; int rtrn; altpath = NULL; login_class = NULL; login_name = NULL; pw = NULL; lc = NULL; login_as_user = false; want_clear = 0; term = '\n'; while ((ch = getopt(argc, argv, "-0iL:P:S:U:u:v")) != -1) switch(ch) { case '-': case 'i': want_clear = 1; break; case '0': term = '\0'; break; case 'U': login_as_user = true; /* FALLTHROUGH */ case 'L': login_name = optarg; break; case 'P': altpath = strdup(optarg); break; case 'S': /* * The -S option, for "split string on spaces, with * support for some simple substitutions"... */ split_spaces(optarg, &optind, &argc, &argv); break; case 'u': if (env_verbosity) fprintf(stderr, "#env unset:\t%s\n", optarg); rtrn = unsetenv(optarg); if (rtrn == -1) err(EXIT_FAILURE, "unsetenv %s", optarg); break; case 'v': env_verbosity++; if (env_verbosity > 1) fprintf(stderr, "#env verbosity now at %d\n", env_verbosity); break; case '?': default: usage(); } if (want_clear) { environ = cleanenv; cleanenv[0] = NULL; if (env_verbosity) fprintf(stderr, "#env clearing environ\n"); } if (login_name != NULL) { login_class = strchr(login_name, '/'); if (login_class) *login_class++ = '\0'; if (*login_name != '\0' && strcmp(login_name, "-") != 0) { pw = getpwnam(login_name); if (pw == NULL) { char *endp = NULL; errno = 0; uid = strtoul(login_name, &endp, 10); if (errno == 0 && *endp == '\0') pw = getpwuid(uid); } if (pw == NULL) errx(EXIT_FAILURE, "no such user: %s", login_name); } /* * Note that it is safe for pw to be null here; the libutil * code handles that, bypassing substitution of $ and using * the class "default" if no class name is given either. */ if (login_class != NULL) { lc = login_getclass(login_class); if (lc == NULL) errx(EXIT_FAILURE, "no such login class: %s", login_class); } else { lc = login_getpwclass(pw); if (lc == NULL) errx(EXIT_FAILURE, "login_getpwclass failed"); } /* * This is not done with setusercontext() because that will * try and use ~/.login_conf even when we don't want it to. */ setclassenvironment(lc, pw, 1); setclassenvironment(lc, pw, 0); if (login_as_user) { login_close(lc); if ((lc = login_getuserclass(pw)) != NULL) { setclassenvironment(lc, pw, 1); setclassenvironment(lc, pw, 0); } } endpwent(); if (lc != NULL) login_close(lc); } for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) { if (env_verbosity) fprintf(stderr, "#env setenv:\t%s\n", *argv); *p = '\0'; rtrn = setenv(*argv, p + 1, 1); *p = '='; if (rtrn == -1) err(EXIT_FAILURE, "setenv %s", *argv); } if (*argv) { if (term == '\0') errx(EXIT_CANCELED, "cannot specify command with -0"); if (altpath) search_paths(altpath, argv); if (env_verbosity) { fprintf(stderr, "#env executing:\t%s\n", *argv); for (parg = argv, argc = 0; *parg; parg++, argc++) fprintf(stderr, "#env arg[%d]=\t'%s'\n", argc, *parg); if (env_verbosity > 1) sleep(1); } execvp(*argv, argv); err(errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE, "%s", *argv); } for (ep = environ; *ep; ep++) (void)printf("%s%c", *ep, term); exit(0); } static void usage(void) { (void)fprintf(stderr, "usage: env [-0iv] [-L|-U user[/class]] [-P utilpath] [-S string] [-u name]\n" " [name=value ...] [utility [argument ...]]\n"); exit(1); } diff --git a/usr.bin/find/main.c b/usr.bin/find/main.c index 45a95a454d94..6090f71d6e7c 100644 --- a/usr.bin/find/main.c +++ b/usr.bin/find/main.c @@ -1,165 +1,165 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Cimarron D. Taylor of the University of California, Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 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. */ static const char copyright[] = "@(#) Copyright (c) 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #if 0 static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 5/4/95"; #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "find.h" time_t now; /* time find was run */ int dotfd; /* starting directory */ int ftsoptions; /* options for the ftsopen(3) call */ int ignore_readdir_race; /* ignore readdir race */ int isdepth; /* do directories on post-order visit */ int isoutput; /* user specified output operator */ int issort; /* do hierarchies in lexicographical order */ int isxargs; /* don't permit xargs delimiting chars */ int mindepth = -1, maxdepth = -1; /* minimum and maximum depth */ int regexp_flags = REG_BASIC; /* use the "basic" regexp by default*/ int exitstatus; -static void usage(void); +static void usage(void) __dead2; int main(int argc, char *argv[]) { char **p, **start; int Hflag, Lflag, ch; (void)setlocale(LC_ALL, ""); (void)time(&now); /* initialize the time-of-day */ p = start = argv; Hflag = Lflag = 0; ftsoptions = FTS_NOSTAT | FTS_PHYSICAL; while ((ch = getopt(argc, argv, "EHLPXdf:sx")) != -1) switch (ch) { case 'E': regexp_flags |= REG_EXTENDED; break; case 'H': Hflag = 1; Lflag = 0; break; case 'L': Lflag = 1; Hflag = 0; break; case 'P': Hflag = Lflag = 0; break; case 'X': isxargs = 1; break; case 'd': isdepth = 1; break; case 'f': *p++ = optarg; break; case 's': issort = 1; break; case 'x': ftsoptions |= FTS_XDEV; break; case '?': default: usage(); } argc -= optind; argv += optind; if (Hflag) ftsoptions |= FTS_COMFOLLOW; if (Lflag) { ftsoptions &= ~FTS_PHYSICAL; ftsoptions |= FTS_LOGICAL; } /* * Find first option to delimit the file list. The first argument * that starts with a -, or is a ! or a ( must be interpreted as a * part of the find expression, according to POSIX .2. */ for (; *argv != NULL; *p++ = *argv++) { if (argv[0][0] == '-') break; if ((argv[0][0] == '!' || argv[0][0] == '(') && argv[0][1] == '\0') break; } if (p == start) usage(); *p = NULL; if ((dotfd = open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) ftsoptions |= FTS_NOCHDIR; exit(find_execute(find_formplan(argv), start)); } static void usage(void) { (void)fprintf(stderr, "%s\n%s\n", "usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]", " find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]"); exit(1); } diff --git a/usr.bin/finger/finger.c b/usr.bin/finger/finger.c index 1211c54eb950..6f357f9d994b 100644 --- a/usr.bin/finger/finger.c +++ b/usr.bin/finger/finger.c @@ -1,409 +1,409 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. * * 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. */ /* * Luke Mewburn added the following on 940622: * - mail status ("No Mail", "Mail read:...", or "New Mail ..., * Unread since ...".) * - 4 digit phone extensions (3210 is printed as x3210.) * - host/office toggling in short format with -h & -o. * - short day names (`Tue' printed instead of `Jun 21' if the * login time is < 6 days. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95"; #endif #endif #include __FBSDID("$FreeBSD$"); /* * Finger prints out information about users. It is not portable since * certain fields (e.g. the full user name, office, and phone numbers) are * extracted from the gecos field of the passwd file which other UNIXes * may not have or may use for other things. * * There are currently two output formats; the short format is one line * per user and displays login name, tty, login time, real name, idle time, * and either remote host information (default) or office location/phone * number, depending on if -h or -o is used respectively. * The long format gives the same information (in a more legible format) as * well as home directory, shell, mail info, and .plan/.project files. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "finger.h" #include "pathnames.h" DB *db; time_t now; static int kflag, mflag, sflag; int entries, gflag, lflag, pplan, oflag; sa_family_t family = PF_UNSPEC; int d_first = -1; char tbuf[1024]; int invoker_root = 0; static void loginlist(void); static int option(int, char **); -static void usage(void); +static void usage(void) __dead2; static void userlist(int, char **); static int option(int argc, char **argv) { int ch; optind = 1; /* reset getopt */ while ((ch = getopt(argc, argv, "46gklmpsho")) != -1) switch(ch) { case '4': family = AF_INET; break; case '6': family = AF_INET6; break; case 'g': gflag = 1; break; case 'k': kflag = 1; /* keep going without utmp */ break; case 'l': lflag = 1; /* long format */ break; case 'm': mflag = 1; /* force exact match of names */ break; case 'p': pplan = 1; /* don't show .plan/.project */ break; case 's': sflag = 1; /* short format */ break; case 'h': oflag = 0; /* remote host info */ break; case 'o': oflag = 1; /* office info */ break; case '?': default: usage(); } return optind; } static void usage(void) { (void)fprintf(stderr, "usage: finger [-46gklmpsho] [user ...] [user@host ...]\n"); exit(1); } int main(int argc, char **argv) { int envargc, argcnt; char *envargv[3]; struct passwd *pw; static char myname[] = "finger"; if (getuid() == 0 || geteuid() == 0) { invoker_root = 1; if ((pw = getpwnam(UNPRIV_NAME)) && pw->pw_uid > 0) { if (setgid(pw->pw_gid) != 0) err(1, "setgid()"); if (setuid(pw->pw_uid) != 0) err(1, "setuid()"); } else { if (setgid(UNPRIV_UGID) != 0) err(1, "setgid()"); if (setuid(UNPRIV_UGID) != 0) err(1, "setuid()"); } } (void) setlocale(LC_ALL, ""); /* remove this line to get remote host */ oflag = 1; /* default to old "office" behavior */ /* * Process environment variables followed by command line arguments. */ if ((envargv[1] = getenv("FINGER"))) { envargc = 2; envargv[0] = myname; envargv[2] = NULL; (void) option(envargc, envargv); } argcnt = option(argc, argv); argc -= argcnt; argv += argcnt; (void)time(&now); setpassent(1); if (!*argv) { /* * Assign explicit "small" format if no names given and -l * not selected. Force the -s BEFORE we get names so proper * screening will be done. */ if (!lflag) sflag = 1; /* if -l not explicit, force -s */ loginlist(); if (entries == 0) (void)printf("No one logged on.\n"); } else { userlist(argc, argv); /* * Assign explicit "large" format if names given and -s not * explicitly stated. Force the -l AFTER we get names so any * remote finger attempts specified won't be mishandled. */ if (!sflag) lflag = 1; /* if -s not explicit, force -l */ } if (entries) { if (lflag) lflag_print(); else sflag_print(); } return (0); } static void loginlist(void) { PERSON *pn; DBT data, key; struct passwd *pw; struct utmpx *user; int r, sflag1; if (kflag) errx(1, "can't list logins without reading utmp"); setutxent(); while ((user = getutxent()) != NULL) { if (user->ut_type != USER_PROCESS) continue; if ((pn = find_person(user->ut_user)) == NULL) { if ((pw = getpwnam(user->ut_user)) == NULL) continue; if (hide(pw)) continue; pn = enter_person(pw); } enter_where(user, pn); } endutxent(); if (db && lflag) for (sflag1 = R_FIRST;; sflag1 = R_NEXT) { PERSON *tmp; r = (*db->seq)(db, &key, &data, sflag1); if (r == -1) err(1, "db seq"); if (r == 1) break; memmove(&tmp, data.data, sizeof tmp); enter_lastlog(tmp); } } static void userlist(int argc, char **argv) { PERSON *pn; DBT data, key; struct utmpx *user; struct passwd *pw; int r, sflag1, *used, *ip; char **ap, **nargv, **np, **p; FILE *conf_fp; char conf_alias[LINE_MAX]; char *conf_realname; int conf_length; if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || (used = calloc(argc, sizeof(int))) == NULL) err(1, NULL); /* Pull out all network requests. */ for (ap = p = argv, np = nargv; *p; ++p) if (strchr(*p, '@')) *np++ = *p; else *ap++ = *p; *np++ = NULL; *ap++ = NULL; if (!*argv) goto net; /* * Mark any arguments beginning with '/' as invalid so that we * don't accidentally confuse them with expansions from finger.conf */ for (p = argv, ip = used; *p; ++p, ++ip) if (**p == '/') { *ip = 1; warnx("%s: no such user", *p); } /* * Traverse the finger alias configuration file of the form * alias:(user|alias), ignoring comment lines beginning '#'. */ if ((conf_fp = fopen(_PATH_FINGERCONF, "r")) != NULL) { while(fgets(conf_alias, sizeof(conf_alias), conf_fp) != NULL) { conf_length = strlen(conf_alias); if (*conf_alias == '#' || conf_alias[--conf_length] != '\n') continue; conf_alias[conf_length] = '\0'; /* Remove trailing LF */ if ((conf_realname = strchr(conf_alias, ':')) == NULL) continue; *conf_realname = '\0'; /* Replace : with NUL */ for (p = argv; *p; ++p) { if (strcmp(*p, conf_alias) == 0) { if ((*p = strdup(conf_realname+1)) == NULL) { err(1, NULL); } } } } (void)fclose(conf_fp); } /* * Traverse the list of possible login names and check the login name * and real name against the name specified by the user. If the name * begins with a '/', try to read the file of that name instead of * gathering the traditional finger information. */ if (mflag) for (p = argv, ip = used; *p; ++p, ++ip) { if (**p != '/' || *ip == 1 || !show_text("", *p, "")) { if (((pw = getpwnam(*p)) != NULL) && !hide(pw)) enter_person(pw); else if (!*ip) warnx("%s: no such user", *p); } } else { while ((pw = getpwent()) != NULL) { for (p = argv, ip = used; *p; ++p, ++ip) if (**p == '/' && *ip != 1 && show_text("", *p, "")) *ip = 1; else if (match(pw, *p) && !hide(pw)) { enter_person(pw); *ip = 1; } } for (p = argv, ip = used; *p; ++p, ++ip) if (!*ip) warnx("%s: no such user", *p); } /* Handle network requests. */ net: for (p = nargv; *p;) { netfinger(*p++); if (*p || entries) printf("\n"); } free(nargv); free(used); if (entries == 0) return; if (kflag) return; /* * Scan thru the list of users currently logged in, saving * appropriate data whenever a match occurs. */ setutxent(); while ((user = getutxent()) != NULL) { if (user->ut_type != USER_PROCESS) continue; if ((pn = find_person(user->ut_user)) == NULL) continue; enter_where(user, pn); } endutxent(); if (db) for (sflag1 = R_FIRST;; sflag1 = R_NEXT) { PERSON *tmp; r = (*db->seq)(db, &key, &data, sflag1); if (r == -1) err(1, "db seq"); if (r == 1) break; memmove(&tmp, data.data, sizeof tmp); enter_lastlog(tmp); } } diff --git a/usr.bin/fold/fold.c b/usr.bin/fold/fold.c index 06473b40e787..e2995ee049cd 100644 --- a/usr.bin/fold/fold.c +++ b/usr.bin/fold/fold.c @@ -1,237 +1,237 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kevin Ruddy. * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1990, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)fold.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #define DEFLINEWIDTH 80 void fold(int); static int newpos(int, wint_t); -static void usage(void); +static void usage(void) __dead2; static int bflag; /* Count bytes, not columns */ static int sflag; /* Split on word boundaries */ int main(int argc, char **argv) { int ch, previous_ch; int rval, width; (void) setlocale(LC_CTYPE, ""); width = -1; previous_ch = 0; while ((ch = getopt(argc, argv, "0123456789bsw:")) != -1) { switch (ch) { case 'b': bflag = 1; break; case 's': sflag = 1; break; case 'w': if ((width = atoi(optarg)) <= 0) { errx(1, "illegal width value"); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* Accept a width as eg. -30. Note that a width * specified using the -w option is always used prior * to this undocumented option. */ switch (previous_ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* The width is a number with multiple digits: * add the last one. */ width = width * 10 + (ch - '0'); break; default: /* Set the width, unless it was previously * set. For instance, the following options * would all give a width of 5 and not 10: * -10 -w5 * -5b10 * -5 -10b */ if (width == -1) width = ch - '0'; break; } break; default: usage(); } previous_ch = ch; } argv += optind; argc -= optind; if (width == -1) width = DEFLINEWIDTH; rval = 0; if (!*argv) fold(width); else for (; *argv; ++argv) if (!freopen(*argv, "r", stdin)) { warn("%s", *argv); rval = 1; } else fold(width); exit(rval); } static void usage(void) { (void)fprintf(stderr, "usage: fold [-bs] [-w width] [file ...]\n"); exit(1); } /* * Fold the contents of standard input to fit within WIDTH columns (or bytes) * and write to standard output. * * If sflag is set, split the line at the last space character on the line. * This flag necessitates storing the line in a buffer until the current * column > width, or a newline or EOF is read. * * The buffer can grow larger than WIDTH due to backspaces and carriage * returns embedded in the input stream. */ void fold(int width) { static wchar_t *buf; static int buf_max; int col, i, indx, space; wint_t ch; col = indx = 0; while ((ch = getwchar()) != WEOF) { if (ch == '\n') { wprintf(L"%.*ls\n", indx, buf); col = indx = 0; continue; } if ((col = newpos(col, ch)) > width) { if (sflag) { i = indx; while (--i >= 0 && !iswblank(buf[i])) ; space = i; } if (sflag && space != -1) { space++; wprintf(L"%.*ls\n", space, buf); wmemmove(buf, buf + space, indx - space); indx -= space; col = 0; for (i = 0; i < indx; i++) col = newpos(col, buf[i]); } else { wprintf(L"%.*ls\n", indx, buf); col = indx = 0; } col = newpos(col, ch); } if (indx + 1 > buf_max) { buf_max += LINE_MAX; buf = realloc(buf, sizeof(*buf) * buf_max); if (buf == NULL) err(1, "realloc()"); } buf[indx++] = ch; } if (indx != 0) wprintf(L"%.*ls", indx, buf); } /* * Update the current column position for a character. */ static int newpos(int col, wint_t ch) { char buf[MB_LEN_MAX]; size_t len; int w; if (bflag) { len = wcrtomb(buf, ch, NULL); col += len; } else switch (ch) { case '\b': if (col > 0) --col; break; case '\r': col = 0; break; case '\t': col = (col + 8) & ~7; break; default: if ((w = wcwidth(ch)) > 0) col += w; break; } return (col); } diff --git a/usr.bin/fortune/strfile/strfile.c b/usr.bin/fortune/strfile/strfile.c index f6cda6cd3900..abc35946e77e 100644 --- a/usr.bin/fortune/strfile/strfile.c +++ b/usr.bin/fortune/strfile/strfile.c @@ -1,464 +1,464 @@ /*- * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ken Arnold. * * 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) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static const char sccsid[] = "@(#)strfile.c 8.1 (Berkeley) 5/31/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "strfile.h" /* * This program takes a file composed of strings separated by * lines starting with two consecutive delimiting character (default * character is '%') and creates another file which consists of a table * describing the file (structure from "strfile.h"), a table of seek * pointers to the start of the strings, and the strings, each terminated * by a null byte. Usage: * * % strfile [-iorsx] [ -cC ] sourcefile [ datafile ] * * C - Allow comments marked by a double delimiter at line's beginning * c - Change delimiting character from '%' to 'C' * s - Silent. Give no summary of data processed at the end of * the run. * o - order the strings in alphabetic order * i - if ordering, ignore case * r - randomize the order of the strings * x - set rotated bit * * Ken Arnold Sept. 7, 1978 -- * * Added ordering options. */ #define STORING_PTRS (Oflag || Rflag) #define CHUNKSIZE 512 #define ALLOC(ptr, sz) do { \ if (ptr == NULL) \ ptr = malloc(CHUNKSIZE * sizeof(*ptr)); \ else if (((sz) + 1) % CHUNKSIZE == 0) \ ptr = realloc(ptr, ((sz) + CHUNKSIZE) * sizeof(*ptr)); \ if (ptr == NULL) { \ fprintf(stderr, "out of space\n"); \ exit(1); \ } \ } while (0) typedef struct { int first; off_t pos; } STR; static char *Infile = NULL, /* input file name */ Outfile[MAXPATHLEN] = "", /* output file name */ Delimch = '%'; /* delimiting character */ static int Cflag = false; /* embedded comments */ static int Sflag = false; /* silent run flag */ static int Oflag = false; /* ordering flag */ static int Iflag = false; /* ignore case flag */ static int Rflag = false; /* randomize order flag */ static int Xflag = false; /* set rotated bit */ static uint32_t Num_pts = 0; /* number of pointers/strings */ static off_t *Seekpts; static FILE *Sort_1, *Sort_2; /* pointers for sorting */ static STRFILE Tbl; /* statistics table */ static STR *Firstch; /* first chars of each string */ static void add_offset(FILE *, off_t); static int cmp_str(const void *, const void *); static int stable_collate_range_cmp(int, int); static void do_order(void); static void getargs(int, char **); static void randomize(void); -static void usage(void); +static void usage(void) __dead2; /* * main: * Drive the sucker. There are two main modes -- either we store * the seek pointers, if the table is to be sorted or randomized, * or we write the pointer directly to the file, if we are to stay * in file order. If the former, we allocate and re-allocate in * CHUNKSIZE blocks; if the latter, we just write each pointer, * and then seek back to the beginning to write in the table. */ int main(int ac, char *av[]) { char *sp, *nsp, dc; FILE *inf, *outf; off_t last_off, pos, *p; size_t length; int first; uint32_t cnt; STR *fp; static char string[257]; setlocale(LC_ALL, ""); getargs(ac, av); /* evalute arguments */ dc = Delimch; if ((inf = fopen(Infile, "r")) == NULL) { perror(Infile); exit(1); } if ((outf = fopen(Outfile, "w")) == NULL) { perror(Outfile); exit(1); } if (!STORING_PTRS) fseek(outf, (long)sizeof(Tbl), SEEK_SET); /* * Write the strings onto the file */ Tbl.str_longlen = 0; Tbl.str_shortlen = 0xffffffff; Tbl.str_delim = dc; Tbl.str_version = VERSION; first = Oflag; add_offset(outf, ftello(inf)); last_off = 0; do { sp = fgets(string, 256, inf); if (sp == NULL || (sp[0] == dc && sp[1] == '\n')) { pos = ftello(inf); length = (size_t)(pos - last_off) - (sp != NULL ? strlen(sp) : 0); last_off = pos; if (length == 0) continue; add_offset(outf, pos); if ((size_t)Tbl.str_longlen < length) Tbl.str_longlen = length; if ((size_t)Tbl.str_shortlen > length) Tbl.str_shortlen = length; first = Oflag; } else if (first) { for (nsp = sp; !isalnum((unsigned char)*nsp); nsp++) continue; ALLOC(Firstch, Num_pts); fp = &Firstch[Num_pts - 1]; if (Iflag && isupper((unsigned char)*nsp)) fp->first = tolower((unsigned char)*nsp); else fp->first = *nsp; fp->pos = Seekpts[Num_pts - 1]; first = false; } } while (sp != NULL); /* * write the tables in */ fclose(inf); Tbl.str_numstr = Num_pts - 1; if (Cflag) Tbl.str_flags |= STR_COMMENTS; if (Oflag) do_order(); else if (Rflag) randomize(); if (Xflag) Tbl.str_flags |= STR_ROTATED; if (!Sflag) { printf("\"%s\" created\n", Outfile); if (Num_pts == 2) puts("There was 1 string"); else printf("There were %u strings\n", Num_pts - 1); printf("Longest string: %u byte%s\n", Tbl.str_longlen, Tbl.str_longlen == 1 ? "" : "s"); printf("Shortest string: %u byte%s\n", Tbl.str_shortlen, Tbl.str_shortlen == 1 ? "" : "s"); } rewind(outf); Tbl.str_version = htobe32(Tbl.str_version); Tbl.str_numstr = htobe32(Tbl.str_numstr); Tbl.str_longlen = htobe32(Tbl.str_longlen); Tbl.str_shortlen = htobe32(Tbl.str_shortlen); Tbl.str_flags = htobe32(Tbl.str_flags); fwrite((char *)&Tbl, sizeof(Tbl), 1, outf); if (STORING_PTRS) { for (p = Seekpts, cnt = Num_pts; cnt--; ++p) *p = htobe64(*p); fwrite(Seekpts, sizeof(*Seekpts), (size_t)Num_pts, outf); } fclose(outf); exit(0); } /* * This routine evaluates arguments from the command line */ void getargs(int argc, char **argv) { int ch; while ((ch = getopt(argc, argv, "Cc:iorsx")) != -1) switch(ch) { case 'C': /* embedded comments */ Cflag++; break; case 'c': /* new delimiting char */ Delimch = *optarg; if (!isascii(Delimch)) { printf("bad delimiting character: '\\%o\n'", (unsigned char)Delimch); } break; case 'i': /* ignore case in ordering */ Iflag++; break; case 'o': /* order strings */ Oflag++; break; case 'r': /* randomize pointers */ Rflag++; break; case 's': /* silent */ Sflag++; break; case 'x': /* set the rotated bit */ Xflag++; break; case '?': default: usage(); } argv += optind; if (*argv) { Infile = *argv; if (*++argv) { if (strlcpy(Outfile, *argv, sizeof(Outfile)) >= sizeof(Outfile)) { fprintf(stderr, "output_file path is too long\n"); exit(1); } } } if (!Infile) { puts("No input file name"); usage(); } if (*Outfile == '\0') { if ((size_t)snprintf(Outfile, sizeof(Outfile), "%s.dat", Infile) >= sizeof(Outfile)) { fprintf(stderr, "generated output_file path is too long\n"); exit(1); } } } void usage(void) { fprintf(stderr, "strfile [-Ciorsx] [-c char] source_file [output_file]\n"); exit(1); } /* * add_offset: * Add an offset to the list, or write it out, as appropriate. */ void add_offset(FILE *fp, off_t off) { off_t beoff; if (!STORING_PTRS) { beoff = htobe64(off); fwrite(&beoff, 1, sizeof(beoff), fp); } else { ALLOC(Seekpts, Num_pts + 1); Seekpts[Num_pts] = off; } Num_pts++; } /* * do_order: * Order the strings alphabetically (possibly ignoring case). */ void do_order(void) { uint32_t i; off_t *lp; STR *fp; Sort_1 = fopen(Infile, "r"); Sort_2 = fopen(Infile, "r"); qsort(Firstch, (size_t)Tbl.str_numstr, sizeof(*Firstch), cmp_str); i = Tbl.str_numstr; lp = Seekpts; fp = Firstch; while (i--) *lp++ = fp++->pos; fclose(Sort_1); fclose(Sort_2); Tbl.str_flags |= STR_ORDERED; } static int stable_collate_range_cmp(int c1, int c2) { static char s1[2], s2[2]; int ret; s1[0] = c1; s2[0] = c2; if ((ret = strcoll(s1, s2)) != 0) return (ret); return (c1 - c2); } /* * cmp_str: * Compare two strings in the file */ int cmp_str(const void *s1, const void *s2) { const STR *p1, *p2; int c1, c2, n1, n2, r; #define SET_N(nf,ch) (nf = (ch == '\n')) #define IS_END(ch,nf) (ch == EOF || (ch == (unsigned char)Delimch && nf)) p1 = (const STR *)s1; p2 = (const STR *)s2; c1 = (unsigned char)p1->first; c2 = (unsigned char)p2->first; if ((r = stable_collate_range_cmp(c1, c2)) != 0) return (r); fseeko(Sort_1, p1->pos, SEEK_SET); fseeko(Sort_2, p2->pos, SEEK_SET); n1 = false; n2 = false; while (!isalnum(c1 = getc(Sort_1)) && c1 != '\0' && c1 != EOF) SET_N(n1, c1); while (!isalnum(c2 = getc(Sort_2)) && c2 != '\0' && c2 != EOF) SET_N(n2, c2); while (!IS_END(c1, n1) && !IS_END(c2, n2)) { if (Iflag) { if (isupper(c1)) c1 = tolower(c1); if (isupper(c2)) c2 = tolower(c2); } if ((r = stable_collate_range_cmp(c1, c2)) != 0) return (r); SET_N(n1, c1); SET_N(n2, c2); c1 = getc(Sort_1); c2 = getc(Sort_2); } if (IS_END(c1, n1)) c1 = 0; if (IS_END(c2, n2)) c2 = 0; return (stable_collate_range_cmp(c1, c2)); } /* * randomize: * Randomize the order of the string table. We must be careful * not to randomize across delimiter boundaries. All * randomization is done within each block. */ void randomize(void) { uint32_t cnt, i; off_t tmp; off_t *sp; Tbl.str_flags |= STR_RANDOM; cnt = Tbl.str_numstr; /* * move things around randomly */ for (sp = Seekpts; cnt > 0; cnt--, sp++) { i = arc4random_uniform(cnt); tmp = sp[0]; sp[0] = sp[i]; sp[i] = tmp; } } diff --git a/usr.bin/from/from.c b/usr.bin/from/from.c index 0b2ad7091e04..5569ec1c2757 100644 --- a/usr.bin/from/from.c +++ b/usr.bin/from/from.c @@ -1,169 +1,169 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)from.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include static int match(const char *, const char *); -static void usage(void); +static void usage(void) __dead2; int main(int argc, char **argv) { FILE *mbox; struct passwd *pwd; int ch, count, newline; const char *file; char *sender, *p; #if MAXPATHLEN > BUFSIZ char buf[MAXPATHLEN]; #else char buf[BUFSIZ]; #endif file = sender = NULL; count = -1; while ((ch = getopt(argc, argv, "cf:s:")) != -1) switch (ch) { case 'c': count = 0; break; case 'f': file = optarg; break; case 's': sender = optarg; for (p = sender; *p; ++p) *p = tolower(*p); break; case '?': default: usage(); } argc -= optind; argv += optind; if (file == NULL) { if (argc) { (void)snprintf(buf, sizeof(buf), "%s/%s", _PATH_MAILDIR, *argv); file = buf; } else { if (!(file = getenv("MAIL"))) { if (!(pwd = getpwuid(getuid()))) errx(1, "no password file entry for you"); file = pwd->pw_name; (void)snprintf(buf, sizeof(buf), "%s/%s", _PATH_MAILDIR, file); file = buf; } } } /* read from stdin */ if (strcmp(file, "-") == 0) { mbox = stdin; } else if ((mbox = fopen(file, "r")) == NULL) { errx(1, "can't read %s", file); } for (newline = 1; fgets(buf, sizeof(buf), mbox);) { if (*buf == '\n') { newline = 1; continue; } if (newline && !strncmp(buf, "From ", 5) && (!sender || match(buf + 5, sender))) { if (count != -1) count++; else printf("%s", buf); } newline = 0; } if (count != -1) printf("There %s %d message%s in your incoming mailbox.\n", count == 1 ? "is" : "are", count, count == 1 ? "" : "s"); fclose(mbox); exit(0); } static void usage(void) { fprintf(stderr, "usage: from [-c] [-f file] [-s sender] [user]\n"); exit(1); } static int match(const char *line, const char *sender) { char ch, pch, first; const char *p, *t; for (first = *sender++;;) { if (isspace(ch = *line)) return(0); ++line; ch = tolower(ch); if (ch != first) continue; for (p = sender, t = line;;) { if (!(pch = *p++)) return(1); ch = tolower(*t); t++; if (ch != pch) break; } } /* NOTREACHED */ } diff --git a/usr.bin/grdc/grdc.c b/usr.bin/grdc/grdc.c index 04cc00b37d6f..72329c07f70e 100644 --- a/usr.bin/grdc/grdc.c +++ b/usr.bin/grdc/grdc.c @@ -1,273 +1,273 @@ /* * Grand digital clock for curses compatible terminals * Usage: grdc [-st] [n] -- run for n seconds (default infinity) * Flags: -s: scroll * -t: output time in 12-hour format * * * modified 10-18-89 for curses (jrl) * 10-18-89 added signal handling * * modified 03-25-03 for 12 hour option * - Samy Al Bahra * * $FreeBSD$ */ #include #include #include #include #include #include #define YBASE 10 #define XBASE 10 #define XLENGTH 58 #define YDEPTH 7 static struct timespec now; static struct tm *tm; static short disp[11] = { 075557, 011111, 071747, 071717, 055711, 074717, 074757, 071111, 075757, 075717, 002020 }; static long old[6], next[6], new[6], mask; static volatile sig_atomic_t sigtermed; static int hascolor = 0; static void set(int, int); static void standt(int); static void movto(int, int); static void sighndl(int); -static void usage(void); +static void usage(void) __dead2; static void sighndl(int signo) { sigtermed = signo; } int main(int argc, char *argv[]) { struct timespec delay; time_t prev_sec; long t, a; int i, j, s, k; int n; int ch; int scrol; int t12; t12 = scrol = 0; while ((ch = getopt(argc, argv, "ts")) != -1) switch (ch) { case 's': scrol = 1; break; case 't': t12 = 1; break; case '?': default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; if (argc > 1) { usage(); /* NOTREACHED */ } if (argc > 0) { n = atoi(*argv) + 1; if (n < 1) { warnx("number of seconds is out of range"); usage(); /* NOTREACHED */ } } else n = 0; initscr(); signal(SIGINT,sighndl); signal(SIGTERM,sighndl); signal(SIGHUP,sighndl); cbreak(); noecho(); curs_set(0); hascolor = has_colors(); if(hascolor) { start_color(); init_pair(1, COLOR_BLACK, COLOR_RED); init_pair(2, COLOR_RED, COLOR_BLACK); init_pair(3, COLOR_WHITE, COLOR_BLACK); attrset(COLOR_PAIR(2)); } clear(); refresh(); if(hascolor) { attrset(COLOR_PAIR(3)); mvaddch(YBASE - 2, XBASE - 3, ACS_ULCORNER); hline(ACS_HLINE, XLENGTH); mvaddch(YBASE - 2, XBASE - 2 + XLENGTH, ACS_URCORNER); mvaddch(YBASE + YDEPTH - 1, XBASE - 3, ACS_LLCORNER); hline(ACS_HLINE, XLENGTH); mvaddch(YBASE + YDEPTH - 1, XBASE - 2 + XLENGTH, ACS_LRCORNER); move(YBASE - 1, XBASE - 3); vline(ACS_VLINE, YDEPTH); move(YBASE - 1, XBASE - 2 + XLENGTH); vline(ACS_VLINE, YDEPTH); attrset(COLOR_PAIR(2)); } clock_gettime(CLOCK_REALTIME_FAST, &now); prev_sec = now.tv_sec; do { mask = 0; tm = localtime(&now.tv_sec); set(tm->tm_sec%10, 0); set(tm->tm_sec/10, 4); set(tm->tm_min%10, 10); set(tm->tm_min/10, 14); if (t12) { if (tm->tm_hour < 12) { if (tm->tm_hour == 0) tm->tm_hour = 12; mvaddstr(YBASE + 5, XBASE + 52, "AM"); } else { if (tm->tm_hour > 12) tm->tm_hour -= 12; mvaddstr(YBASE + 5, XBASE + 52, "PM"); } } set(tm->tm_hour%10, 20); set(tm->tm_hour/10, 24); set(10, 7); set(10, 17); for(k=0; k<6; k++) { if(scrol) { for(i=0; i<5; i++) new[i] = (new[i]&~mask) | (new[i+1]&mask); new[5] = (new[5]&~mask) | (next[k]&mask); } else new[k] = (new[k]&~mask) | (next[k]&mask); next[k] = 0; for(s=1; s>=0; s--) { standt(s); for(i=0; i<6; i++) { if((a = (new[i]^old[i])&(s ? new : old)[i]) != 0) { for(j=0,t=1<<26; t; t>>=1,j++) { if(a&t) { if(!(a&(t<<1))) { movto(YBASE + i, XBASE + 2*j); } addstr(" "); } } } if(!s) { old[i] = new[i]; } } if(!s) { refresh(); } } } movto(6, 0); refresh(); clock_gettime(CLOCK_REALTIME_FAST, &now); if (now.tv_sec == prev_sec) { if (delay.tv_nsec > 0) { delay.tv_sec = 0; delay.tv_nsec = 1000000000 - now.tv_nsec; } else { delay.tv_sec = 1; delay.tv_nsec = 0; } nanosleep(&delay, NULL); clock_gettime(CLOCK_REALTIME_FAST, &now); } n -= now.tv_sec - prev_sec; prev_sec = now.tv_sec; if (sigtermed) { standend(); clear(); refresh(); endwin(); errx(1, "terminated by signal %d", (int)sigtermed); } } while (n); standend(); clear(); refresh(); endwin(); return(0); } static void set(int t, int n) { int i, m; m = 7<>(4-i)*3)&07)< __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * head - give the first few lines of a stream or of each of a set of files * * Bill Joy UCB August 24, 1977 */ static void head(FILE *, intmax_t); static void head_bytes(FILE *, off_t); static void obsolete(char *[]); -static void usage(void); +static void usage(void) __dead2; static const struct option long_opts[] = { {"bytes", required_argument, NULL, 'c'}, {"lines", required_argument, NULL, 'n'}, {"quiet", no_argument, NULL, 'q'}, {"silent", no_argument, NULL, 'q'}, {"verbose", no_argument, NULL, 'v'}, {NULL, no_argument, NULL, 0} }; int main(int argc, char *argv[]) { FILE *fp; off_t bytecnt; intmax_t linecnt; int ch, first, eval; fileargs_t *fa; cap_rights_t rights; int qflag = 0; int vflag = 0; linecnt = -1; eval = 0; bytecnt = -1; obsolete(argv); while ((ch = getopt_long(argc, argv, "+n:c:qv", long_opts, NULL)) != -1) { switch(ch) { case 'c': if (expand_number(optarg, &bytecnt) || bytecnt <= 0) errx(1, "illegal byte count -- %s", optarg); break; case 'n': if (expand_number(optarg, &linecnt) || linecnt <= 0) errx(1, "illegal line count -- %s", optarg); break; case 'q': qflag = 1; vflag = 0; break; case 'v': qflag = 0; vflag = 1; break; case '?': default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; fa = fileargs_init(argc, argv, O_RDONLY, 0, cap_rights_init(&rights, CAP_READ, CAP_FSTAT, CAP_FCNTL), FA_OPEN); if (fa == NULL) err(1, "unable to init casper"); caph_cache_catpages(); if (caph_limit_stdio() < 0 || caph_enter_casper() < 0) err(1, "unable to enter capability mode"); if (linecnt != -1 && bytecnt != -1) errx(1, "can't combine line and byte counts"); if (linecnt == -1) linecnt = 10; if (*argv != NULL) { for (first = 1; *argv != NULL; ++argv) { if ((fp = fileargs_fopen(fa, *argv, "r")) == NULL) { warn("%s", *argv); eval = 1; continue; } if (vflag || (qflag == 0 && argc > 1)) { (void)printf("%s==> %s <==\n", first ? "" : "\n", *argv); first = 0; } if (bytecnt == -1) head(fp, linecnt); else head_bytes(fp, bytecnt); (void)fclose(fp); } } else if (bytecnt == -1) head(stdin, linecnt); else head_bytes(stdin, bytecnt); fileargs_free(fa); exit(eval); } static void head(FILE *fp, intmax_t cnt) { char *cp; size_t error, readlen; while (cnt != 0 && (cp = fgetln(fp, &readlen)) != NULL) { error = fwrite(cp, sizeof(char), readlen, stdout); if (error != readlen) err(1, "stdout"); cnt--; } } static void head_bytes(FILE *fp, off_t cnt) { char buf[4096]; size_t readlen; while (cnt) { if ((uintmax_t)cnt < sizeof(buf)) readlen = cnt; else readlen = sizeof(buf); readlen = fread(buf, sizeof(char), readlen, fp); if (readlen == 0) break; if (fwrite(buf, sizeof(char), readlen, stdout) != readlen) err(1, "stdout"); cnt -= readlen; } } static void obsolete(char *argv[]) { char *ap; while ((ap = *++argv)) { /* Return if "--" or not "-[0-9]*". */ if (ap[0] != '-' || ap[1] == '-' || !isdigit(ap[1])) return; if ((ap = malloc(strlen(*argv) + 2)) == NULL) err(1, NULL); ap[0] = '-'; ap[1] = 'n'; (void)strcpy(ap + 2, *argv + 1); *argv = ap; } } static void usage(void) { (void)fprintf(stderr, "usage: head [-n lines | -c bytes] [file ...]\n"); exit(1); } diff --git a/usr.bin/join/join.c b/usr.bin/join/join.c index 40107802a1f8..0ad4b467793e 100644 --- a/usr.bin/join/join.c +++ b/usr.bin/join/join.c @@ -1,673 +1,673 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Steve Hayman of the Computer Science Department, Indiana University, * Michiro Hikida and David Goodenough. * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)join.c 8.6 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include /* * There's a structure per input file which encapsulates the state of the * file. We repeatedly read lines from each file until we've read in all * the consecutive lines from the file with a common join field. Then we * compare the set of lines with an equivalent set from the other file. */ typedef struct { char *line; /* line */ u_long linealloc; /* line allocated count */ char **fields; /* line field(s) */ u_long fieldcnt; /* line field(s) count */ u_long fieldalloc; /* line field(s) allocated count */ } LINE; typedef struct { FILE *fp; /* file descriptor */ u_long joinf; /* join field (-1, -2, -j) */ int unpair; /* output unpairable lines (-a) */ u_long number; /* 1 for file 1, 2 for file 2 */ LINE *set; /* set of lines with same field */ int pushbool; /* if pushback is set */ u_long pushback; /* line on the stack */ u_long setcnt; /* set count */ u_long setalloc; /* set allocated count */ } INPUT; static INPUT input1 = { NULL, 0, 0, 1, NULL, 0, 0, 0, 0 }, input2 = { NULL, 0, 0, 2, NULL, 0, 0, 0, 0 }; typedef struct { u_long filenum; /* file number */ u_long fieldno; /* field number */ } OLIST; static OLIST *olist; /* output field list */ static u_long olistcnt; /* output field list count */ static u_long olistalloc; /* output field allocated count */ static int joinout = 1; /* show lines with matched join fields (-v) */ static int needsep; /* need separator character */ static int spans = 1; /* span multiple delimiters (-t) */ static char *empty; /* empty field replacement string (-e) */ static wchar_t default_tabchar[] = L" \t"; static wchar_t *tabchar = default_tabchar; /* delimiter characters (-t) */ static int cmp(LINE *, u_long, LINE *, u_long); static void fieldarg(char *); static void joinlines(INPUT *, INPUT *); static int mbscoll(const char *, const char *); static char *mbssep(char **, const wchar_t *); static void obsolete(char **); static void outfield(LINE *, u_long, int); static void outoneline(INPUT *, LINE *); static void outtwoline(INPUT *, LINE *, INPUT *, LINE *); static void slurp(INPUT *); static wchar_t *towcs(const char *); -static void usage(void); +static void usage(void) __dead2; int main(int argc, char *argv[]) { INPUT *F1, *F2; int aflag, ch, cval, vflag; char *end; setlocale(LC_ALL, ""); F1 = &input1; F2 = &input2; aflag = vflag = 0; obsolete(argv); while ((ch = getopt(argc, argv, "\01a:e:j:1:2:o:t:v:")) != -1) { switch (ch) { case '\01': /* See comment in obsolete(). */ aflag = 1; F1->unpair = F2->unpair = 1; break; case '1': if ((F1->joinf = strtol(optarg, &end, 10)) < 1) errx(1, "-1 option field number less than 1"); if (*end) errx(1, "illegal field number -- %s", optarg); --F1->joinf; break; case '2': if ((F2->joinf = strtol(optarg, &end, 10)) < 1) errx(1, "-2 option field number less than 1"); if (*end) errx(1, "illegal field number -- %s", optarg); --F2->joinf; break; case 'a': aflag = 1; switch(strtol(optarg, &end, 10)) { case 1: F1->unpair = 1; break; case 2: F2->unpair = 1; break; default: errx(1, "-a option file number not 1 or 2"); break; } if (*end) errx(1, "illegal file number -- %s", optarg); break; case 'e': empty = optarg; break; case 'j': if ((F1->joinf = F2->joinf = strtol(optarg, &end, 10)) < 1) errx(1, "-j option field number less than 1"); if (*end) errx(1, "illegal field number -- %s", optarg); --F1->joinf; --F2->joinf; break; case 'o': fieldarg(optarg); break; case 't': spans = 0; if (mbrtowc(&tabchar[0], optarg, MB_LEN_MAX, NULL) != strlen(optarg)) errx(1, "illegal tab character specification"); tabchar[1] = L'\0'; break; case 'v': vflag = 1; joinout = 0; switch (strtol(optarg, &end, 10)) { case 1: F1->unpair = 1; break; case 2: F2->unpair = 1; break; default: errx(1, "-v option file number not 1 or 2"); break; } if (*end) errx(1, "illegal file number -- %s", optarg); break; case '?': default: usage(); } } argc -= optind; argv += optind; if (aflag && vflag) errx(1, "the -a and -v options are mutually exclusive"); if (argc != 2) usage(); /* Open the files; "-" means stdin. */ if (!strcmp(*argv, "-")) F1->fp = stdin; else if ((F1->fp = fopen(*argv, "r")) == NULL) err(1, "%s", *argv); ++argv; if (!strcmp(*argv, "-")) F2->fp = stdin; else if ((F2->fp = fopen(*argv, "r")) == NULL) err(1, "%s", *argv); if (F1->fp == stdin && F2->fp == stdin) errx(1, "only one input file may be stdin"); slurp(F1); slurp(F2); while (F1->setcnt && F2->setcnt) { cval = cmp(F1->set, F1->joinf, F2->set, F2->joinf); if (cval == 0) { /* Oh joy, oh rapture, oh beauty divine! */ if (joinout) joinlines(F1, F2); slurp(F1); slurp(F2); } else if (cval < 0) { /* File 1 takes the lead... */ if (F1->unpair) joinlines(F1, NULL); slurp(F1); } else { /* File 2 takes the lead... */ if (F2->unpair) joinlines(F2, NULL); slurp(F2); } } /* * Now that one of the files is used up, optionally output any * remaining lines from the other file. */ if (F1->unpair) while (F1->setcnt) { joinlines(F1, NULL); slurp(F1); } if (F2->unpair) while (F2->setcnt) { joinlines(F2, NULL); slurp(F2); } exit(0); } static void slurp(INPUT *F) { LINE *lp, *lastlp, tmp; size_t len; int cnt; char *bp, *fieldp; /* * Read all of the lines from an input file that have the same * join field. */ F->setcnt = 0; for (lastlp = NULL;; ++F->setcnt) { /* * If we're out of space to hold line structures, allocate * more. Initialize the structure so that we know that this * is new space. */ if (F->setcnt == F->setalloc) { cnt = F->setalloc; F->setalloc += 50; if ((F->set = realloc(F->set, F->setalloc * sizeof(LINE))) == NULL) err(1, NULL); memset(F->set + cnt, 0, 50 * sizeof(LINE)); /* re-set lastlp in case it moved */ if (lastlp != NULL) lastlp = &F->set[F->setcnt - 1]; } /* * Get any pushed back line, else get the next line. Allocate * space as necessary. If taking the line from the stack swap * the two structures so that we don't lose space allocated to * either structure. This could be avoided by doing another * level of indirection, but it's probably okay as is. */ lp = &F->set[F->setcnt]; if (F->setcnt) lastlp = &F->set[F->setcnt - 1]; if (F->pushbool) { tmp = F->set[F->setcnt]; F->set[F->setcnt] = F->set[F->pushback]; F->set[F->pushback] = tmp; F->pushbool = 0; continue; } if ((bp = fgetln(F->fp, &len)) == NULL) return; if (lp->linealloc <= len + 1) { lp->linealloc += MAX(100, len + 1 - lp->linealloc); if ((lp->line = realloc(lp->line, lp->linealloc)) == NULL) err(1, NULL); } memmove(lp->line, bp, len); /* Replace trailing newline, if it exists. */ if (bp[len - 1] == '\n') lp->line[len - 1] = '\0'; else lp->line[len] = '\0'; bp = lp->line; /* Split the line into fields, allocate space as necessary. */ lp->fieldcnt = 0; while ((fieldp = mbssep(&bp, tabchar)) != NULL) { if (spans && *fieldp == '\0') continue; if (lp->fieldcnt == lp->fieldalloc) { lp->fieldalloc += 50; if ((lp->fields = realloc(lp->fields, lp->fieldalloc * sizeof(char *))) == NULL) err(1, NULL); } lp->fields[lp->fieldcnt++] = fieldp; } /* See if the join field value has changed. */ if (lastlp != NULL && cmp(lp, F->joinf, lastlp, F->joinf)) { F->pushbool = 1; F->pushback = F->setcnt; break; } } } static char * mbssep(char **stringp, const wchar_t *delim) { char *s, *tok; const wchar_t *spanp; wchar_t c, sc; size_t n; if ((s = *stringp) == NULL) return (NULL); for (tok = s;;) { n = mbrtowc(&c, s, MB_LEN_MAX, NULL); if (n == (size_t)-1 || n == (size_t)-2) errc(1, EILSEQ, NULL); /* XXX */ s += n; spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-n] = '\0'; *stringp = s; return (tok); } } while (sc != 0); } } static int cmp(LINE *lp1, u_long fieldno1, LINE *lp2, u_long fieldno2) { if (lp1->fieldcnt <= fieldno1) return (lp2->fieldcnt <= fieldno2 ? 0 : 1); if (lp2->fieldcnt <= fieldno2) return (-1); return (mbscoll(lp1->fields[fieldno1], lp2->fields[fieldno2])); } static int mbscoll(const char *s1, const char *s2) { wchar_t *w1, *w2; int ret; if (MB_CUR_MAX == 1) return (strcoll(s1, s2)); if ((w1 = towcs(s1)) == NULL || (w2 = towcs(s2)) == NULL) err(1, NULL); /* XXX */ ret = wcscoll(w1, w2); free(w1); free(w2); return (ret); } static wchar_t * towcs(const char *s) { wchar_t *wcs; size_t n; if ((n = mbsrtowcs(NULL, &s, 0, NULL)) == (size_t)-1) return (NULL); if ((wcs = malloc((n + 1) * sizeof(*wcs))) == NULL) return (NULL); mbsrtowcs(wcs, &s, n + 1, NULL); return (wcs); } static void joinlines(INPUT *F1, INPUT *F2) { u_long cnt1, cnt2; /* * Output the results of a join comparison. The output may be from * either file 1 or file 2 (in which case the first argument is the * file from which to output) or from both. */ if (F2 == NULL) { for (cnt1 = 0; cnt1 < F1->setcnt; ++cnt1) outoneline(F1, &F1->set[cnt1]); return; } for (cnt1 = 0; cnt1 < F1->setcnt; ++cnt1) for (cnt2 = 0; cnt2 < F2->setcnt; ++cnt2) outtwoline(F1, &F1->set[cnt1], F2, &F2->set[cnt2]); } static void outoneline(INPUT *F, LINE *lp) { u_long cnt; /* * Output a single line from one of the files, according to the * join rules. This happens when we are writing unmatched single * lines. Output empty fields in the right places. */ if (olist) for (cnt = 0; cnt < olistcnt; ++cnt) { if (olist[cnt].filenum == (unsigned)F->number) outfield(lp, olist[cnt].fieldno, 0); else if (olist[cnt].filenum == 0) outfield(lp, F->joinf, 0); else outfield(lp, 0, 1); } else { /* * Output the join field, then the remaining fields. */ outfield(lp, F->joinf, 0); for (cnt = 0; cnt < lp->fieldcnt; ++cnt) if (F->joinf != cnt) outfield(lp, cnt, 0); } (void)printf("\n"); if (ferror(stdout)) err(1, "stdout"); needsep = 0; } static void outtwoline(INPUT *F1, LINE *lp1, INPUT *F2, LINE *lp2) { u_long cnt; /* Output a pair of lines according to the join list (if any). */ if (olist) for (cnt = 0; cnt < olistcnt; ++cnt) if (olist[cnt].filenum == 0) { if (lp1->fieldcnt >= F1->joinf) outfield(lp1, F1->joinf, 0); else outfield(lp2, F2->joinf, 0); } else if (olist[cnt].filenum == 1) outfield(lp1, olist[cnt].fieldno, 0); else /* if (olist[cnt].filenum == 2) */ outfield(lp2, olist[cnt].fieldno, 0); else { /* * Output the join field, then the remaining fields from F1 * and F2. */ outfield(lp1, F1->joinf, 0); for (cnt = 0; cnt < lp1->fieldcnt; ++cnt) if (F1->joinf != cnt) outfield(lp1, cnt, 0); for (cnt = 0; cnt < lp2->fieldcnt; ++cnt) if (F2->joinf != cnt) outfield(lp2, cnt, 0); } (void)printf("\n"); if (ferror(stdout)) err(1, "stdout"); needsep = 0; } static void outfield(LINE *lp, u_long fieldno, int out_empty) { if (needsep++) (void)printf("%lc", (wint_t)*tabchar); if (!ferror(stdout)) { if (lp->fieldcnt <= fieldno || out_empty) { if (empty != NULL) (void)printf("%s", empty); } else { if (*lp->fields[fieldno] == '\0') return; (void)printf("%s", lp->fields[fieldno]); } } if (ferror(stdout)) err(1, "stdout"); } /* * Convert an output list argument "2.1, 1.3, 2.4" into an array of output * fields. */ static void fieldarg(char *option) { u_long fieldno, filenum; char *end, *token; while ((token = strsep(&option, ", \t")) != NULL) { if (*token == '\0') continue; if (token[0] == '0') filenum = fieldno = 0; else if ((token[0] == '1' || token[0] == '2') && token[1] == '.') { filenum = token[0] - '0'; fieldno = strtol(token + 2, &end, 10); if (*end) errx(1, "malformed -o option field"); if (fieldno == 0) errx(1, "field numbers are 1 based"); --fieldno; } else errx(1, "malformed -o option field"); if (olistcnt == olistalloc) { olistalloc += 50; if ((olist = realloc(olist, olistalloc * sizeof(OLIST))) == NULL) err(1, NULL); } olist[olistcnt].filenum = filenum; olist[olistcnt].fieldno = fieldno; ++olistcnt; } } static void obsolete(char **argv) { size_t len; char **p, *ap, *t; while ((ap = *++argv) != NULL) { /* Return if "--". */ if (ap[0] == '-' && ap[1] == '-') return; /* skip if not an option */ if (ap[0] != '-') continue; switch (ap[1]) { case 'a': /* * The original join allowed "-a", which meant the * same as -a1 plus -a2. POSIX 1003.2, Draft 11.2 * only specifies this as "-a 1" and "a -2", so we * have to use another option flag, one that is * unlikely to ever be used or accidentally entered * on the command line. (Well, we could reallocate * the argv array, but that hardly seems worthwhile.) */ if (ap[2] == '\0' && (argv[1] == NULL || (strcmp(argv[1], "1") != 0 && strcmp(argv[1], "2") != 0))) { ap[1] = '\01'; warnx("-a option used without an argument; " "reverting to historical behavior"); } break; case 'j': /* * The original join allowed "-j[12] arg" and "-j arg". * Convert the former to "-[12] arg". Don't convert * the latter since getopt(3) can handle it. */ switch(ap[2]) { case '1': if (ap[3] != '\0') goto jbad; ap[1] = '1'; ap[2] = '\0'; break; case '2': if (ap[3] != '\0') goto jbad; ap[1] = '2'; ap[2] = '\0'; break; case '\0': break; default: jbad: errx(1, "illegal option -- %s", ap); usage(); } break; case 'o': /* * The original join allowed "-o arg arg". * Convert to "-o arg -o arg". */ if (ap[2] != '\0') break; for (p = argv + 2; *p; ++p) { if (p[0][0] == '0' || ((p[0][0] != '1' && p[0][0] != '2') || p[0][1] != '.')) break; len = strlen(*p); if (len - 2 != strspn(*p + 2, "0123456789")) break; if ((t = malloc(len + 3)) == NULL) err(1, NULL); t[0] = '-'; t[1] = 'o'; memmove(t + 2, *p, len + 1); *p = t; } argv = p - 1; break; } } } static void usage(void) { (void)fprintf(stderr, "%s %s\n%s\n", "usage: join [-a fileno | -v fileno ] [-e string] [-1 field]", "[-2 field]", " [-o list] [-t char] file1 file2"); exit(1); } diff --git a/usr.bin/ktrace/ktrace.c b/usr.bin/ktrace/ktrace.c index cd53ca03ad44..1b477fca2fc1 100644 --- a/usr.bin/ktrace/ktrace.c +++ b/usr.bin/ktrace/ktrace.c @@ -1,242 +1,242 @@ /*- * 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. */ #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 */ #if 0 #ifndef lint static char sccsid[] = "@(#)ktrace.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "ktrace.h" static char def_tracefile[] = DEF_TRACEFILE; static enum clear { NOTSET, CLEAR, CLEARALL } clear = NOTSET; static int pid; static void no_ktrace(int); static void set_pid_clear(const char *, enum clear); -static void usage(void); +static void usage(void) __dead2; int main(int argc, char *argv[]) { int append, ch, fd, inherit, ops, trpoints; const char *tracefile; mode_t omask; struct stat sb; append = ops = inherit = 0; trpoints = DEF_POINTS; tracefile = def_tracefile; while ((ch = getopt(argc,argv,"aCcdf:g:ip:t:")) != -1) switch((char)ch) { case 'a': append = 1; break; case 'C': set_pid_clear("1", CLEARALL); break; case 'c': set_pid_clear(NULL, CLEAR); break; case 'd': ops |= KTRFLAG_DESCEND; break; case 'f': tracefile = optarg; break; case 'g': set_pid_clear(optarg, NOTSET); pid = -pid; break; case 'i': inherit = 1; break; case 'p': set_pid_clear(optarg, NOTSET); break; case 't': trpoints = getpoints(optarg); if (trpoints < 0) { warnx("unknown facility in %s", optarg); usage(); } break; default: usage(); } argv += optind; argc -= optind; /* must have either -[Cc], a pid or a command */ if (clear == NOTSET && pid == 0 && argc == 0) usage(); /* can't have both a pid and a command */ /* (note that -C sets pid to 1) */ if (pid != 0 && argc > 0) { usage(); } if (inherit) trpoints |= KTRFAC_INHERIT; (void)signal(SIGSYS, no_ktrace); if (clear != NOTSET) { if (clear == CLEARALL) { ops = KTROP_CLEAR | KTRFLAG_DESCEND; trpoints = ALL_POINTS; } else { ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE; } if (ktrace(tracefile, ops, trpoints, pid) < 0) err(1, "%s", tracefile); exit(0); } omask = umask(S_IRWXG|S_IRWXO); if (append) { if ((fd = open(tracefile, O_CREAT | O_WRONLY | O_NONBLOCK, DEFFILEMODE)) < 0) err(1, "%s", tracefile); if (fstat(fd, &sb) != 0 || sb.st_uid != getuid()) errx(1, "refuse to append to %s not owned by you", tracefile); if (!(S_ISREG(sb.st_mode))) errx(1, "%s not regular file", tracefile); } else { if (unlink(tracefile) == -1 && errno != ENOENT) err(1, "unlink %s", tracefile); if ((fd = open(tracefile, O_CREAT | O_EXCL | O_WRONLY, DEFFILEMODE)) < 0) err(1, "%s", tracefile); } (void)umask(omask); (void)close(fd); trpoints |= PROC_ABI_POINTS; if (argc > 0) { if (ktrace(tracefile, ops, trpoints, getpid()) < 0) err(1, "%s", tracefile); execvp(*argv, argv); err(1, "exec of '%s' failed", *argv); } if (ktrace(tracefile, ops, trpoints, pid) < 0) err(1, "%s", tracefile); exit(0); } static void set_pid_clear(const char *p, enum clear cl) { intmax_t n; char *e; if (clear != NOTSET && cl != NOTSET) { /* either -c and -C or either of them twice */ warnx("only one -c or -C flag is permitted"); usage(); } if ((clear == CLEARALL && p != NULL) || (cl == CLEARALL && pid != 0)) { /* both -C and a pid or pgid */ warnx("the -C flag may not be combined with -g or -p"); usage(); } if (p != NULL && pid != 0) { /* either -p and -g or either of them twice */ warnx("only one -g or -p flag is permitted"); usage(); } if (p != NULL) { errno = 0; n = strtoimax(p, &e, 10); /* * 1) not a number, or outside the range of an intmax_t * 2) inside the range of intmax_t but outside the range * of an int, keeping in mind that the pid may be * negated if it's actually a pgid. */ if (*e != '\0' || n < 1 || errno == ERANGE || n > (intmax_t)INT_MAX || n > -(intmax_t)INT_MIN) { warnx("invalid process or group id"); usage(); } pid = n; } if (cl != NOTSET) if ((clear = cl) == CLEARALL) pid = 1; } static void usage(void) { fprintf(stderr, "%s\n%s\n", "usage: ktrace [-aCcdi] [-f trfile] [-g pgrp | -p pid] [-t trstr]", " ktrace [-adi] [-f trfile] [-t trstr] command"); exit(1); } static void no_ktrace(int sig __unused) { fprintf(stderr, "error:\t%s\n\t%s\n", "ktrace() system call not supported in the running kernel", "re-compile kernel with 'options KTRACE'"); exit(1); } diff --git a/usr.bin/ktrdump/ktrdump.c b/usr.bin/ktrdump/ktrdump.c index 0ffd4cdd9352..4718a577f52d 100644 --- a/usr.bin/ktrdump/ktrdump.c +++ b/usr.bin/ktrdump/ktrdump.c @@ -1,406 +1,406 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2002 Jake Burkholder * Copyright (c) 2004 Robert Watson * 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 #include #include #include #include #define SBUFLEN 128 #define USAGE \ "usage: ktrdump [-cflqrtH] [-i ktrfile] [-M core] [-N system] [-o outfile]\n" -static void usage(void); +static void usage(void) __dead2; static struct nlist nl[] = { { .n_name = "_ktr_version" }, { .n_name = "_ktr_entries" }, { .n_name = "_ktr_idx" }, { .n_name = "_ktr_buf" }, { .n_name = NULL } }; static int cflag; static int fflag; static int lflag; static int Mflag; static int Nflag; static int qflag; static int rflag; static int tflag; static int iflag; static int hflag; static char corefile[PATH_MAX]; static char execfile[PATH_MAX]; static char outfile[PATH_MAX] = "stdout"; static char desc[SBUFLEN]; static char errbuf[_POSIX2_LINE_MAX]; static char fbuf[PATH_MAX]; static char obuf[PATH_MAX]; static char sbuf[KTR_PARMS][SBUFLEN]; /* * Reads the ktr trace buffer from kernel memory and prints the trace entries. */ int main(int ac, char **av) { u_long parms[KTR_PARMS]; struct ktr_entry *buf; uintmax_t tlast, tnow; unsigned long bufptr; cap_rights_t rights; struct stat sb; kvm_t *kd; FILE *out; char *p; int version; int entries; int count; int index, index2; int parm; int in; int c; int i = 0; /* * Parse commandline arguments. */ out = stdout; while ((c = getopt(ac, av, "cflqrtHe:i:m:M:N:o:")) != -1) switch (c) { case 'c': cflag = 1; break; case 'N': case 'e': if (strlcpy(execfile, optarg, sizeof(execfile)) >= sizeof(execfile)) errx(1, "%s: File name too long", optarg); Nflag = 1; break; case 'f': fflag = 1; break; case 'i': iflag = 1; if ((in = open(optarg, O_RDONLY)) == -1) err(1, "%s", optarg); cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R); if (caph_rights_limit(in, &rights) < 0) err(1, "unable to limit rights for %s", optarg); break; case 'l': lflag = 1; break; case 'M': case 'm': if (strlcpy(corefile, optarg, sizeof(corefile)) >= sizeof(corefile)) errx(1, "%s: File name too long", optarg); Mflag = 1; break; case 'o': if ((out = fopen(optarg, "w")) == NULL) err(1, "%s", optarg); strlcpy(outfile, optarg, sizeof(outfile)); break; case 'q': qflag++; break; case 'r': rflag = 1; break; case 't': tflag = 1; break; case 'H': hflag = 1; break; case '?': default: usage(); } ac -= optind; av += optind; if (ac != 0) usage(); if (caph_limit_stream(fileno(out), CAPH_WRITE) < 0) err(1, "unable to limit rights for %s", outfile); if (caph_limit_stderr() < 0) err(1, "unable to limit rights for stderr"); /* * Open our execfile and corefile, resolve needed symbols and read in * the trace buffer. */ if ((kd = kvm_openfiles(Nflag ? execfile : NULL, Mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL) errx(1, "%s", errbuf); /* * Cache NLS data, for strerror, for err(3), before entering capability * mode. */ caph_cache_catpages(); count = kvm_nlist(kd, nl); if (count == -1) errx(1, "%s", kvm_geterr(kd)); if (count > 0) errx(1, "failed to resolve ktr symbols"); if (kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1) errx(1, "%s", kvm_geterr(kd)); if (version != KTR_VERSION) errx(1, "ktr version mismatch"); /* * Enter Capsicum sandbox. * * kvm_nlist() above uses kldsym(2) for native kernels, and that isn't * allowed in the sandbox. */ if (caph_enter() < 0) err(1, "unable to enter capability mode"); if (iflag) { if (fstat(in, &sb) == -1) errx(1, "stat"); entries = sb.st_size / sizeof(*buf); index = 0; buf = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, in, 0); if (buf == MAP_FAILED) errx(1, "mmap"); } else { if (kvm_read(kd, nl[1].n_value, &entries, sizeof(entries)) == -1) errx(1, "%s", kvm_geterr(kd)); if ((buf = malloc(sizeof(*buf) * entries)) == NULL) err(1, NULL); if (kvm_read(kd, nl[2].n_value, &index, sizeof(index)) == -1 || kvm_read(kd, nl[3].n_value, &bufptr, sizeof(bufptr)) == -1 || kvm_read(kd, bufptr, buf, sizeof(*buf) * entries) == -1 || kvm_read(kd, nl[2].n_value, &index2, sizeof(index2)) == -1) errx(1, "%s", kvm_geterr(kd)); } /* * Print a nice header. */ if (!qflag) { fprintf(out, "%-6s ", "index"); if (cflag) fprintf(out, "%-3s ", "cpu"); if (tflag) fprintf(out, "%-16s ", "timestamp"); if (fflag) fprintf(out, "%-40s ", "file and line"); if (hflag) fprintf(out, "%-18s ", "tid"); fprintf(out, "%s", "trace"); fprintf(out, "\n"); fprintf(out, "------ "); if (cflag) fprintf(out, "--- "); if (tflag) fprintf(out, "---------------- "); if (fflag) fprintf(out, "---------------------------------------- "); if (hflag) fprintf(out, "------------------ "); fprintf(out, "----- "); fprintf(out, "\n"); } tlast = UINTPTR_MAX; /* * Now tear through the trace buffer. * * In "live" mode, find the oldest entry (first non-NULL entry * after index2) and walk forward. Otherwise, start with the * most recent entry and walk backwards. */ if (!iflag) { if (lflag) { i = index2 + 1 % entries; while (buf[i].ktr_desc == NULL && i != index) { i++; if (i == entries) i = 0; } } else { i = index - 1; if (i < 0) i = entries - 1; } } dump_entries: for (;;) { if (buf[i].ktr_desc == NULL) break; if (kvm_read(kd, (u_long)buf[i].ktr_desc, desc, sizeof(desc)) == -1) errx(1, "%s", kvm_geterr(kd)); desc[sizeof(desc) - 1] = '\0'; parm = 0; for (p = desc; (c = *p++) != '\0';) { if (c != '%') continue; next: if ((c = *p++) == '\0') break; if (c == '%') continue; if (parm == KTR_PARMS) errx(1, "too many parameters in \"%s\"", desc); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '#': case '-': case ' ': case '+': case '\'': case 'h': case 'l': case 'j': case 't': case 'z': case 'q': case 'L': case '.': goto next; case 's': if (kvm_read(kd, (u_long)buf[i].ktr_parms[parm], sbuf[parm], sizeof(sbuf[parm])) == -1) strcpy(sbuf[parm], "(null)"); sbuf[parm][sizeof(sbuf[0]) - 1] = '\0'; parms[parm] = (u_long)sbuf[parm]; parm++; break; default: parms[parm] = buf[i].ktr_parms[parm]; parm++; break; } } fprintf(out, "%6d ", i); if (cflag) fprintf(out, "%3d ", buf[i].ktr_cpu); if (tflag) { tnow = (uintmax_t)buf[i].ktr_timestamp; if (rflag) { if (tlast == UINTPTR_MAX) tlast = tnow; fprintf(out, "%16ju ", !iflag ? tlast - tnow : tnow - tlast); tlast = tnow; } else fprintf(out, "%16ju ", tnow); } if (fflag) { if (kvm_read(kd, (u_long)buf[i].ktr_file, fbuf, sizeof(fbuf)) == -1) strcpy(fbuf, "(null)"); snprintf(obuf, sizeof(obuf), "%s:%d", fbuf, buf[i].ktr_line); fprintf(out, "%-40s ", obuf); } if (hflag) fprintf(out, "%p ", buf[i].ktr_thread); fprintf(out, desc, parms[0], parms[1], parms[2], parms[3], parms[4], parms[5]); fprintf(out, "\n"); if (!iflag) { /* * 'index' and 'index2' are the values of 'ktr_idx' * before and after the KTR buffer was copied into * 'buf'. Since the KTR entries between 'index' and * 'index2' were in flux while the KTR buffer was * being copied to userspace we don't dump them. */ if (lflag) { if (++i == entries) i = 0; if (i == index) break; } else { if (i == index2) break; if (--i < 0) i = entries - 1; } } else { if (++i == entries) break; } } /* * In "live" mode, poll 'ktr_idx' periodically and dump any * new entries since our last pass through the ring. */ if (lflag && !iflag) { while (index == index2) { usleep(50 * 1000); if (kvm_read(kd, nl[2].n_value, &index2, sizeof(index2)) == -1) errx(1, "%s", kvm_geterr(kd)); } i = index; index = index2; if (kvm_read(kd, bufptr, buf, sizeof(*buf) * entries) == -1 || kvm_read(kd, nl[2].n_value, &index2, sizeof(index2)) == -1) errx(1, "%s", kvm_geterr(kd)); goto dump_entries; } return (0); } static void usage(void) { fprintf(stderr, USAGE); exit(1); } diff --git a/usr.bin/leave/leave.c b/usr.bin/leave/leave.c index 1e3d4ed78ae1..bc2d524b7f94 100644 --- a/usr.bin/leave/leave.c +++ b/usr.bin/leave/leave.c @@ -1,194 +1,194 @@ /* * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)leave.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include static void doalarm(u_int); -static void usage(void); +static void usage(void) __dead2; /* * leave [[+]hhmm] * * Reminds you when you have to leave. * Leave prompts for input and goes away if you hit return. * It nags you like a mother hen. */ int main(int argc, char **argv) { u_int secs; int hours, minutes; char c, *cp = NULL; struct tm *t; time_t now; int plusnow, t_12_hour; char buf[50]; if (setlocale(LC_TIME, "") == NULL) warn("setlocale"); if (argc < 2) { #define MSG1 "When do you have to leave? " (void)write(STDOUT_FILENO, MSG1, sizeof(MSG1) - 1); cp = fgets(buf, sizeof(buf), stdin); if (cp == NULL || *cp == '\n') exit(0); } else if (argc > 2) usage(); else cp = argv[1]; if (*cp == '+') { plusnow = 1; ++cp; } else plusnow = 0; for (hours = 0; (c = *cp) && c != '\n'; ++cp) { if (!isdigit(c)) usage(); hours = hours * 10 + (c - '0'); } minutes = hours % 100; hours /= 100; if (minutes < 0 || minutes > 59) usage(); if (plusnow) secs = hours * 60 * 60 + minutes * 60; else { (void)time(&now); t = localtime(&now); if (hours > 23) usage(); /* Convert tol to 12 hr time (0:00...11:59) */ if (hours > 11) hours -= 12; /* Convert tm to 12 hr time (0:00...11:59) */ if (t->tm_hour > 11) t_12_hour = t->tm_hour - 12; else t_12_hour = t->tm_hour; if (hours < t_12_hour || (hours == t_12_hour && minutes <= t->tm_min)) /* Leave time is in the past so we add 12 hrs */ hours += 12; secs = (hours - t_12_hour) * 60 * 60; secs += (minutes - t->tm_min) * 60; secs -= now % 60; /* truncate (now + secs) to min */ } doalarm(secs); exit(0); } void doalarm(u_int secs) { int bother; time_t daytime; char tb[80]; int pid; if ((pid = fork())) { (void)time(&daytime); daytime += secs; strftime(tb, sizeof(tb), "%+", localtime(&daytime)); printf("Alarm set for %s. (pid %d)\n", tb, pid); exit(0); } sleep((u_int)2); /* let parent print set message */ if (secs >= 2) secs -= 2; /* * if write fails, we've lost the terminal through someone else * causing a vhangup by logging in. */ #define FIVEMIN (5 * 60) #define MSG2 "\07\07You have to leave in 5 minutes.\n" if (secs >= FIVEMIN) { sleep(secs - FIVEMIN); if (write(STDOUT_FILENO, MSG2, sizeof(MSG2) - 1) != sizeof(MSG2) - 1) exit(0); secs = FIVEMIN; } #define ONEMIN (60) #define MSG3 "\07\07Just one more minute!\n" if (secs >= ONEMIN) { sleep(secs - ONEMIN); if (write(STDOUT_FILENO, MSG3, sizeof(MSG3) - 1) != sizeof(MSG3) - 1) exit(0); } #define MSG4 "\07\07Time to leave!\n" for (bother = 10; bother--;) { sleep((u_int)ONEMIN); if (write(STDOUT_FILENO, MSG4, sizeof(MSG4) - 1) != sizeof(MSG4) - 1) exit(0); } #define MSG5 "\07\07That was the last time I'll tell you. Bye.\n" (void)write(STDOUT_FILENO, MSG5, sizeof(MSG5) - 1); exit(0); } static void usage(void) { fprintf(stderr, "usage: leave [[+]hhmm]\n"); exit(1); } diff --git a/usr.bin/limits/limits.c b/usr.bin/limits/limits.c index c0c652d065ac..558d8adf1f0a 100644 --- a/usr.bin/limits/limits.c +++ b/usr.bin/limits/limits.c @@ -1,780 +1,780 @@ /*- * Copyright (c) 1997 by * David L. Nugent * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice immediately at the beginning of the file, without modification, * 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. This work was done expressly for inclusion into FreeBSD. Other use * is permitted provided this notation is included. * 4. Absolutely no warranty of function or purpose is made by the authors. * 5. Modifications may be freely made to this file providing the above * conditions are met. * * Display/change(+runprogram)/eval resource limits. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum { SH_NONE, SH_SH, /* sh */ SH_CSH, /* csh */ SH_BASH, /* gnu bash */ SH_TCSH, /* tcsh */ SH_KSH, /* (pd)ksh */ SH_ZSH, /* zsh */ SH_RC, /* rc or es */ SH_NUMBER }; /* eval emitter for popular shells. * Why aren't there any standards here? Most shells support either * the csh 'limit' or sh 'ulimit' command, but each varies just * enough that they aren't very compatible from one to the other. */ static struct { const char * name; /* Name of shell */ const char * inf; /* Name used for 'unlimited' resource */ const char * cmd; /* Intro text */ const char * hard; /* Hard limit text */ const char * soft; /* Soft limit text */ const char * both; /* Hard+Soft limit text */ struct { const char * pfx; const char * sfx; int divisor; } lprm[RLIM_NLIMITS]; } shellparm[] = { { "", "infinity", "Resource limits%s%s:\n", "-max", "-cur", "", { { " cputime%-4s %8s", " secs\n", 1 }, { " filesize%-4s %8s", " kB\n", 1024 }, { " datasize%-4s %8s", " kB\n", 1024 }, { " stacksize%-4s %8s", " kB\n", 1024 }, { " coredumpsize%-4s %8s", " kB\n", 1024 }, { " memoryuse%-4s %8s", " kB\n", 1024 }, { " memorylocked%-4s %8s", " kB\n", 1024 }, { " maxprocesses%-4s %8s", "\n", 1 }, { " openfiles%-4s %8s", "\n", 1 }, { " sbsize%-4s %8s", " bytes\n", 1 }, { " vmemoryuse%-4s %8s", " kB\n", 1024 }, { " pseudo-terminals%-4s %8s", "\n", 1 }, { " swapuse%-4s %8s", " kB\n", 1024 }, { " kqueues%-4s %8s", "\n", 1 }, { " umtxp%-4s %8s", "\n", 1 }, } }, { "sh", "unlimited", "", " -H", " -S", "", { { "ulimit%s -t %s", ";\n", 1 }, { "ulimit%s -f %s", ";\n", 512 }, { "ulimit%s -d %s", ";\n", 1024 }, { "ulimit%s -s %s", ";\n", 1024 }, { "ulimit%s -c %s", ";\n", 512 }, { "ulimit%s -m %s", ";\n", 1024 }, { "ulimit%s -l %s", ";\n", 1024 }, { "ulimit%s -u %s", ";\n", 1 }, { "ulimit%s -n %s", ";\n", 1 }, { "ulimit%s -b %s", ";\n", 1 }, { "ulimit%s -v %s", ";\n", 1024 }, { "ulimit%s -p %s", ";\n", 1 }, { "ulimit%s -w %s", ";\n", 1024 }, { "ulimit%s -k %s", ";\n", 1 }, { "ulimit%s -o %s", ";\n", 1 }, } }, { "csh", "unlimited", "", " -h", "", NULL, { { "limit%s cputime %s", ";\n", 1 }, { "limit%s filesize %s", ";\n", 1024 }, { "limit%s datasize %s", ";\n", 1024 }, { "limit%s stacksize %s", ";\n", 1024 }, { "limit%s coredumpsize %s", ";\n", 1024 }, { "limit%s memoryuse %s", ";\n", 1024 }, { "limit%s memorylocked %s", ";\n", 1024 }, { "limit%s maxproc %s", ";\n", 1 }, { "limit%s openfiles %s", ";\n", 1 }, { "limit%s sbsize %s", ";\n", 1 }, { "limit%s vmemoryuse %s", ";\n", 1024 }, { "limit%s pseudoterminals %s", ";\n", 1 }, { "limit%s swapsize %s", ";\n", 1024 }, { "limit%s kqueues %s", ";\n", 1 }, { "limit%s umtxp %s", ";\n", 1 }, } }, { "bash|bash2", "unlimited", "", " -H", " -S", "", { { "ulimit%s -t %s", ";\n", 1 }, { "ulimit%s -f %s", ";\n", 1024 }, { "ulimit%s -d %s", ";\n", 1024 }, { "ulimit%s -s %s", ";\n", 1024 }, { "ulimit%s -c %s", ";\n", 1024 }, { "ulimit%s -m %s", ";\n", 1024 }, { "ulimit%s -l %s", ";\n", 1024 }, { "ulimit%s -u %s", ";\n", 1 }, { "ulimit%s -n %s", ";\n", 1 }, { "ulimit%s -b %s", ";\n", 1 }, { "ulimit%s -v %s", ";\n", 1024 }, { "ulimit%s -p %s", ";\n", 1 }, { "ulimit%s -w %s", ";\n", 1024 } } }, { "tcsh", "unlimited", "", " -h", "", NULL, { { "limit%s cputime %s", ";\n", 1 }, { "limit%s filesize %s", ";\n", 1024 }, { "limit%s datasize %s", ";\n", 1024 }, { "limit%s stacksize %s", ";\n", 1024 }, { "limit%s coredumpsize %s", ";\n", 1024 }, { "limit%s memoryuse %s", ";\n", 1024 }, { "limit%s memorylocked %s", ";\n", 1024 }, { "limit%s maxproc %s", ";\n", 1 }, { "limit%s descriptors %s", ";\n", 1 }, { "limit%s sbsize %s", ";\n", 1 }, { "limit%s vmemoryuse %s", ";\n", 1024 }, { "limit%s pseudoterminals %s", ";\n", 1 }, { "limit%s swapsize %s", ";\n", 1024 }, { "limit%s kqueues %s", ";\n", 1 }, { "limit%s umtxp %s", ";\n", 1 }, } }, { "ksh|pdksh", "unlimited", "", " -H", " -S", "", { { "ulimit%s -t %s", ";\n", 1 }, { "ulimit%s -f %s", ";\n", 512 }, { "ulimit%s -d %s", ";\n", 1024 }, { "ulimit%s -s %s", ";\n", 1024 }, { "ulimit%s -c %s", ";\n", 512 }, { "ulimit%s -m %s", ";\n", 1024 }, { "ulimit%s -l %s", ";\n", 1024 }, { "ulimit%s -p %s", ";\n", 1 }, { "ulimit%s -n %s", ";\n", 1 }, { "ulimit%s -b %s", ";\n", 1 }, { "ulimit%s -v %s", ";\n", 1024 }, { "ulimit%s -p %s", ";\n", 1 }, { "ulimit%s -w %s", ";\n", 1024 } } }, { "zsh", "unlimited", "", " -H", " -S", "", { { "ulimit%s -t %s", ";\n", 1 }, { "ulimit%s -f %s", ";\n", 512 }, { "ulimit%s -d %s", ";\n", 1024 }, { "ulimit%s -s %s", ";\n", 1024 }, { "ulimit%s -c %s", ";\n", 512 }, { "ulimit%s -m %s", ";\n", 1024 }, { "ulimit%s -l %s", ";\n", 1024 }, { "ulimit%s -u %s", ";\n", 1 }, { "ulimit%s -n %s", ";\n", 1 }, { "ulimit%s -b %s", ";\n", 1 }, { "ulimit%s -v %s", ";\n", 1024 }, { "ulimit%s -p %s", ";\n", 1 }, { "ulimit%s -w %s", ";\n", 1024 } } }, { "rc|es", "unlimited", "", " -h", "", NULL, { { "limit%s cputime %s", ";\n", 1 }, { "limit%s filesize %s", ";\n", 1024 }, { "limit%s datasize %s", ";\n", 1024 }, { "limit%s stacksize %s", ";\n", 1024 }, { "limit%s coredumpsize %s", ";\n", 1024 }, { "limit%s memoryuse %s", ";\n", 1024 }, { "limit%s lockedmemory %s", ";\n", 1024 }, { "limit%s processes %s", ";\n", 1 }, { "limit%s descriptors %s", ";\n", 1 }, { "limit%s sbsize %s", ";\n", 1 }, { "limit%s vmemoryuse %s", ";\n", 1024 }, { "limit%s pseudoterminals %s", ";\n", 1 }, { "limit%s swapuse %s", ";\n", 1024 } } }, { NULL, NULL, NULL, NULL, NULL, NULL, { } } }; static struct { const char * cap; rlim_t (*func)(login_cap_t *, const char *, rlim_t, rlim_t); } resources[RLIM_NLIMITS] = { { "cputime", login_getcaptime }, { "filesize", login_getcapsize }, { "datasize", login_getcapsize }, { "stacksize", login_getcapsize }, { "coredumpsize", login_getcapsize }, { "memoryuse", login_getcapsize }, { "memorylocked", login_getcapsize }, { "maxproc", login_getcapnum }, { "openfiles", login_getcapnum }, { "sbsize", login_getcapsize }, { "vmemoryuse", login_getcapsize }, { "pseudoterminals",login_getcapnum }, { "swapuse", login_getcapsize }, { "kqueues", login_getcapnum }, { "umtxp", login_getcapnum }, }; /* * One letter for each resource levels. * NOTE: There is a dependency on the corresponding * letter index being equal to the resource number. * If sys/resource.h defines are changed, this needs * to be modified accordingly! */ #define RCS_STRING "tfdscmlunbvpwko" static rlim_t resource_num(int which, int ch, const char *str); -static void usage(void); +static void usage(void) __dead2; static int getshelltype(void); static void print_limit(rlim_t limit, unsigned divisor, const char *inf, const char *pfx, const char *sfx, const char *which); static void getrlimit_proc(pid_t pid, int resource, struct rlimit *rlp); static void setrlimit_proc(pid_t pid, int resource, const struct rlimit *rlp); extern char **environ; static const char rcs_string[] = RCS_STRING; int main(int argc, char *argv[]) { char *p, *cls = NULL; char *cleanenv[1]; struct passwd * pwd = NULL; int rcswhich, shelltype; int i, num_limits = 0; int ch, doeval = 0, doall = 0; int rtrn, setproc; login_cap_t * lc = NULL; enum { ANY=0, SOFT=1, HARD=2, BOTH=3, DISPLAYONLY=4 } type = ANY; enum { RCSUNKNOWN=0, RCSSET=1, RCSSEL=2 } todo = RCSUNKNOWN; int which_limits[RLIM_NLIMITS]; rlim_t set_limits[RLIM_NLIMITS]; struct rlimit limits[RLIM_NLIMITS]; pid_t pid; /* init resource tables */ for (i = 0; i < RLIM_NLIMITS; i++) { which_limits[i] = 0; /* Don't set/display any */ set_limits[i] = RLIM_INFINITY; } pid = -1; optarg = NULL; while ((ch = getopt(argc, argv, ":EeC:U:BSHP:ab:c:d:f:l:m:n:s:t:u:v:p:w:k:o:")) != -1) { switch(ch) { case 'a': doall = 1; break; case 'E': environ = cleanenv; cleanenv[0] = NULL; break; case 'e': doeval = 1; break; case 'C': cls = optarg; break; case 'U': if ((pwd = getpwnam(optarg)) == NULL) { if (!isdigit(*optarg) || (pwd = getpwuid(atoi(optarg))) == NULL) { warnx("invalid user `%s'", optarg); usage(); } } break; case 'H': type = HARD; break; case 'S': type = SOFT; break; case 'B': type = SOFT|HARD; break; case 'P': if (!isdigit(*optarg) || (pid = atoi(optarg)) < 0) { warnx("invalid pid `%s'", optarg); usage(); } break; default: case ':': /* Without arg */ if ((p = strchr(rcs_string, optopt)) != NULL) { int rcswhich1 = p - rcs_string; if (optarg && *optarg == '-') { /* 'arg' is actually a switch */ --optind; /* back one arg, and make arg NULL */ optarg = NULL; } todo = optarg == NULL ? RCSSEL : RCSSET; if (type == ANY) type = BOTH; which_limits[rcswhich1] = optarg ? type : DISPLAYONLY; set_limits[rcswhich1] = resource_num(rcswhich1, optopt, optarg); num_limits++; break; } /* FALLTHRU */ case '?': usage(); } optarg = NULL; } if (pid != -1) { if (cls != NULL) { warnx("-C cannot be used with -P option"); usage(); } if (pwd != NULL) { warnx("-U cannot be used with -P option"); usage(); } } /* Get current resource values */ setproc = 0; for (i = 0; i < RLIM_NLIMITS; i++) { if (pid == -1) { getrlimit(i, &limits[i]); } else if (doall || num_limits == 0) { getrlimit_proc(pid, i, &limits[i]); } else if (which_limits[i] != 0) { getrlimit_proc(pid, i, &limits[i]); setproc = 1; } } /* If user was specified, get class from that */ if (pwd != NULL) lc = login_getpwclass(pwd); else if (cls != NULL && *cls != '\0') { lc = login_getclassbyname(cls, NULL); if (lc == NULL || strcmp(cls, lc->lc_class) != 0) fprintf(stderr, "login class '%s' non-existent, using %s\n", cls, lc?lc->lc_class:"current settings"); } /* If we have a login class, update resource table from that */ if (lc != NULL) { for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { char str[40]; rlim_t val; /* current value overridden by resourcename or resourcename-cur */ sprintf(str, "%s-cur", resources[rcswhich].cap); val = resources[rcswhich].func(lc, resources[rcswhich].cap, limits[rcswhich].rlim_cur, limits[rcswhich].rlim_cur); limits[rcswhich].rlim_cur = resources[rcswhich].func(lc, str, val, val); /* maximum value overridden by resourcename or resourcename-max */ sprintf(str, "%s-max", resources[rcswhich].cap); val = resources[rcswhich].func(lc, resources[rcswhich].cap, limits[rcswhich].rlim_max, limits[rcswhich].rlim_max); limits[rcswhich].rlim_max = resources[rcswhich].func(lc, str, val, val); } } /* now, let's determine what we wish to do with all this */ argv += optind; /* If we're setting limits or doing an eval (ie. we're not just * displaying), then check that hard limits are not lower than * soft limits, and force rasing the hard limit if we need to if * we are raising the soft limit, or lower the soft limit if we * are lowering the hard limit. */ if ((*argv || doeval) && getuid() == 0) { for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { if (limits[rcswhich].rlim_max != RLIM_INFINITY) { if (limits[rcswhich].rlim_cur == RLIM_INFINITY) { limits[rcswhich].rlim_max = RLIM_INFINITY; which_limits[rcswhich] |= HARD; } else if (limits[rcswhich].rlim_cur > limits[rcswhich].rlim_max) { if (which_limits[rcswhich] == SOFT) { limits[rcswhich].rlim_max = limits[rcswhich].rlim_cur; which_limits[rcswhich] |= HARD; } else if (which_limits[rcswhich] == HARD) { limits[rcswhich].rlim_cur = limits[rcswhich].rlim_max; which_limits[rcswhich] |= SOFT; } else { /* else.. if we're specifically setting both to * silly values, then let it error out. */ } } } } } /* See if we've overridden anything specific on the command line */ if (num_limits && todo == RCSSET) { for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { if (which_limits[rcswhich] & HARD) limits[rcswhich].rlim_max = set_limits[rcswhich]; if (which_limits[rcswhich] & SOFT) limits[rcswhich].rlim_cur = set_limits[rcswhich]; } } /* If *argv is not NULL, then we are being asked to * (perhaps) set environment variables and run a program */ if (*argv) { if (doeval) { warnx("-e cannot be used with `cmd' option"); usage(); } if (pid != -1) { warnx("-P cannot be used with `cmd' option"); usage(); } login_close(lc); /* set leading environment variables, like eval(1) */ while (*argv && (p = strchr(*argv, '='))) { *p = '\0'; rtrn = setenv(*argv++, p + 1, 1); *p = '='; if (rtrn == -1) err(EXIT_FAILURE, "setenv %s", *argv); } /* Set limits */ for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { if (doall || num_limits == 0 || which_limits[rcswhich] != 0) if (setrlimit(rcswhich, &limits[rcswhich]) == -1) err(1, "setrlimit %s", resources[rcswhich].cap); } if (*argv == NULL) usage(); execvp(*argv, argv); err(1, "%s", *argv); } if (setproc) { for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { if (which_limits[rcswhich] != 0) setrlimit_proc(pid, rcswhich, &limits[rcswhich]); } exit(EXIT_SUCCESS); } shelltype = doeval ? getshelltype() : SH_NONE; if (type == ANY) /* Default to soft limits */ type = SOFT; /* Display limits */ printf(shellparm[shelltype].cmd, lc ? " for class " : " (current)", lc ? lc->lc_class : ""); for (rcswhich = 0; rcswhich < RLIM_NLIMITS; rcswhich++) { if (doall || num_limits == 0 || which_limits[rcswhich] != 0) { if (which_limits[rcswhich] == ANY) which_limits[rcswhich] = type; if (shellparm[shelltype].lprm[rcswhich].pfx) { if (shellparm[shelltype].both && limits[rcswhich].rlim_cur == limits[rcswhich].rlim_max) { print_limit(limits[rcswhich].rlim_max, shellparm[shelltype].lprm[rcswhich].divisor, shellparm[shelltype].inf, shellparm[shelltype].lprm[rcswhich].pfx, shellparm[shelltype].lprm[rcswhich].sfx, shellparm[shelltype].both); } else { if (which_limits[rcswhich] & HARD) { print_limit(limits[rcswhich].rlim_max, shellparm[shelltype].lprm[rcswhich].divisor, shellparm[shelltype].inf, shellparm[shelltype].lprm[rcswhich].pfx, shellparm[shelltype].lprm[rcswhich].sfx, shellparm[shelltype].hard); } if (which_limits[rcswhich] & SOFT) { print_limit(limits[rcswhich].rlim_cur, shellparm[shelltype].lprm[rcswhich].divisor, shellparm[shelltype].inf, shellparm[shelltype].lprm[rcswhich].pfx, shellparm[shelltype].lprm[rcswhich].sfx, shellparm[shelltype].soft); } } } } } login_close(lc); exit(EXIT_SUCCESS); } static void usage(void) { (void)fprintf(stderr, "usage: limits [-C class|-P pid|-U user] [-eaSHBE] " "[-bcdfklmnostuvpw [val]] [[name=val ...] cmd]\n"); exit(EXIT_FAILURE); } static void print_limit(rlim_t limit, unsigned divisor, const char * inf, const char * pfx, const char * sfx, const char * which) { char numbr[64]; if (limit == RLIM_INFINITY) strlcpy(numbr, inf, sizeof(numbr)); else sprintf(numbr, "%jd", (intmax_t)((limit + divisor/2) / divisor)); printf(pfx, which, numbr); printf(sfx, which); } static rlim_t resource_num(int which, int ch, const char *str) { rlim_t res = RLIM_INFINITY; if (str != NULL && !(strcasecmp(str, "inf") == 0 || strcasecmp(str, "infinity") == 0 || strcasecmp(str, "unlimit") == 0 || strcasecmp(str, "unlimited") == 0)) { const char * s = str; char *e; switch (which) { case RLIMIT_CPU: /* time values */ errno = 0; res = 0; while (*s) { rlim_t tim = strtoq(s, &e, 0); if (e == NULL || e == s || errno) break; switch (*e++) { case 0: /* end of string */ e--; default: case 's': case 'S': /* seconds */ break; case 'm': case 'M': /* minutes */ tim *= 60L; break; case 'h': case 'H': /* hours */ tim *= (60L * 60L); break; case 'd': case 'D': /* days */ tim *= (60L * 60L * 24L); break; case 'w': case 'W': /* weeks */ tim *= (60L * 60L * 24L * 7L); break; case 'y': case 'Y': /* Years */ tim *= (60L * 60L * 24L * 365L); } s = e; res += tim; } break; case RLIMIT_FSIZE: /* Size values */ case RLIMIT_DATA: case RLIMIT_STACK: case RLIMIT_CORE: case RLIMIT_RSS: case RLIMIT_MEMLOCK: case RLIMIT_SBSIZE: case RLIMIT_VMEM: case RLIMIT_SWAP: errno = 0; res = 0; while (*s) { rlim_t mult, tim = strtoq(s, &e, 0); if (e == NULL || e == s || errno) break; switch (*e++) { case 0: /* end of string */ e--; default: mult = 1; break; case 'b': case 'B': /* 512-byte blocks */ mult = 512; break; case 'k': case 'K': /* 1024-byte Kilobytes */ mult = 1024; break; case 'm': case 'M': /* 1024-k kbytes */ mult = 1024 * 1024; break; case 'g': case 'G': /* 1Gbyte */ mult = 1024 * 1024 * 1024; break; case 't': case 'T': /* 1TBte */ mult = 1024LL * 1024LL * 1024LL * 1024LL; break; } s = e; res += (tim * mult); } break; case RLIMIT_NPROC: case RLIMIT_NOFILE: case RLIMIT_NPTS: case RLIMIT_KQUEUES: case RLIMIT_UMTXP: res = strtoq(s, &e, 0); s = e; break; } if (*s) { warnx("invalid value -%c `%s'", ch, str); usage(); } } return res; } static int getshellbyname(const char * shell) { int i; const char * q; const char * p = strrchr(shell, '/'); p = p ? p+1 : shell; for (i = 0; (q = shellparm[i].name) != NULL; i++) { while (*q) { int j = strcspn(q, "|"); if (j == 0) break; if (strncmp(p, q, j) == 0) return i; if (*(q += j)) ++q; } } return SH_SH; } /* * Determine the type of shell our parent process is * This is quite tricky, not 100% reliable and probably * not nearly as thorough as it should be. Basically, this * is a "best guess" only, but hopefully will work in * most cases. */ static int getshelltype(void) { pid_t ppid = getppid(); if (ppid != 1) { struct kinfo_proc kp; struct stat st; char path[MAXPATHLEN]; char * shell = getenv("SHELL"); int mib[4]; size_t len; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[3] = ppid; if (shell != NULL && stat(shell, &st) != -1) { struct stat st1; mib[2] = KERN_PROC_PATHNAME; len = sizeof(path); if (sysctl(mib, 4, path, &len, NULL, 0) != -1) { /* $SHELL is actual shell? */ if (stat(path, &st1) != -1 && memcmp(&st, &st1, sizeof st) == 0) return getshellbyname(shell); } } mib[2] = KERN_PROC_PID; len = sizeof(kp); if (sysctl(mib, 4, &kp, &len, NULL, 0) != -1) return getshellbyname(kp.ki_comm); } return SH_SH; } static void getrlimit_proc(pid_t pid, int resource, struct rlimit *rlp) { int error; int name[5]; size_t len; name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_RLIMIT; name[3] = pid; name[4] = resource; len = sizeof(*rlp); error = sysctl(name, 5, rlp, &len, NULL, 0); if (error == -1) err(EXIT_FAILURE, "sysctl: kern.proc.rlimit: %d", pid); if (len != sizeof(*rlp)) errx(EXIT_FAILURE, "sysctl() returns wrong size"); } static void setrlimit_proc(pid_t pid, int resource, const struct rlimit *rlp) { int error; int name[5]; name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_RLIMIT; name[3] = pid; name[4] = resource; error = sysctl(name, 5, NULL, 0, rlp, sizeof(*rlp)); if (error == -1) err(EXIT_FAILURE, "sysctl: kern.proc.rlimit: %d", pid); } diff --git a/usr.bin/lock/lock.c b/usr.bin/lock/lock.c index d8644f7010a9..30b7e7ac9df6 100644 --- a/usr.bin/lock/lock.c +++ b/usr.bin/lock/lock.c @@ -1,315 +1,315 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 1987, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Bob Toxen. * * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1987, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)lock.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); /* * Lock a terminal up until the given key is entered or the given * interval times out. * * Timeout interval is by default TIMEOUT, it can be changed with * an argument of the form -time where time is in minutes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for openpam_ttyconv() */ #define TIMEOUT 15 static void quit(int); static void bye(int); static void hi(int); -static void usage(void); +static void usage(void) __dead2; static struct timeval timeout; static struct timeval zerotime; static struct termios tty, ntty; static long nexttime; /* keep the timeout time */ static int no_timeout; /* lock terminal forever */ static int vtyunlock; /* Unlock flag and code. */ /*ARGSUSED*/ int main(int argc, char **argv) { static const struct pam_conv pamc = { &openpam_ttyconv, NULL }; pam_handle_t *pamh; struct passwd *pw; struct itimerval ntimer, otimer; struct tm *timp; time_t timval; int ch, failures, pam_err, sectimeout, usemine, vtylock; char *ap, *ttynam, *tzn; char hostname[MAXHOSTNAMELEN], s[BUFSIZ], s1[BUFSIZ]; openlog("lock", 0, LOG_AUTH); pam_err = PAM_SYSTEM_ERR; /* pacify GCC */ sectimeout = TIMEOUT; pamh = NULL; pw = NULL; usemine = 0; no_timeout = 0; vtylock = 0; while ((ch = getopt(argc, argv, "npt:v")) != -1) switch((char)ch) { case 't': if ((sectimeout = atoi(optarg)) <= 0) errx(1, "illegal timeout value"); break; case 'p': usemine = 1; if (!(pw = getpwuid(getuid()))) errx(1, "unknown uid %d", getuid()); break; case 'n': no_timeout = 1; break; case 'v': vtylock = 1; break; case '?': default: usage(); } timeout.tv_sec = sectimeout * 60; if (!usemine) { /* -p with PAM or S/key needs privs */ /* discard privs */ if (setuid(getuid()) != 0) errx(1, "setuid failed"); } if (tcgetattr(0, &tty)) /* get information for header */ exit(1); gethostname(hostname, sizeof(hostname)); if (!(ttynam = ttyname(0))) errx(1, "not a terminal?"); if (strncmp(ttynam, _PATH_DEV, strlen(_PATH_DEV)) == 0) ttynam += strlen(_PATH_DEV); timval = time(NULL); nexttime = timval + (sectimeout * 60); timp = localtime(&timval); ap = asctime(timp); tzn = timp->tm_zone; (void)signal(SIGINT, quit); (void)signal(SIGQUIT, quit); ntty = tty; ntty.c_lflag &= ~ECHO; (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &ntty); if (usemine) { pam_err = pam_start("lock", pw->pw_name, &pamc, &pamh); if (pam_err != PAM_SUCCESS) err(1, "pam_start: %s", pam_strerror(NULL, pam_err)); } else { /* get key and check again */ (void)printf("Key: "); if (!fgets(s, sizeof(s), stdin) || *s == '\n') quit(0); (void)printf("\nAgain: "); /* * Don't need EOF test here, if we get EOF, then s1 != s * and the right things will happen. */ (void)fgets(s1, sizeof(s1), stdin); (void)putchar('\n'); if (strcmp(s1, s)) { (void)printf("\07lock: passwords didn't match.\n"); (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); exit(1); } s[0] = '\0'; } /* set signal handlers */ (void)signal(SIGINT, hi); (void)signal(SIGQUIT, hi); (void)signal(SIGTSTP, hi); (void)signal(SIGALRM, bye); ntimer.it_interval = zerotime; ntimer.it_value = timeout; if (!no_timeout) setitimer(ITIMER_REAL, &ntimer, &otimer); if (vtylock) { /* * If this failed, we want to err out; warn isn't good * enough, since we don't want the user to think that * everything is nice and locked because they got a * "Key:" prompt. */ if (ioctl(0, VT_LOCKSWITCH, &vtylock) == -1) { (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); err(1, "locking vty"); } vtyunlock = 0x2; } /* header info */ if (pw != NULL) (void)printf("lock: %s using %s on %s.", pw->pw_name, ttynam, hostname); else (void)printf("lock: %s on %s.", ttynam, hostname); if (no_timeout) (void)printf(" no timeout."); else (void)printf(" timeout in %d minute%s.", sectimeout, sectimeout != 1 ? "s" : ""); if (vtylock) (void)printf(" vty locked."); (void)printf("\ntime now is %.20s%s%s", ap, tzn, ap + 19); failures = 0; for (;;) { if (usemine) { pam_err = pam_authenticate(pamh, 0); if (pam_err == PAM_SUCCESS) break; if (pam_err != PAM_AUTH_ERR && pam_err != PAM_USER_UNKNOWN && pam_err != PAM_MAXTRIES) { syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, pam_err)); } goto tryagain; } (void)printf("Key: "); if (!fgets(s, sizeof(s), stdin)) { clearerr(stdin); hi(0); goto tryagain; } if (!strcmp(s, s1)) break; (void)printf("\07\n"); failures++; if (getuid() == 0) syslog(LOG_NOTICE, "%d ROOT UNLOCK FAILURE%s (%s on %s)", failures, failures > 1 ? "S": "", ttynam, hostname); tryagain: if (tcgetattr(0, &ntty) && (errno != EINTR)) exit(1); sleep(1); /* to discourage guessing */ } if (getuid() == 0) syslog(LOG_NOTICE, "ROOT UNLOCK ON hostname %s port %s", hostname, ttynam); if (usemine) (void)pam_end(pamh, pam_err); quit(0); return(0); /* not reached */ } static void usage(void) { (void)fprintf(stderr, "usage: lock [-npv] [-t timeout]\n"); exit(1); } static void hi(int signo __unused) { time_t timval; timval = time(NULL); (void)printf("lock: type in the unlock key. "); if (no_timeout) { (void)putchar('\n'); } else { (void)printf("timeout in %jd:%jd minutes\n", (intmax_t)(nexttime - timval) / 60, (intmax_t)(nexttime - timval) % 60); } } static void quit(int signo __unused) { (void)putchar('\n'); (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); if (vtyunlock) (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock); exit(0); } static void bye(int signo __unused) { if (!no_timeout) { (void)tcsetattr(0, TCSADRAIN|TCSASOFT, &tty); if (vtyunlock) (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock); (void)printf("lock: timeout\n"); exit(1); } } diff --git a/usr.bin/lockf/lockf.c b/usr.bin/lockf/lockf.c index b330f3e6700d..3f582d014314 100644 --- a/usr.bin/lockf/lockf.c +++ b/usr.bin/lockf/lockf.c @@ -1,248 +1,248 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (C) 1997 John D. Polstra. 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 JOHN D. POLSTRA 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 JOHN D. POLSTRA 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 static int acquire_lock(const char *name, int flags); static void cleanup(void); static void killed(int sig); static void timeout(int sig); -static void usage(void); +static void usage(void) __dead2; static void wait_for_lock(const char *name); static const char *lockname; static int lockfd = -1; static int keep; static volatile sig_atomic_t timed_out; /* * Execute an arbitrary command while holding a file lock. */ int main(int argc, char **argv) { int ch, flags, silent, status, waitsec; pid_t child; silent = keep = 0; flags = O_CREAT | O_RDONLY; waitsec = -1; /* Infinite. */ while ((ch = getopt(argc, argv, "sknt:w")) != -1) { switch (ch) { case 'k': keep = 1; break; case 'n': flags &= ~O_CREAT; break; case 's': silent = 1; break; case 't': { char *endptr; waitsec = strtol(optarg, &endptr, 0); if (*optarg == '\0' || *endptr != '\0' || waitsec < 0) errx(EX_USAGE, "invalid timeout \"%s\"", optarg); } break; case 'w': flags = (flags & ~O_RDONLY) | O_WRONLY; break; default: usage(); } } if (argc - optind < 2) usage(); lockname = argv[optind++]; argc -= optind; argv += optind; if (waitsec > 0) { /* Set up a timeout. */ struct sigaction act; act.sa_handler = timeout; sigemptyset(&act.sa_mask); act.sa_flags = 0; /* Note that we do not set SA_RESTART. */ sigaction(SIGALRM, &act, NULL); alarm(waitsec); } /* * If the "-k" option is not given, then we must not block when * acquiring the lock. If we did, then the lock holder would * unlink the file upon releasing the lock, and we would acquire * a lock on a file with no directory entry. Then another * process could come along and acquire the same lock. To avoid * this problem, we separate out the actions of waiting for the * lock to be available and of actually acquiring the lock. * * That approach produces behavior that is technically correct; * however, it causes some performance & ordering problems for * locks that have a lot of contention. First, it is unfair in * the sense that a released lock isn't necessarily granted to * the process that has been waiting the longest. A waiter may * be starved out indefinitely. Second, it creates a thundering * herd situation each time the lock is released. * * When the "-k" option is used, the unlink race no longer * exists. In that case we can block while acquiring the lock, * avoiding the separate step of waiting for the lock. This * yields fairness and improved performance. */ lockfd = acquire_lock(lockname, flags | O_NONBLOCK); while (lockfd == -1 && !timed_out && waitsec != 0) { if (keep) lockfd = acquire_lock(lockname, flags); else { wait_for_lock(lockname); lockfd = acquire_lock(lockname, flags | O_NONBLOCK); } } if (waitsec > 0) alarm(0); if (lockfd == -1) { /* We failed to acquire the lock. */ if (silent) exit(EX_TEMPFAIL); errx(EX_TEMPFAIL, "%s: already locked", lockname); } /* At this point, we own the lock. */ if (atexit(cleanup) == -1) err(EX_OSERR, "atexit failed"); if ((child = fork()) == -1) err(EX_OSERR, "cannot fork"); if (child == 0) { /* The child process. */ close(lockfd); execvp(argv[0], argv); warn("%s", argv[0]); _exit(1); } /* This is the parent process. */ signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTERM, killed); if (waitpid(child, &status, 0) == -1) err(EX_OSERR, "waitpid failed"); return (WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE); } /* * Try to acquire a lock on the given file, creating the file if * necessary. The flags argument is O_NONBLOCK or 0, depending on * whether we should wait for the lock. Returns an open file descriptor * on success, or -1 on failure. */ static int acquire_lock(const char *name, int flags) { int fd; if ((fd = open(name, O_EXLOCK|flags, 0666)) == -1) { if (errno == EAGAIN || errno == EINTR) return (-1); else if (errno == ENOENT && (flags & O_CREAT) == 0) err(EX_UNAVAILABLE, "%s", name); err(EX_CANTCREAT, "cannot open %s", name); } return (fd); } /* * Remove the lock file. */ static void cleanup(void) { if (keep) flock(lockfd, LOCK_UN); else unlink(lockname); } /* * Signal handler for SIGTERM. Cleans up the lock file, then re-raises * the signal. */ static void killed(int sig) { cleanup(); signal(sig, SIG_DFL); if (kill(getpid(), sig) == -1) err(EX_OSERR, "kill failed"); } /* * Signal handler for SIGALRM. */ static void timeout(int sig __unused) { timed_out = 1; } static void usage(void) { fprintf(stderr, "usage: lockf [-kns] [-t seconds] file command [arguments]\n"); exit(EX_USAGE); } /* * Wait until it might be possible to acquire a lock on the given file. * If the file does not exist, return immediately without creating it. */ static void wait_for_lock(const char *name) { int fd; if ((fd = open(name, O_RDONLY|O_EXLOCK, 0666)) == -1) { if (errno == ENOENT || errno == EINTR) return; err(EX_CANTCREAT, "cannot open %s", name); } close(fd); } diff --git a/usr.bin/look/look.c b/usr.bin/look/look.c index 6335548c07fd..cded8d398401 100644 --- a/usr.bin/look/look.c +++ b/usr.bin/look/look.c @@ -1,363 +1,363 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * David Hitz of Auspex Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1991, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)look.c 8.2 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); /* * look -- find lines in a sorted list. * * The man page said that TABs and SPACEs participate in -d comparisons. * In fact, they were ignored. This implements historic practice, not * the manual page. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" static char _path_words[] = _PATH_WORDS; #define EQUAL 0 #define GREATER 1 #define LESS (-1) static int dflag, fflag; static char *binary_search(wchar_t *, unsigned char *, unsigned char *); static int compare(wchar_t *, unsigned char *, unsigned char *); static char *linear_search(wchar_t *, unsigned char *, unsigned char *); static int look(wchar_t *, unsigned char *, unsigned char *); static wchar_t *prepkey(const char *, wchar_t); static void print_from(wchar_t *, unsigned char *, unsigned char *); -static void usage(void); +static void usage(void) __dead2; static struct option longopts[] = { { "alternative",no_argument, NULL, 'a' }, { "alphanum", no_argument, NULL, 'd' }, { "ignore-case",no_argument, NULL, 'i' }, { "terminate", required_argument, NULL, 't'}, { NULL, 0, NULL, 0 }, }; int main(int argc, char *argv[]) { struct stat sb; int ch, fd, match; wchar_t termchar; unsigned char *back, *front; unsigned const char *file; wchar_t *key; (void) setlocale(LC_CTYPE, ""); file = _path_words; termchar = L'\0'; while ((ch = getopt_long(argc, argv, "+adft:", longopts, NULL)) != -1) switch(ch) { case 'a': /* COMPATIBILITY */ break; case 'd': dflag = 1; break; case 'f': fflag = 1; break; case 't': if (mbrtowc(&termchar, optarg, MB_LEN_MAX, NULL) != strlen(optarg)) errx(2, "invalid termination character"); break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc == 0) usage(); if (argc == 1) /* But set -df by default. */ dflag = fflag = 1; key = prepkey(*argv++, termchar); if (argc >= 2) file = *argv++; match = 1; do { if ((fd = open(file, O_RDONLY, 0)) < 0 || fstat(fd, &sb)) err(2, "%s", file); if ((uintmax_t)sb.st_size > (uintmax_t)SIZE_T_MAX) errx(2, "%s: %s", file, strerror(EFBIG)); if (sb.st_size == 0) { close(fd); continue; } if ((front = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) err(2, "%s", file); back = front + sb.st_size; match *= (look(key, front, back)); close(fd); } while (argc-- > 2 && (file = *argv++)); exit(match); } static wchar_t * prepkey(const char *string, wchar_t termchar) { const char *readp; wchar_t *key, *writep; wchar_t ch; size_t clen; /* * Reformat search string and convert to wide character representation * to avoid doing it multiple times later. */ if ((key = malloc(sizeof(wchar_t) * (strlen(string) + 1))) == NULL) err(2, NULL); readp = string; writep = key; while ((clen = mbrtowc(&ch, readp, MB_LEN_MAX, NULL)) != 0) { if (clen == (size_t)-1 || clen == (size_t)-2) errc(2, EILSEQ, NULL); if (fflag) ch = towlower(ch); if (!dflag || iswalnum(ch)) *writep++ = ch; readp += clen; } *writep = L'\0'; if (termchar != L'\0' && (writep = wcschr(key, termchar)) != NULL) *++writep = L'\0'; return (key); } static int look(wchar_t *string, unsigned char *front, unsigned char *back) { front = binary_search(string, front, back); front = linear_search(string, front, back); if (front) print_from(string, front, back); return (front ? 0 : 1); } /* * Binary search for "string" in memory between "front" and "back". * * This routine is expected to return a pointer to the start of a line at * *or before* the first word matching "string". Relaxing the constraint * this way simplifies the algorithm. * * Invariants: * front points to the beginning of a line at or before the first * matching string. * * back points to the beginning of a line at or after the first * matching line. * * Base of the Invariants. * front = NULL; * back = EOF; * * Advancing the Invariants: * * p = first newline after halfway point from front to back. * * If the string at "p" is not greater than the string to match, * p is the new front. Otherwise it is the new back. * * Termination: * * The definition of the routine allows it return at any point, * since front is always at or before the line to print. * * In fact, it returns when the chosen "p" equals "back". This * implies that there exists a string is least half as long as * (back - front), which in turn implies that a linear search will * be no more expensive than the cost of simply printing a string or two. * * Trying to continue with binary search at this point would be * more trouble than it's worth. */ #define SKIP_PAST_NEWLINE(p, back) \ while (p < back && *p++ != '\n'); static char * binary_search(wchar_t *string, unsigned char *front, unsigned char *back) { unsigned char *p; p = front + (back - front) / 2; SKIP_PAST_NEWLINE(p, back); /* * If the file changes underneath us, make sure we don't * infinitely loop. */ while (p < back && back > front) { if (compare(string, p, back) == GREATER) front = p; else back = p; p = front + (back - front) / 2; SKIP_PAST_NEWLINE(p, back); } return (front); } /* * Find the first line that starts with string, linearly searching from front * to back. * * Return NULL for no such line. * * This routine assumes: * * o front points at the first character in a line. * o front is before or at the first line to be printed. */ static char * linear_search(wchar_t *string, unsigned char *front, unsigned char *back) { while (front < back) { switch (compare(string, front, back)) { case EQUAL: /* Found it. */ return (front); case LESS: /* No such string. */ return (NULL); case GREATER: /* Keep going. */ break; } SKIP_PAST_NEWLINE(front, back); } return (NULL); } /* * Print as many lines as match string, starting at front. */ static void print_from(wchar_t *string, unsigned char *front, unsigned char *back) { for (; front < back && compare(string, front, back) == EQUAL; ++front) { for (; front < back && *front != '\n'; ++front) if (putchar(*front) == EOF) err(2, "stdout"); if (putchar('\n') == EOF) err(2, "stdout"); } } /* * Return LESS, GREATER, or EQUAL depending on how the string1 compares with * string2 (s1 ??? s2). * * o Matches up to len(s1) are EQUAL. * o Matches up to len(s2) are GREATER. * * Compare understands about the -f and -d flags, and treats comparisons * appropriately. * * The string "s1" is null terminated. The string s2 is '\n' terminated (or * "back" terminated). */ static int compare(wchar_t *s1, unsigned char *s2, unsigned char *back) { wchar_t ch1, ch2; size_t len2; for (; *s1 && s2 < back && *s2 != '\n'; ++s1, s2 += len2) { ch1 = *s1; len2 = mbrtowc(&ch2, s2, back - s2, NULL); if (len2 == (size_t)-1 || len2 == (size_t)-2) { ch2 = *s2; len2 = 1; } if (fflag) ch2 = towlower(ch2); if (dflag && !iswalnum(ch2)) { /* Ignore character in comparison. */ --s1; continue; } if (ch1 != ch2) return (ch1 < ch2 ? LESS : GREATER); } return (*s1 ? GREATER : EQUAL); } static void usage(void) { (void)fprintf(stderr, "usage: look [-df] [-t char] string [file ...]\n"); exit(2); }