99e8794195bccc5f7f94d8eb7893ce54ad2f4a70
[packages/trusty/cirros-testvm.git] / cirros-testvm / src-cirros / buildroot-2015.05 / package / elfutils / 0003-fts.patch
1 Add an implementation of the fts_*() functions
2
3 The fts_*() functions are optional in uClibc, and not compiled in our
4 default configuration. The best option would be to migrate this
5 elfutils code to the nftw family of functions, but it requires quite
6 some work.
7
8 So we have several options here:
9
10  *) Enable fts_*() functions in our default uClibc configuration. Not
11     nice since only one package needs them (the help text of uClibc
12     for fts_*() functions explicitly mention that they have been added
13     to be able to build elfutils).
14
15  *) Use gnulib, but it is quite heavy to setup, requires modifications
16     to configure.ac, and other things.
17
18  *) Copy the fts function from uClibc into elfutils source code. This
19     is the solution used below. uClibc is LGPL, and elfutils is
20     LGPL/GPL, so there should not be any licensing issue.
21
22 Of course, the fts_*() functions are only built if they are not
23 already provided by the C library.
24
25 Based on the former patch by Thomas Petazzoni.
26
27 Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
28 Signed-off-by: Vicente Olivert Riera <Vincent.Riera@imgtec.com>
29
30 diff -Nrup a/configure.ac b/configure.ac
31 --- a/configure.ac      2015-01-06 11:37:38.397891424 +0000
32 +++ b/configure.ac      2015-01-06 11:40:53.568258759 +0000
33 @@ -266,6 +266,10 @@ AC_ARG_ENABLE([progs],
34         enable_progs=yes)
35  AM_CONDITIONAL(ENABLE_PROGS, test "$enable_progs" = yes)
36  
37 +AC_CHECK_HEADER([fts.h],
38 +       AC_DEFINE([HAVE_FTS_H], [], [Define if <fts.h> is available in C library]))
39 +AM_CONDITIONAL(HAVE_FTS, test "$ac_cv_header_fts_h" = yes)
40 +
41  dnl Test for zlib and bzlib, gives ZLIB/BZLIB .am
42  dnl conditional and config.h USE_ZLIB/USE_BZLIB #define.
43  save_LIBS="$LIBS"
44 diff -Nrup a/libdwfl/fts.c b/libdwfl/fts.c
45 --- a/libdwfl/fts.c     1970-01-01 01:00:00.000000000 +0100
46 +++ b/libdwfl/fts.c     2015-01-06 11:42:13.481640322 +0000
47 @@ -0,0 +1,1095 @@
48 +/*-
49 + * Copyright (c) 1990, 1993, 1994
50 + *     The Regents of the University of California.  All rights reserved.
51 + *
52 + * Redistribution and use in source and binary forms, with or without
53 + * modification, are permitted provided that the following conditions
54 + * are met:
55 + * 1. Redistributions of source code must retain the above copyright
56 + *    notice, this list of conditions and the following disclaimer.
57 + * 2. Redistributions in binary form must reproduce the above copyright
58 + *    notice, this list of conditions and the following disclaimer in the
59 + *    documentation and/or other materials provided with the distribution.
60 + * 4. Neither the name of the University nor the names of its contributors
61 + *    may be used to endorse or promote products derived from this software
62 + *    without specific prior written permission.
63 + *
64 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 + * SUCH DAMAGE.
75 + */
76 +
77 +#include <sys/param.h>
78 +#include <sys/stat.h>
79 +#include <fcntl.h>
80 +#include <dirent.h>
81 +#include <errno.h>
82 +#include "fts_.h"
83 +#include <stdlib.h>
84 +#include <string.h>
85 +#include <unistd.h>
86 +
87 +/* Largest alignment size needed, minus one.
88 +   Usually long double is the worst case.  */
89 +#ifndef ALIGNBYTES
90 +#define ALIGNBYTES     (__alignof__ (long double) - 1)
91 +#endif
92 +/* Align P to that size.  */
93 +#ifndef ALIGN
94 +#define        ALIGN(p)        (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
95 +#endif
96 +
97 +
98 +static FTSENT  *fts_alloc (FTS *, const char *, size_t);
99 +static FTSENT  *fts_build (FTS *, int);
100 +static void     fts_lfree (FTSENT *);
101 +static void     fts_load (FTS *, FTSENT *);
102 +static size_t   fts_maxarglen (char * const *);
103 +static void     fts_padjust (FTS *, FTSENT *);
104 +static int      fts_palloc (FTS *, size_t);
105 +static FTSENT  *fts_sort (FTS *, FTSENT *, int);
106 +static u_short  fts_stat (FTS *, FTSENT *, int);
107 +static int      fts_safe_changedir (FTS *, FTSENT *, int, const char *);
108 +
109 +#ifndef MAX
110 +#define MAX(a, b)      ({ __typeof__ (a) _a = (a); \
111 +                          __typeof__ (b) _b = (b); \
112 +                          _a > _b ? _a : _b; })
113 +#endif
114 +
115 +#define        ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
116 +
117 +#define CLR(opt)       (sp->fts_options &= ~(opt))
118 +#define        ISSET(opt)      (sp->fts_options & (opt))
119 +#define        SET(opt)        (sp->fts_options |= (opt))
120 +
121 +#define        FCHDIR(sp, fd)  (!ISSET(FTS_NOCHDIR) && fchdir(fd))
122 +
123 +/* fts_build flags */
124 +#define        BCHILD          1               /* fts_children */
125 +#define        BNAMES          2               /* fts_children, names only */
126 +#define        BREAD           3               /* fts_read */
127 +
128 +FTS *
129 +fts_open( char * const *argv, register int options,
130 +               int (*compar) (const FTSENT **, const FTSENT **))
131 +{
132 +       register FTS *sp;
133 +       register FTSENT *p, *root;
134 +       register int nitems;
135 +       FTSENT *parent = NULL;
136 +       FTSENT *tmp = NULL;
137 +
138 +       /* Options check. */
139 +       if (options & ~FTS_OPTIONMASK) {
140 +               errno = EINVAL;
141 +               return (NULL);
142 +       }
143 +
144 +       /* Allocate/initialize the stream */
145 +       if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
146 +               return (NULL);
147 +       memset(sp, 0, sizeof(FTS));
148 +       sp->fts_compar = (int (*) (const void *, const void *)) compar;
149 +       sp->fts_options = options;
150 +
151 +       /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
152 +       if (ISSET(FTS_LOGICAL))
153 +               SET(FTS_NOCHDIR);
154 +
155 +       /*
156 +        * Start out with 1K of path space, and enough, in any case,
157 +        * to hold the user's paths.
158 +        */
159 +#ifndef MAXPATHLEN
160 +#define MAXPATHLEN 1024
161 +#endif
162 +       size_t maxarglen = fts_maxarglen(argv);
163 +       if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
164 +               goto mem1;
165 +
166 +       /* Allocate/initialize root's parent. */
167 +       if (*argv != NULL) {
168 +               if ((parent = fts_alloc(sp, "", 0)) == NULL)
169 +                       goto mem2;
170 +               parent->fts_level = FTS_ROOTPARENTLEVEL;
171 +         }
172 +
173 +       /* Allocate/initialize root(s). */
174 +       for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
175 +               /* Don't allow zero-length paths. */
176 +               size_t len = strlen(*argv);
177 +               if (len == 0) {
178 +                       errno = ENOENT;
179 +                       goto mem3;
180 +               }
181 +
182 +               p = fts_alloc(sp, *argv, len);
183 +               p->fts_level = FTS_ROOTLEVEL;
184 +               p->fts_parent = parent;
185 +               p->fts_accpath = p->fts_name;
186 +               p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
187 +
188 +               /* Command-line "." and ".." are real directories. */
189 +               if (p->fts_info == FTS_DOT)
190 +                       p->fts_info = FTS_D;
191 +
192 +               /*
193 +                * If comparison routine supplied, traverse in sorted
194 +                * order; otherwise traverse in the order specified.
195 +                */
196 +               if (compar) {
197 +                       p->fts_link = root;
198 +                       root = p;
199 +               } else {
200 +                       p->fts_link = NULL;
201 +                       if (root == NULL)
202 +                               tmp = root = p;
203 +                       else {
204 +                               tmp->fts_link = p;
205 +                               tmp = p;
206 +                       }
207 +               }
208 +       }
209 +       if (compar && nitems > 1)
210 +               root = fts_sort(sp, root, nitems);
211 +
212 +       /*
213 +        * Allocate a dummy pointer and make fts_read think that we've just
214 +        * finished the node before the root(s); set p->fts_info to FTS_INIT
215 +        * so that everything about the "current" node is ignored.
216 +        */
217 +       if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
218 +               goto mem3;
219 +       sp->fts_cur->fts_link = root;
220 +       sp->fts_cur->fts_info = FTS_INIT;
221 +
222 +       /*
223 +        * If using chdir(2), grab a file descriptor pointing to dot to ensure
224 +        * that we can get back here; this could be avoided for some paths,
225 +        * but almost certainly not worth the effort.  Slashes, symbolic links,
226 +        * and ".." are all fairly nasty problems.  Note, if we can't get the
227 +        * descriptor we run anyway, just more slowly.
228 +        */
229 +       if (!ISSET(FTS_NOCHDIR)
230 +           && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
231 +               SET(FTS_NOCHDIR);
232 +
233 +       return (sp);
234 +
235 +mem3:  fts_lfree(root);
236 +       free(parent);
237 +mem2:  free(sp->fts_path);
238 +mem1:  free(sp);
239 +       return (NULL);
240 +}
241 +
242 +static void
243 +fts_load(FTS *sp, register FTSENT *p)
244 +{
245 +       register int len;
246 +       register char *cp;
247 +
248 +       /*
249 +        * Load the stream structure for the next traversal.  Since we don't
250 +        * actually enter the directory until after the preorder visit, set
251 +        * the fts_accpath field specially so the chdir gets done to the right
252 +        * place and the user can access the first node.  From fts_open it's
253 +        * known that the path will fit.
254 +        */
255 +       len = p->fts_pathlen = p->fts_namelen;
256 +       memmove(sp->fts_path, p->fts_name, len + 1);
257 +       if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
258 +               len = strlen(++cp);
259 +               memmove(p->fts_name, cp, len + 1);
260 +               p->fts_namelen = len;
261 +       }
262 +       p->fts_accpath = p->fts_path = sp->fts_path;
263 +       sp->fts_dev = p->fts_dev;
264 +}
265 +
266 +int
267 +fts_close(FTS *sp)
268 +{
269 +       register FTSENT *freep, *p;
270 +       int saved_errno;
271 +
272 +       /*
273 +        * This still works if we haven't read anything -- the dummy structure
274 +        * points to the root list, so we step through to the end of the root
275 +        * list which has a valid parent pointer.
276 +        */
277 +       if (sp->fts_cur) {
278 +               for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
279 +                       freep = p;
280 +                       p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
281 +                       free(freep);
282 +               }
283 +               free(p);
284 +       }
285 +
286 +       /* Free up child linked list, sort array, path buffer. */
287 +       if (sp->fts_child)
288 +               fts_lfree(sp->fts_child);
289 +       free(sp->fts_array);
290 +       free(sp->fts_path);
291 +
292 +       /* Return to original directory, save errno if necessary. */
293 +       if (!ISSET(FTS_NOCHDIR)) {
294 +               saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
295 +               (void)close(sp->fts_rfd);
296 +
297 +               /* Set errno and return. */
298 +               if (saved_errno != 0) {
299 +                       /* Free up the stream pointer. */
300 +                       free(sp);
301 +                       errno = saved_errno;
302 +                       return (-1);
303 +               }
304 +       }
305 +
306 +       /* Free up the stream pointer. */
307 +       free(sp);
308 +       return (0);
309 +}
310 +
311 +/*
312 + * Special case of "/" at the end of the path so that slashes aren't
313 + * appended which would cause paths to be written as "....//foo".
314 + */
315 +#define        NAPPEND(p)                                                      \
316 +       (p->fts_path[p->fts_pathlen - 1] == '/'                         \
317 +           ? p->fts_pathlen - 1 : p->fts_pathlen)
318 +
319 +FTSENT *
320 +fts_read(register FTS *sp)
321 +{
322 +       register FTSENT *p, *tmp;
323 +       register int instr;
324 +       register char *t;
325 +       int saved_errno;
326 +
327 +       /* If finished or unrecoverable error, return NULL. */
328 +       if (sp->fts_cur == NULL || ISSET(FTS_STOP))
329 +               return (NULL);
330 +
331 +       /* Set current node pointer. */
332 +       p = sp->fts_cur;
333 +
334 +       /* Save and zero out user instructions. */
335 +       instr = p->fts_instr;
336 +       p->fts_instr = FTS_NOINSTR;
337 +
338 +       /* Any type of file may be re-visited; re-stat and re-turn. */
339 +       if (instr == FTS_AGAIN) {
340 +               p->fts_info = fts_stat(sp, p, 0);
341 +               return (p);
342 +       }
343 +
344 +       /*
345 +        * Following a symlink -- SLNONE test allows application to see
346 +        * SLNONE and recover.  If indirecting through a symlink, have
347 +        * keep a pointer to current location.  If unable to get that
348 +        * pointer, follow fails.
349 +        */
350 +       if (instr == FTS_FOLLOW &&
351 +           (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
352 +               p->fts_info = fts_stat(sp, p, 1);
353 +               if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
354 +                       if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
355 +                               p->fts_errno = errno;
356 +                               p->fts_info = FTS_ERR;
357 +                       } else
358 +                               p->fts_flags |= FTS_SYMFOLLOW;
359 +               }
360 +               return (p);
361 +       }
362 +
363 +       /* Directory in pre-order. */
364 +       if (p->fts_info == FTS_D) {
365 +               /* If skipped or crossed mount point, do post-order visit. */
366 +               if (instr == FTS_SKIP ||
367 +                   (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
368 +                       if (p->fts_flags & FTS_SYMFOLLOW)
369 +                               (void)close(p->fts_symfd);
370 +                       if (sp->fts_child) {
371 +                               fts_lfree(sp->fts_child);
372 +                               sp->fts_child = NULL;
373 +                       }
374 +                       p->fts_info = FTS_DP;
375 +                       return (p);
376 +               }
377 +
378 +               /* Rebuild if only read the names and now traversing. */
379 +               if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
380 +                       CLR(FTS_NAMEONLY);
381 +                       fts_lfree(sp->fts_child);
382 +                       sp->fts_child = NULL;
383 +               }
384 +
385 +               /*
386 +                * Cd to the subdirectory.
387 +                *
388 +                * If have already read and now fail to chdir, whack the list
389 +                * to make the names come out right, and set the parent errno
390 +                * so the application will eventually get an error condition.
391 +                * Set the FTS_DONTCHDIR flag so that when we logically change
392 +                * directories back to the parent we don't do a chdir.
393 +                *
394 +                * If haven't read do so.  If the read fails, fts_build sets
395 +                * FTS_STOP or the fts_info field of the node.
396 +                */
397 +               if (sp->fts_child != NULL) {
398 +                       if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
399 +                               p->fts_errno = errno;
400 +                               p->fts_flags |= FTS_DONTCHDIR;
401 +                               for (p = sp->fts_child; p != NULL;
402 +                                    p = p->fts_link)
403 +                                       p->fts_accpath =
404 +                                           p->fts_parent->fts_accpath;
405 +                       }
406 +               } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
407 +                       if (ISSET(FTS_STOP))
408 +                               return (NULL);
409 +                       return (p);
410 +               }
411 +               p = sp->fts_child;
412 +               sp->fts_child = NULL;
413 +               sp->fts_cur = p;
414 +               goto name;
415 +       }
416 +
417 +       /* Move to the next node on this level. */
418 +next:  tmp = p;
419 +       if ((p = p->fts_link) != NULL) {
420 +               sp->fts_cur = p;
421 +               free(tmp);
422 +
423 +               /*
424 +                * If reached the top, return to the original directory (or
425 +                * the root of the tree), and load the paths for the next root.
426 +                */
427 +               if (p->fts_level == FTS_ROOTLEVEL) {
428 +                       if (FCHDIR(sp, sp->fts_rfd)) {
429 +                               SET(FTS_STOP);
430 +                               return (NULL);
431 +                       }
432 +                       fts_load(sp, p);
433 +                       return p;
434 +               }
435 +
436 +               /*
437 +                * User may have called fts_set on the node.  If skipped,
438 +                * ignore.  If followed, get a file descriptor so we can
439 +                * get back if necessary.
440 +                */
441 +               if (p->fts_instr == FTS_SKIP)
442 +                       goto next;
443 +               if (p->fts_instr == FTS_FOLLOW) {
444 +                       p->fts_info = fts_stat(sp, p, 1);
445 +                       if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
446 +                               if ((p->fts_symfd =
447 +                                   open(".", O_RDONLY, 0)) < 0) {
448 +                                       p->fts_errno = errno;
449 +                                       p->fts_info = FTS_ERR;
450 +                               } else
451 +                                       p->fts_flags |= FTS_SYMFOLLOW;
452 +                       }
453 +                       p->fts_instr = FTS_NOINSTR;
454 +               }
455 +
456 +name:          t = sp->fts_path + NAPPEND(p->fts_parent);
457 +               *t++ = '/';
458 +               memmove(t, p->fts_name, p->fts_namelen + 1);
459 +               return p;
460 +       }
461 +
462 +       /* Move up to the parent node. */
463 +       p = tmp->fts_parent;
464 +       sp->fts_cur = p;
465 +       free(tmp);
466 +
467 +       if (p->fts_level == FTS_ROOTPARENTLEVEL) {
468 +               /*
469 +                * Done; free everything up and set errno to 0 so the user
470 +                * can distinguish between error and EOF.
471 +                */
472 +               free(p);
473 +               errno = 0;
474 +               return (sp->fts_cur = NULL);
475 +       }
476 +
477 +       /* NUL terminate the pathname. */
478 +       sp->fts_path[p->fts_pathlen] = '\0';
479 +
480 +       /*
481 +        * Return to the parent directory.  If at a root node or came through
482 +        * a symlink, go back through the file descriptor.  Otherwise, cd up
483 +        * one directory.
484 +        */
485 +       if (p->fts_level == FTS_ROOTLEVEL) {
486 +               if (FCHDIR(sp, sp->fts_rfd)) {
487 +                       SET(FTS_STOP);
488 +                       return (NULL);
489 +               }
490 +       } else if (p->fts_flags & FTS_SYMFOLLOW) {
491 +               if (FCHDIR(sp, p->fts_symfd)) {
492 +                       saved_errno = errno;
493 +                       (void)close(p->fts_symfd);
494 +                       errno = saved_errno;
495 +                       SET(FTS_STOP);
496 +                       return (NULL);
497 +               }
498 +               (void)close(p->fts_symfd);
499 +       } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
500 +                  fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
501 +               SET(FTS_STOP);
502 +               return (NULL);
503 +       }
504 +       p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
505 +       return p;
506 +}
507 +
508 +/*
509 + * Fts_set takes the stream as an argument although it's not used in this
510 + * implementation; it would be necessary if anyone wanted to add global
511 + * semantics to fts using fts_set.  An error return is allowed for similar
512 + * reasons.
513 + */
514 +/* ARGSUSED */
515 +int
516 +fts_set(FTS *sp, FTSENT *p, int instr)
517 +{
518 +       if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
519 +           instr != FTS_NOINSTR && instr != FTS_SKIP) {
520 +               errno = EINVAL;
521 +               return (1);
522 +       }
523 +       p->fts_instr = instr;
524 +       return (0);
525 +}
526 +
527 +FTSENT *
528 +fts_children(register FTS *sp, int instr)
529 +{
530 +       register FTSENT *p;
531 +       int fd;
532 +
533 +       if (instr != 0 && instr != FTS_NAMEONLY) {
534 +               errno = EINVAL;
535 +               return (NULL);
536 +       }
537 +
538 +       /* Set current node pointer. */
539 +       p = sp->fts_cur;
540 +
541 +       /*
542 +        * Errno set to 0 so user can distinguish empty directory from
543 +        * an error.
544 +        */
545 +       errno = 0;
546 +
547 +       /* Fatal errors stop here. */
548 +       if (ISSET(FTS_STOP))
549 +               return (NULL);
550 +
551 +       /* Return logical hierarchy of user's arguments. */
552 +       if (p->fts_info == FTS_INIT)
553 +               return (p->fts_link);
554 +
555 +       /*
556 +        * If not a directory being visited in pre-order, stop here.  Could
557 +        * allow FTS_DNR, assuming the user has fixed the problem, but the
558 +        * same effect is available with FTS_AGAIN.
559 +        */
560 +       if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
561 +               return (NULL);
562 +
563 +       /* Free up any previous child list. */
564 +       if (sp->fts_child != NULL)
565 +               fts_lfree(sp->fts_child);
566 +
567 +       if (instr == FTS_NAMEONLY) {
568 +               SET(FTS_NAMEONLY);
569 +               instr = BNAMES;
570 +       } else
571 +               instr = BCHILD;
572 +
573 +       /*
574 +        * If using chdir on a relative path and called BEFORE fts_read does
575 +        * its chdir to the root of a traversal, we can lose -- we need to
576 +        * chdir into the subdirectory, and we don't know where the current
577 +        * directory is, so we can't get back so that the upcoming chdir by
578 +        * fts_read will work.
579 +        */
580 +       if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
581 +           ISSET(FTS_NOCHDIR))
582 +               return (sp->fts_child = fts_build(sp, instr));
583 +
584 +       if ((fd = open(".", O_RDONLY, 0)) < 0)
585 +               return (NULL);
586 +       sp->fts_child = fts_build(sp, instr);
587 +       if (fchdir(fd))
588 +               return (NULL);
589 +       (void)close(fd);
590 +       return (sp->fts_child);
591 +}
592 +
593 +/*
594 + * This is the tricky part -- do not casually change *anything* in here.  The
595 + * idea is to build the linked list of entries that are used by fts_children
596 + * and fts_read.  There are lots of special cases.
597 + *
598 + * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
599 + * set and it's a physical walk (so that symbolic links can't be directories),
600 + * we can do things quickly.  First, if it's a 4.4BSD file system, the type
601 + * of the file is in the directory entry.  Otherwise, we assume that the number
602 + * of subdirectories in a node is equal to the number of links to the parent.
603 + * The former skips all stat calls.  The latter skips stat calls in any leaf
604 + * directories and for any files after the subdirectories in the directory have
605 + * been found, cutting the stat calls by about 2/3.
606 + */
607 +static FTSENT *
608 +fts_build(register FTS *sp, int type)
609 +{
610 +       register struct dirent *dp;
611 +       register FTSENT *p, *head;
612 +       register int nitems;
613 +       FTSENT *cur, *tail;
614 +       DIR *dirp;
615 +       void *oldaddr;
616 +       int cderrno, descend, len, level, nlinks, saved_errno,
617 +           nostat, doadjust;
618 +       size_t maxlen;
619 +       char *cp;
620 +
621 +       /* Set current node pointer. */
622 +       cur = sp->fts_cur;
623 +
624 +       /*
625 +        * Open the directory for reading.  If this fails, we're done.
626 +        * If being called from fts_read, set the fts_info field.
627 +        */
628 +#if defined FTS_WHITEOUT && 0
629 +       if (ISSET(FTS_WHITEOUT))
630 +               oflag = DTF_NODUP|DTF_REWIND;
631 +       else
632 +               oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
633 +#else
634 +# define opendir2(path, flag) opendir(path)
635 +#endif
636 +       if ((dirp = opendir2(cur->fts_accpath, oflag)) == NULL) {
637 +               if (type == BREAD) {
638 +                       cur->fts_info = FTS_DNR;
639 +                       cur->fts_errno = errno;
640 +               }
641 +               return (NULL);
642 +       }
643 +
644 +       /*
645 +        * Nlinks is the number of possible entries of type directory in the
646 +        * directory if we're cheating on stat calls, 0 if we're not doing
647 +        * any stat calls at all, -1 if we're doing stats on everything.
648 +        */
649 +       if (type == BNAMES) {
650 +               nlinks = 0;
651 +               /* Be quiet about nostat, GCC. */
652 +               nostat = 0;
653 +       } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
654 +               nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
655 +               nostat = 1;
656 +       } else {
657 +               nlinks = -1;
658 +               nostat = 0;
659 +       }
660 +
661 +#ifdef notdef
662 +       (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
663 +       (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
664 +           ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
665 +#endif
666 +       /*
667 +        * If we're going to need to stat anything or we want to descend
668 +        * and stay in the directory, chdir.  If this fails we keep going,
669 +        * but set a flag so we don't chdir after the post-order visit.
670 +        * We won't be able to stat anything, but we can still return the
671 +        * names themselves.  Note, that since fts_read won't be able to
672 +        * chdir into the directory, it will have to return different path
673 +        * names than before, i.e. "a/b" instead of "b".  Since the node
674 +        * has already been visited in pre-order, have to wait until the
675 +        * post-order visit to return the error.  There is a special case
676 +        * here, if there was nothing to stat then it's not an error to
677 +        * not be able to stat.  This is all fairly nasty.  If a program
678 +        * needed sorted entries or stat information, they had better be
679 +        * checking FTS_NS on the returned nodes.
680 +        */
681 +       cderrno = 0;
682 +       if (nlinks || type == BREAD) {
683 +               if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
684 +                       if (nlinks && type == BREAD)
685 +                               cur->fts_errno = errno;
686 +                       cur->fts_flags |= FTS_DONTCHDIR;
687 +                       descend = 0;
688 +                       cderrno = errno;
689 +                       (void)closedir(dirp);
690 +                       dirp = NULL;
691 +               } else
692 +                       descend = 1;
693 +       } else
694 +               descend = 0;
695 +
696 +       /*
697 +        * Figure out the max file name length that can be stored in the
698 +        * current path -- the inner loop allocates more path as necessary.
699 +        * We really wouldn't have to do the maxlen calculations here, we
700 +        * could do them in fts_read before returning the path, but it's a
701 +        * lot easier here since the length is part of the dirent structure.
702 +        *
703 +        * If not changing directories set a pointer so that can just append
704 +        * each new name into the path.
705 +        */
706 +       len = NAPPEND(cur);
707 +       if (ISSET(FTS_NOCHDIR)) {
708 +               cp = sp->fts_path + len;
709 +               *cp++ = '/';
710 +       } else {
711 +               /* GCC, you're too verbose. */
712 +               cp = NULL;
713 +       }
714 +       len++;
715 +       maxlen = sp->fts_pathlen - len;
716 +
717 +       level = cur->fts_level + 1;
718 +
719 +       /* Read the directory, attaching each entry to the `link' pointer. */
720 +       doadjust = 0;
721 +       for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
722 +               if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
723 +                       continue;
724 +
725 +               if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
726 +                       goto mem1;
727 +               if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
728 +                       oldaddr = sp->fts_path;
729 +                       if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
730 +                               /*
731 +                                * No more memory for path or structures.  Save
732 +                                * errno, free up the current structure and the
733 +                                * structures already allocated.
734 +                                */
735 +mem1:                          saved_errno = errno;
736 +                               free(p);
737 +                               fts_lfree(head);
738 +                               (void)closedir(dirp);
739 +                               cur->fts_info = FTS_ERR;
740 +                               SET(FTS_STOP);
741 +                               errno = saved_errno;
742 +                               return (NULL);
743 +                       }
744 +                       /* Did realloc() change the pointer? */
745 +                       if (oldaddr != sp->fts_path) {
746 +                               doadjust = 1;
747 +                               if (ISSET(FTS_NOCHDIR))
748 +                                       cp = sp->fts_path + len;
749 +                       }
750 +                       maxlen = sp->fts_pathlen - len;
751 +               }
752 +
753 +               if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
754 +                       /*
755 +                        * In an FTSENT, fts_pathlen is a u_short so it is
756 +                        * possible to wraparound here.  If we do, free up
757 +                        * the current structure and the structures already
758 +                        * allocated, then error out with ENAMETOOLONG.
759 +                        */
760 +                       free(p);
761 +                       fts_lfree(head);
762 +                       (void)closedir(dirp);
763 +                       cur->fts_info = FTS_ERR;
764 +                       SET(FTS_STOP);
765 +                       errno = ENAMETOOLONG;
766 +                       return (NULL);
767 +               }
768 +               p->fts_level = level;
769 +               p->fts_parent = sp->fts_cur;
770 +               p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
771 +
772 +#if defined FTS_WHITEOUT && 0
773 +               if (dp->d_type == DT_WHT)
774 +                       p->fts_flags |= FTS_ISW;
775 +#endif
776 +
777 +#if 0
778 +               /* Unreachable code.  cderrno is only ever set to a nonnull
779 +                  value if dirp is closed at the same time.  But then we
780 +                  cannot enter this loop.  */
781 +               if (cderrno) {
782 +                       if (nlinks) {
783 +                               p->fts_info = FTS_NS;
784 +                               p->fts_errno = cderrno;
785 +                       } else
786 +                               p->fts_info = FTS_NSOK;
787 +                       p->fts_accpath = cur->fts_accpath;
788 +               } else
789 +#endif
790 +               if (nlinks == 0
791 +#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
792 +                          || (nostat &&
793 +                              dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
794 +#endif
795 +                   ) {
796 +                       p->fts_accpath =
797 +                           ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
798 +                       p->fts_info = FTS_NSOK;
799 +               } else {
800 +                       /* Build a file name for fts_stat to stat. */
801 +                       if (ISSET(FTS_NOCHDIR)) {
802 +                               p->fts_accpath = p->fts_path;
803 +                               memmove(cp, p->fts_name, p->fts_namelen + 1);
804 +                       } else
805 +                               p->fts_accpath = p->fts_name;
806 +                       /* Stat it. */
807 +                       p->fts_info = fts_stat(sp, p, 0);
808 +
809 +                       /* Decrement link count if applicable. */
810 +                       if (nlinks > 0 && (p->fts_info == FTS_D ||
811 +                           p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
812 +                               --nlinks;
813 +               }
814 +
815 +               /* We walk in directory order so "ls -f" doesn't get upset. */
816 +               p->fts_link = NULL;
817 +               if (head == NULL)
818 +                       head = tail = p;
819 +               else {
820 +                       tail->fts_link = p;
821 +                       tail = p;
822 +               }
823 +               ++nitems;
824 +       }
825 +       if (dirp)
826 +               (void)closedir(dirp);
827 +
828 +       /*
829 +        * If realloc() changed the address of the path, adjust the
830 +        * addresses for the rest of the tree and the dir list.
831 +        */
832 +       if (doadjust)
833 +               fts_padjust(sp, head);
834 +
835 +       /*
836 +        * If not changing directories, reset the path back to original
837 +        * state.
838 +        */
839 +       if (ISSET(FTS_NOCHDIR)) {
840 +               if (len == sp->fts_pathlen || nitems == 0)
841 +                       --cp;
842 +               *cp = '\0';
843 +       }
844 +
845 +       /*
846 +        * If descended after called from fts_children or after called from
847 +        * fts_read and nothing found, get back.  At the root level we use
848 +        * the saved fd; if one of fts_open()'s arguments is a relative path
849 +        * to an empty directory, we wind up here with no other way back.  If
850 +        * can't get back, we're done.
851 +        */
852 +       if (descend && (type == BCHILD || !nitems) &&
853 +           (cur->fts_level == FTS_ROOTLEVEL ?
854 +            FCHDIR(sp, sp->fts_rfd) :
855 +            fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
856 +               cur->fts_info = FTS_ERR;
857 +               SET(FTS_STOP);
858 +               fts_lfree(head);
859 +               return (NULL);
860 +       }
861 +
862 +       /* If didn't find anything, return NULL. */
863 +       if (!nitems) {
864 +               if (type == BREAD)
865 +                       cur->fts_info = FTS_DP;
866 +               fts_lfree(head);
867 +               return (NULL);
868 +       }
869 +
870 +       /* Sort the entries. */
871 +       if (sp->fts_compar && nitems > 1)
872 +               head = fts_sort(sp, head, nitems);
873 +       return (head);
874 +}
875 +
876 +static u_short
877 +fts_stat(FTS *sp, register FTSENT *p, int follow)
878 +{
879 +       register FTSENT *t;
880 +       register dev_t dev;
881 +       register ino_t ino;
882 +       struct stat *sbp, sb;
883 +       int saved_errno;
884 +
885 +       /* If user needs stat info, stat buffer already allocated. */
886 +       sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
887 +
888 +#if defined FTS_WHITEOUT && 0
889 +       /* check for whiteout */
890 +       if (p->fts_flags & FTS_ISW) {
891 +               if (sbp != &sb) {
892 +                       memset(sbp, '\0', sizeof (*sbp));
893 +                       sbp->st_mode = S_IFWHT;
894 +               }
895 +               return (FTS_W);
896 +       }
897 +#endif
898 +
899 +       /*
900 +        * If doing a logical walk, or application requested FTS_FOLLOW, do
901 +        * a stat(2).  If that fails, check for a non-existent symlink.  If
902 +        * fail, set the errno from the stat call.
903 +        */
904 +       if (ISSET(FTS_LOGICAL) || follow) {
905 +               if (stat(p->fts_accpath, sbp)) {
906 +                       saved_errno = errno;
907 +                       if (!lstat(p->fts_accpath, sbp)) {
908 +                               errno = 0;
909 +                               return (FTS_SLNONE);
910 +                       }
911 +                       p->fts_errno = saved_errno;
912 +                       goto err;
913 +               }
914 +       } else if (lstat(p->fts_accpath, sbp)) {
915 +               p->fts_errno = errno;
916 +err:           memset(sbp, 0, sizeof(struct stat));
917 +               return (FTS_NS);
918 +       }
919 +
920 +       if (S_ISDIR(sbp->st_mode)) {
921 +               /*
922 +                * Set the device/inode.  Used to find cycles and check for
923 +                * crossing mount points.  Also remember the link count, used
924 +                * in fts_build to limit the number of stat calls.  It is
925 +                * understood that these fields are only referenced if fts_info
926 +                * is set to FTS_D.
927 +                */
928 +               dev = p->fts_dev = sbp->st_dev;
929 +               ino = p->fts_ino = sbp->st_ino;
930 +               p->fts_nlink = sbp->st_nlink;
931 +
932 +               if (ISDOT(p->fts_name))
933 +                       return (FTS_DOT);
934 +
935 +               /*
936 +                * Cycle detection is done by brute force when the directory
937 +                * is first encountered.  If the tree gets deep enough or the
938 +                * number of symbolic links to directories is high enough,
939 +                * something faster might be worthwhile.
940 +                */
941 +               for (t = p->fts_parent;
942 +                   t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
943 +                       if (ino == t->fts_ino && dev == t->fts_dev) {
944 +                               p->fts_cycle = t;
945 +                               return (FTS_DC);
946 +                       }
947 +               return (FTS_D);
948 +       }
949 +       if (S_ISLNK(sbp->st_mode))
950 +               return (FTS_SL);
951 +       if (S_ISREG(sbp->st_mode))
952 +               return (FTS_F);
953 +       return (FTS_DEFAULT);
954 +}
955 +
956 +static FTSENT *
957 +fts_sort(FTS *sp, FTSENT *head, register int nitems)
958 +{
959 +       register FTSENT **ap, *p;
960 +
961 +       /*
962 +        * Construct an array of pointers to the structures and call qsort(3).
963 +        * Reassemble the array in the order returned by qsort.  If unable to
964 +        * sort for memory reasons, return the directory entries in their
965 +        * current order.  Allocate enough space for the current needs plus
966 +        * 40 so don't realloc one entry at a time.
967 +        */
968 +       if (nitems > sp->fts_nitems) {
969 +               struct _ftsent **a;
970 +
971 +               sp->fts_nitems = nitems + 40;
972 +               if ((a = realloc(sp->fts_array,
973 +                   (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
974 +                       free(sp->fts_array);
975 +                       sp->fts_array = NULL;
976 +                       sp->fts_nitems = 0;
977 +                       return (head);
978 +               }
979 +               sp->fts_array = a;
980 +       }
981 +       for (ap = sp->fts_array, p = head; p; p = p->fts_link)
982 +               *ap++ = p;
983 +       qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
984 +       for (head = *(ap = sp->fts_array); --nitems; ++ap)
985 +               ap[0]->fts_link = ap[1];
986 +       ap[0]->fts_link = NULL;
987 +       return (head);
988 +}
989 +
990 +static FTSENT *
991 +fts_alloc(FTS *sp, const char *name, size_t namelen)
992 +{
993 +       register FTSENT *p;
994 +       size_t len;
995 +
996 +       /*
997 +        * The file name is a variable length array and no stat structure is
998 +        * necessary if the user has set the nostat bit.  Allocate the FTSENT
999 +        * structure, the file name and the stat structure in one chunk, but
1000 +        * be careful that the stat structure is reasonably aligned.  Since the
1001 +        * fts_name field is declared to be of size 1, the fts_name pointer is
1002 +        * namelen + 2 before the first possible address of the stat structure.
1003 +        */
1004 +       len = sizeof(FTSENT) + namelen;
1005 +       if (!ISSET(FTS_NOSTAT))
1006 +               len += sizeof(struct stat) + ALIGNBYTES;
1007 +       if ((p = malloc(len)) == NULL)
1008 +               return (NULL);
1009 +
1010 +       /* Copy the name and guarantee NUL termination. */
1011 +       memmove(p->fts_name, name, namelen);
1012 +       p->fts_name[namelen] = '\0';
1013 +
1014 +       if (!ISSET(FTS_NOSTAT))
1015 +               p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
1016 +       p->fts_namelen = namelen;
1017 +       p->fts_path = sp->fts_path;
1018 +       p->fts_errno = 0;
1019 +       p->fts_flags = 0;
1020 +       p->fts_instr = FTS_NOINSTR;
1021 +       p->fts_number = 0;
1022 +       p->fts_pointer = NULL;
1023 +       return (p);
1024 +}
1025 +
1026 +static void
1027 +fts_lfree(register FTSENT *head)
1028 +{
1029 +       register FTSENT *p;
1030 +
1031 +       /* Free a linked list of structures. */
1032 +       while ((p = head)) {
1033 +               head = head->fts_link;
1034 +               free(p);
1035 +       }
1036 +}
1037 +
1038 +/*
1039 + * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
1040 + * Most systems will allow creation of paths much longer than MAXPATHLEN, even
1041 + * though the kernel won't resolve them.  Add the size (not just what's needed)
1042 + * plus 256 bytes so don't realloc the path 2 bytes at a time.
1043 + */
1044 +static int
1045 +fts_palloc(FTS *sp, size_t more)
1046 +{
1047 +       char *p;
1048 +
1049 +       sp->fts_pathlen += more + 256;
1050 +       /*
1051 +        * Check for possible wraparound.  In an FTS, fts_pathlen is
1052 +        * a signed int but in an FTSENT it is an unsigned short.
1053 +        * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
1054 +        */
1055 +       if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
1056 +               free(sp->fts_path);
1057 +               sp->fts_path = NULL;
1058 +               errno = ENAMETOOLONG;
1059 +               return (1);
1060 +       }
1061 +       p = realloc(sp->fts_path, sp->fts_pathlen);
1062 +       if (p == NULL) {
1063 +               free(sp->fts_path);
1064 +               sp->fts_path = NULL;
1065 +               return 1;
1066 +       }
1067 +       sp->fts_path = p;
1068 +       return 0;
1069 +}
1070 +
1071 +/*
1072 + * When the path is realloc'd, have to fix all of the pointers in structures
1073 + * already returned.
1074 + */
1075 +static void
1076 +fts_padjust(FTS *sp, FTSENT *head)
1077 +{
1078 +       FTSENT *p;
1079 +       char *addr = sp->fts_path;
1080 +
1081 +#define        ADJUST(p) do {                                                  \
1082 +       if ((p)->fts_accpath != (p)->fts_name) {                        \
1083 +               (p)->fts_accpath =                                      \
1084 +                   (char *)addr + ((p)->fts_accpath - (p)->fts_path);  \
1085 +       }                                                               \
1086 +       (p)->fts_path = addr;                                           \
1087 +} while (0)
1088 +       /* Adjust the current set of children. */
1089 +       for (p = sp->fts_child; p; p = p->fts_link)
1090 +               ADJUST(p);
1091 +
1092 +       /* Adjust the rest of the tree, including the current level. */
1093 +       for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
1094 +               ADJUST(p);
1095 +               p = p->fts_link ? p->fts_link : p->fts_parent;
1096 +       }
1097 +}
1098 +
1099 +static size_t
1100 +fts_maxarglen(char * const *argv)
1101 +{
1102 +       size_t len, max;
1103 +
1104 +       for (max = 0; *argv; ++argv)
1105 +               if ((len = strlen(*argv)) > max)
1106 +                       max = len;
1107 +       return (max + 1);
1108 +}
1109 +
1110 +/*
1111 + * Change to dir specified by fd or p->fts_accpath without getting
1112 + * tricked by someone changing the world out from underneath us.
1113 + * Assumes p->fts_dev and p->fts_ino are filled in.
1114 + */
1115 +static int
1116 +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
1117 +{
1118 +       int ret, oerrno, newfd;
1119 +       struct stat64 sb;
1120 +
1121 +       newfd = fd;
1122 +       if (ISSET(FTS_NOCHDIR))
1123 +               return (0);
1124 +       if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
1125 +               return (-1);
1126 +       if (fstat64(newfd, &sb)) {
1127 +               ret = -1;
1128 +               goto bail;
1129 +       }
1130 +       if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
1131 +               errno = ENOENT;         /* disinformation */
1132 +               ret = -1;
1133 +               goto bail;
1134 +       }
1135 +       ret = fchdir(newfd);
1136 +bail:
1137 +       oerrno = errno;
1138 +       if (fd < 0)
1139 +               (void)close(newfd);
1140 +       errno = oerrno;
1141 +       return (ret);
1142 +}
1143 diff -Nrup a/libdwfl/fts_.h b/libdwfl/fts_.h
1144 --- a/libdwfl/fts_.h    1970-01-01 01:00:00.000000000 +0100
1145 +++ b/libdwfl/fts_.h    2015-01-06 11:42:13.481640322 +0000
1146 @@ -0,0 +1,131 @@
1147 +/*
1148 + * Copyright (c) 1989, 1993
1149 + *     The Regents of the University of California.  All rights reserved.
1150 + *
1151 + * Redistribution and use in source and binary forms, with or without
1152 + * modification, are permitted provided that the following conditions
1153 + * are met:
1154 + * 1. Redistributions of source code must retain the above copyright
1155 + *    notice, this list of conditions and the following disclaimer.
1156 + * 2. Redistributions in binary form must reproduce the above copyright
1157 + *    notice, this list of conditions and the following disclaimer in the
1158 + *    documentation and/or other materials provided with the distribution.
1159 + * 4. Neither the name of the University nor the names of its contributors
1160 + *    may be used to endorse or promote products derived from this software
1161 + *    without specific prior written permission.
1162 + *
1163 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1164 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1165 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1166 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1167 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1168 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1169 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1170 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1171 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1172 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1173 + * SUCH DAMAGE.
1174 + *
1175 + *     @(#)fts.h       8.3 (Berkeley) 8/14/94
1176 + */
1177 +
1178 +#ifndef        _FTS_H
1179 +#define        _FTS_H 1
1180 +
1181 +#include <features.h>
1182 +#include <sys/types.h>
1183 +
1184 +/* The fts interface is incompatible with the LFS interface which
1185 +   transparently uses the 64-bit file access functions.  */
1186 +#ifdef __USE_FILE_OFFSET64
1187 +# error "<fts.h> cannot be used with -D_FILE_OFFSET_BITS==64"
1188 +#endif
1189 +
1190 +
1191 +typedef struct {
1192 +       struct _ftsent *fts_cur;        /* current node */
1193 +       struct _ftsent *fts_child;      /* linked list of children */
1194 +       struct _ftsent **fts_array;     /* sort array */
1195 +       dev_t fts_dev;                  /* starting device # */
1196 +       char *fts_path;                 /* path for this descent */
1197 +       int fts_rfd;                    /* fd for root */
1198 +       int fts_pathlen;                /* sizeof(path) */
1199 +       int fts_nitems;                 /* elements in the sort array */
1200 +       int (*fts_compar) (const void *, const void *); /* compare fn */
1201 +
1202 +#define        FTS_COMFOLLOW   0x0001          /* follow command line symlinks */
1203 +#define        FTS_LOGICAL     0x0002          /* logical walk */
1204 +#define        FTS_NOCHDIR     0x0004          /* don't change directories */
1205 +#define        FTS_NOSTAT      0x0008          /* don't get stat info */
1206 +#define        FTS_PHYSICAL    0x0010          /* physical walk */
1207 +#define        FTS_SEEDOT      0x0020          /* return dot and dot-dot */
1208 +#define        FTS_XDEV        0x0040          /* don't cross devices */
1209 +#define FTS_WHITEOUT   0x0080          /* return whiteout information */
1210 +#define        FTS_OPTIONMASK  0x00ff          /* valid user option mask */
1211 +
1212 +#define        FTS_NAMEONLY    0x0100          /* (private) child names only */
1213 +#define        FTS_STOP        0x0200          /* (private) unrecoverable error */
1214 +       int fts_options;                /* fts_open options, global flags */
1215 +} FTS;
1216 +
1217 +typedef struct _ftsent {
1218 +       struct _ftsent *fts_cycle;      /* cycle node */
1219 +       struct _ftsent *fts_parent;     /* parent directory */
1220 +       struct _ftsent *fts_link;       /* next file in directory */
1221 +       long fts_number;                /* local numeric value */
1222 +       void *fts_pointer;              /* local address value */
1223 +       char *fts_accpath;              /* access path */
1224 +       char *fts_path;                 /* root path */
1225 +       int fts_errno;                  /* errno for this node */
1226 +       int fts_symfd;                  /* fd for symlink */
1227 +       u_short fts_pathlen;            /* strlen(fts_path) */
1228 +       u_short fts_namelen;            /* strlen(fts_name) */
1229 +
1230 +       ino_t fts_ino;                  /* inode */
1231 +       dev_t fts_dev;                  /* device */
1232 +       nlink_t fts_nlink;              /* link count */
1233 +
1234 +#define        FTS_ROOTPARENTLEVEL     -1
1235 +#define        FTS_ROOTLEVEL            0
1236 +       short fts_level;                /* depth (-1 to N) */
1237 +
1238 +#define        FTS_D            1              /* preorder directory */
1239 +#define        FTS_DC           2              /* directory that causes cycles */
1240 +#define        FTS_DEFAULT      3              /* none of the above */
1241 +#define        FTS_DNR          4              /* unreadable directory */
1242 +#define        FTS_DOT          5              /* dot or dot-dot */
1243 +#define        FTS_DP           6              /* postorder directory */
1244 +#define        FTS_ERR          7              /* error; errno is set */
1245 +#define        FTS_F            8              /* regular file */
1246 +#define        FTS_INIT         9              /* initialized only */
1247 +#define        FTS_NS          10              /* stat(2) failed */
1248 +#define        FTS_NSOK        11              /* no stat(2) requested */
1249 +#define        FTS_SL          12              /* symbolic link */
1250 +#define        FTS_SLNONE      13              /* symbolic link without target */
1251 +#define FTS_W          14              /* whiteout object */
1252 +       u_short fts_info;               /* user flags for FTSENT structure */
1253 +
1254 +#define        FTS_DONTCHDIR    0x01           /* don't chdir .. to the parent */
1255 +#define        FTS_SYMFOLLOW    0x02           /* followed a symlink to get here */
1256 +       u_short fts_flags;              /* private flags for FTSENT structure */
1257 +
1258 +#define        FTS_AGAIN        1              /* read node again */
1259 +#define        FTS_FOLLOW       2              /* follow symbolic link */
1260 +#define        FTS_NOINSTR      3              /* no instructions */
1261 +#define        FTS_SKIP         4              /* discard node */
1262 +       u_short fts_instr;              /* fts_set() instructions */
1263 +
1264 +       struct stat *fts_statp;         /* stat(2) information */
1265 +       char fts_name[1];               /* file name */
1266 +} FTSENT;
1267 +
1268 +__BEGIN_DECLS
1269 +FTSENT *fts_children (FTS *, int);
1270 +int     fts_close (FTS *);
1271 +FTS    *fts_open (char * const *, int,
1272 +                  int (*)(const FTSENT **, const FTSENT **));
1273 +FTSENT *fts_read (FTS *);
1274 +int     fts_set (FTS *, FTSENT *, int) __THROW;
1275 +__END_DECLS
1276 +
1277 +#endif /* fts.h */
1278 diff -Nrup a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
1279 --- a/libdwfl/linux-kernel-modules.c    2014-11-22 22:43:52.000000000 +0000
1280 +++ b/libdwfl/linux-kernel-modules.c    2015-01-06 11:44:25.610924805 +0000
1281 @@ -29,7 +29,11 @@
1282  /* We include this before config.h because it can't handle _FILE_OFFSET_BITS.
1283     Everything we need here is fine if its declarations just come first.  */
1284  
1285 +#ifdef HAVE_FTS_H
1286  #include <fts.h>
1287 +#else
1288 +#include <fts_.h>
1289 +#endif
1290  
1291  #include <config.h>
1292  
1293 diff -Nrup a/libdwfl/Makefile.am b/libdwfl/Makefile.am
1294 --- a/libdwfl/Makefile.am       2014-06-17 19:51:09.000000000 +0100
1295 +++ b/libdwfl/Makefile.am       2015-01-06 11:45:25.442959369 +0000
1296 @@ -79,6 +79,9 @@ endif
1297  if LZMA
1298  libdwfl_a_SOURCES += lzma.c
1299  endif
1300 +if !HAVE_FTS
1301 +libdwfl_a_SOURCES += fts.c
1302 +endif
1303  
1304  libdwfl = $(libdw)
1305  libdw = ../libdw/libdw.so