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: stable/11/bin/pax/gen_subs.c 312072 2017-01-13 13:37:09Z kib $"); 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'; 112312072Skib (void)fprintf(fp, "%s%2ju %-12s %-12s ", f_mode, 113312072Skib (uintmax_t)sbp->st_nlink, 114202193Sed name_uid(sbp->st_uid, 1), name_gid(sbp->st_gid, 1)); 1151556Srgrimes 1161556Srgrimes /* 1171556Srgrimes * print device id's for devices, or sizes for other nodes 1181556Srgrimes */ 1191556Srgrimes if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) 1201556Srgrimes# ifdef NET2_STAT 12176351Skris (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev), 12220420Ssteve MINOR(sbp->st_rdev)); 1231556Srgrimes# else 12476351Skris (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), 12520420Ssteve (unsigned long)MINOR(sbp->st_rdev)); 1261556Srgrimes# endif 1271556Srgrimes else { 1281556Srgrimes# ifdef NET2_STAT 12976351Skris (void)fprintf(fp, "%9lu ", sbp->st_size); 1301556Srgrimes# else 131104548Stjr (void)fprintf(fp, "%9ju ", (uintmax_t)sbp->st_size); 1321556Srgrimes# endif 1331556Srgrimes } 1341556Srgrimes 1351556Srgrimes /* 1361556Srgrimes * print name and link info for hard and soft links 1371556Srgrimes */ 13876351Skris (void)fprintf(fp, "%s %s", f_date, arcn->name); 1391556Srgrimes if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 14076351Skris (void)fprintf(fp, " == %s\n", arcn->ln_name); 1411556Srgrimes else if (arcn->type == PAX_SLK) 14276351Skris (void)fprintf(fp, " => %s\n", arcn->ln_name); 1431556Srgrimes else 14476351Skris (void)putc('\n', fp); 14576351Skris (void)fflush(fp); 1461556Srgrimes return; 1471556Srgrimes} 1481556Srgrimes 1491556Srgrimes/* 1501556Srgrimes * tty_ls() 1511556Srgrimes * print a short summary of file to tty. 1521556Srgrimes */ 1531556Srgrimes 1541556Srgrimesvoid 15590113Simpls_tty(ARCHD *arcn) 1561556Srgrimes{ 1571556Srgrimes char f_date[DATELEN]; 1581556Srgrimes char f_mode[MODELEN]; 159114583Smarkm const char *timefrmt; 1601556Srgrimes 16174567Sache if (d_first < 0) 16274567Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 16374567Sache 16476017Skris if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL)) 16574567Sache timefrmt = d_first ? OLDFRMTD : OLDFRMTM; 16673345Sru else 16774567Sache timefrmt = d_first ? CURFRMTD : CURFRMTM; 1681556Srgrimes 1691556Srgrimes /* 1701556Srgrimes * convert time to string, and print 1711556Srgrimes */ 1721556Srgrimes if (strftime(f_date, DATELEN, timefrmt, 1731556Srgrimes localtime(&(arcn->sb.st_mtime))) == 0) 1741556Srgrimes f_date[0] = '\0'; 1751556Srgrimes strmode(arcn->sb.st_mode, f_mode); 1761556Srgrimes tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name); 1771556Srgrimes return; 1781556Srgrimes} 1791556Srgrimes 1801556Srgrimes/* 1811556Srgrimes * l_strncpy() 18276351Skris * copy src to dest up to len chars (stopping at first '\0'). 18376351Skris * when src is shorter than len, pads to len with '\0'. 1841556Srgrimes * Return: 1851556Srgrimes * number of chars copied. (Note this is a real performance win over 18676351Skris * doing a strncpy(), a strlen(), and then a possible memset()) 1871556Srgrimes */ 1881556Srgrimes 1891556Srgrimesint 190114583Smarkml_strncpy(char *dest, const char *src, int len) 1911556Srgrimes{ 19290113Simp char *stop; 19390113Simp char *start; 1941556Srgrimes 1951556Srgrimes stop = dest + len; 1961556Srgrimes start = dest; 1971556Srgrimes while ((dest < stop) && (*src != '\0')) 1981556Srgrimes *dest++ = *src++; 19976351Skris len = dest - start; 20076351Skris while (dest < stop) 20176351Skris *dest++ = '\0'; 20276351Skris return(len); 2031556Srgrimes} 2041556Srgrimes 2051556Srgrimes/* 2061556Srgrimes * asc_ul() 2071556Srgrimes * convert hex/octal character string into a u_long. We do not have to 2081556Srgrimes * check for overflow! (the headers in all supported formats are not large 2091556Srgrimes * enough to create an overflow). 2101556Srgrimes * NOTE: strings passed to us are NOT TERMINATED. 2111556Srgrimes * Return: 2121556Srgrimes * unsigned long value 2131556Srgrimes */ 2141556Srgrimes 2151556Srgrimesu_long 21690113Simpasc_ul(char *str, int len, int base) 2171556Srgrimes{ 21890113Simp char *stop; 2191556Srgrimes u_long tval = 0; 2201556Srgrimes 2211556Srgrimes stop = str + len; 2221556Srgrimes 2231556Srgrimes /* 2241556Srgrimes * skip over leading blanks and zeros 2251556Srgrimes */ 2261556Srgrimes while ((str < stop) && ((*str == ' ') || (*str == '0'))) 2271556Srgrimes ++str; 2281556Srgrimes 2291556Srgrimes /* 2301556Srgrimes * for each valid digit, shift running value (tval) over to next digit 2311556Srgrimes * and add next digit 2321556Srgrimes */ 2331556Srgrimes if (base == HEX) { 2341556Srgrimes while (str < stop) { 2351556Srgrimes if ((*str >= '0') && (*str <= '9')) 2361556Srgrimes tval = (tval << 4) + (*str++ - '0'); 2371556Srgrimes else if ((*str >= 'A') && (*str <= 'F')) 2381556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'A'); 2391556Srgrimes else if ((*str >= 'a') && (*str <= 'f')) 2401556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'a'); 2411556Srgrimes else 2421556Srgrimes break; 2431556Srgrimes } 2441556Srgrimes } else { 2451556Srgrimes while ((str < stop) && (*str >= '0') && (*str <= '7')) 2461556Srgrimes tval = (tval << 3) + (*str++ - '0'); 2471556Srgrimes } 2481556Srgrimes return(tval); 2491556Srgrimes} 2501556Srgrimes 2511556Srgrimes/* 2521556Srgrimes * ul_asc() 2531556Srgrimes * convert an unsigned long into an hex/oct ascii string. pads with LEADING 2541556Srgrimes * ascii 0's to fill string completely 2551556Srgrimes * NOTE: the string created is NOT TERMINATED. 2561556Srgrimes */ 2571556Srgrimes 2581556Srgrimesint 25990113Simpul_asc(u_long val, char *str, int len, int base) 2601556Srgrimes{ 26190113Simp char *pt; 2621556Srgrimes u_long digit; 2638855Srgrimes 2641556Srgrimes /* 2651556Srgrimes * WARNING str is not '\0' terminated by this routine 2661556Srgrimes */ 2671556Srgrimes pt = str + len - 1; 2681556Srgrimes 2691556Srgrimes /* 2701556Srgrimes * do a tailwise conversion (start at right most end of string to place 2711556Srgrimes * least significant digit). Keep shifting until conversion value goes 2721556Srgrimes * to zero (all digits were converted) 2731556Srgrimes */ 2741556Srgrimes if (base == HEX) { 2751556Srgrimes while (pt >= str) { 2761556Srgrimes if ((digit = (val & 0xf)) < 10) 2771556Srgrimes *pt-- = '0' + (char)digit; 2788855Srgrimes else 2791556Srgrimes *pt-- = 'a' + (char)(digit - 10); 2801556Srgrimes if ((val = (val >> 4)) == (u_long)0) 2811556Srgrimes break; 2821556Srgrimes } 2831556Srgrimes } else { 2841556Srgrimes while (pt >= str) { 2851556Srgrimes *pt-- = '0' + (char)(val & 0x7); 2861556Srgrimes if ((val = (val >> 3)) == (u_long)0) 2871556Srgrimes break; 2881556Srgrimes } 2891556Srgrimes } 2901556Srgrimes 2911556Srgrimes /* 2921556Srgrimes * pad with leading ascii ZEROS. We return -1 if we ran out of space. 2931556Srgrimes */ 2941556Srgrimes while (pt >= str) 2951556Srgrimes *pt-- = '0'; 2961556Srgrimes if (val != (u_long)0) 2971556Srgrimes return(-1); 2981556Srgrimes return(0); 2991556Srgrimes} 3001556Srgrimes 3011556Srgrimes#ifndef NET2_STAT 3021556Srgrimes/* 3031556Srgrimes * asc_uqd() 3041556Srgrimes * convert hex/octal character string into a u_quad_t. We do not have to 3051556Srgrimes * check for overflow! (the headers in all supported formats are not large 3061556Srgrimes * enough to create an overflow). 3071556Srgrimes * NOTE: strings passed to us are NOT TERMINATED. 3081556Srgrimes * Return: 3091556Srgrimes * u_quad_t value 3101556Srgrimes */ 3111556Srgrimes 3121556Srgrimesu_quad_t 31390113Simpasc_uqd(char *str, int len, int base) 3141556Srgrimes{ 31590113Simp char *stop; 3161556Srgrimes u_quad_t tval = 0; 3171556Srgrimes 3181556Srgrimes stop = str + len; 3191556Srgrimes 3201556Srgrimes /* 3211556Srgrimes * skip over leading blanks and zeros 3221556Srgrimes */ 3231556Srgrimes while ((str < stop) && ((*str == ' ') || (*str == '0'))) 3241556Srgrimes ++str; 3251556Srgrimes 3261556Srgrimes /* 3271556Srgrimes * for each valid digit, shift running value (tval) over to next digit 3281556Srgrimes * and add next digit 3291556Srgrimes */ 3301556Srgrimes if (base == HEX) { 3311556Srgrimes while (str < stop) { 3321556Srgrimes if ((*str >= '0') && (*str <= '9')) 3331556Srgrimes tval = (tval << 4) + (*str++ - '0'); 3341556Srgrimes else if ((*str >= 'A') && (*str <= 'F')) 3351556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'A'); 3361556Srgrimes else if ((*str >= 'a') && (*str <= 'f')) 3371556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'a'); 3381556Srgrimes else 3391556Srgrimes break; 3401556Srgrimes } 3411556Srgrimes } else { 3421556Srgrimes while ((str < stop) && (*str >= '0') && (*str <= '7')) 3431556Srgrimes tval = (tval << 3) + (*str++ - '0'); 3441556Srgrimes } 3451556Srgrimes return(tval); 3461556Srgrimes} 3471556Srgrimes 3481556Srgrimes/* 3491556Srgrimes * uqd_asc() 3501556Srgrimes * convert an u_quad_t into a hex/oct ascii string. pads with LEADING 3511556Srgrimes * ascii 0's to fill string completely 3521556Srgrimes * NOTE: the string created is NOT TERMINATED. 3531556Srgrimes */ 3541556Srgrimes 3551556Srgrimesint 35690113Simpuqd_asc(u_quad_t val, char *str, int len, int base) 3571556Srgrimes{ 35890113Simp char *pt; 3591556Srgrimes u_quad_t digit; 3608855Srgrimes 3611556Srgrimes /* 3621556Srgrimes * WARNING str is not '\0' terminated by this routine 3631556Srgrimes */ 3641556Srgrimes pt = str + len - 1; 3651556Srgrimes 3661556Srgrimes /* 3671556Srgrimes * do a tailwise conversion (start at right most end of string to place 3681556Srgrimes * least significant digit). Keep shifting until conversion value goes 3691556Srgrimes * to zero (all digits were converted) 3701556Srgrimes */ 3711556Srgrimes if (base == HEX) { 3721556Srgrimes while (pt >= str) { 3731556Srgrimes if ((digit = (val & 0xf)) < 10) 3741556Srgrimes *pt-- = '0' + (char)digit; 3758855Srgrimes else 3761556Srgrimes *pt-- = 'a' + (char)(digit - 10); 3771556Srgrimes if ((val = (val >> 4)) == (u_quad_t)0) 3781556Srgrimes break; 3791556Srgrimes } 3801556Srgrimes } else { 3811556Srgrimes while (pt >= str) { 3821556Srgrimes *pt-- = '0' + (char)(val & 0x7); 3831556Srgrimes if ((val = (val >> 3)) == (u_quad_t)0) 3841556Srgrimes break; 3851556Srgrimes } 3861556Srgrimes } 3871556Srgrimes 3881556Srgrimes /* 3891556Srgrimes * pad with leading ascii ZEROS. We return -1 if we ran out of space. 3901556Srgrimes */ 3911556Srgrimes while (pt >= str) 3921556Srgrimes *pt-- = '0'; 3931556Srgrimes if (val != (u_quad_t)0) 3941556Srgrimes return(-1); 3951556Srgrimes return(0); 3961556Srgrimes} 3971556Srgrimes#endif 398