1 /* $OpenBSD: gen_subs.c,v 1.20 2009/10/27 23:59:22 deraadt 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/time.h> 39 #include <sys/stat.h> 40 #include <sys/param.h> 41 #include <stdio.h> 42 #include <tzfile.h> 43 #include <utmp.h> 44 #include <unistd.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <vis.h> 48 #include "pax.h" 49 #include "extern.h" 50 51 /* 52 * a collection of general purpose subroutines used by pax 53 */ 54 55 /* 56 * constants used by ls_list() when printing out archive members 57 */ 58 #define MODELEN 20 59 #define DATELEN 64 60 #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) 61 #define CURFRMT "%b %e %H:%M" 62 #define OLDFRMT "%b %e %Y" 63 #define NAME_WIDTH 8 64 65 /* 66 * ls_list() 67 * list the members of an archive in ls format 68 */ 69 70 void 71 ls_list(ARCHD *arcn, time_t now, FILE *fp) 72 { 73 struct stat *sbp; 74 char f_mode[MODELEN]; 75 char f_date[DATELEN]; 76 const char *timefrmt; 77 int term; 78 79 term = zeroflag ? '\0' : '\n'; /* path termination character */ 80 81 /* 82 * if not verbose, just print the file name 83 */ 84 if (!vflag) { 85 if (zeroflag) 86 (void)fputs(arcn->name, fp); 87 else 88 safe_print(arcn->name, fp); 89 (void)putc(term, fp); 90 (void)fflush(fp); 91 return; 92 } 93 94 /* 95 * user wants long mode 96 */ 97 sbp = &(arcn->sb); 98 strmode(sbp->st_mode, f_mode); 99 100 if (ltmfrmt == NULL) { 101 /* 102 * no locale specified format. time format based on age 103 * compared to the time pax was started. 104 */ 105 if ((sbp->st_mtime + SIXMONTHS) <= now) 106 timefrmt = OLDFRMT; 107 else 108 timefrmt = CURFRMT; 109 } else 110 timefrmt = ltmfrmt; 111 112 /* 113 * print file mode, link count, uid, gid and time 114 */ 115 if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0) 116 f_date[0] = '\0'; 117 (void)fprintf(fp, "%s%2u %-*.*s %-*.*s ", f_mode, sbp->st_nlink, 118 NAME_WIDTH, UT_NAMESIZE, name_uid(sbp->st_uid, 1), 119 NAME_WIDTH, UT_NAMESIZE, name_gid(sbp->st_gid, 1)); 120 121 /* 122 * print device id's for devices, or sizes for other nodes 123 */ 124 if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) 125 # ifdef LONG_OFF_T 126 (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev), 127 # else 128 (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), 129 # endif 130 (unsigned long)MINOR(sbp->st_rdev)); 131 else { 132 # ifdef LONG_OFF_T 133 (void)fprintf(fp, "%9lu ", sbp->st_size); 134 # else 135 (void)fprintf(fp, "%9qu ", sbp->st_size); 136 # endif 137 } 138 139 /* 140 * print name and link info for hard and soft links 141 */ 142 (void)fputs(f_date, fp); 143 (void)putc(' ', fp); 144 safe_print(arcn->name, fp); 145 if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { 146 fputs(" == ", fp); 147 safe_print(arcn->ln_name, fp); 148 } else if (arcn->type == PAX_SLK) { 149 fputs(" -> ", fp); 150 safe_print(arcn->ln_name, fp); 151 } 152 (void)putc(term, fp); 153 (void)fflush(fp); 154 return; 155 } 156 157 /* 158 * tty_ls() 159 * print a short summary of file to tty. 160 */ 161 162 void 163 ls_tty(ARCHD *arcn) 164 { 165 char f_date[DATELEN]; 166 char f_mode[MODELEN]; 167 const char *timefrmt; 168 169 if (ltmfrmt == NULL) { 170 /* 171 * no locale specified format 172 */ 173 if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL)) 174 timefrmt = OLDFRMT; 175 else 176 timefrmt = CURFRMT; 177 } else 178 timefrmt = ltmfrmt; 179 180 /* 181 * convert time to string, and print 182 */ 183 if (strftime(f_date, DATELEN, timefrmt, 184 localtime(&(arcn->sb.st_mtime))) == 0) 185 f_date[0] = '\0'; 186 strmode(arcn->sb.st_mode, f_mode); 187 tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name); 188 return; 189 } 190 191 void 192 safe_print(const char *str, FILE *fp) 193 { 194 char visbuf[5]; 195 const char *cp; 196 197 /* 198 * if printing to a tty, use vis(3) to print special characters. 199 */ 200 if (isatty(fileno(fp))) { 201 for (cp = str; *cp; cp++) { 202 (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]); 203 (void)fputs(visbuf, fp); 204 } 205 } else { 206 (void)fputs(str, fp); 207 } 208 } 209 210 /* 211 * asc_ul() 212 * convert hex/octal character string into a u_long. We do not have to 213 * check for overflow! (the headers in all supported formats are not large 214 * enough to create an overflow). 215 * NOTE: strings passed to us are NOT TERMINATED. 216 * Return: 217 * unsigned long value 218 */ 219 220 u_long 221 asc_ul(char *str, int len, int base) 222 { 223 char *stop; 224 u_long tval = 0; 225 226 stop = str + len; 227 228 /* 229 * skip over leading blanks and zeros 230 */ 231 while ((str < stop) && ((*str == ' ') || (*str == '0'))) 232 ++str; 233 234 /* 235 * for each valid digit, shift running value (tval) over to next digit 236 * and add next digit 237 */ 238 if (base == HEX) { 239 while (str < stop) { 240 if ((*str >= '0') && (*str <= '9')) 241 tval = (tval << 4) + (*str++ - '0'); 242 else if ((*str >= 'A') && (*str <= 'F')) 243 tval = (tval << 4) + 10 + (*str++ - 'A'); 244 else if ((*str >= 'a') && (*str <= 'f')) 245 tval = (tval << 4) + 10 + (*str++ - 'a'); 246 else 247 break; 248 } 249 } else { 250 while ((str < stop) && (*str >= '0') && (*str <= '7')) 251 tval = (tval << 3) + (*str++ - '0'); 252 } 253 return(tval); 254 } 255 256 /* 257 * ul_asc() 258 * convert an unsigned long into an hex/oct ascii string. pads with LEADING 259 * ascii 0's to fill string completely 260 * NOTE: the string created is NOT TERMINATED. 261 */ 262 263 int 264 ul_asc(u_long val, char *str, int len, int base) 265 { 266 char *pt; 267 u_long digit; 268 269 /* 270 * WARNING str is not '\0' terminated by this routine 271 */ 272 pt = str + len - 1; 273 274 /* 275 * do a tailwise conversion (start at right most end of string to place 276 * least significant digit). Keep shifting until conversion value goes 277 * to zero (all digits were converted) 278 */ 279 if (base == HEX) { 280 while (pt >= str) { 281 if ((digit = (val & 0xf)) < 10) 282 *pt-- = '0' + (char)digit; 283 else 284 *pt-- = 'a' + (char)(digit - 10); 285 if ((val = (val >> 4)) == (u_long)0) 286 break; 287 } 288 } else { 289 while (pt >= str) { 290 *pt-- = '0' + (char)(val & 0x7); 291 if ((val = (val >> 3)) == (u_long)0) 292 break; 293 } 294 } 295 296 /* 297 * pad with leading ascii ZEROS. We return -1 if we ran out of space. 298 */ 299 while (pt >= str) 300 *pt-- = '0'; 301 if (val != (u_long)0) 302 return(-1); 303 return(0); 304 } 305 306 #ifndef LONG_OFF_T 307 /* 308 * asc_uqd() 309 * convert hex/octal character string into a u_quad_t. We do not have to 310 * check for overflow! (the headers in all supported formats are not large 311 * enough to create an overflow). 312 * NOTE: strings passed to us are NOT TERMINATED. 313 * Return: 314 * u_quad_t value 315 */ 316 317 u_quad_t 318 asc_uqd(char *str, int len, int base) 319 { 320 char *stop; 321 u_quad_t tval = 0; 322 323 stop = str + len; 324 325 /* 326 * skip over leading blanks and zeros 327 */ 328 while ((str < stop) && ((*str == ' ') || (*str == '0'))) 329 ++str; 330 331 /* 332 * for each valid digit, shift running value (tval) over to next digit 333 * and add next digit 334 */ 335 if (base == HEX) { 336 while (str < stop) { 337 if ((*str >= '0') && (*str <= '9')) 338 tval = (tval << 4) + (*str++ - '0'); 339 else if ((*str >= 'A') && (*str <= 'F')) 340 tval = (tval << 4) + 10 + (*str++ - 'A'); 341 else if ((*str >= 'a') && (*str <= 'f')) 342 tval = (tval << 4) + 10 + (*str++ - 'a'); 343 else 344 break; 345 } 346 } else { 347 while ((str < stop) && (*str >= '0') && (*str <= '7')) 348 tval = (tval << 3) + (*str++ - '0'); 349 } 350 return(tval); 351 } 352 353 /* 354 * uqd_asc() 355 * convert an u_quad_t into a hex/oct ascii string. pads with LEADING 356 * ascii 0's to fill string completely 357 * NOTE: the string created is NOT TERMINATED. 358 */ 359 360 int 361 uqd_asc(u_quad_t val, char *str, int len, int base) 362 { 363 char *pt; 364 u_quad_t digit; 365 366 /* 367 * WARNING str is not '\0' terminated by this routine 368 */ 369 pt = str + len - 1; 370 371 /* 372 * do a tailwise conversion (start at right most end of string to place 373 * least significant digit). Keep shifting until conversion value goes 374 * to zero (all digits were converted) 375 */ 376 if (base == HEX) { 377 while (pt >= str) { 378 if ((digit = (val & 0xf)) < 10) 379 *pt-- = '0' + (char)digit; 380 else 381 *pt-- = 'a' + (char)(digit - 10); 382 if ((val = (val >> 4)) == (u_quad_t)0) 383 break; 384 } 385 } else { 386 while (pt >= str) { 387 *pt-- = '0' + (char)(val & 0x7); 388 if ((val = (val >> 3)) == (u_quad_t)0) 389 break; 390 } 391 } 392 393 /* 394 * pad with leading ascii ZEROS. We return -1 if we ran out of space. 395 */ 396 while (pt >= str) 397 *pt-- = '0'; 398 if (val != (u_quad_t)0) 399 return(-1); 400 return(0); 401 } 402 #endif 403 404 /* 405 * Copy at max min(bufz, fieldsz) chars from field to buf, stopping 406 * at the first NUL char. NUL terminate buf if there is room left. 407 */ 408 size_t 409 fieldcpy(char *buf, size_t bufsz, const char *field, size_t fieldsz) 410 { 411 char *p = buf; 412 const char *q = field; 413 size_t i = 0; 414 415 if (fieldsz > bufsz) 416 fieldsz = bufsz; 417 while (i < fieldsz && *q != '\0') { 418 *p++ = *q++; 419 i++; 420 } 421 if (i < bufsz) 422 *p = '\0'; 423 return(i); 424 } 425