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