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