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 <unistd.h> 491556Srgrimes#include <stdlib.h> 501556Srgrimes#include <string.h> 511556Srgrimes#include "pax.h" 521556Srgrimes#include "extern.h" 531556Srgrimes 541556Srgrimes/* 551556Srgrimes * a collection of general purpose subroutines used by pax 561556Srgrimes */ 571556Srgrimes 581556Srgrimes/* 591556Srgrimes * constants used by ls_list() when printing out archive members 601556Srgrimes */ 611556Srgrimes#define MODELEN 20 621556Srgrimes#define DATELEN 64 639987Swollman#define SIXMONTHS ((365 / 2) * 86400) 6474567Sache#define CURFRMTM "%b %e %H:%M" 6574567Sache#define OLDFRMTM "%b %e %Y" 6674567Sache#define CURFRMTD "%e %b %H:%M" 6774567Sache#define OLDFRMTD "%e %b %Y" 681556Srgrimes 6974567Sachestatic int d_first = -1; 7074567Sache 711556Srgrimes/* 721556Srgrimes * ls_list() 731556Srgrimes * list the members of an archive in ls format 741556Srgrimes */ 751556Srgrimes 761556Srgrimesvoid 7790113Simpls_list(ARCHD *arcn, time_t now, FILE *fp) 781556Srgrimes{ 7990113Simp struct stat *sbp; 801556Srgrimes char f_mode[MODELEN]; 811556Srgrimes char f_date[DATELEN]; 82114583Smarkm const char *timefrmt; 831556Srgrimes 841556Srgrimes /* 851556Srgrimes * if not verbose, just print the file name 861556Srgrimes */ 871556Srgrimes if (!vflag) { 8876351Skris (void)fprintf(fp, "%s\n", arcn->name); 8976351Skris (void)fflush(fp); 901556Srgrimes return; 911556Srgrimes } 921556Srgrimes 9374567Sache if (d_first < 0) 9474567Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 951556Srgrimes /* 961556Srgrimes * user wants long mode 971556Srgrimes */ 981556Srgrimes sbp = &(arcn->sb); 991556Srgrimes strmode(sbp->st_mode, f_mode); 1001556Srgrimes 10173345Sru /* 10273345Sru * time format based on age compared to the time pax was started. 10373345Sru */ 10473345Sru if ((sbp->st_mtime + SIXMONTHS) <= now) 10574567Sache timefrmt = d_first ? OLDFRMTD : OLDFRMTM; 10673345Sru else 10774567Sache timefrmt = d_first ? CURFRMTD : CURFRMTM; 1081556Srgrimes 1091556Srgrimes /* 1101556Srgrimes * print file mode, link count, uid, gid and time 1111556Srgrimes */ 1121556Srgrimes if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0) 1131556Srgrimes f_date[0] = '\0'; 114202193Sed (void)fprintf(fp, "%s%2u %-12s %-12s ", f_mode, sbp->st_nlink, 115202193Sed name_uid(sbp->st_uid, 1), name_gid(sbp->st_gid, 1)); 1161556Srgrimes 1171556Srgrimes /* 1181556Srgrimes * print device id's for devices, or sizes for other nodes 1191556Srgrimes */ 1201556Srgrimes if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) 1211556Srgrimes# ifdef NET2_STAT 12276351Skris (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev), 12320420Ssteve MINOR(sbp->st_rdev)); 1241556Srgrimes# else 12576351Skris (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), 12620420Ssteve (unsigned long)MINOR(sbp->st_rdev)); 1271556Srgrimes# endif 1281556Srgrimes else { 1291556Srgrimes# ifdef NET2_STAT 13076351Skris (void)fprintf(fp, "%9lu ", sbp->st_size); 1311556Srgrimes# else 132104548Stjr (void)fprintf(fp, "%9ju ", (uintmax_t)sbp->st_size); 1331556Srgrimes# endif 1341556Srgrimes } 1351556Srgrimes 1361556Srgrimes /* 1371556Srgrimes * print name and link info for hard and soft links 1381556Srgrimes */ 13976351Skris (void)fprintf(fp, "%s %s", f_date, arcn->name); 1401556Srgrimes if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 14176351Skris (void)fprintf(fp, " == %s\n", arcn->ln_name); 1421556Srgrimes else if (arcn->type == PAX_SLK) 14376351Skris (void)fprintf(fp, " => %s\n", arcn->ln_name); 1441556Srgrimes else 14576351Skris (void)putc('\n', fp); 14676351Skris (void)fflush(fp); 1471556Srgrimes return; 1481556Srgrimes} 1491556Srgrimes 1501556Srgrimes/* 1511556Srgrimes * tty_ls() 1521556Srgrimes * print a short summary of file to tty. 1531556Srgrimes */ 1541556Srgrimes 1551556Srgrimesvoid 15690113Simpls_tty(ARCHD *arcn) 1571556Srgrimes{ 1581556Srgrimes char f_date[DATELEN]; 1591556Srgrimes char f_mode[MODELEN]; 160114583Smarkm const char *timefrmt; 1611556Srgrimes 16274567Sache if (d_first < 0) 16374567Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 16474567Sache 16576017Skris if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL)) 16674567Sache timefrmt = d_first ? OLDFRMTD : OLDFRMTM; 16773345Sru else 16874567Sache timefrmt = d_first ? CURFRMTD : CURFRMTM; 1691556Srgrimes 1701556Srgrimes /* 1711556Srgrimes * convert time to string, and print 1721556Srgrimes */ 1731556Srgrimes if (strftime(f_date, DATELEN, timefrmt, 1741556Srgrimes localtime(&(arcn->sb.st_mtime))) == 0) 1751556Srgrimes f_date[0] = '\0'; 1761556Srgrimes strmode(arcn->sb.st_mode, f_mode); 1771556Srgrimes tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name); 1781556Srgrimes return; 1791556Srgrimes} 1801556Srgrimes 1811556Srgrimes/* 1821556Srgrimes * l_strncpy() 18376351Skris * copy src to dest up to len chars (stopping at first '\0'). 18476351Skris * when src is shorter than len, pads to len with '\0'. 1851556Srgrimes * Return: 1861556Srgrimes * number of chars copied. (Note this is a real performance win over 18776351Skris * doing a strncpy(), a strlen(), and then a possible memset()) 1881556Srgrimes */ 1891556Srgrimes 1901556Srgrimesint 191114583Smarkml_strncpy(char *dest, const char *src, int len) 1921556Srgrimes{ 19390113Simp char *stop; 19490113Simp char *start; 1951556Srgrimes 1961556Srgrimes stop = dest + len; 1971556Srgrimes start = dest; 1981556Srgrimes while ((dest < stop) && (*src != '\0')) 1991556Srgrimes *dest++ = *src++; 20076351Skris len = dest - start; 20176351Skris while (dest < stop) 20276351Skris *dest++ = '\0'; 20376351Skris return(len); 2041556Srgrimes} 2051556Srgrimes 2061556Srgrimes/* 2071556Srgrimes * asc_ul() 2081556Srgrimes * convert hex/octal character string into a u_long. We do not have to 2091556Srgrimes * check for overflow! (the headers in all supported formats are not large 2101556Srgrimes * enough to create an overflow). 2111556Srgrimes * NOTE: strings passed to us are NOT TERMINATED. 2121556Srgrimes * Return: 2131556Srgrimes * unsigned long value 2141556Srgrimes */ 2151556Srgrimes 2161556Srgrimesu_long 21790113Simpasc_ul(char *str, int len, int base) 2181556Srgrimes{ 21990113Simp char *stop; 2201556Srgrimes u_long tval = 0; 2211556Srgrimes 2221556Srgrimes stop = str + len; 2231556Srgrimes 2241556Srgrimes /* 2251556Srgrimes * skip over leading blanks and zeros 2261556Srgrimes */ 2271556Srgrimes while ((str < stop) && ((*str == ' ') || (*str == '0'))) 2281556Srgrimes ++str; 2291556Srgrimes 2301556Srgrimes /* 2311556Srgrimes * for each valid digit, shift running value (tval) over to next digit 2321556Srgrimes * and add next digit 2331556Srgrimes */ 2341556Srgrimes if (base == HEX) { 2351556Srgrimes while (str < stop) { 2361556Srgrimes if ((*str >= '0') && (*str <= '9')) 2371556Srgrimes tval = (tval << 4) + (*str++ - '0'); 2381556Srgrimes else if ((*str >= 'A') && (*str <= 'F')) 2391556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'A'); 2401556Srgrimes else if ((*str >= 'a') && (*str <= 'f')) 2411556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'a'); 2421556Srgrimes else 2431556Srgrimes break; 2441556Srgrimes } 2451556Srgrimes } else { 2461556Srgrimes while ((str < stop) && (*str >= '0') && (*str <= '7')) 2471556Srgrimes tval = (tval << 3) + (*str++ - '0'); 2481556Srgrimes } 2491556Srgrimes return(tval); 2501556Srgrimes} 2511556Srgrimes 2521556Srgrimes/* 2531556Srgrimes * ul_asc() 2541556Srgrimes * convert an unsigned long into an hex/oct ascii string. pads with LEADING 2551556Srgrimes * ascii 0's to fill string completely 2561556Srgrimes * NOTE: the string created is NOT TERMINATED. 2571556Srgrimes */ 2581556Srgrimes 2591556Srgrimesint 26090113Simpul_asc(u_long val, char *str, int len, int base) 2611556Srgrimes{ 26290113Simp char *pt; 2631556Srgrimes u_long digit; 2648855Srgrimes 2651556Srgrimes /* 2661556Srgrimes * WARNING str is not '\0' terminated by this routine 2671556Srgrimes */ 2681556Srgrimes pt = str + len - 1; 2691556Srgrimes 2701556Srgrimes /* 2711556Srgrimes * do a tailwise conversion (start at right most end of string to place 2721556Srgrimes * least significant digit). Keep shifting until conversion value goes 2731556Srgrimes * to zero (all digits were converted) 2741556Srgrimes */ 2751556Srgrimes if (base == HEX) { 2761556Srgrimes while (pt >= str) { 2771556Srgrimes if ((digit = (val & 0xf)) < 10) 2781556Srgrimes *pt-- = '0' + (char)digit; 2798855Srgrimes else 2801556Srgrimes *pt-- = 'a' + (char)(digit - 10); 2811556Srgrimes if ((val = (val >> 4)) == (u_long)0) 2821556Srgrimes break; 2831556Srgrimes } 2841556Srgrimes } else { 2851556Srgrimes while (pt >= str) { 2861556Srgrimes *pt-- = '0' + (char)(val & 0x7); 2871556Srgrimes if ((val = (val >> 3)) == (u_long)0) 2881556Srgrimes break; 2891556Srgrimes } 2901556Srgrimes } 2911556Srgrimes 2921556Srgrimes /* 2931556Srgrimes * pad with leading ascii ZEROS. We return -1 if we ran out of space. 2941556Srgrimes */ 2951556Srgrimes while (pt >= str) 2961556Srgrimes *pt-- = '0'; 2971556Srgrimes if (val != (u_long)0) 2981556Srgrimes return(-1); 2991556Srgrimes return(0); 3001556Srgrimes} 3011556Srgrimes 3021556Srgrimes#ifndef NET2_STAT 3031556Srgrimes/* 3041556Srgrimes * asc_uqd() 3051556Srgrimes * convert hex/octal character string into a u_quad_t. We do not have to 3061556Srgrimes * check for overflow! (the headers in all supported formats are not large 3071556Srgrimes * enough to create an overflow). 3081556Srgrimes * NOTE: strings passed to us are NOT TERMINATED. 3091556Srgrimes * Return: 3101556Srgrimes * u_quad_t value 3111556Srgrimes */ 3121556Srgrimes 3131556Srgrimesu_quad_t 31490113Simpasc_uqd(char *str, int len, int base) 3151556Srgrimes{ 31690113Simp char *stop; 3171556Srgrimes u_quad_t tval = 0; 3181556Srgrimes 3191556Srgrimes stop = str + len; 3201556Srgrimes 3211556Srgrimes /* 3221556Srgrimes * skip over leading blanks and zeros 3231556Srgrimes */ 3241556Srgrimes while ((str < stop) && ((*str == ' ') || (*str == '0'))) 3251556Srgrimes ++str; 3261556Srgrimes 3271556Srgrimes /* 3281556Srgrimes * for each valid digit, shift running value (tval) over to next digit 3291556Srgrimes * and add next digit 3301556Srgrimes */ 3311556Srgrimes if (base == HEX) { 3321556Srgrimes while (str < stop) { 3331556Srgrimes if ((*str >= '0') && (*str <= '9')) 3341556Srgrimes tval = (tval << 4) + (*str++ - '0'); 3351556Srgrimes else if ((*str >= 'A') && (*str <= 'F')) 3361556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'A'); 3371556Srgrimes else if ((*str >= 'a') && (*str <= 'f')) 3381556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'a'); 3391556Srgrimes else 3401556Srgrimes break; 3411556Srgrimes } 3421556Srgrimes } else { 3431556Srgrimes while ((str < stop) && (*str >= '0') && (*str <= '7')) 3441556Srgrimes tval = (tval << 3) + (*str++ - '0'); 3451556Srgrimes } 3461556Srgrimes return(tval); 3471556Srgrimes} 3481556Srgrimes 3491556Srgrimes/* 3501556Srgrimes * uqd_asc() 3511556Srgrimes * convert an u_quad_t into a hex/oct ascii string. pads with LEADING 3521556Srgrimes * ascii 0's to fill string completely 3531556Srgrimes * NOTE: the string created is NOT TERMINATED. 3541556Srgrimes */ 3551556Srgrimes 3561556Srgrimesint 35790113Simpuqd_asc(u_quad_t val, char *str, int len, int base) 3581556Srgrimes{ 35990113Simp char *pt; 3601556Srgrimes u_quad_t digit; 3618855Srgrimes 3621556Srgrimes /* 3631556Srgrimes * WARNING str is not '\0' terminated by this routine 3641556Srgrimes */ 3651556Srgrimes pt = str + len - 1; 3661556Srgrimes 3671556Srgrimes /* 3681556Srgrimes * do a tailwise conversion (start at right most end of string to place 3691556Srgrimes * least significant digit). Keep shifting until conversion value goes 3701556Srgrimes * to zero (all digits were converted) 3711556Srgrimes */ 3721556Srgrimes if (base == HEX) { 3731556Srgrimes while (pt >= str) { 3741556Srgrimes if ((digit = (val & 0xf)) < 10) 3751556Srgrimes *pt-- = '0' + (char)digit; 3768855Srgrimes else 3771556Srgrimes *pt-- = 'a' + (char)(digit - 10); 3781556Srgrimes if ((val = (val >> 4)) == (u_quad_t)0) 3791556Srgrimes break; 3801556Srgrimes } 3811556Srgrimes } else { 3821556Srgrimes while (pt >= str) { 3831556Srgrimes *pt-- = '0' + (char)(val & 0x7); 3841556Srgrimes if ((val = (val >> 3)) == (u_quad_t)0) 3851556Srgrimes break; 3861556Srgrimes } 3871556Srgrimes } 3881556Srgrimes 3891556Srgrimes /* 3901556Srgrimes * pad with leading ascii ZEROS. We return -1 if we ran out of space. 3911556Srgrimes */ 3921556Srgrimes while (pt >= str) 3931556Srgrimes *pt-- = '0'; 3941556Srgrimes if (val != (u_quad_t)0) 3951556Srgrimes return(-1); 3961556Srgrimes return(0); 3971556Srgrimes} 3981556Srgrimes#endif 399