Bug Summary

File:src/usr.bin/mg/cscope.c
Warning:line 544, column 8
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cscope.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/mg/obj -resource-dir /usr/local/llvm16/lib/clang/16 -D REGEX -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/mg/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/mg/cscope.c
1/* $OpenBSD: cscope.c,v 1.22 2023/03/08 04:43:11 guenther Exp $ */
2
3/*
4 * This file is in the public domain.
5 *
6 * Author: Sunil Nimmagadda <sunil@openbsd.org>
7 */
8
9#include <sys/queue.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <ctype.h>
13#include <errno(*__errno()).h>
14#include <fcntl.h>
15#include <fnmatch.h>
16#include <limits.h>
17#include <signal.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22
23#include "def.h"
24
25#define CSSYMBOL0 0
26#define CSDEFINITION1 1
27#define CSCALLEDFUNCS2 2
28#define CSCALLERFUNCS3 3
29#define CSTEXT4 4
30#define CSEGREP6 6
31#define CSFINDFILE7 7
32#define CSINCLUDES8 8
33
34struct cstokens {
35 const char *fname;
36 const char *function;
37 const char *lineno;
38 const char *pattern;
39};
40
41struct csmatch {
42 TAILQ_ENTRY(csmatch)struct { struct csmatch *tqe_next; struct csmatch **tqe_prev;
}
entry;
43 int lineno;
44};
45
46struct csrecord {
47 TAILQ_ENTRY(csrecord)struct { struct csrecord *tqe_next; struct csrecord **tqe_prev
; }
entry;
48 char *filename;
49 TAILQ_HEAD(matches, csmatch)struct matches { struct csmatch *tqh_first; struct csmatch **
tqh_last; }
matches;
50};
51
52static TAILQ_HEAD(csrecords, csrecord)struct csrecords { struct csrecord *tqh_first; struct csrecord
**tqh_last; }
csrecords = TAILQ_HEAD_INITIALIZER(csrecords){ ((void *)0), &(csrecords).tqh_first };
53static struct csrecord *addentryr;
54static struct csrecord *currecord;
55static struct csmatch *curmatch;
56static const char *addentryfn;
57static const char *csprompt[] = {
58 "Find this symbol: ",
59 "Find this global definition: ",
60 "Find functions called by this function: ",
61 "Find functions calling this function: ",
62 "Find this text string: ",
63 "Change this text string: ",
64 "Find this egrep pattern: ",
65 "Find this file: ",
66 "Find files #including this file: "
67};
68
69static int addentry(struct buffer *, char *);
70static void csflush(void);
71static int do_cscope(int);
72static int csexists(const char *);
73static int getattr(char *, struct cstokens *);
74static int jumptomatch(void);
75static void prettyprint(struct buffer *, struct cstokens *);
76static const char *ltrim(const char *);
77
78/*
79 * Find this symbol. Bound to C-c s s
80 */
81int
82cssymbol(int f, int n)
83{
84 return (do_cscope(CSSYMBOL0));
85}
86
87/*
88 * Find this global definition. Bound to C-c s d
89 */
90int
91csdefinition(int f, int n)
92{
93 return (do_cscope(CSDEFINITION1));
94}
95
96/*
97 * Find functions called by this function. Bound to C-c s l
98 */
99int
100csfuncalled(int f, int n)
101{
102 return (do_cscope(CSCALLEDFUNCS2));
103}
104
105/*
106 * Find functions calling this function. Bound to C-c s c
107 */
108int
109cscallerfuncs(int f, int n)
110{
111 return (do_cscope(CSCALLERFUNCS3));
112}
113
114/*
115 * Find this text. Bound to C-c s t
116 */
117int
118csfindtext(int f, int n)
119{
120 return (do_cscope(CSTEXT4));
121}
122
123/*
124 * Find this egrep pattern. Bound to C-c s e
125 */
126int
127csegrep(int f, int n)
128{
129 return (do_cscope(CSEGREP6));
130}
131
132/*
133 * Find this file. Bound to C-c s f
134 */
135int
136csfindfile(int f, int n)
137{
138 return (do_cscope(CSFINDFILE7));
139}
140
141/*
142 * Find files #including this file. Bound to C-c s i
143 */
144int
145csfindinc(int f, int n)
146{
147 return (do_cscope(CSINCLUDES8));
1
Calling 'do_cscope'
148}
149
150/*
151 * Create list of files to index in the given directory
152 * using cscope-indexer.
153 */
154int
155cscreatelist(int f, int n)
156{
157 struct buffer *bp;
158 struct stat sb;
159 FILE *fpipe;
160 char dir[NFILEN1024], cmd[BUFSIZ1024], title[BUFSIZ1024], *line, *bufp;
161 size_t sz;
162 ssize_t len;
163 int clen;
164
165 line = NULL((void *)0);
166 sz = 0;
167
168 if (getbufcwd(dir, sizeof(dir)) == FALSE0)
169 dir[0] = '\0';
170
171 bufp = eread("Index files in directory: ", dir,
172 sizeof(dir), EFCR0x0010 | EFDEF0x0020 | EFNEW0x0008 | EFNUL0x0040);
173
174 if (bufp == NULL((void *)0))
175 return (ABORT2);
176 else if (bufp[0] == '\0')
177 return (FALSE0);
178
179 if (stat(dir, &sb) == -1)
180 return(dobeep_msgs("stat:", strerror(errno(*__errno()))));
181 else if (S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000) == 0)
182 return(dobeep_msgs(dir, "Not a directory"));
183
184 if (csexists("cscope-indexer") == FALSE0)
185 return(dobeep_msg("no such file or directory, cscope-indexer"));
186
187 clen = snprintf(cmd, sizeof(cmd), "cscope-indexer -v %s", dir);
188 if (clen < 0 || clen >= sizeof(cmd))
189 return (FALSE0);
190
191 if ((fpipe = popen(cmd, "r")) == NULL((void *)0))
192 return(dobeep_msg("problem opening pipe"));
193
194 bp = bfind("*cscope*", TRUE1);
195 if (bclear(bp) != TRUE1) {
196 pclose(fpipe);
197 return (FALSE0);
198 }
199 bp->b_flag |= BFREADONLY0x10;
200
201 clen = snprintf(title, sizeof(title), "%s%s",
202 "Creating cscope file list 'cscope.files' in: ", dir);
203 if (clen < 0 || clen >= sizeof(title)) {
204 pclose(fpipe);
205 return (FALSE0);
206 }
207 addline(bp, title)addlinef(bp, "%s", title);
208 addline(bp, "")addlinef(bp, "%s", "");
209 while ((len = getline(&line, &sz, fpipe)) != -1) {
210 if (line[len - 1] == *bp->b_nlchr)
211 line[len - 1] = '\0';
212 addline(bp, line)addlinef(bp, "%s", line);
213 }
214 free(line);
215 if (ferror(fpipe)(!__isthreaded ? (((fpipe)->_flags & 0x0040) != 0) : (
ferror)(fpipe))
)
216 ewprintf("Problem reading pipe");
217 pclose(fpipe);
218 return (popbuftop(bp, WNONE0x00));
219}
220
221/*
222 * Next Symbol. Bound to C-c s n
223 */
224int
225csnextmatch(int f, int n)
226{
227 struct csrecord *r;
228 struct csmatch *m;
229
230 if (curmatch == NULL((void *)0)) {
231 if ((r = TAILQ_FIRST(&csrecords)((&csrecords)->tqh_first)) == NULL((void *)0))
232 return(dobeep_msg("The *cscope* buffer does "
233 "not exist yet"));
234
235 currecord = r;
236 curmatch = TAILQ_FIRST(&r->matches)((&r->matches)->tqh_first);
237 } else {
238 m = TAILQ_NEXT(curmatch, entry)((curmatch)->entry.tqe_next);
239 if (m == NULL((void *)0)) {
240 r = TAILQ_NEXT(currecord, entry)((currecord)->entry.tqe_next);
241 if (r == NULL((void *)0)) {
242 return(dobeep_msg("The end of *cscope* buffer "
243 "has been reached"));
244 } else {
245 currecord = r;
246 curmatch = TAILQ_FIRST(&currecord->matches)((&currecord->matches)->tqh_first);
247 }
248 } else
249 curmatch = m;
250 }
251 return (jumptomatch());
252}
253
254/*
255 * Previous Symbol. Bound to C-c s p
256 */
257int
258csprevmatch(int f, int n)
259{
260 struct csmatch *m;
261 struct csrecord *r;
262
263 if (curmatch == NULL((void *)0))
264 return (FALSE0);
265 else {
266 m = TAILQ_PREV(curmatch, matches, entry)(*(((struct matches *)((curmatch)->entry.tqe_prev))->tqh_last
))
;
267 if (m)
268 curmatch = m;
269 else {
270 r = TAILQ_PREV(currecord, csrecords, entry)(*(((struct csrecords *)((currecord)->entry.tqe_prev))->
tqh_last))
;
271 if (r == NULL((void *)0)) {
272 return(dobeep_msg("The beginning of *cscope* "
273 "buffer has been reached"));
274 } else {
275 currecord = r;
276 curmatch = TAILQ_LAST(&currecord->matches,(*(((struct matches *)((&currecord->matches)->tqh_last
))->tqh_last))
277 matches)(*(((struct matches *)((&currecord->matches)->tqh_last
))->tqh_last))
;
278 }
279 }
280 }
281 return (jumptomatch());
282}
283
284/*
285 * Next file.
286 */
287int
288csnextfile(int f, int n)
289{
290 struct csrecord *r;
291
292 if (curmatch == NULL((void *)0)) {
293 if ((r = TAILQ_FIRST(&csrecords)((&csrecords)->tqh_first)) == NULL((void *)0))
294 return(dobeep_msg("The *cscope* buffer does not "
295 "exist yet"));
296 } else {
297 if ((r = TAILQ_NEXT(currecord, entry)((currecord)->entry.tqe_next)) == NULL((void *)0))
298 return(dobeep_msg("The end of *cscope* buffer has "
299 "been reached"));
300 }
301 currecord = r;
302 curmatch = TAILQ_FIRST(&currecord->matches)((&currecord->matches)->tqh_first);
303 return (jumptomatch());
304}
305
306/*
307 * Previous file.
308 */
309int
310csprevfile(int f, int n)
311{
312 struct csrecord *r;
313
314 if (curmatch == NULL((void *)0)) {
315 if ((r = TAILQ_FIRST(&csrecords)((&csrecords)->tqh_first)) == NULL((void *)0))
316 return(dobeep_msg("The *cscope* buffer does not"
317 "exist yet"));
318 } else {
319 if ((r = TAILQ_PREV(currecord, csrecords, entry)(*(((struct csrecords *)((currecord)->entry.tqe_prev))->
tqh_last))
) == NULL((void *)0))
320 return(dobeep_msg("The beginning of *cscope* buffer "
321 "has been reached"));
322 }
323 currecord = r;
324 curmatch = TAILQ_FIRST(&currecord->matches)((&currecord->matches)->tqh_first);
325 return (jumptomatch());
326}
327
328/*
329 * The current symbol location is extracted from currecord->filename and
330 * curmatch->lineno. Load the file similar to filevisit and goto the
331 * lineno recorded.
332 */
333int
334jumptomatch(void)
335{
336 struct buffer *bp;
337 char *adjf;
338
339 if (curmatch == NULL((void *)0) || currecord == NULL((void *)0))
340 return (FALSE0);
341 adjf = adjustname(currecord->filename, TRUE1);
342 if (adjf == NULL((void *)0))
343 return (FALSE0);
344 if ((bp = findbuffer(adjf)) == NULL((void *)0))
345 return (FALSE0);
346 curbp = bp;
347 if (showbuffer(bp, curwp, WFFULL0x08) != TRUE1)
348 return (FALSE0);
349 if (bp->b_fname[0] == '\0') {
350 if (readin(adjf) != TRUE1)
351 killbuffer(bp);
352 }
353 gotoline(FFARG7, curmatch->lineno);
354 return (TRUE1);
355}
356
357/*
358 * Ask for the symbol, construct cscope commandline with the symbol
359 * and passed in index. Popen cscope, read the output into *cscope*
360 * buffer and pop it.
361 */
362int
363do_cscope(int i)
364{
365 struct buffer *bp;
366 FILE *fpipe;
367 char pattern[MAX_TOKEN64], cmd[BUFSIZ1024], title[BUFSIZ1024];
368 char *p, *buf;
369 int clen, nores = 0;
370 size_t sz;
371 ssize_t len;
372
373 buf = NULL((void *)0);
374 sz = 0;
375
376 /* If current buffer isn't a source file just return */
377 if (fnmatch("*.[chy]", curbp->b_fname, 0) != 0)
2
Assuming the condition is false
3
Taking false branch
378 return(dobeep_msg("C-c s not defined"));
379
380 if (curtoken(0, 1, pattern) == FALSE0)
4
Assuming the condition is false
5
Taking false branch
381 return (FALSE0);
382 p = eread("%s", pattern, MAX_TOKEN64, EFNEW0x0008 | EFCR0x0010 | EFDEF0x0020, csprompt[i]);
383 if (p == NULL((void *)0))
6
Assuming 'p' is not equal to NULL
7
Taking false branch
384 return (ABORT2);
385 else if (p[0] == '\0')
8
Assuming the condition is false
9
Taking false branch
386 return (FALSE0);
387
388 if (csexists("cscope") == FALSE0)
10
Assuming the condition is false
11
Taking false branch
389 return(dobeep_msg("no such file or directory, cscope"));
390
391 csflush();
12
Calling 'csflush'
392 clen = snprintf(cmd, sizeof(cmd), "cscope -L -%d %s 2>/dev/null",
393 i, pattern);
394 if (clen < 0 || clen >= sizeof(cmd))
395 return (FALSE0);
396
397 if ((fpipe = popen(cmd, "r")) == NULL((void *)0))
398 return(dobeep_msg("problem opening pipe"));
399
400 bp = bfind("*cscope*", TRUE1);
401 if (bclear(bp) != TRUE1) {
402 pclose(fpipe);
403 return (FALSE0);
404 }
405 bp->b_flag |= BFREADONLY0x10;
406
407 clen = snprintf(title, sizeof(title), "%s%s", csprompt[i], pattern);
408 if (clen < 0 || clen >= sizeof(title)) {
409 pclose(fpipe);
410 return (FALSE0);
411 }
412 addline(bp, title)addlinef(bp, "%s", title);
413 addline(bp, "")addlinef(bp, "%s", "");
414 addline(bp, "-------------------------------------------------------------------------------")addlinef(bp, "%s", "-------------------------------------------------------------------------------"
)
;
415 while ((len = getline(&buf, &sz, fpipe)) != -1) {
416 if (buf[len - 1] == *bp->b_nlchr)
417 buf[len - 1] = '\0';
418 if (addentry(bp, buf) != TRUE1) {
419 free(buf);
420 return (FALSE0);
421 }
422 nores = 1;
423 }
424 free(buf);
425 if (ferror(fpipe)(!__isthreaded ? (((fpipe)->_flags & 0x0040) != 0) : (
ferror)(fpipe))
)
426 ewprintf("Problem reading pipe");
427 pclose(fpipe);
428 addline(bp, "-------------------------------------------------------------------------------")addlinef(bp, "%s", "-------------------------------------------------------------------------------"
)
;
429 if (nores == 0)
430 ewprintf("No matches were found.");
431 return (popbuftop(bp, WNONE0x00));
432}
433
434/*
435 * For each line read from cscope output, extract the tokens,
436 * add them to list and pretty print a line in *cscope* buffer.
437 */
438int
439addentry(struct buffer *bp, char *csline)
440{
441 struct csrecord *r;
442 struct csmatch *m;
443 struct cstokens t;
444 int lineno;
445 char buf[BUFSIZ1024];
446 const char *errstr;
447
448 r = NULL((void *)0);
449 if (getattr(csline, &t) == FALSE0)
450 return (FALSE0);
451
452 lineno = strtonum(t.lineno, INT_MIN(-0x7fffffff-1), INT_MAX0x7fffffff, &errstr);
453 if (errstr)
454 return (FALSE0);
455
456 if (addentryfn == NULL((void *)0) || strcmp(addentryfn, t.fname) != 0) {
457 if ((r = malloc(sizeof(struct csrecord))) == NULL((void *)0))
458 return (FALSE0);
459 addentryr = r;
460 if ((r->filename = strndup(t.fname, NFILEN1024)) == NULL((void *)0))
461 goto cleanup;
462 addentryfn = r->filename;
463 TAILQ_INIT(&r->matches)do { (&r->matches)->tqh_first = ((void *)0); (&
r->matches)->tqh_last = &(&r->matches)->tqh_first
; } while (0)
;
464 if ((m = malloc(sizeof(struct csmatch))) == NULL((void *)0))
465 goto cleanup;
466 m->lineno = lineno;
467 TAILQ_INSERT_TAIL(&r->matches, m, entry)do { (m)->entry.tqe_next = ((void *)0); (m)->entry.tqe_prev
= (&r->matches)->tqh_last; *(&r->matches)->
tqh_last = (m); (&r->matches)->tqh_last = &(m)->
entry.tqe_next; } while (0)
;
468 TAILQ_INSERT_TAIL(&csrecords, r, entry)do { (r)->entry.tqe_next = ((void *)0); (r)->entry.tqe_prev
= (&csrecords)->tqh_last; *(&csrecords)->tqh_last
= (r); (&csrecords)->tqh_last = &(r)->entry.tqe_next
; } while (0)
;
469 addline(bp, "")addlinef(bp, "%s", "");
470 if (snprintf(buf, sizeof(buf), "*** %s", t.fname) < 0)
471 goto cleanup;
472 addline(bp, buf)addlinef(bp, "%s", buf);
473 } else {
474 if ((m = malloc(sizeof(struct csmatch))) == NULL((void *)0))
475 goto cleanup;
476 m->lineno = lineno;
477 TAILQ_INSERT_TAIL(&addentryr->matches, m, entry)do { (m)->entry.tqe_next = ((void *)0); (m)->entry.tqe_prev
= (&addentryr->matches)->tqh_last; *(&addentryr
->matches)->tqh_last = (m); (&addentryr->matches
)->tqh_last = &(m)->entry.tqe_next; } while (0)
;
478 }
479 prettyprint(bp, &t);
480 return (TRUE1);
481cleanup:
482 free(r);
483 return (FALSE0);
484}
485
486/*
487 * Cscope line: <filename> <function> <lineno> <pattern>
488 */
489int
490getattr(char *line, struct cstokens *t)
491{
492 char *p;
493
494 if ((p = strchr(line, ' ')) == NULL((void *)0))
495 return (FALSE0);
496 *p++ = '\0';
497 t->fname = line;
498 line = p;
499
500 if ((p = strchr(line, ' ')) == NULL((void *)0))
501 return (FALSE0);
502 *p++ = '\0';
503 t->function = line;
504 line = p;
505
506 if ((p = strchr(line, ' ')) == NULL((void *)0))
507 return (FALSE0);
508 *p++ = '\0';
509 t->lineno = line;
510
511 if (*p == '\0')
512 return (FALSE0);
513 t->pattern = p;
514
515 return (TRUE1);
516}
517
518void
519prettyprint(struct buffer *bp, struct cstokens *t)
520{
521 char buf[BUFSIZ1024];
522
523 if (snprintf(buf, sizeof(buf), "%s[%s]\t\t%s",
524 t->function, t->lineno, ltrim(t->pattern)) < 0)
525 return;
526 addline(bp, buf)addlinef(bp, "%s", buf);
527}
528
529const char *
530ltrim(const char *s)
531{
532 while (isblank((unsigned char)*s))
533 s++;
534 return s;
535}
536
537void
538csflush(void)
539{
540 struct csrecord *r;
541 struct csmatch *m;
542
543 while ((r = TAILQ_FIRST(&csrecords)((&csrecords)->tqh_first)) != NULL((void *)0)) {
13
Assuming the condition is true
14
Loop condition is true. Entering loop body
21
Loop condition is true. Entering loop body
544 free(r->filename);
22
Use of memory after it is freed
545 while ((m = TAILQ_FIRST(&r->matches)((&r->matches)->tqh_first)) != NULL((void *)0)) {
15
Assuming the condition is false
16
Loop condition is false. Execution continues on line 549
546 TAILQ_REMOVE(&r->matches, m, entry)do { if (((m)->entry.tqe_next) != ((void *)0)) (m)->entry
.tqe_next->entry.tqe_prev = (m)->entry.tqe_prev; else (
&r->matches)->tqh_last = (m)->entry.tqe_prev; *(
m)->entry.tqe_prev = (m)->entry.tqe_next; ; ; } while (
0)
;
547 free(m);
548 }
549 TAILQ_REMOVE(&csrecords, r, entry)do { if (((r)->entry.tqe_next) != ((void *)0)) (r)->entry
.tqe_next->entry.tqe_prev = (r)->entry.tqe_prev; else (
&csrecords)->tqh_last = (r)->entry.tqe_prev; *(r)->
entry.tqe_prev = (r)->entry.tqe_next; ; ; } while (0)
;
17
Assuming field 'tqe_next' is equal to null
18
Taking false branch
19
Loop condition is false. Exiting loop
550 free(r);
20
Memory is released
551 }
552 addentryr = NULL((void *)0);
553 addentryfn = NULL((void *)0);
554 currecord = NULL((void *)0);
555 curmatch = NULL((void *)0);
556}
557
558/*
559 * Check if the cmd exists in $PATH. Split on ":" and iterate through
560 * all paths in $PATH.
561 */
562int
563csexists(const char *cmd)
564{
565 char fname[NFILEN1024], *dir, *path, *pathc, *tmp;
566 int len, dlen;
567
568 /* Special case if prog contains '/' */
569 if (strchr(cmd, '/')) {
570 if (access(cmd, F_OK0) == -1)
571 return (FALSE0);
572 else
573 return (TRUE1);
574 }
575 if ((tmp = getenv("PATH")) == NULL((void *)0))
576 return (FALSE0);
577 if ((pathc = path = strndup(tmp, NFILEN1024)) == NULL((void *)0))
578 return(dobeep_msg("out of memory"));
579
580 while ((dir = strsep(&path, ":")) != NULL((void *)0)) {
581 if (*dir == '\0')
582 continue;
583
584 dlen = strlen(dir);
585 while (dlen > 0 && dir[dlen-1] == '/')
586 dir[--dlen] = '\0'; /* strip trailing '/' */
587
588 len = snprintf(fname, sizeof(fname), "%s/%s", dir, cmd);
589 if (len < 0 || len >= sizeof(fname)) {
590 (void)dobeep_msg("path too long");
591 goto cleanup;
592 }
593 if(access(fname, F_OK0) == 0) {
594 free(pathc);
595 return (TRUE1);
596 }
597 }
598cleanup:
599 free(pathc);
600 return (FALSE0);
601}