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