1/**
2 * \file
3 * \brief SKB library functions
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <stddef.h>
17#include <string.h>
18#include <stdarg.h>
19
20#include <barrelfish/barrelfish.h>
21#include <skb/skb.h>
22#include <if/skb_defs.h>
23#include <barrelfish/core_state_arch.h>
24#include "skb_internal.h"
25
26#define BUFFER_SIZE skb__run_call_input_MAX_ARGUMENT_SIZE
27#define OUTPUT_SIZE skb__run_response_output_MAX_ARGUMENT_SIZE
28
29/* XXX: The following static chars make the skb connection not thread
30   safe and we probably don't want to put them in the per dispatcher
31   corestate as they are so big. */
32static char buffer[skb__run_call_input_MAX_ARGUMENT_SIZE + 1];
33static char output[skb__run_response_output_MAX_ARGUMENT_SIZE + 1];
34static char error_output[skb__run_response_str_error_MAX_ARGUMENT_SIZE + 1];
35static char *last_goal;
36static int error_code;
37
38int skb_read_error_code(void)
39{
40    return error_code;
41}
42
43char *skb_get_output(void)
44{
45    return (output);
46}
47
48char *skb_get_error_output(void)
49{
50    return (error_output);
51}
52
53char *skb_get_last_goal(void)
54{
55    return last_goal;
56}
57
58errval_t skb_execute(char *goal)
59{
60    errval_t err;
61    struct skb_state *skb_state = get_skb_state();
62
63    last_goal = goal;
64    err = skb_state->skb->rpc_tx_vtbl.run(skb_state->skb, goal, output,
65            error_output, &error_code);
66    if (err_is_fail(err)) {
67        return err_push(err, SKB_ERR_RUN);
68    }
69
70    if (error_code != 0) {
71        return err_push(err, SKB_ERR_EXECUTION);
72    }
73
74    return err;
75}
76
77errval_t skb_add_fact(char *fmt, ...)
78{
79    errval_t err;
80    va_list va_l;
81    va_start(va_l, fmt);
82    int len = skb_vsnprintf(buffer, BUFFER_SIZE, fmt, va_l);
83    va_end(va_l);
84
85    if (len >= BUFFER_SIZE) {
86        err = SKB_ERR_OVERFLOW;
87        goto out;
88    }
89
90    if (len > 0 && buffer[len - 1] == '.') {
91        len--;
92    }
93
94    SKB_DEBUG("skb_add_fact(): %s\n", buffer);
95    int assert_len = snprintf(buffer + len, BUFFER_SIZE - len,
96                              "assert(%.*s).", len, buffer);
97    if (assert_len >= BUFFER_SIZE - len) {
98        err = SKB_ERR_OVERFLOW;
99        goto out;
100    }
101
102    err = skb_execute(buffer + len);
103
104out:
105    return err;
106}
107
108errval_t skb_execute_query(char *fmt, ...)
109{
110    va_list va_l;
111    va_start(va_l, fmt);
112    int len = skb_vsnprintf(buffer, BUFFER_SIZE, fmt, va_l);
113    va_end(va_l);
114
115#if 0
116    va_start(va_l, fmt);
117    char* buffer2 = malloc(BUFFER_SIZE+1);
118    len = vsnprintf(buffer2, BUFFER_SIZE, fmt, va_l);
119    va_end(va_l);
120    if (strcmp(buffer, buffer2) != 0) {
121        printf("%s:%s:%d: fmt = %s\n", __FILE__, __FUNCTION__, __LINE__, fmt);
122        printf("%s:%s:%d: skb_vsnprintf: %s\n", __FILE__, __FUNCTION__, __LINE__, buffer);
123        printf("%s:%s:%d: vsnprintf: %s\n", __FILE__, __FUNCTION__, __LINE__, buffer2);
124        USER_PANIC("skb_vsnprintf doesn't quite work!");
125    }
126    free(buffer2);
127#endif
128
129    if (len >= BUFFER_SIZE) {
130        return SKB_ERR_OVERFLOW;
131    }
132
133    if (len > 0 && buffer[len - 1] == '.') {
134        buffer[len - 1] = '\0';
135    }
136
137    return skb_execute(buffer);
138}
139
140static inline int count_expected_conversions(char *s, int len)
141{
142    int expected_conversions = 0;
143    //count the number of single occurences of '%' to calculate the expected
144    //number of conversions made by sscanf
145    //if % is followed by % -> escapes % and hence not a conversion
146    //if % is followed by * -> ignore output hence not a conversion
147    for (int i = 0; i < len; i++) {
148        if ((s[i] == '%') &&
149            (
150             ((i + 1 < len) && (s[i + 1] != '%') && (s[i + 1] != '*')) ||
151             (i + 1 >= len))
152            ) {
153            expected_conversions++;
154        }
155    }
156    return (expected_conversions);
157}
158
159errval_t skb_vread_output_at(char *out, char *fmt, va_list va_l)
160{
161    int expected_conversions = 0;
162    int nr_conversions;
163    int fmtlen = strlen(fmt);
164    expected_conversions = count_expected_conversions(fmt, fmtlen);
165    nr_conversions = skb_vsscanf(out, fmt, va_l);
166    if (nr_conversions != expected_conversions) {
167        printf("skb_vread_output_at(): Could not convert the SKB's result (expected conversions=%d, got instead=%d)\n",
168               expected_conversions, nr_conversions);
169        printf("SKB returned: %s\nSKB error: %s\n", skb_get_output(), skb_get_error_output());
170        printf("%s:%s:%d: fmt = %s out = %s\n", __FILE__, __FUNCTION__, __LINE__, fmt, out);
171        return SKB_ERR_CONVERSION_ERROR;
172    }
173    return SYS_ERR_OK;
174}
175
176errval_t skb_read_output_at(char *out, char *fmt, ...)
177{
178    errval_t r;
179    va_list va_l;
180
181    va_start(va_l, fmt);
182    r = skb_vread_output_at(out, fmt, va_l);
183    va_end(va_l);
184
185    return(r);
186}
187
188errval_t skb_read_output(char *fmt, ...)
189{
190    errval_t r;
191    va_list va_l;
192    va_start(va_l, fmt);
193    r = skb_vread_output_at(skb_get_output(), fmt, va_l);
194    va_end(va_l);
195    return r;
196}
197
198
199void skb_read_list_init_offset(struct list_parser_status *status, char *s,
200                               int offset)
201{
202    status->s = s + offset;
203    status->conv_ptr = s;
204    status->len = strlen(s);
205    status->element_name[0] = 0;
206    status->expected_conversions = -1;
207}
208
209void skb_read_list_init(struct list_parser_status *status)
210{
211    skb_read_list_init_offset(status, skb_get_output(), 0);
212}
213
214bool skb_read_list(struct list_parser_status *status, char *fmt, ...)
215{
216    va_list va_l;
217    va_start(va_l, fmt);
218
219    int nr_conversions;
220    int lpar = 0;
221    int fmtlen = strlen(fmt);
222    if (status->element_name[0] == 0) {
223        for (lpar = 0; lpar < fmtlen; lpar++) {
224            if (fmt[lpar] == '(') {
225                break;
226            }
227        }
228        strncpy(status->element_name, fmt,
229                (lpar < ELEMENT_NAME_BUF_SIZE) ? lpar : ELEMENT_NAME_BUF_SIZE);
230        status->element_name[
231                (lpar < ELEMENT_NAME_BUF_SIZE) ? lpar : ELEMENT_NAME_BUF_SIZE
232                            ] = 0;
233        status->element_len = lpar;
234    }
235    if (status->expected_conversions == -1) {
236        status->expected_conversions =
237            count_expected_conversions(fmt, fmtlen);
238    }
239
240    //iterate over all buselements
241    while (status->conv_ptr < status->s + status->len) {
242        // search the beginning of the next buselement
243        while ((status->conv_ptr < status->s + status->len) &&
244               (strncmp(status->conv_ptr, status->element_name,
245                        status->element_len)) != 0) {
246                    status->conv_ptr++;
247        }
248        //convert the string to single elements and numbers
249        nr_conversions = skb_vsscanf(status->conv_ptr, fmt, va_l);
250        va_end(va_l);
251        status->conv_ptr++;
252        if (nr_conversions != status->expected_conversions) {
253            return false;
254        }
255        return true;
256    }
257    return false;
258}
259