1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * @APPLE_LICENSE_HEADER_END@
31 */
32
33/*
34**
35**  NAME:
36**
37**      epstatus.c
38**
39**  FACILITY:
40**
41**      Endpoint mapper status.
42**
43**  ABSTRACT:
44**
45**	EPSTATUS - a tool to display endpoint mapper registrations.
46**
47*/
48
49#if HAVE_CONFIG_H
50#include <config.h>
51#endif
52
53#include <dce/rpc.h>
54#include <dce/dce.h>
55#include <dce/dce_error.h>
56
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <stdarg.h>
61#include <getopt.h>
62#if HAVE_SYSEXITS_H
63#include <sysexits.h>
64#endif
65
66#ifndef EX_OSERR
67#define EX_OSERR 71
68#endif
69
70#ifndef EX_USAGE
71#define EX_USAGE 64
72#endif
73
74struct ep_table_entry
75{
76    rpc_if_id_t		    te_interface;
77    rpc_binding_handle_t    te_binding;
78    idl_uuid_t		    te_uuid;
79    idl_char *		    te_annotation;
80};
81
82static const char PROGNAME[] = "epstatus";
83static boolean verbose = false;
84
85#if __GNUC__
86static void
87status_message(
88    FILE * file,
89    error_status_t status,
90    const char * fmt,
91    ...) __attribute__((__format__ (__printf__, 3, 4)));
92#endif
93
94static void
95status_message(
96    FILE * file,
97    error_status_t status,
98    const char * fmt,
99    ...)
100{
101    dce_error_string_t message;
102    error_status_t error_status;
103
104    va_list args;
105
106    dce_error_inq_text(status, message,
107                       (int *)&error_status);
108    if (error_status != rpc_s_ok)
109    {
110        snprintf(message, sizeof(message), "RPC error %#x", status);
111    }
112
113    va_start(args, fmt);
114    vfprintf(file, fmt, args);
115    fprintf(file, " %s\n", message);
116    va_end(args);
117}
118
119static void
120epstatus_usage(void)
121{
122    fprintf(stderr, "usage: %s [-v]\n", PROGNAME);
123    fprintf(stderr, "    -v: Print verbose status messages\n");
124}
125
126static rpc_binding_handle_t
127ep_binding_from_protseq(
128    const idl_char * protseq)
129{
130    error_status_t status;
131    unsigned_char_p_t string_binding;
132    rpc_binding_handle_t binding = NULL;
133
134    rpc_string_binding_compose(NULL, (unsigned_char_p_t)protseq,
135                               NULL, NULL, NULL, &string_binding, &status);
136    if (status != rpc_s_ok)
137    {
138        status_message(stderr, status,
139		"%s: failed to compose %s binding", PROGNAME, protseq);
140	return NULL;
141    }
142
143    if (verbose)
144    {
145        printf("composed binding string '%s' from protoseq '%s'\n",
146               string_binding, protseq);
147    }
148
149    rpc_binding_from_string_binding(string_binding, &binding, &status);
150    if (status != rpc_s_ok)
151    {
152        status_message(stderr, status,
153		"%s: failed to create %s binding handle",
154		PROGNAME, protseq);
155
156	rpc_string_free(&string_binding, &status);
157	return NULL;
158    }
159
160    /* XXX Setting the timeout doesn't actually seem to allow ncadg_ip_udp
161     * to timeout when the endpoint mapper is not there. Not really sure
162     * why this  is.
163     */
164    rpc_mgmt_set_com_timeout(binding, rpc_c_binding_min_timeout, &status);
165
166    rpc_string_free(&string_binding, &status);
167    return binding;
168}
169
170static void
171ep_table_entry_free(
172    struct ep_table_entry * te)
173{
174    error_status_t status;
175
176    if (!te)
177    {
178        return;
179    }
180
181    if (te->te_binding)
182    {
183        rpc_binding_free(&te->te_binding, &status);
184    }
185
186    if (te->te_annotation)
187    {
188        rpc_string_free(&te->te_annotation, &status);
189    }
190}
191
192static void
193ep_table_entry_display(
194    const struct ep_table_entry * te)
195{
196    error_status_t status;
197
198    unsigned_char_p_t rpc_string = NULL;
199
200    printf("interface version: %u.%u\n",
201           te->te_interface.vers_major,
202           te->te_interface.vers_minor);
203
204    uuid_to_string((uuid_p_t)&te->te_interface.uuid, &rpc_string, &status);
205    if (status == rpc_s_ok)
206    {
207        printf("interface UUID: %s\n", rpc_string);
208        rpc_string_free(&rpc_string, &status);
209    }
210    else
211    {
212        status_message(stdout, status, "interface UUID:");
213    }
214
215    if (te->te_binding)
216    {
217        rpc_binding_to_string_binding(te->te_binding,
218                                      &rpc_string, &status);
219        if (status == rpc_s_ok)
220        {
221            printf("binding: %s\n", rpc_string);
222            rpc_string_free(&rpc_string, &status);
223        }
224	else
225        {
226            status_message(stdout, status, "binding:");
227        }
228
229    }
230    else
231    {
232        printf("binding:\n");
233    }
234
235    uuid_to_string((uuid_p_t)&te->te_uuid, &rpc_string, &status);
236    if (status == rpc_s_ok)
237    {
238        printf("object UUID: %s\n", rpc_string);
239        rpc_string_free(&rpc_string, &status);
240    }
241    else
242    {
243        status_message(stdout, status, "object UUID:");
244    }
245
246    printf("annotation: %s\n",
247           te->te_annotation ? (const char *)te->te_annotation : "");
248}
249
250static error_status_t
251ep_status_display(
252    const idl_char * protseq,
253    rpc_binding_handle_t binding,
254    unsigned * count)
255{
256    error_status_t status;
257    rpc_ep_inq_handle_t inquiry;
258
259    *count = 0;
260
261    if (verbose)
262    {
263        printf("querying endpoints status over %s\n", protseq);
264    }
265
266    rpc_mgmt_ep_elt_inq_begin(binding, rpc_c_ep_all_elts,
267                              NULL, rpc_c_vers_all, NULL, &inquiry, &status);
268    if (status != rpc_s_ok)
269    {
270        return status;
271    }
272
273    for (;;)
274    {
275        struct ep_table_entry te;
276        memset(&te, 0, sizeof(te));
277
278        rpc_mgmt_ep_elt_inq_next(inquiry, &te.te_interface,
279		&te.te_binding, &te.te_uuid, &te.te_annotation, &status);
280
281        if (status == rpc_s_ok)
282        {
283            (*count)++;
284            ep_table_entry_display(&te);
285            ep_table_entry_free(&te);
286        }
287	else if (status == rpc_s_no_more_elements)
288        {
289            break;
290        }
291	else
292        {
293            error_status_t tmp;
294            status_message(stderr, status,
295		    "%s: endpoint mapper failed on %s,",
296		    PROGNAME, protseq);
297            rpc_mgmt_ep_elt_inq_done(&inquiry, &tmp);
298            return status;
299        }
300
301    }
302
303    rpc_mgmt_ep_elt_inq_done(&inquiry, &status);
304    return rpc_s_ok;
305}
306
307int main(int argc, const char ** argv)
308{
309    error_status_t status;
310    unsigned i;
311    int opt;
312
313    rpc_protseq_vector_p_t protseq;
314
315    while ((opt = getopt(argc, (void *)argv, "v")) != -1)
316    {
317        switch (opt)
318        {
319        case 'v':
320            verbose = true;
321            break;
322        default:
323            epstatus_usage();
324            exit(EX_USAGE);
325        }
326    }
327
328    rpc_network_inq_protseqs(&protseq, &status);
329    if (status != rpc_s_ok)
330    {
331        status_message(stderr, status,
332		"%s: no installed protocols", PROGNAME);
333	exit(EX_OSERR);
334    }
335
336    /* For all the installed protocols, try to dump the endpoint mapper
337     * database.
338     */
339    for (i = 0; i < protseq->count; ++i)
340    {
341        rpc_binding_handle_t binding;
342        unsigned count = 0;
343
344        binding = ep_binding_from_protseq(protseq->protseq[i]);
345        if (binding)
346        {
347            status = ep_status_display(protseq->protseq[i], binding, &count);
348
349            if (status == rpc_s_ok)
350            {
351                rpc_binding_free(&binding, &status);
352                printf("%u endpoints registered\n", count);
353                break;
354            }
355
356            rpc_binding_free(&binding, &status);
357        }
358    }
359
360    rpc_protseq_vector_free(&protseq, &status);
361
362    return 0;
363}
364