1 /* 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1987, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/capsicum.h> 33 #include <sys/types.h> 34 35 #include <capsicum_helpers.h> 36 #include <ctype.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <getopt.h> 40 #include <inttypes.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include <libutil.h> 47 48 #include <libcasper.h> 49 #include <casper/cap_fileargs.h> 50 51 /* 52 * head - give the first few lines of a stream or of each of a set of files 53 * 54 * Bill Joy UCB August 24, 1977 55 */ 56 57 static void head(FILE *, intmax_t); 58 static void head_bytes(FILE *, off_t); 59 static void obsolete(char *[]); 60 static void usage(void) __dead2; 61 62 static const struct option long_opts[] = 63 { 64 {"bytes", required_argument, NULL, 'c'}, 65 {"lines", required_argument, NULL, 'n'}, 66 {"quiet", no_argument, NULL, 'q'}, 67 {"silent", no_argument, NULL, 'q'}, 68 {"verbose", no_argument, NULL, 'v'}, 69 {NULL, no_argument, NULL, 0} 70 }; 71 72 int 73 main(int argc, char *argv[]) 74 { 75 FILE *fp; 76 off_t bytecnt; 77 intmax_t linecnt; 78 int ch, first, eval; 79 fileargs_t *fa; 80 cap_rights_t rights; 81 int qflag = 0; 82 int vflag = 0; 83 84 linecnt = -1; 85 eval = 0; 86 bytecnt = -1; 87 88 obsolete(argv); 89 while ((ch = getopt_long(argc, argv, "+n:c:qv", long_opts, NULL)) != -1) { 90 switch(ch) { 91 case 'c': 92 if (expand_number(optarg, &bytecnt) || bytecnt <= 0) 93 errx(1, "illegal byte count -- %s", optarg); 94 break; 95 case 'n': 96 if (expand_number(optarg, &linecnt) || linecnt <= 0) 97 errx(1, "illegal line count -- %s", optarg); 98 break; 99 case 'q': 100 qflag = 1; 101 vflag = 0; 102 break; 103 case 'v': 104 qflag = 0; 105 vflag = 1; 106 break; 107 case '?': 108 default: 109 usage(); 110 /* NOTREACHED */ 111 } 112 } 113 argc -= optind; 114 argv += optind; 115 116 fa = fileargs_init(argc, argv, O_RDONLY, 0, 117 cap_rights_init(&rights, CAP_READ, CAP_FSTAT, CAP_FCNTL), FA_OPEN); 118 if (fa == NULL) 119 err(1, "unable to init casper"); 120 121 caph_cache_catpages(); 122 if (caph_limit_stdio() < 0 || caph_enter_casper() < 0) 123 err(1, "unable to enter capability mode"); 124 125 if (linecnt != -1 && bytecnt != -1) 126 errx(1, "can't combine line and byte counts"); 127 if (linecnt == -1) 128 linecnt = 10; 129 if (*argv != NULL) { 130 for (first = 1; *argv != NULL; ++argv) { 131 if ((fp = fileargs_fopen(fa, *argv, "r")) == NULL) { 132 warn("%s", *argv); 133 eval = 1; 134 continue; 135 } 136 if (vflag || (qflag == 0 && argc > 1)) { 137 (void)printf("%s==> %s <==\n", 138 first ? "" : "\n", *argv); 139 first = 0; 140 } 141 if (bytecnt == -1) 142 head(fp, linecnt); 143 else 144 head_bytes(fp, bytecnt); 145 (void)fclose(fp); 146 } 147 } else if (bytecnt == -1) 148 head(stdin, linecnt); 149 else 150 head_bytes(stdin, bytecnt); 151 152 fileargs_free(fa); 153 exit(eval); 154 } 155 156 static void 157 head(FILE *fp, intmax_t cnt) 158 { 159 char *cp = NULL; 160 size_t error, bufsize = 0; 161 ssize_t readlen; 162 163 while (cnt != 0 && (readlen = getline(&cp, &bufsize, fp)) >= 0) { 164 error = fwrite(cp, sizeof(char), readlen, stdout); 165 if ((ssize_t)error != readlen) 166 err(1, "stdout"); 167 cnt--; 168 } 169 } 170 171 static void 172 head_bytes(FILE *fp, off_t cnt) 173 { 174 char buf[4096]; 175 size_t readlen; 176 177 while (cnt) { 178 if ((uintmax_t)cnt < sizeof(buf)) 179 readlen = cnt; 180 else 181 readlen = sizeof(buf); 182 readlen = fread(buf, sizeof(char), readlen, fp); 183 if (readlen == 0) 184 break; 185 if (fwrite(buf, sizeof(char), readlen, stdout) != readlen) 186 err(1, "stdout"); 187 cnt -= readlen; 188 } 189 } 190 191 static void 192 obsolete(char *argv[]) 193 { 194 char *ap; 195 196 while ((ap = *++argv)) { 197 /* Return if "--" or not "-[0-9]*". */ 198 if (ap[0] != '-' || ap[1] == '-' || !isdigit(ap[1])) 199 return; 200 if ((ap = malloc(strlen(*argv) + 2)) == NULL) 201 err(1, NULL); 202 ap[0] = '-'; 203 ap[1] = 'n'; 204 (void)strcpy(ap + 2, *argv + 1); 205 *argv = ap; 206 } 207 } 208 209 static void 210 usage(void) 211 { 212 213 (void)fprintf(stderr, "usage: head [-n lines | -c bytes] [file ...]\n"); 214 exit(1); 215 } 216