1 /* $OpenBSD: gen_subs.c,v 1.34 2024/04/27 19:49:42 florian 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. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <grp.h>
40 #include <pwd.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <utmp.h>
47 #include <vis.h>
48
49 #include "pax.h"
50 #include "extern.h"
51
52 /*
53 * a collection of general purpose subroutines used by pax
54 */
55
56 /*
57 * constants used by ls_list() when printing out archive members
58 */
59 #define MODELEN 20
60 #define DATELEN 64
61 #define SECSPERDAY (24 * 60 * 60)
62 #define SIXMONTHS (SECSPERDAY * 365 / 2)
63 #define CURFRMT "%b %e %H:%M"
64 #define OLDFRMT "%b %e %Y"
65 #define NAME_WIDTH 8
66 #define TIMEFMT(t, now) \
67 (((t) + SIXMONTHS <= (now) || (t) > (now)) ? OLDFRMT : CURFRMT)
68
69 /*
70 * ls_list()
71 * list the members of an archive in ls format
72 */
73
74 void
ls_list(ARCHD * arcn,time_t now,FILE * fp)75 ls_list(ARCHD *arcn, time_t now, FILE *fp)
76 {
77 struct stat *sbp;
78 struct tm *tm;
79 char f_mode[MODELEN];
80 char f_date[DATELEN];
81 int term;
82
83 term = zeroflag ? '\0' : '\n'; /* path termination character */
84
85 /*
86 * if not verbose, just print the file name
87 */
88 if (!vflag) {
89 if (zeroflag)
90 (void)fputs(arcn->name, fp);
91 else
92 safe_print(arcn->name, fp);
93 (void)putc(term, fp);
94 (void)fflush(fp);
95 return;
96 }
97
98 /*
99 * user wants long mode
100 */
101 sbp = &(arcn->sb);
102 strmode(sbp->st_mode, f_mode);
103
104 /*
105 * print file mode, link count, uid, gid and time
106 */
107 if ((tm = localtime(&(sbp->st_mtime))) == NULL)
108 f_date[0] = '\0';
109 else if (strftime(f_date, sizeof(f_date), TIMEFMT(sbp->st_mtime, now),
110 tm) == 0)
111 f_date[0] = '\0';
112 (void)fprintf(fp, "%s%2u %-*.*s %-*.*s ", f_mode, sbp->st_nlink,
113 NAME_WIDTH, UT_NAMESIZE, user_from_uid(sbp->st_uid, 0),
114 NAME_WIDTH, UT_NAMESIZE, group_from_gid(sbp->st_gid, 0));
115
116 /*
117 * print device id's for devices, or sizes for other nodes
118 */
119 if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
120 (void)fprintf(fp, "%4lu, %4lu ",
121 (unsigned long)MAJOR(sbp->st_rdev),
122 (unsigned long)MINOR(sbp->st_rdev));
123 else {
124 (void)fprintf(fp, "%9llu ", sbp->st_size);
125 }
126
127 /*
128 * print name and link info for hard and soft links
129 */
130 (void)fputs(f_date, fp);
131 (void)putc(' ', fp);
132 safe_print(arcn->name, fp);
133 if (PAX_IS_HARDLINK(arcn->type)) {
134 fputs(" == ", fp);
135 safe_print(arcn->ln_name, fp);
136 } else if (arcn->type == PAX_SLK) {
137 fputs(" -> ", fp);
138 safe_print(arcn->ln_name, fp);
139 }
140 (void)putc(term, fp);
141 (void)fflush(fp);
142 }
143
144 /*
145 * tty_ls()
146 * print a short summary of file to tty.
147 */
148
149 void
ls_tty(ARCHD * arcn)150 ls_tty(ARCHD *arcn)
151 {
152 struct tm *tm;
153 char f_date[DATELEN];
154 char f_mode[MODELEN];
155 time_t now = time(NULL);
156
157 /*
158 * convert time to string, and print
159 */
160 if ((tm = localtime(&(arcn->sb.st_mtime))) == NULL)
161 f_date[0] = '\0';
162 else if (strftime(f_date, DATELEN, TIMEFMT(arcn->sb.st_mtime, now),
163 tm) == 0)
164 f_date[0] = '\0';
165 strmode(arcn->sb.st_mode, f_mode);
166 tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
167 }
168
169 void
safe_print(const char * str,FILE * fp)170 safe_print(const char *str, FILE *fp)
171 {
172 char visbuf[5];
173 const char *cp;
174
175 /*
176 * if printing to a tty, use vis(3) to print special characters.
177 */
178 if (isatty(fileno(fp))) {
179 for (cp = str; *cp; cp++) {
180 (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
181 (void)fputs(visbuf, fp);
182 }
183 } else {
184 (void)fputs(str, fp);
185 }
186 }
187
188 /*
189 * asc_ul()
190 * convert hex/octal character string into a u_long. We do not have to
191 * check for overflow! (the headers in all supported formats are not large
192 * enough to create an overflow).
193 * NOTE: strings passed to us are NOT TERMINATED.
194 * Return:
195 * unsigned long value
196 */
197
198 u_long
asc_ul(char * str,int len,int base)199 asc_ul(char *str, int len, int base)
200 {
201 char *stop;
202 u_long tval = 0;
203
204 stop = str + len;
205
206 /*
207 * skip over leading blanks and zeros
208 */
209 while ((str < stop) && ((*str == ' ') || (*str == '0')))
210 ++str;
211
212 /*
213 * for each valid digit, shift running value (tval) over to next digit
214 * and add next digit
215 */
216 if (base == HEX) {
217 while (str < stop) {
218 if ((*str >= '0') && (*str <= '9'))
219 tval = (tval << 4) + (*str++ - '0');
220 else if ((*str >= 'A') && (*str <= 'F'))
221 tval = (tval << 4) + 10 + (*str++ - 'A');
222 else if ((*str >= 'a') && (*str <= 'f'))
223 tval = (tval << 4) + 10 + (*str++ - 'a');
224 else
225 break;
226 }
227 } else {
228 while ((str < stop) && (*str >= '0') && (*str <= '7'))
229 tval = (tval << 3) + (*str++ - '0');
230 }
231 return(tval);
232 }
233
234 /*
235 * ul_asc()
236 * convert an unsigned long into an hex/oct ascii string. pads with LEADING
237 * ascii 0's to fill string completely
238 * NOTE: the string created is NOT TERMINATED.
239 */
240
241 int
ul_asc(u_long val,char * str,int len,int base)242 ul_asc(u_long val, char *str, int len, int base)
243 {
244 char *pt;
245 u_long digit;
246
247 /*
248 * WARNING str is not '\0' terminated by this routine
249 */
250 pt = str + len - 1;
251
252 /*
253 * do a tailwise conversion (start at right most end of string to place
254 * least significant digit). Keep shifting until conversion value goes
255 * to zero (all digits were converted)
256 */
257 if (base == HEX) {
258 while (pt >= str) {
259 if ((digit = (val & 0xf)) < 10)
260 *pt-- = '0' + (char)digit;
261 else
262 *pt-- = 'a' + (char)(digit - 10);
263 val >>= 4;
264 if (val == 0)
265 break;
266 }
267 } else {
268 while (pt >= str) {
269 *pt-- = '0' + (char)(val & 0x7);
270 val >>= 3;
271 if (val == 0)
272 break;
273 }
274 }
275
276 /*
277 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
278 */
279 while (pt >= str)
280 *pt-- = '0';
281 if (val != 0)
282 return(-1);
283 return(0);
284 }
285
286 /*
287 * asc_ull()
288 * Convert hex/octal character string into a unsigned long long.
289 * We do not have to check for overflow! (The headers in all
290 * supported formats are not large enough to create an overflow).
291 * NOTE: strings passed to us are NOT TERMINATED.
292 * Return:
293 * unsigned long long value
294 */
295
296 unsigned long long
asc_ull(char * str,int len,int base)297 asc_ull(char *str, int len, int base)
298 {
299 char *stop;
300 unsigned long long tval = 0;
301
302 stop = str + len;
303
304 /*
305 * skip over leading blanks and zeros
306 */
307 while ((str < stop) && ((*str == ' ') || (*str == '0')))
308 ++str;
309
310 /*
311 * for each valid digit, shift running value (tval) over to next digit
312 * and add next digit
313 */
314 if (base == HEX) {
315 while (str < stop) {
316 if ((*str >= '0') && (*str <= '9'))
317 tval = (tval << 4) + (*str++ - '0');
318 else if ((*str >= 'A') && (*str <= 'F'))
319 tval = (tval << 4) + 10 + (*str++ - 'A');
320 else if ((*str >= 'a') && (*str <= 'f'))
321 tval = (tval << 4) + 10 + (*str++ - 'a');
322 else
323 break;
324 }
325 } else {
326 while ((str < stop) && (*str >= '0') && (*str <= '7'))
327 tval = (tval << 3) + (*str++ - '0');
328 }
329 return(tval);
330 }
331
332 /*
333 * ull_asc()
334 * Convert an unsigned long long into a hex/oct ascii string.
335 * Pads with LEADING ascii 0's to fill string completely
336 * NOTE: the string created is NOT TERMINATED.
337 */
338
339 int
ull_asc(unsigned long long val,char * str,int len,int base)340 ull_asc(unsigned long long val, char *str, int len, int base)
341 {
342 char *pt;
343 unsigned long long digit;
344
345 /*
346 * WARNING str is not '\0' terminated by this routine
347 */
348 pt = str + len - 1;
349
350 /*
351 * do a tailwise conversion (start at right most end of string to place
352 * least significant digit). Keep shifting until conversion value goes
353 * to zero (all digits were converted)
354 */
355 if (base == HEX) {
356 while (pt >= str) {
357 if ((digit = (val & 0xf)) < 10)
358 *pt-- = '0' + (char)digit;
359 else
360 *pt-- = 'a' + (char)(digit - 10);
361 val >>= 4;
362 if (val == 0)
363 break;
364 }
365 } else {
366 while (pt >= str) {
367 *pt-- = '0' + (char)(val & 0x7);
368 val >>= 3;
369 if (val == 0)
370 break;
371 }
372 }
373
374 /*
375 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
376 */
377 while (pt >= str)
378 *pt-- = '0';
379 if (val != 0)
380 return(-1);
381 return(0);
382 }
383
384 /*
385 * Copy at max min(bufz, fieldsz) chars from field to buf, stopping
386 * at the first NUL char. NUL terminate buf if there is room left.
387 */
388 size_t
fieldcpy(char * buf,size_t bufsz,const char * field,size_t fieldsz)389 fieldcpy(char *buf, size_t bufsz, const char *field, size_t fieldsz)
390 {
391 char *p = buf;
392 const char *q = field;
393 size_t i = 0;
394
395 if (fieldsz > bufsz)
396 fieldsz = bufsz;
397 while (i < fieldsz && *q != '\0') {
398 *p++ = *q++;
399 i++;
400 }
401 if (i < bufsz)
402 *p = '\0';
403 return(i);
404 }
405