| 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  | 
    20  | 
    NODE ginfo, *root;  | 
    |
56  | 
    int c_cur, c_next;  | 
    ||
57  | 
    char *buf, *tbuf = NULL;  | 
    ||
58  | 
    10  | 
    size_t len;  | 
    |
59  | 
    |||
60  | 
    last = root = NULL;  | 
    ||
61  | 
    10  | 
    bzero(&ginfo, sizeof(ginfo));  | 
    |
62  | 
    centry = &ginfo;  | 
    ||
63  | 
    c_cur = c_next = 0;  | 
    ||
64  | 
    ✓✓ | 3516  | 
    for (lineno = 1; (buf = fgetln(stdin, &len));  | 
    
65  | 
    1748  | 
    	    ++lineno, c_cur = c_next, c_next = 0) { | 
    |
66  | 
    /* Null-terminate the line. */  | 
    ||
67  | 
    ✓✗ | 1748  | 
    		if (buf[len - 1] == '\n') { | 
    
68  | 
    1748  | 
    buf[--len] = '\0';  | 
    |
69  | 
    1748  | 
    		} 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  | 
    ✓✓ | 31660  | 
    for (p = buf; isspace((unsigned char)*p); p++)  | 
    
79  | 
    ;  | 
    ||
80  | 
    |||
81  | 
    /* If nothing but whitespace or comment char, continue. */  | 
    ||
82  | 
    ✓✓✓✓ | 
    3377  | 
    if (*p == '\0' || *p == '#')  | 
    
83  | 
    continue;  | 
    ||
84  | 
    |||
85  | 
    /* See if next line is continuation line. */  | 
    ||
86  | 
    ✓✓ | 1510  | 
    		if (buf[len - 1] == '\\') { | 
    
87  | 
    c_next = 1;  | 
    ||
88  | 
    ✓✗ | 7  | 
    if (--len == 0)  | 
    
89  | 
    continue;  | 
    ||
90  | 
    7  | 
    buf[len] = '\0';  | 
    |
91  | 
    7  | 
    }  | 
    |
92  | 
    |||
93  | 
    #ifdef DEBUG  | 
    ||
94  | 
    		(void)fprintf(stderr, "line %d: {%s}\n", lineno, p); | 
    ||
95  | 
    #endif  | 
    ||
96  | 
    ✓✓ | 1510  | 
    		if (c_cur) { | 
    
97  | 
    7  | 
    set(p, centry);  | 
    |
98  | 
    7  | 
    continue;  | 
    |
99  | 
    }  | 
    ||
100  | 
    |||
101  | 
    /* Grab file name, "$", "set", or "unset". */  | 
    ||
102  | 
    ✗✓ | 1503  | 
    if ((p = strtok(p, "\n\t ")) == NULL)  | 
    
103  | 
    			error("missing field"); | 
    ||
104  | 
    |||
105  | 
    ✓✓ | 1503  | 
    if (p[0] == '/')  | 
    
106  | 
    ✓✗✓ | 1300  | 
    			switch(p[1]) { | 
    
107  | 
    case 's':  | 
    ||
108  | 
    ✓✗ | 16  | 
    if (strcmp(p + 1, "set"))  | 
    
109  | 
    break;  | 
    ||
110  | 
    16  | 
    set(NULL, &ginfo);  | 
    |
111  | 
    16  | 
    continue;  | 
    |
112  | 
    case 'u':  | 
    ||
113  | 
    if (strcmp(p + 1, "unset"))  | 
    ||
114  | 
    break;  | 
    ||
115  | 
    unset(NULL, &ginfo);  | 
    ||
116  | 
    continue;  | 
    ||
117  | 
    }  | 
    ||
118  | 
    |||
119  | 
    ✗✓ | 1487  | 
    if (strchr(p, '/'))  | 
    
120  | 
    			error("slash character in file name"); | 
    ||
121  | 
    |||
122  | 
    ✓✓ | 1487  | 
    		if (!strcmp(p, "..")) { | 
    
123  | 
    /* Don't go up, if haven't gone down. */  | 
    ||
124  | 
    ✓✗ | 679  | 
    if (!root)  | 
    
125  | 
    goto noparent;  | 
    ||
126  | 
    ✓✓✓✓ | 
    1345  | 
    			if (last->type != F_DIR || last->flags & F_DONE) { | 
    
127  | 
    ✓✗ | 119  | 
    if (last == root)  | 
    
128  | 
    goto noparent;  | 
    ||
129  | 
    119  | 
    last = last->parent;  | 
    |
130  | 
    119  | 
    }  | 
    |
131  | 
    679  | 
    last->flags |= F_DONE;  | 
    |
132  | 
    679  | 
    continue;  | 
    |
133  | 
    |||
134  | 
    noparent:		error("no parent node"); | 
    ||
135  | 
    }  | 
    ||
136  | 
    |||
137  | 
    808  | 
    len = strlen(p) + 1; /* NUL in struct _node */  | 
    |
138  | 
    ✗✓ | 808  | 
    if ((centry = calloc(1, sizeof(NODE) + len - 1)) == NULL)  | 
    
139  | 
    			error("%s", strerror(errno)); | 
    ||
140  | 
    808  | 
    *centry = ginfo;  | 
    |
141  | 
    #define MAGIC "?*["  | 
    ||
142  | 
    ✗✓ | 808  | 
    if (strpbrk(p, MAGIC))  | 
    
143  | 
    centry->flags |= F_MAGIC;  | 
    ||
144  | 
    ✗✓ | 808  | 
    		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  | 
    808  | 
    set(NULL, centry);  | 
    |
150  | 
    |||
151  | 
    ✓✓ | 808  | 
    		if (!root) { | 
    
152  | 
    last = root = centry;  | 
    ||
153  | 
    10  | 
    root->parent = root;  | 
    |
154  | 
    ✓✓✓✓ | 
    1508  | 
    		} else if (last->type == F_DIR && !(last->flags & F_DONE)) { | 
    
155  | 
    130  | 
    centry->parent = last;  | 
    |
156  | 
    130  | 
    last = last->child = centry;  | 
    |
157  | 
    130  | 
    		} else { | 
    |
158  | 
    668  | 
    centry->parent = last->parent;  | 
    |
159  | 
    668  | 
    centry->prev = last;  | 
    |
160  | 
    668  | 
    last = last->next = centry;  | 
    |
161  | 
    }  | 
    ||
162  | 
    }  | 
    ||
163  | 
    10  | 
    free(tbuf);  | 
    |
164  | 
    10  | 
    return (root);  | 
    |
165  | 
    10  | 
    }  | 
    |
166  | 
    |||
167  | 
    static void  | 
    ||
168  | 
    set(char *t, NODE *ip)  | 
    ||
169  | 
    { | 
    ||
170  | 
    int type;  | 
    ||
171  | 
    1662  | 
    char *kw, *val = NULL;  | 
    |
172  | 
    struct group *gr;  | 
    ||
173  | 
    struct passwd *pw;  | 
    ||
174  | 
    void *m;  | 
    ||
175  | 
    831  | 
    int value;  | 
    |
176  | 
    831  | 
    u_int32_t fset, fclr;  | 
    |
177  | 
    831  | 
    char *ep;  | 
    |
178  | 
    size_t len;  | 
    ||
179  | 
    |||
180  | 
    ✓✓ | 4122  | 
    	for (; (kw = strtok(t, "= \t\n")); t = NULL) { | 
    
181  | 
    1230  | 
    ip->flags |= type = parsekey(kw, &value);  | 
    |
182  | 
    ✓✓✗✓ | 
    2359  | 
    if (value && (val = strtok(NULL, " \t\n")) == NULL)  | 
    
183  | 
    			error("missing value"); | 
    ||
184  | 
    ✗✗✗✗ ✓✓✗✗ ✗✗✗✗ ✗✓✗✓ ✓  | 
    2148  | 
    		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  | 
    ✗✓ | 278  | 
    if ((gr = getgrnam(val)) == NULL)  | 
    
211  | 
    			    error("unknown group %s", val); | 
    ||
212  | 
    278  | 
    ip->st_gid = gr->gr_gid;  | 
    |
213  | 
    278  | 
    break;  | 
    |
214  | 
    case F_IGN:  | 
    ||
215  | 
    /* just set flag bit */  | 
    ||
216  | 
    break;  | 
    ||
217  | 
    case F_MODE:  | 
    ||
218  | 
    ✗✓ | 338  | 
    if ((m = setmode(val)) == NULL)  | 
    
219  | 
    				error("invalid file mode %s", val); | 
    ||
220  | 
    338  | 
    ip->st_mode = getmode(m, 0);  | 
    |
221  | 
    338  | 
    free(m);  | 
    |
222  | 
    338  | 
    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  | 
    ✗✓✓✓ ✗✗✗  | 
    211  | 
    			switch(*val) { | 
    
269  | 
    case 'b':  | 
    ||
270  | 
    if (!strcmp(val, "block"))  | 
    ||
271  | 
    ip->type = F_BLOCK;  | 
    ||
272  | 
    break;  | 
    ||
273  | 
    case 'c':  | 
    ||
274  | 
    ✓✗ | 2  | 
    if (!strcmp(val, "char"))  | 
    
275  | 
    2  | 
    ip->type = F_CHAR;  | 
    |
276  | 
    break;  | 
    ||
277  | 
    case 'd':  | 
    ||
278  | 
    ✓✗ | 94  | 
    if (!strcmp(val, "dir"))  | 
    
279  | 
    94  | 
    ip->type = F_DIR;  | 
    |
280  | 
    break;  | 
    ||
281  | 
    case 'f':  | 
    ||
282  | 
    ✓✗ | 115  | 
    if (!strcmp(val, "file"))  | 
    
283  | 
    115  | 
    ip->type = F_FILE;  | 
    |
284  | 
    ✗✓ | 115  | 
    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  | 
    ✗✓ | 302  | 
    if ((pw = getpwnam(val)) == NULL)  | 
    
306  | 
    			    error("unknown user %s", val); | 
    ||
307  | 
    302  | 
    ip->st_uid = pw->pw_uid;  | 
    |
308  | 
    302  | 
    break;  | 
    |
309  | 
    }  | 
    ||
310  | 
    }  | 
    ||
311  | 
    831  | 
    }  | 
    |
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) |