xref: /freebsd/bin/pax/gen_subs.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
1 /*-
2  * Copyright (c) 1992 Keith Muller.
3  * Copyright (c) 1992, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Keith Muller of the University of California, San Diego.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)gen_subs.c	8.1 (Berkeley) 5/31/93";
41 #endif
42 static const char rcsid[] =
43 	"$Id$";
44 #endif /* not lint */
45 
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <sys/stat.h>
49 #include <stdio.h>
50 #include <utmp.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include "pax.h"
55 #include "extern.h"
56 
57 /*
58  * a collection of general purpose subroutines used by pax
59  */
60 
61 /*
62  * constants used by ls_list() when printing out archive members
63  */
64 #define MODELEN 20
65 #define DATELEN 64
66 #define SIXMONTHS	 ((365 / 2) * 86400)
67 #define CURFRMT		"%b %e %H:%M"
68 #define OLDFRMT		"%b %e  %Y"
69 #ifndef UT_NAMESIZE
70 #define UT_NAMESIZE	8
71 #endif
72 #define UT_GRPSIZE	6
73 
74 /*
75  * ls_list()
76  *	list the members of an archive in ls format
77  */
78 
79 #if __STDC__
80 void
81 ls_list(register ARCHD *arcn, time_t now)
82 #else
83 void
84 ls_list(arcn, now)
85 	register ARCHD *arcn;
86 	time_t now;
87 #endif
88 {
89 	register struct stat *sbp;
90 	char f_mode[MODELEN];
91 	char f_date[DATELEN];
92 	char *timefrmt;
93 
94 	/*
95 	 * if not verbose, just print the file name
96 	 */
97 	if (!vflag) {
98 		(void)printf("%s\n", arcn->name);
99 		(void)fflush(stdout);
100 		return;
101 	}
102 
103 	/*
104 	 * user wants long mode
105 	 */
106 	sbp = &(arcn->sb);
107 	strmode(sbp->st_mode, f_mode);
108 
109 	if (ltmfrmt == NULL) {
110 		/*
111 		 * no locale specified format. time format based on age
112 		 * compared to the time pax was started.
113 		 */
114 		if ((sbp->st_mtime + SIXMONTHS) <= now)
115 			timefrmt = OLDFRMT;
116 		else
117 			timefrmt = CURFRMT;
118 	} else
119 		timefrmt = ltmfrmt;
120 
121 	/*
122 	 * print file mode, link count, uid, gid and time
123 	 */
124 	if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
125 		f_date[0] = '\0';
126 	(void)printf("%s%2u %-*s %-*s ", f_mode, sbp->st_nlink, UT_NAMESIZE,
127 		name_uid(sbp->st_uid, 1), UT_GRPSIZE,
128 		name_gid(sbp->st_gid, 1));
129 
130 	/*
131 	 * print device id's for devices, or sizes for other nodes
132 	 */
133 	if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
134 #		ifdef NET2_STAT
135 		(void)printf("%4u,%4u ", MAJOR(sbp->st_rdev),
136 		    MINOR(sbp->st_rdev));
137 #		else
138 		(void)printf("%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
139 		    (unsigned long)MINOR(sbp->st_rdev));
140 #		endif
141 	else {
142 #		ifdef NET2_STAT
143 		(void)printf("%9lu ", sbp->st_size);
144 #		else
145 		(void)printf("%9qu ", sbp->st_size);
146 #		endif
147 	}
148 
149 	/*
150 	 * print name and link info for hard and soft links
151 	 */
152 	(void)printf("%s %s", f_date, arcn->name);
153 	if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
154 		(void)printf(" == %s\n", arcn->ln_name);
155 	else if (arcn->type == PAX_SLK)
156 		(void)printf(" => %s\n", arcn->ln_name);
157 	else
158 		(void)putchar('\n');
159 	(void)fflush(stdout);
160 	return;
161 }
162 
163 /*
164  * tty_ls()
165  * 	print a short summary of file to tty.
166  */
167 
168 #if __STDC__
169 void
170 ls_tty(register ARCHD *arcn)
171 #else
172 void
173 ls_tty(arcn)
174 	register ARCHD *arcn;
175 #endif
176 {
177 	char f_date[DATELEN];
178 	char f_mode[MODELEN];
179 	char *timefrmt;
180 
181 	if (ltmfrmt == NULL) {
182 		/*
183 		 * no locale specified format
184 		 */
185 		if ((arcn->sb.st_mtime + SIXMONTHS) <= time((time_t *)NULL))
186 			timefrmt = OLDFRMT;
187 		else
188 			timefrmt = CURFRMT;
189 	} else
190 		timefrmt = ltmfrmt;
191 
192 	/*
193 	 * convert time to string, and print
194 	 */
195 	if (strftime(f_date, DATELEN, timefrmt,
196 	    localtime(&(arcn->sb.st_mtime))) == 0)
197 		f_date[0] = '\0';
198 	strmode(arcn->sb.st_mode, f_mode);
199 	tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
200 	return;
201 }
202 
203 /*
204  * zf_strncpy()
205  *	copy src to dest up to len chars (stopping at first '\0'), when src is
206  *	shorter than len, pads to len with '\0'. big performance win (and
207  *	a lot easier to code) over strncpy(), then a strlen() then a
208  *	bzero(). (or doing the bzero() first).
209  */
210 
211 #if __STDC__
212 void
213 zf_strncpy(register char *dest, register char *src, int len)
214 #else
215 void
216 zf_strncpy(dest, src, len)
217 	register char *dest;
218 	register char *src;
219 	int len;
220 #endif
221 {
222 	register char *stop;
223 
224 	stop = dest + len;
225 	while ((dest < stop) && (*src != '\0'))
226 		*dest++ = *src++;
227 	while (dest < stop)
228 		*dest++ = '\0';
229 	return;
230 }
231 
232 /*
233  * l_strncpy()
234  *	copy src to dest up to len chars (stopping at first '\0')
235  * Return:
236  *	number of chars copied. (Note this is a real performance win over
237  *	doing a strncpy() then a strlen()
238  */
239 
240 #if __STDC__
241 int
242 l_strncpy(register char *dest, register char *src, int len)
243 #else
244 int
245 l_strncpy(dest, src, len)
246 	register char *dest;
247 	register char *src;
248 	int len;
249 #endif
250 {
251 	register char *stop;
252 	register char *start;
253 
254 	stop = dest + len;
255 	start = dest;
256 	while ((dest < stop) && (*src != '\0'))
257 		*dest++ = *src++;
258 	if (dest < stop)
259 		*dest = '\0';
260 	return(dest - start);
261 }
262 
263 /*
264  * asc_ul()
265  *	convert hex/octal character string into a u_long. We do not have to
266  *	check for overflow! (the headers in all supported formats are not large
267  *	enough to create an overflow).
268  *	NOTE: strings passed to us are NOT TERMINATED.
269  * Return:
270  *	unsigned long value
271  */
272 
273 #if __STDC__
274 u_long
275 asc_ul(register char *str, int len, register int base)
276 #else
277 u_long
278 asc_ul(str, len, base)
279 	register char *str;
280 	int len;
281 	register int base;
282 #endif
283 {
284 	register char *stop;
285 	u_long tval = 0;
286 
287 	stop = str + len;
288 
289 	/*
290 	 * skip over leading blanks and zeros
291 	 */
292 	while ((str < stop) && ((*str == ' ') || (*str == '0')))
293 		++str;
294 
295 	/*
296 	 * for each valid digit, shift running value (tval) over to next digit
297 	 * and add next digit
298 	 */
299 	if (base == HEX) {
300 		while (str < stop) {
301 			if ((*str >= '0') && (*str <= '9'))
302 				tval = (tval << 4) + (*str++ - '0');
303 			else if ((*str >= 'A') && (*str <= 'F'))
304 				tval = (tval << 4) + 10 + (*str++ - 'A');
305 			else if ((*str >= 'a') && (*str <= 'f'))
306 				tval = (tval << 4) + 10 + (*str++ - 'a');
307 			else
308 				break;
309 		}
310 	} else {
311  		while ((str < stop) && (*str >= '0') && (*str <= '7'))
312 			tval = (tval << 3) + (*str++ - '0');
313 	}
314 	return(tval);
315 }
316 
317 /*
318  * ul_asc()
319  *	convert an unsigned long into an hex/oct ascii string. pads with LEADING
320  *	ascii 0's to fill string completely
321  *	NOTE: the string created is NOT TERMINATED.
322  */
323 
324 #if __STDC__
325 int
326 ul_asc(u_long val, register char *str, register int len, register int base)
327 #else
328 int
329 ul_asc(val, str, len, base)
330 	u_long val;
331 	register char *str;
332 	register int len;
333 	register int base;
334 #endif
335 {
336 	register char *pt;
337 	u_long digit;
338 
339 	/*
340 	 * WARNING str is not '\0' terminated by this routine
341 	 */
342 	pt = str + len - 1;
343 
344 	/*
345 	 * do a tailwise conversion (start at right most end of string to place
346 	 * least significant digit). Keep shifting until conversion value goes
347 	 * to zero (all digits were converted)
348 	 */
349 	if (base == HEX) {
350 		while (pt >= str) {
351 			if ((digit = (val & 0xf)) < 10)
352 				*pt-- = '0' + (char)digit;
353 			else
354 				*pt-- = 'a' + (char)(digit - 10);
355 			if ((val = (val >> 4)) == (u_long)0)
356 				break;
357 		}
358 	} else {
359 		while (pt >= str) {
360 			*pt-- = '0' + (char)(val & 0x7);
361 			if ((val = (val >> 3)) == (u_long)0)
362 				break;
363 		}
364 	}
365 
366 	/*
367 	 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
368 	 */
369 	while (pt >= str)
370 		*pt-- = '0';
371 	if (val != (u_long)0)
372 		return(-1);
373 	return(0);
374 }
375 
376 #ifndef NET2_STAT
377 /*
378  * asc_uqd()
379  *	convert hex/octal character string into a u_quad_t. We do not have to
380  *	check for overflow! (the headers in all supported formats are not large
381  *	enough to create an overflow).
382  *	NOTE: strings passed to us are NOT TERMINATED.
383  * Return:
384  *	u_quad_t value
385  */
386 
387 #if __STDC__
388 u_quad_t
389 asc_uqd(register char *str, int len, register int base)
390 #else
391 u_quad_t
392 asc_uqd(str, len, base)
393 	register char *str;
394 	int len;
395 	register int base;
396 #endif
397 {
398 	register char *stop;
399 	u_quad_t tval = 0;
400 
401 	stop = str + len;
402 
403 	/*
404 	 * skip over leading blanks and zeros
405 	 */
406 	while ((str < stop) && ((*str == ' ') || (*str == '0')))
407 		++str;
408 
409 	/*
410 	 * for each valid digit, shift running value (tval) over to next digit
411 	 * and add next digit
412 	 */
413 	if (base == HEX) {
414 		while (str < stop) {
415 			if ((*str >= '0') && (*str <= '9'))
416 				tval = (tval << 4) + (*str++ - '0');
417 			else if ((*str >= 'A') && (*str <= 'F'))
418 				tval = (tval << 4) + 10 + (*str++ - 'A');
419 			else if ((*str >= 'a') && (*str <= 'f'))
420 				tval = (tval << 4) + 10 + (*str++ - 'a');
421 			else
422 				break;
423 		}
424 	} else {
425  		while ((str < stop) && (*str >= '0') && (*str <= '7'))
426 			tval = (tval << 3) + (*str++ - '0');
427 	}
428 	return(tval);
429 }
430 
431 /*
432  * uqd_asc()
433  *	convert an u_quad_t into a hex/oct ascii string. pads with LEADING
434  *	ascii 0's to fill string completely
435  *	NOTE: the string created is NOT TERMINATED.
436  */
437 
438 #if __STDC__
439 int
440 uqd_asc(u_quad_t val, register char *str, register int len, register int base)
441 #else
442 int
443 uqd_asc(val, str, len, base)
444 	u_quad_t val;
445 	register char *str;
446 	register int len;
447 	register int base;
448 #endif
449 {
450 	register char *pt;
451 	u_quad_t digit;
452 
453 	/*
454 	 * WARNING str is not '\0' terminated by this routine
455 	 */
456 	pt = str + len - 1;
457 
458 	/*
459 	 * do a tailwise conversion (start at right most end of string to place
460 	 * least significant digit). Keep shifting until conversion value goes
461 	 * to zero (all digits were converted)
462 	 */
463 	if (base == HEX) {
464 		while (pt >= str) {
465 			if ((digit = (val & 0xf)) < 10)
466 				*pt-- = '0' + (char)digit;
467 			else
468 				*pt-- = 'a' + (char)(digit - 10);
469 			if ((val = (val >> 4)) == (u_quad_t)0)
470 				break;
471 		}
472 	} else {
473 		while (pt >= str) {
474 			*pt-- = '0' + (char)(val & 0x7);
475 			if ((val = (val >> 3)) == (u_quad_t)0)
476 				break;
477 		}
478 	}
479 
480 	/*
481 	 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
482 	 */
483 	while (pt >= str)
484 		*pt-- = '0';
485 	if (val != (u_quad_t)0)
486 		return(-1);
487 	return(0);
488 }
489 #endif
490