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