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 40 static char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93"; 41 #endif 42 static const char rcsid[] = 43 "$Id$"; 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 "%b %e %H:%M" 68 #define OLDFRMT "%b %e %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__ 80 void 81 ls_list(register ARCHD *arcn, time_t now) 82 #else 83 void 84 ls_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 if (ltmfrmt == NULL) { 110 /* 111 * no locale specified format. time format based on age 112 * compared to the time pax was started. 113 */ 114 if ((sbp->st_mtime + SIXMONTHS) <= now) 115 timefrmt = OLDFRMT; 116 else 117 timefrmt = CURFRMT; 118 } else 119 timefrmt = ltmfrmt; 120 121 /* 122 * print file mode, link count, uid, gid and time 123 */ 124 if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0) 125 f_date[0] = '\0'; 126 (void)printf("%s%2u %-*s %-*s ", f_mode, sbp->st_nlink, UT_NAMESIZE, 127 name_uid(sbp->st_uid, 1), UT_GRPSIZE, 128 name_gid(sbp->st_gid, 1)); 129 130 /* 131 * print device id's for devices, or sizes for other nodes 132 */ 133 if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) 134 # ifdef NET2_STAT 135 (void)printf("%4u,%4u ", MAJOR(sbp->st_rdev), 136 MINOR(sbp->st_rdev)); 137 # else 138 (void)printf("%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), 139 (unsigned long)MINOR(sbp->st_rdev)); 140 # endif 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__ 169 void 170 ls_tty(register ARCHD *arcn) 171 #else 172 void 173 ls_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__ 212 void 213 zf_strncpy(register char *dest, register char *src, int len) 214 #else 215 void 216 zf_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__ 241 int 242 l_strncpy(register char *dest, register char *src, int len) 243 #else 244 int 245 l_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__ 274 u_long 275 asc_ul(register char *str, int len, register int base) 276 #else 277 u_long 278 asc_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__ 325 int 326 ul_asc(u_long val, register char *str, register int len, register int base) 327 #else 328 int 329 ul_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__ 388 u_quad_t 389 asc_uqd(register char *str, int len, register int base) 390 #else 391 u_quad_t 392 asc_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__ 439 int 440 uqd_asc(u_quad_t val, register char *str, register int len, register int base) 441 #else 442 int 443 uqd_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