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