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