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