1/*
2   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13*/
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif /* HAVE_CONFIG_H */
18
19#include <unistd.h>
20#include <sys/types.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <stdarg.h>
24#include <limits.h>
25#include <string.h>
26#include <errno.h>
27
28#include <atalk/adouble.h>
29#include <atalk/cnid.h>
30#include <atalk/cnid_dbd_private.h>
31#include <atalk/volinfo.h>
32#include <atalk/bstrlib.h>
33#include <atalk/bstradd.h>
34#include <atalk/directory.h>
35#include <atalk/util.h>
36#include <atalk/unicode.h>
37#include "ad.h"
38
39static volatile sig_atomic_t alarmed;
40
41/*
42  SIGNAL handling:
43  catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
44*/
45
46static void sig_handler(int signo)
47{
48    alarmed = 1;
49    return;
50}
51
52static void set_signal(void)
53{
54    struct sigaction sv;
55
56    sv.sa_handler = sig_handler;
57    sv.sa_flags = SA_RESTART;
58    sigemptyset(&sv.sa_mask);
59    if (sigaction(SIGTERM, &sv, NULL) < 0)
60        ERROR("error in sigaction(SIGTERM): %s", strerror(errno));
61
62    if (sigaction(SIGINT, &sv, NULL) < 0)
63        ERROR("error in sigaction(SIGINT): %s", strerror(errno));
64
65    memset(&sv, 0, sizeof(struct sigaction));
66    sv.sa_handler = SIG_IGN;
67    sigemptyset(&sv.sa_mask);
68
69    if (sigaction(SIGABRT, &sv, NULL) < 0)
70        ERROR("error in sigaction(SIGABRT): %s", strerror(errno));
71
72    if (sigaction(SIGHUP, &sv, NULL) < 0)
73        ERROR("error in sigaction(SIGHUP): %s", strerror(errno));
74
75    if (sigaction(SIGQUIT, &sv, NULL) < 0)
76        ERROR("error in sigaction(SIGQUIT): %s", strerror(errno));
77}
78
79static void usage_find(void)
80{
81    printf(
82        "Usage: ad find [-v VOLUME_PATH] NAME\n"
83        );
84}
85
86int ad_find(int argc, char **argv)
87{
88    int c, ret;
89    afpvol_t vol;
90    const char *srchvol = getcwdpath();
91
92    while ((c = getopt(argc-1, &argv[1], ":v:")) != -1) {
93        switch(c) {
94        case 'v':
95            srchvol = strdup(optarg);
96            break;
97        case ':':
98        case '?':
99            usage_find();
100            return -1;
101            break;
102        }
103
104    }
105    optind++;
106
107    if ((argc - optind) != 1) {
108        usage_find();
109        exit(1);
110    }
111
112    set_signal();
113    cnid_init();
114
115    if (openvol(srchvol, &vol) != 0)
116        ERROR("Cant open volume \"%s\"", srchvol);
117
118    uint16_t flags = CONV_TOLOWER;
119    char namebuf[MAXPATHLEN + 1];
120    if (convert_charset(vol.volinfo.v_volcharset,
121                        vol.volinfo.v_volcharset,
122                        vol.volinfo.v_maccharset,
123                        argv[optind],
124                        strlen(argv[optind]),
125                        namebuf,
126                        MAXPATHLEN,
127                        &flags) == (size_t)-1) {
128        ERROR("conversion error");
129    }
130
131    int count;
132    char resbuf[DBD_MAX_SRCH_RSLTS * sizeof(cnid_t)];
133    if ((count = cnid_find(vol.volume.v_cdb,
134                           namebuf,
135                           strlen(namebuf),
136                           resbuf,
137                           sizeof(resbuf))) < 1) {
138        ret = 1;
139    } else {
140        ret = 0;
141        cnid_t cnid;
142        char *bufp = resbuf;
143        bstring sep = bfromcstr("/");
144        while (count--) {
145            memcpy(&cnid, bufp, sizeof(cnid_t));
146            bufp += sizeof(cnid_t);
147
148            bstring path = NULL;
149            bstring volpath = bfromcstr(vol.volinfo.v_path);
150            BSTRING_STRIP_SLASH(volpath);
151            char buffer[12 + MAXPATHLEN + 1];
152            int buflen = 12 + MAXPATHLEN + 1;
153            char *name;
154            cnid_t did = cnid;
155            struct bstrList *pathlist = bstrListCreateMin(32);
156
157            while (did != DIRDID_ROOT) {
158                if ((name = cnid_resolve(vol.volume.v_cdb, &did, buffer, buflen)) == NULL)
159                    goto next;
160                bstrListPush(pathlist, bfromcstr(name));
161            }
162            bstrListPush(pathlist, volpath);
163            path = bjoinInv(pathlist, sep);
164
165            printf("%s\n", cfrombstr(path));
166
167        next:
168            bstrListDestroy(pathlist);
169            bdestroy(path);
170        }
171        bdestroy(sep);
172    }
173
174    closevol(&vol);
175
176    return ret;
177}
178