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