1 /* $OpenBSD: gen_subs.c,v 1.32 2016/08/26 05:06:14 guenther Exp $ */ 2 /* $NetBSD: gen_subs.c,v 1.5 1995/03/21 09:07:26 cgd Exp $ */ 3 4 /*- 5 * Copyright (c) 1992 Keith Muller. 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Keith Muller of the University of California, San Diego. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <grp.h> 40 #include <pwd.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <time.h> 45 #include <unistd.h> 46 #include <utmp.h> 47 #include <vis.h> 48 49 #include "pax.h" 50 #include "extern.h" 51 52 /* 53 * a collection of general purpose subroutines used by pax 54 */ 55 56 /* 57 * constants used by ls_list() when printing out archive members 58 */ 59 #define MODELEN 20 60 #define DATELEN 64 61 #define SECSPERDAY (24 * 60 * 60) 62 #define SIXMONTHS (SECSPERDAY * 365 / 2) 63 #define CURFRMT "%b %e %H:%M" 64 #define OLDFRMT "%b %e %Y" 65 #define NAME_WIDTH 8 66 #define TIMEFMT(t, now) \ 67 (((t) + SIXMONTHS <= (now) || (t) > (now)) ? OLDFRMT : CURFRMT) 68 69 /* 70 * ls_list() 71 * list the members of an archive in ls format 72 */ 73 74 void 75 ls_list(ARCHD *arcn, time_t now, FILE *fp) 76 { 77 struct stat *sbp; 78 char f_mode[MODELEN]; 79 char f_date[DATELEN]; 80 int term; 81 82 term = zeroflag ? '\0' : '\n'; /* path termination character */ 83 84 /* 85 * if not verbose, just print the file name 86 */ 87 if (!vflag) { 88 if (zeroflag) 89 (void)fputs(arcn->name, fp); 90 else 91 safe_print(arcn->name, fp); 92 (void)putc(term, fp); 93 (void)fflush(fp); 94 return; 95 } 96 97 /* 98 * user wants long mode 99 */ 100 sbp = &(arcn->sb); 101 strmode(sbp->st_mode, f_mode); 102 103 /* 104 * print file mode, link count, uid, gid and time 105 */ 106 if (strftime(f_date, sizeof(f_date), TIMEFMT(sbp->st_mtime, now), 107 localtime(&(sbp->st_mtime))) == 0) 108 f_date[0] = '\0'; 109 (void)fprintf(fp, "%s%2u %-*.*s %-*.*s ", f_mode, sbp->st_nlink, 110 NAME_WIDTH, UT_NAMESIZE, user_from_uid(sbp->st_uid, 0), 111 NAME_WIDTH, UT_NAMESIZE, group_from_gid(sbp->st_gid, 0)); 112 113 /* 114 * print device id's for devices, or sizes for other nodes 115 */ 116 if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) 117 (void)fprintf(fp, "%4lu, %4lu ", 118 (unsigned long)MAJOR(sbp->st_rdev), 119 (unsigned long)MINOR(sbp->st_rdev)); 120 else { 121 (void)fprintf(fp, "%9llu ", sbp->st_size); 122 } 123 124 /* 125 * print name and link info for hard and soft links 126 */ 127 (void)fputs(f_date, fp); 128 (void)putc(' ', fp); 129 safe_print(arcn->name, fp); 130 if (PAX_IS_HARDLINK(arcn->type)) { 131 fputs(" == ", fp); 132 safe_print(arcn->ln_name, fp); 133 } else if (arcn->type == PAX_SLK) { 134 fputs(" -> ", fp); 135 safe_print(arcn->ln_name, fp); 136 } 137 (void)putc(term, fp); 138 (void)fflush(fp); 139 } 140 141 /* 142 * tty_ls() 143 * print a short summary of file to tty. 144 */ 145 146 void 147 ls_tty(ARCHD *arcn) 148 { 149 char f_date[DATELEN]; 150 char f_mode[MODELEN]; 151 time_t now = time(NULL); 152 153 /* 154 * convert time to string, and print 155 */ 156 if (strftime(f_date, DATELEN, TIMEFMT(arcn->sb.st_mtime, now), 157 localtime(&(arcn->sb.st_mtime))) == 0) 158 f_date[0] = '\0'; 159 strmode(arcn->sb.st_mode, f_mode); 160 tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name); 161 } 162 163 void 164 safe_print(const char *str, FILE *fp) 165 { 166 char visbuf[5]; 167 const char *cp; 168 169 /* 170 * if printing to a tty, use vis(3) to print special characters. 171 */ 172 if (isatty(fileno(fp))) { 173 for (cp = str; *cp; cp++) { 174 (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]); 175 (void)fputs(visbuf, fp); 176 } 177 } else { 178 (void)fputs(str, fp); 179 } 180 } 181 182 /* 183 * asc_ul() 184 * convert hex/octal character string into a u_long. We do not have to 185 * check for overflow! (the headers in all supported formats are not large 186 * enough to create an overflow). 187 * NOTE: strings passed to us are NOT TERMINATED. 188 * Return: 189 * unsigned long value 190 */ 191 192 u_long 193 asc_ul(char *str, int len, int base) 194 { 195 char *stop; 196 u_long tval = 0; 197 198 stop = str + len; 199 200 /* 201 * skip over leading blanks and zeros 202 */ 203 while ((str < stop) && ((*str == ' ') || (*str == '0'))) 204 ++str; 205 206 /* 207 * for each valid digit, shift running value (tval) over to next digit 208 * and add next digit 209 */ 210 if (base == HEX) { 211 while (str < stop) { 212 if ((*str >= '0') && (*str <= '9')) 213 tval = (tval << 4) + (*str++ - '0'); 214 else if ((*str >= 'A') && (*str <= 'F')) 215 tval = (tval << 4) + 10 + (*str++ - 'A'); 216 else if ((*str >= 'a') && (*str <= 'f')) 217 tval = (tval << 4) + 10 + (*str++ - 'a'); 218 else 219 break; 220 } 221 } else { 222 while ((str < stop) && (*str >= '0') && (*str <= '7')) 223 tval = (tval << 3) + (*str++ - '0'); 224 } 225 return(tval); 226 } 227 228 /* 229 * ul_asc() 230 * convert an unsigned long into an hex/oct ascii string. pads with LEADING 231 * ascii 0's to fill string completely 232 * NOTE: the string created is NOT TERMINATED. 233 */ 234 235 int 236 ul_asc(u_long val, char *str, int len, int base) 237 { 238 char *pt; 239 u_long digit; 240 241 /* 242 * WARNING str is not '\0' terminated by this routine 243 */ 244 pt = str + len - 1; 245 246 /* 247 * do a tailwise conversion (start at right most end of string to place 248 * least significant digit). Keep shifting until conversion value goes 249 * to zero (all digits were converted) 250 */ 251 if (base == HEX) { 252 while (pt >= str) { 253 if ((digit = (val & 0xf)) < 10) 254 *pt-- = '0' + (char)digit; 255 else 256 *pt-- = 'a' + (char)(digit - 10); 257 val >>= 4; 258 if (val == 0) 259 break; 260 } 261 } else { 262 while (pt >= str) { 263 *pt-- = '0' + (char)(val & 0x7); 264 val >>= 3; 265 if (val == 0) 266 break; 267 } 268 } 269 270 /* 271 * pad with leading ascii ZEROS. We return -1 if we ran out of space. 272 */ 273 while (pt >= str) 274 *pt-- = '0'; 275 if (val != 0) 276 return(-1); 277 return(0); 278 } 279 280 /* 281 * asc_ull() 282 * Convert hex/octal character string into a unsigned long long. 283 * We do not have to check for overflow! (The headers in all 284 * supported formats are not large enough to create an overflow). 285 * NOTE: strings passed to us are NOT TERMINATED. 286 * Return: 287 * unsigned long long value 288 */ 289 290 unsigned long long 291 asc_ull(char *str, int len, int base) 292 { 293 char *stop; 294 unsigned long long tval = 0; 295 296 stop = str + len; 297 298 /* 299 * skip over leading blanks and zeros 300 */ 301 while ((str < stop) && ((*str == ' ') || (*str == '0'))) 302 ++str; 303 304 /* 305 * for each valid digit, shift running value (tval) over to next digit 306 * and add next digit 307 */ 308 if (base == HEX) { 309 while (str < stop) { 310 if ((*str >= '0') && (*str <= '9')) 311 tval = (tval << 4) + (*str++ - '0'); 312 else if ((*str >= 'A') && (*str <= 'F')) 313 tval = (tval << 4) + 10 + (*str++ - 'A'); 314 else if ((*str >= 'a') && (*str <= 'f')) 315 tval = (tval << 4) + 10 + (*str++ - 'a'); 316 else 317 break; 318 } 319 } else { 320 while ((str < stop) && (*str >= '0') && (*str <= '7')) 321 tval = (tval << 3) + (*str++ - '0'); 322 } 323 return(tval); 324 } 325 326 /* 327 * ull_asc() 328 * Convert an unsigned long long into a hex/oct ascii string. 329 * Pads with LEADING ascii 0's to fill string completely 330 * NOTE: the string created is NOT TERMINATED. 331 */ 332 333 int 334 ull_asc(unsigned long long val, char *str, int len, int base) 335 { 336 char *pt; 337 unsigned long long digit; 338 339 /* 340 * WARNING str is not '\0' terminated by this routine 341 */ 342 pt = str + len - 1; 343 344 /* 345 * do a tailwise conversion (start at right most end of string to place 346 * least significant digit). Keep shifting until conversion value goes 347 * to zero (all digits were converted) 348 */ 349 if (base == HEX) { 350 while (pt >= str) { 351 if ((digit = (val & 0xf)) < 10) 352 *pt-- = '0' + (char)digit; 353 else 354 *pt-- = 'a' + (char)(digit - 10); 355 val >>= 4; 356 if (val == 0) 357 break; 358 } 359 } else { 360 while (pt >= str) { 361 *pt-- = '0' + (char)(val & 0x7); 362 val >>= 3; 363 if (val == 0) 364 break; 365 } 366 } 367 368 /* 369 * pad with leading ascii ZEROS. We return -1 if we ran out of space. 370 */ 371 while (pt >= str) 372 *pt-- = '0'; 373 if (val != 0) 374 return(-1); 375 return(0); 376 } 377 378 /* 379 * Copy at max min(bufz, fieldsz) chars from field to buf, stopping 380 * at the first NUL char. NUL terminate buf if there is room left. 381 */ 382 size_t 383 fieldcpy(char *buf, size_t bufsz, const char *field, size_t fieldsz) 384 { 385 char *p = buf; 386 const char *q = field; 387 size_t i = 0; 388 389 if (fieldsz > bufsz) 390 fieldsz = bufsz; 391 while (i < fieldsz && *q != '\0') { 392 *p++ = *q++; 393 i++; 394 } 395 if (i < bufsz) 396 *p = '\0'; 397 return(i); 398 } 399