11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1992 Keith Muller. 31556Srgrimes * Copyright (c) 1992, 1993 41556Srgrimes * The Regents of the University of California. All rights reserved. 51556Srgrimes * 61556Srgrimes * This code is derived from software contributed to Berkeley by 71556Srgrimes * Keith Muller of the University of California, San Diego. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3536049Scharnier#if 0 3636049Scharnierstatic char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93"; 3736049Scharnier#endif 381556Srgrimes#endif /* not lint */ 3999110Sobrien#include <sys/cdefs.h> 4099110Sobrien__FBSDID("$FreeBSD$"); 411556Srgrimes 421556Srgrimes#include <sys/types.h> 431556Srgrimes#include <sys/time.h> 441556Srgrimes#include <sys/stat.h> 4574567Sache#include <langinfo.h> 46104548Stjr#include <stdint.h> 471556Srgrimes#include <stdio.h> 481556Srgrimes#include <string.h> 491556Srgrimes#include "pax.h" 501556Srgrimes#include "extern.h" 511556Srgrimes 521556Srgrimes/* 531556Srgrimes * a collection of general purpose subroutines used by pax 541556Srgrimes */ 551556Srgrimes 561556Srgrimes/* 571556Srgrimes * constants used by ls_list() when printing out archive members 581556Srgrimes */ 591556Srgrimes#define MODELEN 20 601556Srgrimes#define DATELEN 64 619987Swollman#define SIXMONTHS ((365 / 2) * 86400) 6274567Sache#define CURFRMTM "%b %e %H:%M" 6374567Sache#define OLDFRMTM "%b %e %Y" 6474567Sache#define CURFRMTD "%e %b %H:%M" 6574567Sache#define OLDFRMTD "%e %b %Y" 661556Srgrimes 6774567Sachestatic int d_first = -1; 6874567Sache 691556Srgrimes/* 701556Srgrimes * ls_list() 711556Srgrimes * list the members of an archive in ls format 721556Srgrimes */ 731556Srgrimes 741556Srgrimesvoid 7590113Simpls_list(ARCHD *arcn, time_t now, FILE *fp) 761556Srgrimes{ 7790113Simp struct stat *sbp; 781556Srgrimes char f_mode[MODELEN]; 791556Srgrimes char f_date[DATELEN]; 80114583Smarkm const char *timefrmt; 811556Srgrimes 821556Srgrimes /* 831556Srgrimes * if not verbose, just print the file name 841556Srgrimes */ 851556Srgrimes if (!vflag) { 8676351Skris (void)fprintf(fp, "%s\n", arcn->name); 8776351Skris (void)fflush(fp); 881556Srgrimes return; 891556Srgrimes } 901556Srgrimes 9174567Sache if (d_first < 0) 9274567Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 931556Srgrimes /* 941556Srgrimes * user wants long mode 951556Srgrimes */ 961556Srgrimes sbp = &(arcn->sb); 971556Srgrimes strmode(sbp->st_mode, f_mode); 981556Srgrimes 9973345Sru /* 10073345Sru * time format based on age compared to the time pax was started. 10173345Sru */ 10273345Sru if ((sbp->st_mtime + SIXMONTHS) <= now) 10374567Sache timefrmt = d_first ? OLDFRMTD : OLDFRMTM; 10473345Sru else 10574567Sache timefrmt = d_first ? CURFRMTD : CURFRMTM; 1061556Srgrimes 1071556Srgrimes /* 1081556Srgrimes * print file mode, link count, uid, gid and time 1091556Srgrimes */ 1101556Srgrimes if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0) 1111556Srgrimes f_date[0] = '\0'; 112202193Sed (void)fprintf(fp, "%s%2u %-12s %-12s ", f_mode, sbp->st_nlink, 113202193Sed name_uid(sbp->st_uid, 1), name_gid(sbp->st_gid, 1)); 1141556Srgrimes 1151556Srgrimes /* 1161556Srgrimes * print device id's for devices, or sizes for other nodes 1171556Srgrimes */ 1181556Srgrimes if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) 1191556Srgrimes# ifdef NET2_STAT 12076351Skris (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev), 12120420Ssteve MINOR(sbp->st_rdev)); 1221556Srgrimes# else 12376351Skris (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), 12420420Ssteve (unsigned long)MINOR(sbp->st_rdev)); 1251556Srgrimes# endif 1261556Srgrimes else { 1271556Srgrimes# ifdef NET2_STAT 12876351Skris (void)fprintf(fp, "%9lu ", sbp->st_size); 1291556Srgrimes# else 130104548Stjr (void)fprintf(fp, "%9ju ", (uintmax_t)sbp->st_size); 1311556Srgrimes# endif 1321556Srgrimes } 1331556Srgrimes 1341556Srgrimes /* 1351556Srgrimes * print name and link info for hard and soft links 1361556Srgrimes */ 13776351Skris (void)fprintf(fp, "%s %s", f_date, arcn->name); 1381556Srgrimes if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 13976351Skris (void)fprintf(fp, " == %s\n", arcn->ln_name); 1401556Srgrimes else if (arcn->type == PAX_SLK) 14176351Skris (void)fprintf(fp, " => %s\n", arcn->ln_name); 1421556Srgrimes else 14376351Skris (void)putc('\n', fp); 14476351Skris (void)fflush(fp); 1451556Srgrimes return; 1461556Srgrimes} 1471556Srgrimes 1481556Srgrimes/* 1491556Srgrimes * tty_ls() 1501556Srgrimes * print a short summary of file to tty. 1511556Srgrimes */ 1521556Srgrimes 1531556Srgrimesvoid 15490113Simpls_tty(ARCHD *arcn) 1551556Srgrimes{ 1561556Srgrimes char f_date[DATELEN]; 1571556Srgrimes char f_mode[MODELEN]; 158114583Smarkm const char *timefrmt; 1591556Srgrimes 16074567Sache if (d_first < 0) 16174567Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 16274567Sache 16376017Skris if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL)) 16474567Sache timefrmt = d_first ? OLDFRMTD : OLDFRMTM; 16573345Sru else 16674567Sache timefrmt = d_first ? CURFRMTD : CURFRMTM; 1671556Srgrimes 1681556Srgrimes /* 1691556Srgrimes * convert time to string, and print 1701556Srgrimes */ 1711556Srgrimes if (strftime(f_date, DATELEN, timefrmt, 1721556Srgrimes localtime(&(arcn->sb.st_mtime))) == 0) 1731556Srgrimes f_date[0] = '\0'; 1741556Srgrimes strmode(arcn->sb.st_mode, f_mode); 1751556Srgrimes tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name); 1761556Srgrimes return; 1771556Srgrimes} 1781556Srgrimes 1791556Srgrimes/* 1801556Srgrimes * l_strncpy() 18176351Skris * copy src to dest up to len chars (stopping at first '\0'). 18276351Skris * when src is shorter than len, pads to len with '\0'. 1831556Srgrimes * Return: 1841556Srgrimes * number of chars copied. (Note this is a real performance win over 18576351Skris * doing a strncpy(), a strlen(), and then a possible memset()) 1861556Srgrimes */ 1871556Srgrimes 1881556Srgrimesint 189114583Smarkml_strncpy(char *dest, const char *src, int len) 1901556Srgrimes{ 19190113Simp char *stop; 19290113Simp char *start; 1931556Srgrimes 1941556Srgrimes stop = dest + len; 1951556Srgrimes start = dest; 1961556Srgrimes while ((dest < stop) && (*src != '\0')) 1971556Srgrimes *dest++ = *src++; 19876351Skris len = dest - start; 19976351Skris while (dest < stop) 20076351Skris *dest++ = '\0'; 20176351Skris return(len); 2021556Srgrimes} 2031556Srgrimes 2041556Srgrimes/* 2051556Srgrimes * asc_ul() 2061556Srgrimes * convert hex/octal character string into a u_long. We do not have to 2071556Srgrimes * check for overflow! (the headers in all supported formats are not large 2081556Srgrimes * enough to create an overflow). 2091556Srgrimes * NOTE: strings passed to us are NOT TERMINATED. 2101556Srgrimes * Return: 2111556Srgrimes * unsigned long value 2121556Srgrimes */ 2131556Srgrimes 2141556Srgrimesu_long 21590113Simpasc_ul(char *str, int len, int base) 2161556Srgrimes{ 21790113Simp char *stop; 2181556Srgrimes u_long tval = 0; 2191556Srgrimes 2201556Srgrimes stop = str + len; 2211556Srgrimes 2221556Srgrimes /* 2231556Srgrimes * skip over leading blanks and zeros 2241556Srgrimes */ 2251556Srgrimes while ((str < stop) && ((*str == ' ') || (*str == '0'))) 2261556Srgrimes ++str; 2271556Srgrimes 2281556Srgrimes /* 2291556Srgrimes * for each valid digit, shift running value (tval) over to next digit 2301556Srgrimes * and add next digit 2311556Srgrimes */ 2321556Srgrimes if (base == HEX) { 2331556Srgrimes while (str < stop) { 2341556Srgrimes if ((*str >= '0') && (*str <= '9')) 2351556Srgrimes tval = (tval << 4) + (*str++ - '0'); 2361556Srgrimes else if ((*str >= 'A') && (*str <= 'F')) 2371556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'A'); 2381556Srgrimes else if ((*str >= 'a') && (*str <= 'f')) 2391556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'a'); 2401556Srgrimes else 2411556Srgrimes break; 2421556Srgrimes } 2431556Srgrimes } else { 2441556Srgrimes while ((str < stop) && (*str >= '0') && (*str <= '7')) 2451556Srgrimes tval = (tval << 3) + (*str++ - '0'); 2461556Srgrimes } 2471556Srgrimes return(tval); 2481556Srgrimes} 2491556Srgrimes 2501556Srgrimes/* 2511556Srgrimes * ul_asc() 2521556Srgrimes * convert an unsigned long into an hex/oct ascii string. pads with LEADING 2531556Srgrimes * ascii 0's to fill string completely 2541556Srgrimes * NOTE: the string created is NOT TERMINATED. 2551556Srgrimes */ 2561556Srgrimes 2571556Srgrimesint 25890113Simpul_asc(u_long val, char *str, int len, int base) 2591556Srgrimes{ 26090113Simp char *pt; 2611556Srgrimes u_long digit; 2628855Srgrimes 2631556Srgrimes /* 2641556Srgrimes * WARNING str is not '\0' terminated by this routine 2651556Srgrimes */ 2661556Srgrimes pt = str + len - 1; 2671556Srgrimes 2681556Srgrimes /* 2691556Srgrimes * do a tailwise conversion (start at right most end of string to place 2701556Srgrimes * least significant digit). Keep shifting until conversion value goes 2711556Srgrimes * to zero (all digits were converted) 2721556Srgrimes */ 2731556Srgrimes if (base == HEX) { 2741556Srgrimes while (pt >= str) { 2751556Srgrimes if ((digit = (val & 0xf)) < 10) 2761556Srgrimes *pt-- = '0' + (char)digit; 2778855Srgrimes else 2781556Srgrimes *pt-- = 'a' + (char)(digit - 10); 2791556Srgrimes if ((val = (val >> 4)) == (u_long)0) 2801556Srgrimes break; 2811556Srgrimes } 2821556Srgrimes } else { 2831556Srgrimes while (pt >= str) { 2841556Srgrimes *pt-- = '0' + (char)(val & 0x7); 2851556Srgrimes if ((val = (val >> 3)) == (u_long)0) 2861556Srgrimes break; 2871556Srgrimes } 2881556Srgrimes } 2891556Srgrimes 2901556Srgrimes /* 2911556Srgrimes * pad with leading ascii ZEROS. We return -1 if we ran out of space. 2921556Srgrimes */ 2931556Srgrimes while (pt >= str) 2941556Srgrimes *pt-- = '0'; 2951556Srgrimes if (val != (u_long)0) 2961556Srgrimes return(-1); 2971556Srgrimes return(0); 2981556Srgrimes} 2991556Srgrimes 3001556Srgrimes#ifndef NET2_STAT 3011556Srgrimes/* 3021556Srgrimes * asc_uqd() 3031556Srgrimes * convert hex/octal character string into a u_quad_t. We do not have to 3041556Srgrimes * check for overflow! (the headers in all supported formats are not large 3051556Srgrimes * enough to create an overflow). 3061556Srgrimes * NOTE: strings passed to us are NOT TERMINATED. 3071556Srgrimes * Return: 3081556Srgrimes * u_quad_t value 3091556Srgrimes */ 3101556Srgrimes 3111556Srgrimesu_quad_t 31290113Simpasc_uqd(char *str, int len, int base) 3131556Srgrimes{ 31490113Simp char *stop; 3151556Srgrimes u_quad_t tval = 0; 3161556Srgrimes 3171556Srgrimes stop = str + len; 3181556Srgrimes 3191556Srgrimes /* 3201556Srgrimes * skip over leading blanks and zeros 3211556Srgrimes */ 3221556Srgrimes while ((str < stop) && ((*str == ' ') || (*str == '0'))) 3231556Srgrimes ++str; 3241556Srgrimes 3251556Srgrimes /* 3261556Srgrimes * for each valid digit, shift running value (tval) over to next digit 3271556Srgrimes * and add next digit 3281556Srgrimes */ 3291556Srgrimes if (base == HEX) { 3301556Srgrimes while (str < stop) { 3311556Srgrimes if ((*str >= '0') && (*str <= '9')) 3321556Srgrimes tval = (tval << 4) + (*str++ - '0'); 3331556Srgrimes else if ((*str >= 'A') && (*str <= 'F')) 3341556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'A'); 3351556Srgrimes else if ((*str >= 'a') && (*str <= 'f')) 3361556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'a'); 3371556Srgrimes else 3381556Srgrimes break; 3391556Srgrimes } 3401556Srgrimes } else { 3411556Srgrimes while ((str < stop) && (*str >= '0') && (*str <= '7')) 3421556Srgrimes tval = (tval << 3) + (*str++ - '0'); 3431556Srgrimes } 3441556Srgrimes return(tval); 3451556Srgrimes} 3461556Srgrimes 3471556Srgrimes/* 3481556Srgrimes * uqd_asc() 3491556Srgrimes * convert an u_quad_t into a hex/oct ascii string. pads with LEADING 3501556Srgrimes * ascii 0's to fill string completely 3511556Srgrimes * NOTE: the string created is NOT TERMINATED. 3521556Srgrimes */ 3531556Srgrimes 3541556Srgrimesint 35590113Simpuqd_asc(u_quad_t val, char *str, int len, int base) 3561556Srgrimes{ 35790113Simp char *pt; 3581556Srgrimes u_quad_t digit; 3598855Srgrimes 3601556Srgrimes /* 3611556Srgrimes * WARNING str is not '\0' terminated by this routine 3621556Srgrimes */ 3631556Srgrimes pt = str + len - 1; 3641556Srgrimes 3651556Srgrimes /* 3661556Srgrimes * do a tailwise conversion (start at right most end of string to place 3671556Srgrimes * least significant digit). Keep shifting until conversion value goes 3681556Srgrimes * to zero (all digits were converted) 3691556Srgrimes */ 3701556Srgrimes if (base == HEX) { 3711556Srgrimes while (pt >= str) { 3721556Srgrimes if ((digit = (val & 0xf)) < 10) 3731556Srgrimes *pt-- = '0' + (char)digit; 3748855Srgrimes else 3751556Srgrimes *pt-- = 'a' + (char)(digit - 10); 3761556Srgrimes if ((val = (val >> 4)) == (u_quad_t)0) 3771556Srgrimes break; 3781556Srgrimes } 3791556Srgrimes } else { 3801556Srgrimes while (pt >= str) { 3811556Srgrimes *pt-- = '0' + (char)(val & 0x7); 3821556Srgrimes if ((val = (val >> 3)) == (u_quad_t)0) 3831556Srgrimes break; 3841556Srgrimes } 3851556Srgrimes } 3861556Srgrimes 3871556Srgrimes /* 3881556Srgrimes * pad with leading ascii ZEROS. We return -1 if we ran out of space. 3891556Srgrimes */ 3901556Srgrimes while (pt >= str) 3911556Srgrimes *pt-- = '0'; 3921556Srgrimes if (val != (u_quad_t)0) 3931556Srgrimes return(-1); 3941556Srgrimes return(0); 3951556Srgrimes} 3961556Srgrimes#endif 397