gen_subs.c revision 76017
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 * 3. All advertising materials mentioning features or use of this software 181556Srgrimes * must display the following acknowledgement: 191556Srgrimes * This product includes software developed by the University of 201556Srgrimes * California, Berkeley and its contributors. 211556Srgrimes * 4. Neither the name of the University nor the names of its contributors 221556Srgrimes * may be used to endorse or promote products derived from this software 231556Srgrimes * without specific prior written permission. 241556Srgrimes * 251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351556Srgrimes * SUCH DAMAGE. 361556Srgrimes */ 371556Srgrimes 381556Srgrimes#ifndef lint 3936049Scharnier#if 0 4036049Scharnierstatic char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93"; 4136049Scharnier#endif 4236049Scharnierstatic const char rcsid[] = 4350471Speter "$FreeBSD: head/bin/pax/gen_subs.c 76017 2001-04-26 08:37:00Z kris $"; 441556Srgrimes#endif /* not lint */ 451556Srgrimes 461556Srgrimes#include <sys/types.h> 471556Srgrimes#include <sys/time.h> 481556Srgrimes#include <sys/stat.h> 4974567Sache#include <langinfo.h> 501556Srgrimes#include <stdio.h> 511556Srgrimes#include <utmp.h> 521556Srgrimes#include <unistd.h> 531556Srgrimes#include <stdlib.h> 541556Srgrimes#include <string.h> 551556Srgrimes#include "pax.h" 561556Srgrimes#include "extern.h" 571556Srgrimes 581556Srgrimes/* 591556Srgrimes * a collection of general purpose subroutines used by pax 601556Srgrimes */ 611556Srgrimes 621556Srgrimes/* 631556Srgrimes * constants used by ls_list() when printing out archive members 641556Srgrimes */ 651556Srgrimes#define MODELEN 20 661556Srgrimes#define DATELEN 64 679987Swollman#define SIXMONTHS ((365 / 2) * 86400) 6874567Sache#define CURFRMTM "%b %e %H:%M" 6974567Sache#define OLDFRMTM "%b %e %Y" 7074567Sache#define CURFRMTD "%e %b %H:%M" 7174567Sache#define OLDFRMTD "%e %b %Y" 721556Srgrimes#ifndef UT_NAMESIZE 731556Srgrimes#define UT_NAMESIZE 8 741556Srgrimes#endif 751556Srgrimes#define UT_GRPSIZE 6 761556Srgrimes 7774567Sachestatic int d_first = -1; 7874567Sache 791556Srgrimes/* 801556Srgrimes * ls_list() 811556Srgrimes * list the members of an archive in ls format 821556Srgrimes */ 831556Srgrimes 8476017Skris#ifdef __STDC__ 851556Srgrimesvoid 861556Srgrimesls_list(register ARCHD *arcn, time_t now) 871556Srgrimes#else 881556Srgrimesvoid 891556Srgrimesls_list(arcn, now) 901556Srgrimes register ARCHD *arcn; 911556Srgrimes time_t now; 921556Srgrimes#endif 931556Srgrimes{ 941556Srgrimes register struct stat *sbp; 951556Srgrimes char f_mode[MODELEN]; 961556Srgrimes char f_date[DATELEN]; 971556Srgrimes char *timefrmt; 981556Srgrimes 991556Srgrimes /* 1001556Srgrimes * if not verbose, just print the file name 1011556Srgrimes */ 1021556Srgrimes if (!vflag) { 1031556Srgrimes (void)printf("%s\n", arcn->name); 1041556Srgrimes (void)fflush(stdout); 1051556Srgrimes return; 1061556Srgrimes } 1071556Srgrimes 10874567Sache if (d_first < 0) 10974567Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 1101556Srgrimes /* 1111556Srgrimes * user wants long mode 1121556Srgrimes */ 1131556Srgrimes sbp = &(arcn->sb); 1141556Srgrimes strmode(sbp->st_mode, f_mode); 1151556Srgrimes 11673345Sru /* 11773345Sru * time format based on age compared to the time pax was started. 11873345Sru */ 11973345Sru if ((sbp->st_mtime + SIXMONTHS) <= now) 12074567Sache timefrmt = d_first ? OLDFRMTD : OLDFRMTM; 12173345Sru else 12274567Sache timefrmt = d_first ? CURFRMTD : CURFRMTM; 1231556Srgrimes 1241556Srgrimes /* 1251556Srgrimes * print file mode, link count, uid, gid and time 1261556Srgrimes */ 1271556Srgrimes if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0) 1281556Srgrimes f_date[0] = '\0'; 1291556Srgrimes (void)printf("%s%2u %-*s %-*s ", f_mode, sbp->st_nlink, UT_NAMESIZE, 1301556Srgrimes name_uid(sbp->st_uid, 1), UT_GRPSIZE, 1311556Srgrimes name_gid(sbp->st_gid, 1)); 1321556Srgrimes 1331556Srgrimes /* 1341556Srgrimes * print device id's for devices, or sizes for other nodes 1351556Srgrimes */ 1361556Srgrimes if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) 1371556Srgrimes# ifdef NET2_STAT 1381556Srgrimes (void)printf("%4u,%4u ", MAJOR(sbp->st_rdev), 13920420Ssteve MINOR(sbp->st_rdev)); 1401556Srgrimes# else 1417165Sjoerg (void)printf("%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), 14220420Ssteve (unsigned long)MINOR(sbp->st_rdev)); 1431556Srgrimes# endif 1441556Srgrimes else { 1451556Srgrimes# ifdef NET2_STAT 1461556Srgrimes (void)printf("%9lu ", sbp->st_size); 1471556Srgrimes# else 1481556Srgrimes (void)printf("%9qu ", sbp->st_size); 1491556Srgrimes# endif 1501556Srgrimes } 1511556Srgrimes 1521556Srgrimes /* 1531556Srgrimes * print name and link info for hard and soft links 1541556Srgrimes */ 1551556Srgrimes (void)printf("%s %s", f_date, arcn->name); 1561556Srgrimes if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 1571556Srgrimes (void)printf(" == %s\n", arcn->ln_name); 1581556Srgrimes else if (arcn->type == PAX_SLK) 1591556Srgrimes (void)printf(" => %s\n", arcn->ln_name); 1601556Srgrimes else 1611556Srgrimes (void)putchar('\n'); 1621556Srgrimes (void)fflush(stdout); 1631556Srgrimes return; 1641556Srgrimes} 1651556Srgrimes 1661556Srgrimes/* 1671556Srgrimes * tty_ls() 1681556Srgrimes * print a short summary of file to tty. 1691556Srgrimes */ 1701556Srgrimes 17176017Skris#ifdef __STDC__ 1721556Srgrimesvoid 1731556Srgrimesls_tty(register ARCHD *arcn) 1741556Srgrimes#else 1751556Srgrimesvoid 1761556Srgrimesls_tty(arcn) 1771556Srgrimes register ARCHD *arcn; 1781556Srgrimes#endif 1791556Srgrimes{ 1801556Srgrimes char f_date[DATELEN]; 1811556Srgrimes char f_mode[MODELEN]; 1821556Srgrimes char *timefrmt; 1831556Srgrimes 18474567Sache if (d_first < 0) 18574567Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 18674567Sache 18776017Skris if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL)) 18874567Sache timefrmt = d_first ? OLDFRMTD : OLDFRMTM; 18973345Sru else 19074567Sache timefrmt = d_first ? CURFRMTD : CURFRMTM; 1911556Srgrimes 1921556Srgrimes /* 1931556Srgrimes * convert time to string, and print 1941556Srgrimes */ 1951556Srgrimes if (strftime(f_date, DATELEN, timefrmt, 1961556Srgrimes localtime(&(arcn->sb.st_mtime))) == 0) 1971556Srgrimes f_date[0] = '\0'; 1981556Srgrimes strmode(arcn->sb.st_mode, f_mode); 1991556Srgrimes tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name); 2001556Srgrimes return; 2011556Srgrimes} 2021556Srgrimes 2031556Srgrimes/* 2041556Srgrimes * zf_strncpy() 2051556Srgrimes * copy src to dest up to len chars (stopping at first '\0'), when src is 2068855Srgrimes * shorter than len, pads to len with '\0'. big performance win (and 2071556Srgrimes * a lot easier to code) over strncpy(), then a strlen() then a 20876017Skris * memset(). (or doing the memset() first). 2091556Srgrimes */ 2101556Srgrimes 21176017Skris#ifdef __STDC__ 2121556Srgrimesvoid 2131556Srgrimeszf_strncpy(register char *dest, register char *src, int len) 2141556Srgrimes#else 2151556Srgrimesvoid 2161556Srgrimeszf_strncpy(dest, src, len) 2171556Srgrimes register char *dest; 2181556Srgrimes register char *src; 2191556Srgrimes int len; 2201556Srgrimes#endif 2211556Srgrimes{ 2221556Srgrimes register char *stop; 2231556Srgrimes 2241556Srgrimes stop = dest + len; 2251556Srgrimes while ((dest < stop) && (*src != '\0')) 2261556Srgrimes *dest++ = *src++; 2271556Srgrimes while (dest < stop) 2281556Srgrimes *dest++ = '\0'; 2291556Srgrimes return; 2301556Srgrimes} 2311556Srgrimes 2321556Srgrimes/* 2331556Srgrimes * l_strncpy() 2341556Srgrimes * copy src to dest up to len chars (stopping at first '\0') 2351556Srgrimes * Return: 2361556Srgrimes * number of chars copied. (Note this is a real performance win over 2371556Srgrimes * doing a strncpy() then a strlen() 2381556Srgrimes */ 2391556Srgrimes 24076017Skris#ifdef __STDC__ 2411556Srgrimesint 2421556Srgrimesl_strncpy(register char *dest, register char *src, int len) 2431556Srgrimes#else 2441556Srgrimesint 2451556Srgrimesl_strncpy(dest, src, len) 2461556Srgrimes register char *dest; 2471556Srgrimes register char *src; 2481556Srgrimes int len; 2491556Srgrimes#endif 2501556Srgrimes{ 2511556Srgrimes register char *stop; 2521556Srgrimes register char *start; 2531556Srgrimes 2541556Srgrimes stop = dest + len; 2551556Srgrimes start = dest; 2561556Srgrimes while ((dest < stop) && (*src != '\0')) 2571556Srgrimes *dest++ = *src++; 2581556Srgrimes if (dest < stop) 2591556Srgrimes *dest = '\0'; 2601556Srgrimes return(dest - start); 2611556Srgrimes} 2621556Srgrimes 2631556Srgrimes/* 2641556Srgrimes * asc_ul() 2651556Srgrimes * convert hex/octal character string into a u_long. We do not have to 2661556Srgrimes * check for overflow! (the headers in all supported formats are not large 2671556Srgrimes * enough to create an overflow). 2681556Srgrimes * NOTE: strings passed to us are NOT TERMINATED. 2691556Srgrimes * Return: 2701556Srgrimes * unsigned long value 2711556Srgrimes */ 2721556Srgrimes 27376017Skris#ifdef __STDC__ 2741556Srgrimesu_long 2751556Srgrimesasc_ul(register char *str, int len, register int base) 2761556Srgrimes#else 2771556Srgrimesu_long 2781556Srgrimesasc_ul(str, len, base) 2791556Srgrimes register char *str; 2801556Srgrimes int len; 2811556Srgrimes register int base; 2821556Srgrimes#endif 2831556Srgrimes{ 2841556Srgrimes register char *stop; 2851556Srgrimes u_long tval = 0; 2861556Srgrimes 2871556Srgrimes stop = str + len; 2881556Srgrimes 2891556Srgrimes /* 2901556Srgrimes * skip over leading blanks and zeros 2911556Srgrimes */ 2921556Srgrimes while ((str < stop) && ((*str == ' ') || (*str == '0'))) 2931556Srgrimes ++str; 2941556Srgrimes 2951556Srgrimes /* 2961556Srgrimes * for each valid digit, shift running value (tval) over to next digit 2971556Srgrimes * and add next digit 2981556Srgrimes */ 2991556Srgrimes if (base == HEX) { 3001556Srgrimes while (str < stop) { 3011556Srgrimes if ((*str >= '0') && (*str <= '9')) 3021556Srgrimes tval = (tval << 4) + (*str++ - '0'); 3031556Srgrimes else if ((*str >= 'A') && (*str <= 'F')) 3041556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'A'); 3051556Srgrimes else if ((*str >= 'a') && (*str <= 'f')) 3061556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'a'); 3071556Srgrimes else 3081556Srgrimes break; 3091556Srgrimes } 3101556Srgrimes } else { 3111556Srgrimes while ((str < stop) && (*str >= '0') && (*str <= '7')) 3121556Srgrimes tval = (tval << 3) + (*str++ - '0'); 3131556Srgrimes } 3141556Srgrimes return(tval); 3151556Srgrimes} 3161556Srgrimes 3171556Srgrimes/* 3181556Srgrimes * ul_asc() 3191556Srgrimes * convert an unsigned long into an hex/oct ascii string. pads with LEADING 3201556Srgrimes * ascii 0's to fill string completely 3211556Srgrimes * NOTE: the string created is NOT TERMINATED. 3221556Srgrimes */ 3231556Srgrimes 32476017Skris#ifdef __STDC__ 3251556Srgrimesint 3261556Srgrimesul_asc(u_long val, register char *str, register int len, register int base) 3271556Srgrimes#else 3281556Srgrimesint 3291556Srgrimesul_asc(val, str, len, base) 3301556Srgrimes u_long val; 3311556Srgrimes register char *str; 3321556Srgrimes register int len; 3331556Srgrimes register int base; 3341556Srgrimes#endif 3351556Srgrimes{ 3361556Srgrimes register char *pt; 3371556Srgrimes u_long digit; 3388855Srgrimes 3391556Srgrimes /* 3401556Srgrimes * WARNING str is not '\0' terminated by this routine 3411556Srgrimes */ 3421556Srgrimes pt = str + len - 1; 3431556Srgrimes 3441556Srgrimes /* 3451556Srgrimes * do a tailwise conversion (start at right most end of string to place 3461556Srgrimes * least significant digit). Keep shifting until conversion value goes 3471556Srgrimes * to zero (all digits were converted) 3481556Srgrimes */ 3491556Srgrimes if (base == HEX) { 3501556Srgrimes while (pt >= str) { 3511556Srgrimes if ((digit = (val & 0xf)) < 10) 3521556Srgrimes *pt-- = '0' + (char)digit; 3538855Srgrimes else 3541556Srgrimes *pt-- = 'a' + (char)(digit - 10); 3551556Srgrimes if ((val = (val >> 4)) == (u_long)0) 3561556Srgrimes break; 3571556Srgrimes } 3581556Srgrimes } else { 3591556Srgrimes while (pt >= str) { 3601556Srgrimes *pt-- = '0' + (char)(val & 0x7); 3611556Srgrimes if ((val = (val >> 3)) == (u_long)0) 3621556Srgrimes break; 3631556Srgrimes } 3641556Srgrimes } 3651556Srgrimes 3661556Srgrimes /* 3671556Srgrimes * pad with leading ascii ZEROS. We return -1 if we ran out of space. 3681556Srgrimes */ 3691556Srgrimes while (pt >= str) 3701556Srgrimes *pt-- = '0'; 3711556Srgrimes if (val != (u_long)0) 3721556Srgrimes return(-1); 3731556Srgrimes return(0); 3741556Srgrimes} 3751556Srgrimes 3761556Srgrimes#ifndef NET2_STAT 3771556Srgrimes/* 3781556Srgrimes * asc_uqd() 3791556Srgrimes * convert hex/octal character string into a u_quad_t. We do not have to 3801556Srgrimes * check for overflow! (the headers in all supported formats are not large 3811556Srgrimes * enough to create an overflow). 3821556Srgrimes * NOTE: strings passed to us are NOT TERMINATED. 3831556Srgrimes * Return: 3841556Srgrimes * u_quad_t value 3851556Srgrimes */ 3861556Srgrimes 38776017Skris#ifdef __STDC__ 3881556Srgrimesu_quad_t 3891556Srgrimesasc_uqd(register char *str, int len, register int base) 3901556Srgrimes#else 3911556Srgrimesu_quad_t 3921556Srgrimesasc_uqd(str, len, base) 3931556Srgrimes register char *str; 3941556Srgrimes int len; 3951556Srgrimes register int base; 3961556Srgrimes#endif 3971556Srgrimes{ 3981556Srgrimes register char *stop; 3991556Srgrimes u_quad_t tval = 0; 4001556Srgrimes 4011556Srgrimes stop = str + len; 4021556Srgrimes 4031556Srgrimes /* 4041556Srgrimes * skip over leading blanks and zeros 4051556Srgrimes */ 4061556Srgrimes while ((str < stop) && ((*str == ' ') || (*str == '0'))) 4071556Srgrimes ++str; 4081556Srgrimes 4091556Srgrimes /* 4101556Srgrimes * for each valid digit, shift running value (tval) over to next digit 4111556Srgrimes * and add next digit 4121556Srgrimes */ 4131556Srgrimes if (base == HEX) { 4141556Srgrimes while (str < stop) { 4151556Srgrimes if ((*str >= '0') && (*str <= '9')) 4161556Srgrimes tval = (tval << 4) + (*str++ - '0'); 4171556Srgrimes else if ((*str >= 'A') && (*str <= 'F')) 4181556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'A'); 4191556Srgrimes else if ((*str >= 'a') && (*str <= 'f')) 4201556Srgrimes tval = (tval << 4) + 10 + (*str++ - 'a'); 4211556Srgrimes else 4221556Srgrimes break; 4231556Srgrimes } 4241556Srgrimes } else { 4251556Srgrimes while ((str < stop) && (*str >= '0') && (*str <= '7')) 4261556Srgrimes tval = (tval << 3) + (*str++ - '0'); 4271556Srgrimes } 4281556Srgrimes return(tval); 4291556Srgrimes} 4301556Srgrimes 4311556Srgrimes/* 4321556Srgrimes * uqd_asc() 4331556Srgrimes * convert an u_quad_t into a hex/oct ascii string. pads with LEADING 4341556Srgrimes * ascii 0's to fill string completely 4351556Srgrimes * NOTE: the string created is NOT TERMINATED. 4361556Srgrimes */ 4371556Srgrimes 43876017Skris#ifdef __STDC__ 4391556Srgrimesint 4401556Srgrimesuqd_asc(u_quad_t val, register char *str, register int len, register int base) 4411556Srgrimes#else 4421556Srgrimesint 4431556Srgrimesuqd_asc(val, str, len, base) 4441556Srgrimes u_quad_t val; 4451556Srgrimes register char *str; 4461556Srgrimes register int len; 4471556Srgrimes register int base; 4481556Srgrimes#endif 4491556Srgrimes{ 4501556Srgrimes register char *pt; 4511556Srgrimes u_quad_t digit; 4528855Srgrimes 4531556Srgrimes /* 4541556Srgrimes * WARNING str is not '\0' terminated by this routine 4551556Srgrimes */ 4561556Srgrimes pt = str + len - 1; 4571556Srgrimes 4581556Srgrimes /* 4591556Srgrimes * do a tailwise conversion (start at right most end of string to place 4601556Srgrimes * least significant digit). Keep shifting until conversion value goes 4611556Srgrimes * to zero (all digits were converted) 4621556Srgrimes */ 4631556Srgrimes if (base == HEX) { 4641556Srgrimes while (pt >= str) { 4651556Srgrimes if ((digit = (val & 0xf)) < 10) 4661556Srgrimes *pt-- = '0' + (char)digit; 4678855Srgrimes else 4681556Srgrimes *pt-- = 'a' + (char)(digit - 10); 4691556Srgrimes if ((val = (val >> 4)) == (u_quad_t)0) 4701556Srgrimes break; 4711556Srgrimes } 4721556Srgrimes } else { 4731556Srgrimes while (pt >= str) { 4741556Srgrimes *pt-- = '0' + (char)(val & 0x7); 4751556Srgrimes if ((val = (val >> 3)) == (u_quad_t)0) 4761556Srgrimes break; 4771556Srgrimes } 4781556Srgrimes } 4791556Srgrimes 4801556Srgrimes /* 4811556Srgrimes * pad with leading ascii ZEROS. We return -1 if we ran out of space. 4821556Srgrimes */ 4831556Srgrimes while (pt >= str) 4841556Srgrimes *pt-- = '0'; 4851556Srgrimes if (val != (u_quad_t)0) 4861556Srgrimes return(-1); 4871556Srgrimes return(0); 4881556Srgrimes} 4891556Srgrimes#endif 490