1/** 2 * \file 3 * \brief Get/Set client API implementation 4 * 5 * This file provides convenience functions to interface with the 6 * octopus.if RPC calls. 7 */ 8 9/* 10 * Copyright (c) 2011, 2012, ETH Zurich. 11 * All rights reserved. 12 * 13 * This file is distributed under the terms in the attached LICENSE file. 14 * If you do not find this file, copies can be found by writing to: 15 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 16 */ 17 18#include <stdlib.h> 19#include <stdio.h> 20#include <stdarg.h> 21 22#include <barrelfish/barrelfish.h> 23 24#include <if/octopus_defs.h> 25#include <if/octopus_thc.h> 26 27#include <octopus/init.h> 28#include <octopus/getset.h> 29#include <octopus/parser/ast.h> 30#include <octopus/trigger.h> 31 32#include "common.h" 33 34/** 35 * \brief Retrieve all record names matching a given query. 36 * 37 * \param[out] names Names of all records matching the query. 38 * Needs to be freed by the client (use oct_free_names) in 39 * case of SYS_ERR_OK/LIB_ERR_MALLOC_FAIL. 40 * \param[out] size Number of records matching the query. 0 in case of error. 41 * \param[in] query Query sent to the server 42 * \param ... Parameters used to build query with help of vsprintf. 43 * 44 * \retval SYS_ERR_OK 45 * \retval OCT_ERR_NO_RECORD 46 * \retval OCT_ERR_PARSER_FAIL 47 * \retval OCT_ERR_ENGINE_FAIL 48 * \retval LIB_ERR_MALLOC_FAIL 49 */ 50errval_t oct_get_names(char*** names, size_t* len, const char* query, ...) 51{ 52 assert(query != NULL); 53 54 errval_t err = SYS_ERR_OK; 55 va_list args; 56 57 char* buf = NULL; 58 *len = 0; 59 60 FORMAT_QUERY(query, args, buf); // buf 61 62 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 63 64 struct octopus_get_names_response__rx_args reply; 65 err = cl->call_seq.get_names(cl, buf, NOP_TRIGGER, reply.output, 66 &reply.tid, &reply.error_code); 67 if (err_is_ok(err)) { 68 err = reply.error_code; 69 } 70 71 if (err_is_ok(err)) { 72 err = oct_parse_names(reply.output, names, len); 73 //qsort(*names, *len, sizeof(char*), cmpstringp); 74 } 75 76 free(buf); 77 return err; 78} 79 80/** 81 * \brief Gets one record matching the given query. 82 * 83 * \param[out] data Record returned by the server. 84 * \param[in] query The query sent to the server. 85 * \param ... Additional arguments to format the query using vsprintf. 86 * 87 * \retval SYS_ERR_OK 88 * \retval OCT_ERR_NO_RECORD 89 * \retval OCT_ERR_AMBIGOUS_QUERY TODO! 90 * \retval OCT_ERR_PARSER_FAIL 91 * \retval OCT_ERR_ENGINE_FAIL 92 */ 93errval_t oct_get(char** data, const char* query, ...) 94{ 95 assert(query != NULL); 96 errval_t err = SYS_ERR_OK; 97 va_list args; 98 99 char* buf = NULL; 100 FORMAT_QUERY(query, args, buf); 101 102 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 103 assert(cl != NULL); 104 105 struct octopus_get_response__rx_args reply; 106 err = cl->call_seq.get(cl, buf, NOP_TRIGGER, reply.output, 107 &reply.tid, &reply.error_code); 108 109 if (err_is_ok(err)) { 110 err = reply.error_code; 111 } 112 113 free(buf); 114 115 if (err_is_fail(err)) { 116 return err; 117 } 118 119 if (data) { 120 *data = strdup(reply.output); 121 } 122 123 124 return err; 125} 126 127/** 128 * \brief Sets a record. 129 * 130 * \param query The record to set. 131 * \param ... Additional arguments to format the query using vsprintf. 132 * 133 * \retval SYS_ERR_OK 134 * \retval OCT_ERR_NO_RECORD_NAME 135 * \retval OCT_ERR_PARSER_FAIL 136 * \retval OCT_ERR_ENGINE_FAIL 137 */ 138errval_t oct_set(const char* query, ...) 139{ 140 assert(query != NULL); 141 errval_t err = SYS_ERR_OK; 142 va_list args; 143 144 char* buf = NULL; 145 FORMAT_QUERY(query, args, buf); 146 147 // Send to Server 148 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 149 150 errval_t error_code; 151 err = cl->call_seq.set(cl, buf, SET_DEFAULT, NOP_TRIGGER, false, NULL, NULL, 152 &error_code); 153 154 if (err_is_ok(err)) { 155 err = error_code; 156 } 157 158 free(buf); 159 return err; 160} 161 162/** 163 * \brief Sets a record. 164 * 165 * \param query The record to set. 166 * \param mode A combination of mode bits (see getset.h). 167 * \param ... Additional arguments to format the query using vsprintf. 168 * 169 * \retval SYS_ERR_OK 170 * \retval OCT_ERR_NO_RECORD_NAME 171 * \retval OCT_ERR_PARSER_FAIL 172 * \retval OCT_ERR_ENGINE_FAIL 173 */ 174errval_t oct_mset(oct_mode_t mode, const char* query, ...) 175{ 176 assert(query != NULL); 177 errval_t err = SYS_ERR_OK; 178 va_list args; 179 180 char* buf = NULL; 181 FORMAT_QUERY(query, args, buf); 182 183 // Send to Server 184 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 185 186 errval_t error_code; 187 err = cl->call_seq.set(cl, buf, mode, NOP_TRIGGER, false, NULL, NULL, 188 &error_code); 189 190 if (err_is_ok(err)) { 191 err = error_code; 192 } 193 194 free(buf); 195 return err; 196} 197 198/** 199 * \brief Sets a record and returns and in case of no error 200 * returns it to the client. 201 * 202 * Additonally the mode how a record is set can be specified. 203 * 204 * \param mode A combination of mode bits (see getset.h). 205 * \param[out] record The new record. 206 * \param[in] query The record to set. 207 * \param ... Additional arguments to format the query using vsprintf. 208 * 209 * \retval SYS_ERR_OK 210 * \retval OCT_ERR_NO_RECORD_NAME 211 * \retval OCT_ERR_PARSER_FAIL 212 * \retval OCT_ERR_ENGINE_FAIL 213 * 214 * TODO maybe remove this function completely and let all use rpc call for set 215 * directly if they want to a non-trivial set? 216 */ 217errval_t oct_set_get(oct_mode_t mode, char** record, const char* query, ...) 218{ 219 assert(query != NULL); 220 errval_t err = SYS_ERR_OK; 221 va_list args; 222 223 char* buf = NULL; 224 FORMAT_QUERY(query, args, buf); 225 226 // Send to Server 227 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 228 struct octopus_set_response__rx_args reply; 229 err = cl->call_seq.set(cl, buf, mode, NOP_TRIGGER, true, reply.record, 230 &reply.tid, &reply.error_code); 231 if (err_is_ok(err)) { 232 err = reply.error_code; 233 } 234 235 free(buf); 236 237 if (err_is_fail(err)) { 238 return err; 239 } 240 241 if (record) { 242 *record = strdup(reply.record); 243 } 244 245 return err; 246} 247 248/** 249 * \brief Gets one record using the ID capability as the key/name. 250 * 251 * \param[out] data Record returned by the server. 252 * \param[in] idcap ID capability used as the key/name of the record. 253 * 254 * \retval SYS_ERR_OK 255 * \retval OCT_ERR_NO_RECORD 256 * \retval OCT_ERR_PARSER_FAIL 257 * \retval OCT_ERR_ENGINE_FAIL 258 */ 259errval_t oct_get_with_idcap(char **data, struct capref idcap) 260{ 261 assert(!capref_is_null(idcap)); 262 errval_t err = SYS_ERR_OK; 263 264 struct octopus_thc_client_binding_t *cl = oct_get_thc_client(); 265 assert(cl != NULL); 266 struct octopus_get_with_idcap_response__rx_args reply; 267 err = cl->call_seq.get_with_idcap(cl, idcap, NOP_TRIGGER, reply.output, 268 &reply.tid, &reply.error_code); 269 270 if (err_is_ok(err)) { 271 err = reply.error_code; 272 } 273 274 if (err_is_fail(err)) { 275 return err; 276 } 277 278 if (data) { 279 *data = strdup(reply.output); 280 } 281 282 return err; 283} 284 285/** 286 * \brief Sets a record using the ID capability as the name/key of the record. 287 * 288 * \param idcap ID capability used as the name/key of the record. 289 * \param attributes Attributes of the record. 290 * \param ... Additional arguments to format the attributes using 291 * vsprintf. 292 * 293 * \retval SYS_ERR_OK 294 * \retval OCT_ERR_NO_RECORD_NAME 295 * \retval OCT_ERR_PARSER_FAIL 296 * \retval OCT_ERR_ENGINE_FAIL 297 */ 298errval_t oct_set_with_idcap(struct capref idcap, const char *attributes, ...) 299{ 300 assert(!capref_is_null(idcap)); 301 assert(attributes != NULL); 302 errval_t err = SYS_ERR_OK; 303 va_list args; 304 305 char *buf = NULL; 306 FORMAT_QUERY(attributes, args, buf); 307 308 // Send to Server 309 struct octopus_thc_client_binding_t *cl = oct_get_thc_client(); 310 311 errval_t error_code; 312 err = cl->call_seq.set_with_idcap(cl, idcap, buf, SET_DEFAULT, NOP_TRIGGER, 313 false, NULL, NULL, &error_code); 314 315 if (err_is_ok(err)) { 316 err = error_code; 317 } 318 319 free(buf); 320 return err; 321} 322 323/** 324 * \brief Deletes all records matching the given query. 325 * 326 * \param query Specifies the record(s) to be deleted. 327 * \param ... Additional arguments to format the query using vsprintf. 328 * 329 * \retval SYS_ERR_OK 330 * \retval OCT_ERR_NO_RECORD 331 * \retval OCT_ERR_NO_RECORD_NAME 332 * \retval OCT_ERR_ENGINE_FAIL 333 * \retval OCT_ERR_PARSER_FAIL 334 * 335 * TODO: Atm only name of record is included in del query on server. 336 */ 337errval_t oct_del(const char* query, ...) 338{ 339 assert(query != NULL); 340 errval_t err = SYS_ERR_OK; 341 va_list args; 342 343 char* buf = NULL; 344 FORMAT_QUERY(query, args, buf); 345 346 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 347 errval_t error_code; 348 err = cl->call_seq.del(cl, buf, NOP_TRIGGER, NULL, &error_code); 349 if (err_is_ok(err)) { 350 err = error_code; 351 } 352 353 free(buf); 354 return err; 355} 356 357/** 358 * \brief Checks if a result for a given query exists. 359 * 360 * \param query Results are searched based on the query. 361 * \param ... Additional arguments to format the query using vsprintf. 362 * 363 * \retval SYS_ERR_OK 364 * \retval OCT_ERR_NO_RECORD 365 * \retval OCT_ERR_PARSER_FAIL 366 * \retval OCT_ERR_ENGINE_FAIL 367 **/ 368errval_t oct_exists(const char* query, ...) 369{ 370 assert(query != NULL); 371 errval_t err = SYS_ERR_OK; 372 va_list args; 373 374 char* buf = NULL; 375 FORMAT_QUERY(query, args, buf); 376 377 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 378 errval_t error_code; 379 err = cl->call_seq.exists(cl, buf, NOP_TRIGGER, NULL, &error_code); 380 if (err_is_ok(err)) { 381 err = error_code; 382 } 383 384 free(buf); 385 return err; 386} 387 388/** 389 * \brief Waits until a given record exists. 390 * 391 * \param record Record that matched the query, callee has to free this. 392 * \param query Format of record to wait for. 393 * \param ... Additional arguments to format query. 394 * 395 * \note This call blocks on the octopus RPC waitset if the record is not there yet. 396 * 397 * \retval SYS_ERR_OK 398 */ 399errval_t oct_wait_for(char** record, const char *query, ...) 400{ 401 assert(query != NULL); 402 errval_t err = SYS_ERR_OK; 403 va_list args; 404 405 char* buf = NULL; 406 FORMAT_QUERY(query, args, buf); 407 408 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 409 410 struct octopus_wait_for_response__rx_args reply; 411 err = cl->call_seq.wait_for(cl, buf, reply.record, &reply.error_code); 412 if (err_is_fail(err)) { 413 goto out; 414 } 415 err = reply.error_code; 416 417 if (err_is_fail(err)) { 418 goto out; 419 } 420 421 if (record) { 422 *record = strdup(reply.record); 423 } 424 425out: 426 free(buf); 427 return err; 428} 429