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