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