Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cscope.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/lib/clang/13.0.0 -D REGEX -internal-isystem /usr/local/lib/clang/13.0.0/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 -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/mg/cscope.c
1/* $OpenBSD: cscope.c,v 1.20 2021/03/01 10:51:14 lum 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 */
81/* ARGSUSED */
82int
83cssymbol(int f, int n)
84{
85 return (do_cscope(CSSYMBOL0));
86}
87
88/*
89 * Find this global definition. Bound to C-c s d
90 */
91/* ARGSUSED */int
92csdefinition(int f, int n)
93{
94 return (do_cscope(CSDEFINITION1));
95}
96
97/*
98 * Find functions called by this function. Bound to C-c s l
99 */
100/* ARGSUSED */
101int
102csfuncalled(int f, int n)
103{
104 return (do_cscope(CSCALLEDFUNCS2));
105}
106
107/*
108 * Find functions calling this function. Bound to C-c s c
109 */
110/* ARGSUSED */
111int
112cscallerfuncs(int f, int n)
113{
114 return (do_cscope(CSCALLERFUNCS3));
115}
116
117/*
118 * Find this text. Bound to C-c s t
119 */
120/* ARGSUSED */
121int
122csfindtext(int f, int n)
123{
124 return (do_cscope(CSTEXT4));
125}
126
127/*
128 * Find this egrep pattern. Bound to C-c s e
129 */
130/* ARGSUSED */
131int
132csegrep(int f, int n)
133{
134 return (do_cscope(CSEGREP6));
135}
136
137/*
138 * Find this file. Bound to C-c s f
139 */
140/* ARGSUSED */
141int
142csfindfile(int f, int n)
143{
144 return (do_cscope(CSFINDFILE7));
145}
146
147/*
148 * Find files #including this file. Bound to C-c s i
149 */
150/* ARGSUSED */
151int
152csfindinc(int f, int n)
153{
154 return (do_cscope(CSINCLUDES8));
1
Calling 'do_cscope'
155}
156
157/*
158 * Create list of files to index in the given directory
159 * using cscope-indexer.
160 */
161/* ARGSUSED */
162int
163cscreatelist(int f, int n)
164{
165 struct buffer *bp;
166 struct stat sb;
167 FILE *fpipe;
168 char dir[NFILEN1024], cmd[BUFSIZ1024], title[BUFSIZ1024], *line, *bufp;
169 size_t sz;
170 ssize_t len;
171 int clen;
172
173 line = NULL((void *)0);
174 sz = 0;
175
176 if (getbufcwd(dir, sizeof(dir)) == FALSE0)
177 dir[0] = '\0';
178
179 bufp = eread("Index files in directory: ", dir,
180 sizeof(dir), EFCR0x0010 | EFDEF0x0020 | EFNEW0x0008 | EFNUL0x0040);
181
182 if (bufp == NULL((void *)0))
183 return (ABORT2);
184 else if (bufp[0] == '\0')
185 return (FALSE0);
186
187 if (stat(dir, &sb) == -1)
188 return(dobeep_msgs("stat: %s", strerror(errno(*__errno()))));
189 else if (S_ISDIR(sb.st_mode)((sb.st_mode & 0170000) == 0040000) == 0)
190 return(dobeep_msgs("%s: Not a directory", dir));
191
192 if (csexists("cscope-indexer") == FALSE0)
193 return(dobeep_msg("no such file or directory, cscope-indexer"));
194
195 clen = snprintf(cmd, sizeof(cmd), "cscope-indexer -v %s", dir);
196 if (clen < 0 || clen >= sizeof(cmd))
197 return (FALSE0);
198
199 if ((fpipe = popen(cmd, "r")) == NULL((void *)0))
200 return(dobeep_msg("problem opening pipe"));
201
202 bp = bfind("*cscope*", TRUE1);
203 if (bclear(bp) != TRUE1) {
204 pclose(fpipe);
205 return (FALSE0);
206 }
207 bp->b_flag |= BFREADONLY0x10;
208
209 clen = snprintf(title, sizeof(title), "%s%s",
210 "Creating cscope file list 'cscope.files' in: ", dir);
211 if (clen < 0 || clen >= sizeof(title)) {
212 pclose(fpipe);
213 return (FALSE0);
214 }
215 addline(bp, title)addlinef(bp, "%s", title);
216 addline(bp, "")addlinef(bp, "%s", "");
217 while ((len = getline(&line, &sz, fpipe)) != -1) {
218 if (line[len - 1] == *bp->b_nlchr)
219 line[len - 1] = '\0';
220 addline(bp, line)addlinef(bp, "%s", line);
221 }
222 free(line);
223 if (ferror(fpipe)(!__isthreaded ? (((fpipe)->_flags & 0x0040) != 0) : (
ferror)(fpipe))
)
224 ewprintf("Problem reading pipe");
225 pclose(fpipe);
226 return (popbuftop(bp, WNONE0x00));
227}
228
229/*
230 * Next Symbol. Bound to C-c s n
231 */
232/* ARGSUSED */
233int
234csnextmatch(int f, int n)
235{
236 struct csrecord *r;
237 struct csmatch *m;
238
239 if (curmatch == NULL((void *)0)) {
240 if ((r = TAILQ_FIRST(&csrecords)((&csrecords)->tqh_first)) == NULL((void *)0))
241 return(dobeep_msg("The *cscope* buffer does "
242 "not exist yet"));
243
244 currecord = r;
245 curmatch = TAILQ_FIRST(&r->matches)((&r->matches)->tqh_first);
246 } else {
247 m = TAILQ_NEXT(curmatch, entry)((curmatch)->entry.tqe_next);
248 if (m == NULL((void *)0)) {
249 r = TAILQ_NEXT(currecord, entry)((currecord)->entry.tqe_next);
250 if (r == NULL((void *)0)) {
251 return(dobeep_msg("The end of *cscope* buffer "
252 "has been reached"));
253 } else {
254 currecord = r;
255 curmatch = TAILQ_FIRST(&currecord->matches)((&currecord->matches)->tqh_first);
256 }
257 } else
258 curmatch = m;
259 }
260 return (jumptomatch());
261}
262
263/*
264 * Previous Symbol. Bound to C-c s p
265 */
266/* ARGSUSED */
267int
268csprevmatch(int f, int n)
269{
270 struct csmatch *m;
271 struct csrecord *r;
272
273 if (curmatch == NULL((void *)0))
274 return (FALSE0);
275 else {
276 m = TAILQ_PREV(curmatch, matches, entry)(*(((struct matches *)((curmatch)->entry.tqe_prev))->tqh_last
))
;
277 if (m)
278 curmatch = m;
279 else {
280 r = TAILQ_PREV(currecord, csrecords, entry)(*(((struct csrecords *)((currecord)->entry.tqe_prev))->
tqh_last))
;
281 if (r == NULL((void *)0)) {
282 return(dobeep_msg("The beginning of *cscope* "
283 "buffer has been reached"));
284 } else {
285 currecord = r;
286 curmatch = TAILQ_LAST(&currecord->matches,(*(((struct matches *)((&currecord->matches)->tqh_last
))->tqh_last))
287 matches)(*(((struct matches *)((&currecord->matches)->tqh_last
))->tqh_last))
;
288 }
289 }
290 }
291 return (jumptomatch());
292}
293
294/*
295 * Next file.
296 */
297int
298csnextfile(int f, int n)
299{
300 struct csrecord *r;
301
302 if (curmatch == NULL((void *)0)) {
303 if ((r = TAILQ_FIRST(&csrecords)((&csrecords)->tqh_first)) == NULL((void *)0))
304 return(dobeep_msg("The *cscope* buffer does not "
305 "exist yet"));
306 } else {
307 if ((r = TAILQ_NEXT(currecord, entry)((currecord)->entry.tqe_next)) == NULL((void *)0))
308 return(dobeep_msg("The end of *cscope* buffer has "
309 "been reached"));
310 }
311 currecord = r;
312 curmatch = TAILQ_FIRST(&currecord->matches)((&currecord->matches)->tqh_first);
313 return (jumptomatch());
314}
315
316/*
317 * Previous file.
318 */
319int
320csprevfile(int f, int n)
321{
322 struct csrecord *r;
323
324 if (curmatch == NULL((void *)0)) {
325 if ((r = TAILQ_FIRST(&csrecords)((&csrecords)->tqh_first)) == NULL((void *)0))
326 return(dobeep_msg("The *cscope* buffer does not"
327 "exist yet"));
328 } else {
329 if ((r = TAILQ_PREV(currecord, csrecords, entry)(*(((struct csrecords *)((currecord)->entry.tqe_prev))->
tqh_last))
) == NULL((void *)0))
330 return(dobeep_msg("The beginning of *cscope* buffer "
331 "has been reached"));
332 }
333 currecord = r;
334 curmatch = TAILQ_FIRST(&currecord->matches)((&currecord->matches)->tqh_first);
335 return (jumptomatch());
336}
337
338/*
339 * The current symbol location is extracted from currecord->filename and
340 * curmatch->lineno. Load the file similar to filevisit and goto the
341 * lineno recorded.
342 */
343int
344jumptomatch(void)
345{
346 struct buffer *bp;
347 char *adjf;
348
349 if (curmatch == NULL((void *)0) || currecord == NULL((void *)0))
350 return (FALSE0);
351 adjf = adjustname(currecord->filename, TRUE1);
352 if (adjf == NULL((void *)0))
353 return (FALSE0);
354 if ((bp = findbuffer(adjf)) == NULL((void *)0))
355 return (FALSE0);
356 curbp = bp;
357 if (showbuffer(bp, curwp, WFFULL0x08) != TRUE1)
358 return (FALSE0);
359 if (bp->b_fname[0] == '\0') {
360 if (readin(adjf) != TRUE1)
361 killbuffer(bp);
362 }
363 gotoline(FFARG7, curmatch->lineno);
364 return (TRUE1);
365}
366
367/*
368 * Ask for the symbol, construct cscope commandline with the symbol
369 * and passed in index. Popen cscope, read the output into *cscope*
370 * buffer and pop it.
371 */
372int
373do_cscope(int i)
374{
375 struct buffer *bp;
376 FILE *fpipe;
377 char pattern[MAX_TOKEN64], cmd[BUFSIZ1024], title[BUFSIZ1024];
378 char *p, *buf;
379 int clen, nores = 0;
380 size_t sz;
381 ssize_t len;
382
383 buf = NULL((void *)0);
384 sz = 0;
385
386 /* If current buffer isn't a source file just return */
387 if (fnmatch("*.[chy]", curbp->b_fname, 0) != 0)
2
Assuming the condition is false
3
Taking false branch
388 return(dobeep_msg("C-c s not defined"));
389
390 if (curtoken(0, 1, pattern) == FALSE0)
4
Assuming the condition is false
5
Taking false branch
391 return (FALSE0);
392 p = eread("%s", pattern, MAX_TOKEN64, EFNEW0x0008 | EFCR0x0010 | EFDEF0x0020, csprompt[i]);
393 if (p == NULL((void *)0))
6
Assuming 'p' is not equal to NULL
7
Taking false branch
394 return (ABORT2);
395 else if (p[0] == '\0')
8
Assuming the condition is false
9
Taking false branch
396 return (FALSE0);
397
398 if (csexists("cscope") == FALSE0)
10
Assuming the condition is false
11
Taking false branch
399 return(dobeep_msg("no such file or directory, cscope"));
400
401 csflush();
12
Calling 'csflush'
402 clen = snprintf(cmd, sizeof(cmd), "cscope -L -%d %s 2>/dev/null",
403 i, pattern);
404 if (clen < 0 || clen >= sizeof(cmd))
405 return (FALSE0);
406
407 if ((fpipe = popen(cmd, "r")) == NULL((void *)0))
408 return(dobeep_msg("problem opening pipe"));
409
410 bp = bfind("*cscope*", TRUE1);
411 if (bclear(bp) != TRUE1) {
412 pclose(fpipe);
413 return (FALSE0);
414 }
415 bp->b_flag |= BFREADONLY0x10;
416
417 clen = snprintf(title, sizeof(title), "%s%s", csprompt[i], pattern);
418 if (clen < 0 || clen >= sizeof(title)) {
419 pclose(fpipe);
420 return (FALSE0);
421 }
422 addline(bp, title)addlinef(bp, "%s", title);
423 addline(bp, "")addlinef(bp, "%s", "");
424 addline(bp, "-------------------------------------------------------------------------------")addlinef(bp, "%s", "-------------------------------------------------------------------------------"
)
;
425 while ((len = getline(&buf, &sz, fpipe)) != -1) {
426 if (buf[len - 1] == *bp->b_nlchr)
427 buf[len - 1] = '\0';
428 if (addentry(bp, buf) != TRUE1) {
429 free(buf);
430 return (FALSE0);
431 }
432 nores = 1;
433 }
434 free(buf);
435 if (ferror(fpipe)(!__isthreaded ? (((fpipe)->_flags & 0x0040) != 0) : (
ferror)(fpipe))
)
436 ewprintf("Problem reading pipe");
437 pclose(fpipe);
438 addline(bp, "-------------------------------------------------------------------------------")addlinef(bp, "%s", "-------------------------------------------------------------------------------"
)
;
439 if (nores == 0)
440 ewprintf("No matches were found.");
441 return (popbuftop(bp, WNONE0x00));
442}
443
444/*
445 * For each line read from cscope output, extract the tokens,
446 * add them to list and pretty print a line in *cscope* buffer.
447 */
448int
449addentry(struct buffer *bp, char *csline)
450{
451 struct csrecord *r;
452 struct csmatch *m;
453 struct cstokens t;
454 int lineno;
455 char buf[BUFSIZ1024];
456 const char *errstr;
457
458 r = NULL((void *)0);
459 if (getattr(csline, &t) == FALSE0)
460 return (FALSE0);
461
462 lineno = strtonum(t.lineno, INT_MIN(-2147483647 -1), INT_MAX2147483647, &errstr);
463 if (errstr)
464 return (FALSE0);
465
466 if (addentryfn == NULL((void *)0) || strcmp(addentryfn, t.fname) != 0) {
467 if ((r = malloc(sizeof(struct csrecord))) == NULL((void *)0))
468 return (FALSE0);
469 addentryr = r;
470 if ((r->filename = strndup(t.fname, NFILEN1024)) == NULL((void *)0))
471 goto cleanup;
472 addentryfn = r->filename;
473 TAILQ_INIT(&r->matches)do { (&r->matches)->tqh_first = ((void *)0); (&
r->matches)->tqh_last = &(&r->matches)->tqh_first
; } while (0)
;
474 if ((m = malloc(sizeof(struct csmatch))) == NULL((void *)0))
475 goto cleanup;
476 m->lineno = lineno;
477 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)
;
478 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)
;
479 addline(bp, "")addlinef(bp, "%s", "");
480 if (snprintf(buf, sizeof(buf), "*** %s", t.fname) < 0)
481 goto cleanup;
482 addline(bp, buf)addlinef(bp, "%s", buf);
483 } else {
484 if ((m = malloc(sizeof(struct csmatch))) == NULL((void *)0))
485 goto cleanup;
486 m->lineno = lineno;
487 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)
;
488 }
489 prettyprint(bp, &t);
490 return (TRUE1);
491cleanup:
492 free(r);
493 return (FALSE0);
494}
495
496/*
497 * Cscope line: <filename> <function> <lineno> <pattern>
498 */
499int
500getattr(char *line, struct cstokens *t)
501{
502 char *p;
503
504 if ((p = strchr(line, ' ')) == NULL((void *)0))
505 return (FALSE0);
506 *p++ = '\0';
507 t->fname = line;
508 line = p;
509
510 if ((p = strchr(line, ' ')) == NULL((void *)0))
511 return (FALSE0);
512 *p++ = '\0';
513 t->function = line;
514 line = p;
515
516 if ((p = strchr(line, ' ')) == NULL((void *)0))
517 return (FALSE0);
518 *p++ = '\0';
519 t->lineno = line;
520
521 if (*p == '\0')
522 return (FALSE0);
523 t->pattern = p;
524
525 return (TRUE1);
526}
527
528void
529prettyprint(struct buffer *bp, struct cstokens *t)
530{
531 char buf[BUFSIZ1024];
532
533 if (snprintf(buf, sizeof(buf), "%s[%s]\t\t%s",
534 t->function, t->lineno, ltrim(t->pattern)) < 0)
535 return;
536 addline(bp, buf)addlinef(bp, "%s", buf);
537}
538
539const char *
540ltrim(const char *s)
541{
542 while (isblank((unsigned char)*s))
543 s++;
544 return s;
545}
546
547void
548csflush(void)
549{
550 struct csrecord *r;
551 struct csmatch *m;
552
553 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
554 free(r->filename);
22
Use of memory after it is freed
555 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 559
556 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)
;
557 free(m);
558 }
559 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
560 free(r);
20
Memory is released
561 }
562 addentryr = NULL((void *)0);
563 addentryfn = NULL((void *)0);
564 currecord = NULL((void *)0);
565 curmatch = NULL((void *)0);
566}
567
568/*
569 * Check if the cmd exists in $PATH. Split on ":" and iterate through
570 * all paths in $PATH.
571 */
572int
573csexists(const char *cmd)
574{
575 char fname[NFILEN1024], *dir, *path, *pathc, *tmp;
576 int len, dlen;
577
578 /* Special case if prog contains '/' */
579 if (strchr(cmd, '/')) {
580 if (access(cmd, F_OK0) == -1)
581 return (FALSE0);
582 else
583 return (TRUE1);
584 }
585 if ((tmp = getenv("PATH")) == NULL((void *)0))
586 return (FALSE0);
587 if ((pathc = path = strndup(tmp, NFILEN1024)) == NULL((void *)0))
588 return(dobeep_msg("out of memory"));
589
590 while ((dir = strsep(&path, ":")) != NULL((void *)0)) {
591 if (*dir == '\0')
592 continue;
593
594 dlen = strlen(dir);
595 while (dlen > 0 && dir[dlen-1] == '/')
596 dir[--dlen] = '\0'; /* strip trailing '/' */
597
598 len = snprintf(fname, sizeof(fname), "%s/%s", dir, cmd);
599 if (len < 0 || len >= sizeof(fname)) {
600 (void)dobeep_msg("path too long");
601 goto cleanup;
602 }
603 if(access(fname, F_OK0) == 0) {
604 free(pathc);
605 return (TRUE1);
606 }
607 }
608cleanup:
609 free(pathc);
610 return (FALSE0);
611}