GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $NetBSD: spec.c,v 1.6 1995/03/07 21:12:12 cgd Exp $ */ |
||
2 |
/* $OpenBSD: spec.c,v 1.28 2016/08/16 16:41:46 krw Exp $ */ |
||
3 |
|||
4 |
/*- |
||
5 |
* Copyright (c) 1989, 1993 |
||
6 |
* The Regents of the University of California. All rights reserved. |
||
7 |
* |
||
8 |
* Redistribution and use in source and binary forms, with or without |
||
9 |
* modification, are permitted provided that the following conditions |
||
10 |
* are met: |
||
11 |
* 1. Redistributions of source code must retain the above copyright |
||
12 |
* notice, this list of conditions and the following disclaimer. |
||
13 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
14 |
* notice, this list of conditions and the following disclaimer in the |
||
15 |
* documentation and/or other materials provided with the distribution. |
||
16 |
* 3. Neither the name of the University nor the names of its contributors |
||
17 |
* may be used to endorse or promote products derived from this software |
||
18 |
* without specific prior written permission. |
||
19 |
* |
||
20 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
||
21 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
22 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
23 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
||
24 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
25 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
26 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
27 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
28 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
29 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
30 |
* SUCH DAMAGE. |
||
31 |
*/ |
||
32 |
|||
33 |
#include <sys/types.h> |
||
34 |
#include <sys/stat.h> |
||
35 |
#include <pwd.h> |
||
36 |
#include <grp.h> |
||
37 |
#include <errno.h> |
||
38 |
#include <unistd.h> |
||
39 |
#include <stdio.h> |
||
40 |
#include <ctype.h> |
||
41 |
#include <vis.h> |
||
42 |
#include "mtree.h" |
||
43 |
#include "extern.h" |
||
44 |
|||
45 |
int lineno; /* Current spec line number. */ |
||
46 |
|||
47 |
static void set(char *, NODE *); |
||
48 |
static void unset(char *, NODE *); |
||
49 |
|||
50 |
NODE * |
||
51 |
spec(void) |
||
52 |
{ |
||
53 |
NODE *centry, *last; |
||
54 |
char *p; |
||
55 |
8 |
NODE ginfo, *root; |
|
56 |
int c_cur, c_next; |
||
57 |
char *buf, *tbuf = NULL; |
||
58 |
4 |
size_t len; |
|
59 |
|||
60 |
last = root = NULL; |
||
61 |
4 |
bzero(&ginfo, sizeof(ginfo)); |
|
62 |
centry = &ginfo; |
||
63 |
c_cur = c_next = 0; |
||
64 |
✓✓ | 56 |
for (lineno = 1; (buf = fgetln(stdin, &len)); |
65 |
24 |
++lineno, c_cur = c_next, c_next = 0) { |
|
66 |
/* Null-terminate the line. */ |
||
67 |
✓✗ | 24 |
if (buf[len - 1] == '\n') { |
68 |
24 |
buf[--len] = '\0'; |
|
69 |
24 |
} else { |
|
70 |
/* EOF with no newline. */ |
||
71 |
tbuf = malloc(len + 1); |
||
72 |
memcpy(tbuf, buf, len); |
||
73 |
tbuf[len] = '\0'; |
||
74 |
buf = tbuf; |
||
75 |
} |
||
76 |
|||
77 |
/* Skip leading whitespace. */ |
||
78 |
✗✓ | 48 |
for (p = buf; isspace((unsigned char)*p); p++) |
79 |
; |
||
80 |
|||
81 |
/* If nothing but whitespace or comment char, continue. */ |
||
82 |
✓✗✓✓ |
48 |
if (*p == '\0' || *p == '#') |
83 |
continue; |
||
84 |
|||
85 |
/* See if next line is continuation line. */ |
||
86 |
✓✓ | 20 |
if (buf[len - 1] == '\\') { |
87 |
c_next = 1; |
||
88 |
✓✗ | 4 |
if (--len == 0) |
89 |
continue; |
||
90 |
4 |
buf[len] = '\0'; |
|
91 |
4 |
} |
|
92 |
|||
93 |
#ifdef DEBUG |
||
94 |
(void)fprintf(stderr, "line %d: {%s}\n", lineno, p); |
||
95 |
#endif |
||
96 |
✓✓ | 20 |
if (c_cur) { |
97 |
4 |
set(p, centry); |
|
98 |
4 |
continue; |
|
99 |
} |
||
100 |
|||
101 |
/* Grab file name, "$", "set", or "unset". */ |
||
102 |
✗✓ | 16 |
if ((p = strtok(p, "\n\t ")) == NULL) |
103 |
error("missing field"); |
||
104 |
|||
105 |
✓✓ | 16 |
if (p[0] == '/') |
106 |
✓✗✓ | 16 |
switch(p[1]) { |
107 |
case 's': |
||
108 |
✓✗ | 8 |
if (strcmp(p + 1, "set")) |
109 |
break; |
||
110 |
8 |
set(NULL, &ginfo); |
|
111 |
8 |
continue; |
|
112 |
case 'u': |
||
113 |
if (strcmp(p + 1, "unset")) |
||
114 |
break; |
||
115 |
unset(NULL, &ginfo); |
||
116 |
continue; |
||
117 |
} |
||
118 |
|||
119 |
✗✓ | 8 |
if (strchr(p, '/')) |
120 |
error("slash character in file name"); |
||
121 |
|||
122 |
✗✓ | 8 |
if (!strcmp(p, "..")) { |
123 |
/* Don't go up, if haven't gone down. */ |
||
124 |
if (!root) |
||
125 |
goto noparent; |
||
126 |
if (last->type != F_DIR || last->flags & F_DONE) { |
||
127 |
if (last == root) |
||
128 |
goto noparent; |
||
129 |
last = last->parent; |
||
130 |
} |
||
131 |
last->flags |= F_DONE; |
||
132 |
continue; |
||
133 |
|||
134 |
noparent: error("no parent node"); |
||
135 |
} |
||
136 |
|||
137 |
8 |
len = strlen(p) + 1; /* NUL in struct _node */ |
|
138 |
✗✓ | 8 |
if ((centry = calloc(1, sizeof(NODE) + len - 1)) == NULL) |
139 |
error("%s", strerror(errno)); |
||
140 |
8 |
*centry = ginfo; |
|
141 |
#define MAGIC "?*[" |
||
142 |
✗✓ | 8 |
if (strpbrk(p, MAGIC)) |
143 |
centry->flags |= F_MAGIC; |
||
144 |
✗✓ | 8 |
if (strunvis(centry->name, p) == -1) { |
145 |
fprintf(stderr, |
||
146 |
"mtree: filename (%s) encoded incorrectly\n", p); |
||
147 |
strlcpy(centry->name, p, len); |
||
148 |
} |
||
149 |
8 |
set(NULL, centry); |
|
150 |
|||
151 |
✓✓ | 8 |
if (!root) { |
152 |
last = root = centry; |
||
153 |
4 |
root->parent = root; |
|
154 |
✓✗✓✗ |
12 |
} else if (last->type == F_DIR && !(last->flags & F_DONE)) { |
155 |
4 |
centry->parent = last; |
|
156 |
4 |
last = last->child = centry; |
|
157 |
4 |
} else { |
|
158 |
centry->parent = last->parent; |
||
159 |
centry->prev = last; |
||
160 |
last = last->next = centry; |
||
161 |
} |
||
162 |
} |
||
163 |
4 |
free(tbuf); |
|
164 |
4 |
return (root); |
|
165 |
4 |
} |
|
166 |
|||
167 |
static void |
||
168 |
set(char *t, NODE *ip) |
||
169 |
{ |
||
170 |
int type; |
||
171 |
40 |
char *kw, *val = NULL; |
|
172 |
struct group *gr; |
||
173 |
struct passwd *pw; |
||
174 |
void *m; |
||
175 |
20 |
int value; |
|
176 |
20 |
u_int32_t fset, fclr; |
|
177 |
20 |
char *ep; |
|
178 |
size_t len; |
||
179 |
|||
180 |
✓✓ | 56 |
for (; (kw = strtok(t, "= \t\n")); t = NULL) { |
181 |
8 |
ip->flags |= type = parsekey(kw, &value); |
|
182 |
✓✗✗✓ |
16 |
if (value && (val = strtok(NULL, " \t\n")) == NULL) |
183 |
error("missing value"); |
||
184 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓✗✗ ✗ |
8 |
switch(type) { |
185 |
case F_CKSUM: |
||
186 |
ip->cksum = strtoul(val, &ep, 10); |
||
187 |
if (*ep) |
||
188 |
error("invalid checksum %s", val); |
||
189 |
break; |
||
190 |
case F_MD5: |
||
191 |
ip->md5digest = strdup(val); |
||
192 |
if (!ip->md5digest) |
||
193 |
error("%s", strerror(errno)); |
||
194 |
break; |
||
195 |
case F_FLAGS: |
||
196 |
if (!strcmp(val, "none")) { |
||
197 |
ip->file_flags = 0; |
||
198 |
break; |
||
199 |
} |
||
200 |
if (strtofflags(&val, &fset, &fclr)) |
||
201 |
error("%s", strerror(errno)); |
||
202 |
ip->file_flags = fset; |
||
203 |
break; |
||
204 |
case F_GID: |
||
205 |
ip->st_gid = strtoul(val, &ep, 10); |
||
206 |
if (*ep) |
||
207 |
error("invalid gid %s", val); |
||
208 |
break; |
||
209 |
case F_GNAME: |
||
210 |
if ((gr = getgrnam(val)) == NULL) |
||
211 |
error("unknown group %s", val); |
||
212 |
ip->st_gid = gr->gr_gid; |
||
213 |
break; |
||
214 |
case F_IGN: |
||
215 |
/* just set flag bit */ |
||
216 |
break; |
||
217 |
case F_MODE: |
||
218 |
if ((m = setmode(val)) == NULL) |
||
219 |
error("invalid file mode %s", val); |
||
220 |
ip->st_mode = getmode(m, 0); |
||
221 |
free(m); |
||
222 |
break; |
||
223 |
case F_NLINK: |
||
224 |
ip->st_nlink = strtoul(val, &ep, 10); |
||
225 |
if (*ep) |
||
226 |
error("invalid link count %s", val); |
||
227 |
break; |
||
228 |
case F_RMD160: |
||
229 |
ip->rmd160digest = strdup(val); |
||
230 |
if (!ip->rmd160digest) |
||
231 |
error("%s", strerror(errno)); |
||
232 |
break; |
||
233 |
case F_SHA1: |
||
234 |
ip->sha1digest = strdup(val); |
||
235 |
if (!ip->sha1digest) |
||
236 |
error("%s", strerror(errno)); |
||
237 |
break; |
||
238 |
case F_SHA256: |
||
239 |
ip->sha256digest = strdup(val); |
||
240 |
if (!ip->sha256digest) |
||
241 |
error("%s", strerror(errno)); |
||
242 |
break; |
||
243 |
case F_SIZE: |
||
244 |
ip->st_size = strtoll(val, &ep, 10); |
||
245 |
if (*ep) |
||
246 |
error("invalid size %s", val); |
||
247 |
break; |
||
248 |
case F_SLINK: |
||
249 |
len = strlen(val) + 1; |
||
250 |
if ((ip->slink = malloc(len)) == NULL) |
||
251 |
error("%s", strerror(errno)); |
||
252 |
if (strunvis(ip->slink, val) == -1) { |
||
253 |
fprintf(stderr, |
||
254 |
"mtree: filename (%s) encoded incorrectly\n", val); |
||
255 |
strlcpy(ip->slink, val, len); |
||
256 |
} |
||
257 |
break; |
||
258 |
case F_TIME: |
||
259 |
ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); |
||
260 |
if (*ep != '.') |
||
261 |
error("invalid time %s", val); |
||
262 |
val = ep + 1; |
||
263 |
ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10); |
||
264 |
if (*ep) |
||
265 |
error("invalid time %s", val); |
||
266 |
break; |
||
267 |
case F_TYPE: |
||
268 |
✗✗✓✓ ✗✗✗ |
8 |
switch(*val) { |
269 |
case 'b': |
||
270 |
if (!strcmp(val, "block")) |
||
271 |
ip->type = F_BLOCK; |
||
272 |
break; |
||
273 |
case 'c': |
||
274 |
if (!strcmp(val, "char")) |
||
275 |
ip->type = F_CHAR; |
||
276 |
break; |
||
277 |
case 'd': |
||
278 |
✓✗ | 4 |
if (!strcmp(val, "dir")) |
279 |
4 |
ip->type = F_DIR; |
|
280 |
break; |
||
281 |
case 'f': |
||
282 |
✓✗ | 4 |
if (!strcmp(val, "file")) |
283 |
4 |
ip->type = F_FILE; |
|
284 |
✗✓ | 4 |
if (!strcmp(val, "fifo")) |
285 |
ip->type = F_FIFO; |
||
286 |
break; |
||
287 |
case 'l': |
||
288 |
if (!strcmp(val, "link")) |
||
289 |
ip->type = F_LINK; |
||
290 |
break; |
||
291 |
case 's': |
||
292 |
if (!strcmp(val, "socket")) |
||
293 |
ip->type = F_SOCK; |
||
294 |
break; |
||
295 |
default: |
||
296 |
error("unknown file type %s", val); |
||
297 |
} |
||
298 |
break; |
||
299 |
case F_UID: |
||
300 |
ip->st_uid = strtoul(val, &ep, 10); |
||
301 |
if (*ep) |
||
302 |
error("invalid uid %s", val); |
||
303 |
break; |
||
304 |
case F_UNAME: |
||
305 |
if ((pw = getpwnam(val)) == NULL) |
||
306 |
error("unknown user %s", val); |
||
307 |
ip->st_uid = pw->pw_uid; |
||
308 |
break; |
||
309 |
} |
||
310 |
} |
||
311 |
20 |
} |
|
312 |
|||
313 |
static void |
||
314 |
unset(char *t, NODE *ip) |
||
315 |
{ |
||
316 |
char *p; |
||
317 |
|||
318 |
while ((p = strtok(t, "\n\t "))) |
||
319 |
ip->flags &= ~parsekey(p, NULL); |
||
320 |
} |
Generated by: GCOVR (Version 3.3) |