gen_subs.c revision 7165
1/*- 2 * Copyright (c) 1992 Keith Muller. 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Keith Muller of the University of California, San Diego. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * $Id: gen_subs.c,v 1.2 1994/09/24 02:56:22 davidg Exp $ 38 */ 39 40#ifndef lint 41static char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93"; 42#endif /* not lint */ 43 44#include <sys/types.h> 45#include <sys/time.h> 46#include <sys/stat.h> 47#include <sys/param.h> 48#include <stdio.h> 49#include <ctype.h> 50#include <tzfile.h> 51#include <utmp.h> 52#include <unistd.h> 53#include <stdlib.h> 54#include <string.h> 55#include "pax.h" 56#include "extern.h" 57 58/* 59 * a collection of general purpose subroutines used by pax 60 */ 61 62/* 63 * constants used by ls_list() when printing out archive members 64 */ 65#define MODELEN 20 66#define DATELEN 64 67#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) 68#define CURFRMT "%b %e %H:%M" 69#define OLDFRMT "%b %e %Y" 70#ifndef UT_NAMESIZE 71#define UT_NAMESIZE 8 72#endif 73#define UT_GRPSIZE 6 74 75/* 76 * ls_list() 77 * list the members of an archive in ls format 78 */ 79 80#if __STDC__ 81void 82ls_list(register ARCHD *arcn, time_t now) 83#else 84void 85ls_list(arcn, now) 86 register ARCHD *arcn; 87 time_t now; 88#endif 89{ 90 register struct stat *sbp; 91 char f_mode[MODELEN]; 92 char f_date[DATELEN]; 93 char *timefrmt; 94 95 /* 96 * if not verbose, just print the file name 97 */ 98 if (!vflag) { 99 (void)printf("%s\n", arcn->name); 100 (void)fflush(stdout); 101 return; 102 } 103 104 /* 105 * user wants long mode 106 */ 107 sbp = &(arcn->sb); 108 strmode(sbp->st_mode, f_mode); 109 110 if (ltmfrmt == NULL) { 111 /* 112 * no locale specified format. time format based on age 113 * compared to the time pax was started. 114 */ 115 if ((sbp->st_mtime + SIXMONTHS) <= now) 116 timefrmt = OLDFRMT; 117 else 118 timefrmt = CURFRMT; 119 } else 120 timefrmt = ltmfrmt; 121 122 /* 123 * print file mode, link count, uid, gid and time 124 */ 125 if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0) 126 f_date[0] = '\0'; 127 (void)printf("%s%2u %-*s %-*s ", f_mode, sbp->st_nlink, UT_NAMESIZE, 128 name_uid(sbp->st_uid, 1), UT_GRPSIZE, 129 name_gid(sbp->st_gid, 1)); 130 131 /* 132 * print device id's for devices, or sizes for other nodes 133 */ 134 if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) 135# ifdef NET2_STAT 136 (void)printf("%4u,%4u ", MAJOR(sbp->st_rdev), 137# else 138 (void)printf("%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), 139# endif 140 MINOR(sbp->st_rdev)); 141 else { 142# ifdef NET2_STAT 143 (void)printf("%9lu ", sbp->st_size); 144# else 145 (void)printf("%9qu ", sbp->st_size); 146# endif 147 } 148 149 /* 150 * print name and link info for hard and soft links 151 */ 152 (void)printf("%s %s", f_date, arcn->name); 153 if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 154 (void)printf(" == %s\n", arcn->ln_name); 155 else if (arcn->type == PAX_SLK) 156 (void)printf(" => %s\n", arcn->ln_name); 157 else 158 (void)putchar('\n'); 159 (void)fflush(stdout); 160 return; 161} 162 163/* 164 * tty_ls() 165 * print a short summary of file to tty. 166 */ 167 168#if __STDC__ 169void 170ls_tty(register ARCHD *arcn) 171#else 172void 173ls_tty(arcn) 174 register ARCHD *arcn; 175#endif 176{ 177 char f_date[DATELEN]; 178 char f_mode[MODELEN]; 179 char *timefrmt; 180 181 if (ltmfrmt == NULL) { 182 /* 183 * no locale specified format 184 */ 185 if ((arcn->sb.st_mtime + SIXMONTHS) <= time((time_t *)NULL)) 186 timefrmt = OLDFRMT; 187 else 188 timefrmt = CURFRMT; 189 } else 190 timefrmt = ltmfrmt; 191 192 /* 193 * convert time to string, and print 194 */ 195 if (strftime(f_date, DATELEN, timefrmt, 196 localtime(&(arcn->sb.st_mtime))) == 0) 197 f_date[0] = '\0'; 198 strmode(arcn->sb.st_mode, f_mode); 199 tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name); 200 return; 201} 202 203/* 204 * zf_strncpy() 205 * copy src to dest up to len chars (stopping at first '\0'), when src is 206 * shorter than len, pads to len with '\0'. big performance win (and 207 * a lot easier to code) over strncpy(), then a strlen() then a 208 * bzero(). (or doing the bzero() first). 209 */ 210 211#if __STDC__ 212void 213zf_strncpy(register char *dest, register char *src, int len) 214#else 215void 216zf_strncpy(dest, src, len) 217 register char *dest; 218 register char *src; 219 int len; 220#endif 221{ 222 register char *stop; 223 224 stop = dest + len; 225 while ((dest < stop) && (*src != '\0')) 226 *dest++ = *src++; 227 while (dest < stop) 228 *dest++ = '\0'; 229 return; 230} 231 232/* 233 * l_strncpy() 234 * copy src to dest up to len chars (stopping at first '\0') 235 * Return: 236 * number of chars copied. (Note this is a real performance win over 237 * doing a strncpy() then a strlen() 238 */ 239 240#if __STDC__ 241int 242l_strncpy(register char *dest, register char *src, int len) 243#else 244int 245l_strncpy(dest, src, len) 246 register char *dest; 247 register char *src; 248 int len; 249#endif 250{ 251 register char *stop; 252 register char *start; 253 254 stop = dest + len; 255 start = dest; 256 while ((dest < stop) && (*src != '\0')) 257 *dest++ = *src++; 258 if (dest < stop) 259 *dest = '\0'; 260 return(dest - start); 261} 262 263/* 264 * asc_ul() 265 * convert hex/octal character string into a u_long. We do not have to 266 * check for overflow! (the headers in all supported formats are not large 267 * enough to create an overflow). 268 * NOTE: strings passed to us are NOT TERMINATED. 269 * Return: 270 * unsigned long value 271 */ 272 273#if __STDC__ 274u_long 275asc_ul(register char *str, int len, register int base) 276#else 277u_long 278asc_ul(str, len, base) 279 register char *str; 280 int len; 281 register int base; 282#endif 283{ 284 register char *stop; 285 u_long tval = 0; 286 287 stop = str + len; 288 289 /* 290 * skip over leading blanks and zeros 291 */ 292 while ((str < stop) && ((*str == ' ') || (*str == '0'))) 293 ++str; 294 295 /* 296 * for each valid digit, shift running value (tval) over to next digit 297 * and add next digit 298 */ 299 if (base == HEX) { 300 while (str < stop) { 301 if ((*str >= '0') && (*str <= '9')) 302 tval = (tval << 4) + (*str++ - '0'); 303 else if ((*str >= 'A') && (*str <= 'F')) 304 tval = (tval << 4) + 10 + (*str++ - 'A'); 305 else if ((*str >= 'a') && (*str <= 'f')) 306 tval = (tval << 4) + 10 + (*str++ - 'a'); 307 else 308 break; 309 } 310 } else { 311 while ((str < stop) && (*str >= '0') && (*str <= '7')) 312 tval = (tval << 3) + (*str++ - '0'); 313 } 314 return(tval); 315} 316 317/* 318 * ul_asc() 319 * convert an unsigned long into an hex/oct ascii string. pads with LEADING 320 * ascii 0's to fill string completely 321 * NOTE: the string created is NOT TERMINATED. 322 */ 323 324#if __STDC__ 325int 326ul_asc(u_long val, register char *str, register int len, register int base) 327#else 328int 329ul_asc(val, str, len, base) 330 u_long val; 331 register char *str; 332 register int len; 333 register int base; 334#endif 335{ 336 register char *pt; 337 u_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 if ((val = (val >> 4)) == (u_long)0) 356 break; 357 } 358 } else { 359 while (pt >= str) { 360 *pt-- = '0' + (char)(val & 0x7); 361 if ((val = (val >> 3)) == (u_long)0) 362 break; 363 } 364 } 365 366 /* 367 * pad with leading ascii ZEROS. We return -1 if we ran out of space. 368 */ 369 while (pt >= str) 370 *pt-- = '0'; 371 if (val != (u_long)0) 372 return(-1); 373 return(0); 374} 375 376#ifndef NET2_STAT 377/* 378 * asc_uqd() 379 * convert hex/octal character string into a u_quad_t. We do not have to 380 * check for overflow! (the headers in all supported formats are not large 381 * enough to create an overflow). 382 * NOTE: strings passed to us are NOT TERMINATED. 383 * Return: 384 * u_quad_t value 385 */ 386 387#if __STDC__ 388u_quad_t 389asc_uqd(register char *str, int len, register int base) 390#else 391u_quad_t 392asc_uqd(str, len, base) 393 register char *str; 394 int len; 395 register int base; 396#endif 397{ 398 register char *stop; 399 u_quad_t tval = 0; 400 401 stop = str + len; 402 403 /* 404 * skip over leading blanks and zeros 405 */ 406 while ((str < stop) && ((*str == ' ') || (*str == '0'))) 407 ++str; 408 409 /* 410 * for each valid digit, shift running value (tval) over to next digit 411 * and add next digit 412 */ 413 if (base == HEX) { 414 while (str < stop) { 415 if ((*str >= '0') && (*str <= '9')) 416 tval = (tval << 4) + (*str++ - '0'); 417 else if ((*str >= 'A') && (*str <= 'F')) 418 tval = (tval << 4) + 10 + (*str++ - 'A'); 419 else if ((*str >= 'a') && (*str <= 'f')) 420 tval = (tval << 4) + 10 + (*str++ - 'a'); 421 else 422 break; 423 } 424 } else { 425 while ((str < stop) && (*str >= '0') && (*str <= '7')) 426 tval = (tval << 3) + (*str++ - '0'); 427 } 428 return(tval); 429} 430 431/* 432 * uqd_asc() 433 * convert an u_quad_t into a hex/oct ascii string. pads with LEADING 434 * ascii 0's to fill string completely 435 * NOTE: the string created is NOT TERMINATED. 436 */ 437 438#if __STDC__ 439int 440uqd_asc(u_quad_t val, register char *str, register int len, register int base) 441#else 442int 443uqd_asc(val, str, len, base) 444 u_quad_t val; 445 register char *str; 446 register int len; 447 register int base; 448#endif 449{ 450 register char *pt; 451 u_quad_t digit; 452 453 /* 454 * WARNING str is not '\0' terminated by this routine 455 */ 456 pt = str + len - 1; 457 458 /* 459 * do a tailwise conversion (start at right most end of string to place 460 * least significant digit). Keep shifting until conversion value goes 461 * to zero (all digits were converted) 462 */ 463 if (base == HEX) { 464 while (pt >= str) { 465 if ((digit = (val & 0xf)) < 10) 466 *pt-- = '0' + (char)digit; 467 else 468 *pt-- = 'a' + (char)(digit - 10); 469 if ((val = (val >> 4)) == (u_quad_t)0) 470 break; 471 } 472 } else { 473 while (pt >= str) { 474 *pt-- = '0' + (char)(val & 0x7); 475 if ((val = (val >> 3)) == (u_quad_t)0) 476 break; 477 } 478 } 479 480 /* 481 * pad with leading ascii ZEROS. We return -1 if we ran out of space. 482 */ 483 while (pt >= str) 484 *pt-- = '0'; 485 if (val != (u_quad_t)0) 486 return(-1); 487 return(0); 488} 489#endif 490