/* * libxlu_cfg.c - xl configuration file parsing: setup and helper functions * * Copyright (C) 2010 Citrix Ltd. * Author Ian Jackson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 only. with the special * exception on linking described in file LICENSE. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. */ #include #include "libxlu_internal.h" #include "libxlu_cfg_y.h" #include "libxlu_cfg_l.h" #include "libxlu_cfg_i.h" XLU_Config *xlu_cfg_init(FILE *report, const char *report_filename) { XLU_Config *cfg; cfg= malloc(sizeof(*cfg)); if (!cfg) return 0; cfg->report= report; cfg->filename= strdup(report_filename); if (!cfg->filename) { free(cfg); return 0; } cfg->settings= 0; return cfg; } static int ctx_prep(CfgParseContext *ctx, XLU_Config *cfg) { int e; ctx->cfg= cfg; ctx->err= 0; ctx->lexerrlineno= -1; ctx->likely_python= 0; ctx->scanner= 0; e= xlu__cfg_yylex_init_extra(ctx, &ctx->scanner); if (e) { fprintf(cfg->report,"%s: unable to create scanner: %s\n", cfg->filename, strerror(e)); return e; } return 0; } static void ctx_dispose(CfgParseContext *ctx) { if (ctx->scanner) xlu__cfg_yylex_destroy(ctx->scanner); } static void parse(CfgParseContext *ctx) { /* On return, ctx.err will be updated with the error status. */ int r; xlu__cfg_yyset_lineno(1, ctx->scanner); r= xlu__cfg_yyparse(ctx); if (r) assert(ctx->err); if (ctx->err && ctx->likely_python) { fputs( "warning: Config file looks like it contains Python code.\n" "warning: Arbitrary Python is no longer supported.\n" "warning: See http://wiki.xen.org/xenwiki/PythonInXlConfig\n", ctx->cfg->report); } } int xlu_cfg_readfile(XLU_Config *cfg, const char *real_filename) { FILE *f = 0; int e; CfgParseContext ctx; e = ctx_prep(&ctx, cfg); if (e) { ctx.err= e; goto xe; } f= fopen(real_filename, "r"); if (!f) { ctx.err = errno; fprintf(cfg->report,"%s: unable to open configuration file: %s\n", real_filename, strerror(e)); goto xe; } xlu__cfg_yyrestart(f, ctx.scanner); parse(&ctx); xe: ctx_dispose(&ctx); if (f) fclose(f); return ctx.err; } int xlu_cfg_readdata(XLU_Config *cfg, const char *data, int length) { int e; YY_BUFFER_STATE buf= 0; CfgParseContext ctx; e= ctx_prep(&ctx, cfg); if (e) { ctx.err= e; goto xe; } buf = xlu__cfg_yy_scan_bytes(data, length, ctx.scanner); if (!buf) { fprintf(cfg->report,"%s: unable to allocate scanner buffer\n", cfg->filename); ctx.err= ENOMEM; goto xe; } parse(&ctx); xe: if (buf) xlu__cfg_yy_delete_buffer(buf, ctx.scanner); ctx_dispose(&ctx); return ctx.err; } void xlu__cfg_set_free(XLU_ConfigSetting *set) { int i; if (!set) return; free(set->name); for (i=0; invalues; i++) free(set->values[i]); free(set->values); free(set); } void xlu_cfg_destroy(XLU_Config *cfg) { XLU_ConfigSetting *set, *set_next; for (set= cfg->settings; set; set= set_next) { set_next= set->next; xlu__cfg_set_free(set); } free(cfg->filename); free(cfg); } static XLU_ConfigSetting *find(const XLU_Config *cfg, const char *n) { XLU_ConfigSetting *set; for (set= cfg->settings; set; set= set->next) if (!strcmp(set->name, n)) return set; return 0; } static int find_atom(const XLU_Config *cfg, const char *n, XLU_ConfigSetting **set_r) { XLU_ConfigSetting *set; set= find(cfg,n); if (!set) return ESRCH; if (set->avalues!=1) { fprintf(cfg->report, "%s:%d: warning: parameter `%s' is" " a list but should be a single value\n", cfg->filename, set->lineno, n); return EINVAL; } *set_r= set; return 0; } int xlu_cfg_get_string(const XLU_Config *cfg, const char *n, const char **value_r) { XLU_ConfigSetting *set; int e; e= find_atom(cfg,n,&set); if (e) return e; *value_r= set->values[0]; return 0; } int xlu_cfg_replace_string(const XLU_Config *cfg, const char *n, char **value_r) { XLU_ConfigSetting *set; int e; e= find_atom(cfg,n,&set); if (e) return e; free(*value_r); *value_r= strdup(set->values[0]); return 0; } int xlu_cfg_get_long(const XLU_Config *cfg, const char *n, long *value_r) { long l; XLU_ConfigSetting *set; int e; char *ep; e= find_atom(cfg,n,&set); if (e) return e; errno= 0; l= strtol(set->values[0], &ep, 0); e= errno; if (errno) { e= errno; assert(e==EINVAL || e==ERANGE); fprintf(cfg->report, "%s:%d: warning: parameter `%s' could not be parsed" " as a number: %s\n", cfg->filename, set->lineno, n, strerror(e)); return e; } if (*ep || ep==set->values[0]) { fprintf(cfg->report, "%s:%d: warning: parameter `%s' is not a valid number\n", cfg->filename, set->lineno, n); return EINVAL; } *value_r= l; return 0; } int xlu_cfg_get_list(const XLU_Config *cfg, const char *n, XLU_ConfigList **list_r, int *entries_r, int dont_warn) { XLU_ConfigSetting *set; set= find(cfg,n); if (!set) return ESRCH; if (set->avalues==1) { if (!dont_warn) { fprintf(cfg->report, "%s:%d: warning: parameter `%s' is a single value" " but should be a list\n", cfg->filename, set->lineno, n); } return EINVAL; } if (list_r) *list_r= set; if (entries_r) *entries_r= set->nvalues; return 0; } const char *xlu_cfg_get_listitem(const XLU_ConfigList *set, int entry) { if (entry < 0 || entry >= set->nvalues) return 0; return set->values[entry]; } XLU_ConfigSetting *xlu__cfg_set_mk(CfgParseContext *ctx, int alloc, char *atom) { XLU_ConfigSetting *set= 0; if (ctx->err) goto x; assert(!!alloc == !!atom); set= malloc(sizeof(*set)); if (!set) goto xe; set->name= 0; /* tbd */ set->avalues= alloc; if (!alloc) { set->nvalues= 0; set->values= 0; } else { set->values= malloc(sizeof(*set->values) * alloc); if (!set->values) goto xe; set->nvalues= 1; set->values[0]= atom; } return set; xe: ctx->err= errno; x: free(set); free(atom); return 0; } void xlu__cfg_set_add(CfgParseContext *ctx, XLU_ConfigSetting *set, char *atom) { if (ctx->err) return; assert(atom); if (set->nvalues >= set->avalues) { int new_avalues; char **new_values; if (set->avalues > INT_MAX / 100) { ctx->err= ERANGE; return; } new_avalues= set->avalues * 4; new_values= realloc(set->values, sizeof(*new_values) * new_avalues); if (!new_values) { ctx->err= errno; free(atom); return; } set->values= new_values; set->avalues= new_avalues; } set->values[set->nvalues++]= atom; } void xlu__cfg_set_store(CfgParseContext *ctx, char *name, XLU_ConfigSetting *set, int lineno) { if (ctx->err) return; assert(name); set->name= name; set->lineno= lineno; set->next= ctx->cfg->settings; ctx->cfg->settings= set; } char *xlu__cfgl_strdup(CfgParseContext *ctx, const char *src) { char *result; if (ctx->err) return 0; result= strdup(src); if (!result) ctx->err= errno; return result; } char *xlu__cfgl_dequote(CfgParseContext *ctx, const char *src) { char *result; const char *p; char *q; int len, c, nc; if (ctx->err) return 0; len= strlen(src); assert(len>=2 && src[0]==src[len-1]); result= malloc(len-1); if (!result) { ctx->err= errno; return 0; } q= result; for (p= src+1; p < src+len-1; ) { c= *p++; if (c=='\\') { assert(p < src+len-1); nc= *p++; if (nc=='"' || nc=='\'' || nc=='\\') { *q++= nc; } else if (nc=='a') { *q++= '\007'; } else if (nc=='b') { *q++= '\010'; } else if (nc=='f') { *q++= '\014'; } else if (nc=='n') { *q++= '\n'; } else if (nc=='r') { *q++= '\r'; } else if (nc=='t') { *q++= '\t'; } else if (nc=='v') { *q++= '\013'; } else if (nc=='x') { #define NUMERIC_CHAR(minlen,maxlen,base,basetext) do{ \ char numbuf[(maxlen)+1], *ep; \ unsigned long val; \ \ strncpy(numbuf,p,(maxlen)); \ numbuf[(maxlen)]= 0; \ val= strtoul(numbuf, &ep, (base)); \ if (ep <= numbuf+(minlen)) { \ xlu__cfgl_lexicalerror(ctx,"invalid digit after" \ " backslash " basetext "numerical character escape" \ " in quoted string"); \ ctx->err= EINVAL; \ goto x; \ } \ p += (ep - numbuf); \ }while(0) p++; NUMERIC_CHAR(2,2,16,"hex"); } else if (nc>='0' && nc<='7') { NUMERIC_CHAR(1,3,10,"octal"); } assert(p <= src+len-1); } else { *q++= c; } } x: *q++= 0; return result; } void xlu__cfgl_lexicalerror(CfgParseContext *ctx, char const *msg) { YYLTYPE loc; loc.first_line= xlu__cfg_yyget_lineno(ctx->scanner); xlu__cfg_yyerror(&loc, ctx, msg); ctx->lexerrlineno= loc.first_line; } void xlu__cfg_yyerror(YYLTYPE *loc, CfgParseContext *ctx, char const *msg) { const char *text, *newline; int len, lineno; lineno= loc->first_line; if (lineno <= ctx->lexerrlineno) return; text= xlu__cfg_yyget_text(ctx->scanner); len= xlu__cfg_yyget_leng(ctx->scanner); newline= ""; if (len>0 && text[len-1]=='\n') { len--; lineno--; if (!len) { newline= ""; } } while (len>0 && (text[len-1]=='\t' || text[len-1]==' ')) { len--; } fprintf(ctx->cfg->report, "%s:%d: config parsing error near %s%.*s%s%s: %s\n", ctx->cfg->filename, lineno, len?"`":"", len, text, len?"'":"", newline, msg); if (!ctx->err) ctx->err= EINVAL; } /* * Local variables: * mode: C * c-basic-offset: 4 * indent-tabs-mode: nil * End: */ und-color: #ffffc0; padding: 0 5px 0 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; } .highlight .hll { background-color: #ffffcc } .highlight { background: #ffffff; } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
                 2011,2012 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ch.h"
#include "hal.h"
#include "test.h"
#include "shell.h"
#include "chprintf.h"

#define SHELL_WA_SIZE       THD_WA_SIZE(4096)
#define CONSOLE_WA_SIZE     THD_WA_SIZE(4096)
#define TEST_WA_SIZE        THD_WA_SIZE(4096)

#define cputs(msg) chMsgSend(cdtp, (msg_t)msg)

static Thread *cdtp;
static Thread *shelltp1;
static Thread *shelltp2;

static void cmd_mem(BaseSequentialStream *chp, int argc, char *argv[]) {
  size_t n, size;

  (void)argv;
  if (argc > 0) {
    chprintf(chp, "Usage: mem\r\n");
    return;
  }
  n = chHeapStatus(NULL, &size);
  chprintf(chp, "core free memory : %u bytes\r\n", chCoreStatus());
  chprintf(chp, "heap fragments   : %u\r\n", n);
  chprintf(chp, "heap free total  : %u bytes\r\n", size);
}

static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) {
  static const char *states[] = {THD_STATE_NAMES};
  Thread *tp;

  (void)argv;
  if (argc > 0) {
    chprintf(chp, "Usage: threads\r\n");
    return;
  }
  chprintf(chp, "    addr    stack prio refs     state time\r\n");
  tp = chRegFirstThread();
  do {
    chprintf(chp, "%.8lx %.8lx %4lu %4lu %9s %lu\r\n",
            (uint32_t)tp, (uint32_t)tp->p_ctx.esp,
            (uint32_t)tp->p_prio, (uint32_t)(tp->p_refs - 1),
            states[tp->p_state], (uint32_t)tp->p_time);
    tp = chRegNextThread(tp);
  } while (tp != NULL);
}

static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) {
  Thread *tp;

  (void)argv;
  if (argc > 0) {
    chprintf(chp, "Usage: test\r\n");
    return;
  }
  tp = chThdCreateFromHeap(NULL, TEST_WA_SIZE, chThdGetPriority(),
                           TestThread, chp);
  if (tp == NULL) {
    chprintf(chp, "out of memory\r\n");
    return;
  }
  chThdWait(tp);
}

static const ShellCommand commands[] = {
  {"mem", cmd_mem},
  {"threads", cmd_threads},
  {"test", cmd_test},
  {NULL, NULL}
};

static const ShellConfig shell_cfg1 = {
  (BaseSequentialStream *)&SD1,
  commands
};

static const ShellConfig shell_cfg2 = {
  (BaseSequentialStream *)&SD2,
  commands
};

/*
 * Console print server done using synchronous messages. This makes the access
 * to the C printf() thread safe and the print operation atomic among threads.
 * In this example the message is the zero terminated string itself.
 */
static msg_t console_thread(void *arg) {

  (void)arg;
  while (!chThdShouldTerminate()) {
    Thread *tp = chMsgWait();
    puts((char *)chMsgGet(tp));
    fflush(stdout);
    chMsgRelease(tp, RDY_OK);
  }
  return 0;
}

/**
 * @brief Shell termination handler.
 *
 * @param[in] id event id.
 */
static void termination_handler(eventid_t id) {

  (void)id;
  if (shelltp1 && chThdTerminated(shelltp1)) {
    chThdWait(shelltp1);
    shelltp1 = NULL;
    chThdSleepMilliseconds(10);
    cputs("Init: shell on SD1 terminated");
    chSysLock();
    chOQResetI(&SD1.oqueue);
    chSysUnlock();
  }
  if (shelltp2 && chThdTerminated(shelltp2)) {
    chThdWait(shelltp2);
    shelltp2 = NULL;
    chThdSleepMilliseconds(10);
    cputs("Init: shell on SD2 terminated");
    chSysLock();
    chOQResetI(&SD2.oqueue);
    chSysUnlock();
  }
}

static EventListener sd1fel, sd2fel;

/**
 * @brief SD1 status change handler.
 *
 * @param[in] id event id.
 */
static void sd1_handler(eventid_t id) {
  flagsmask_t flags;

  (void)id;
  flags = chEvtGetAndClearFlags(&sd1fel);
  if ((flags & CHN_CONNECTED) && (shelltp1 == NULL)) {
    cputs("Init: connection on SD1");
    shelltp1 = shellCreate(&shell_cfg1, SHELL_WA_SIZE, NORMALPRIO + 1);
  }
  if (flags & CHN_DISCONNECTED) {
    cputs("Init: disconnection on SD1");
    chSysLock();
    chIQResetI(&SD1.iqueue);
    chSysUnlock();
  }
}

/**
 * @brief SD2 status change handler.
 *
 * @param[in] id event id.
 */
static void sd2_handler(eventid_t id) {
  flagsmask_t flags;

  (void)id;
  flags = chEvtGetAndClearFlags(&sd2fel);
  if ((flags & CHN_CONNECTED) && (shelltp2 == NULL)) {
    cputs("Init: connection on SD2");
    shelltp2 = shellCreate(&shell_cfg2, SHELL_WA_SIZE, NORMALPRIO + 10);
  }
  if (flags & CHN_DISCONNECTED) {
    cputs("Init: disconnection on SD2");
    chSysLock();
    chIQResetI(&SD2.iqueue);
    chSysUnlock();
  }
}

static evhandler_t fhandlers[] = {
  termination_handler,
  sd1_handler,
  sd2_handler
};

/*------------------------------------------------------------------------*
 * Simulator main.                                                        *
 *------------------------------------------------------------------------*/
int main(void) {
  EventListener tel;

  /*
   * System initializations.
   * - HAL initialization, this also initializes the configured device drivers
   *   and performs the board-specific initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active.
   */
  halInit();
  chSysInit();

  /*
   * Serial ports (simulated) initialization.
   */
  sdStart(&SD1, NULL);
  sdStart(&SD2, NULL);

  /*
   * Shell manager initialization.
   */
  shellInit();
  chEvtRegister(&shell_terminated, &tel, 0);

  /*
   * Console thread started.
   */
  cdtp = chThdCreateFromHeap(NULL, CONSOLE_WA_SIZE, NORMALPRIO + 1,
                             console_thread, NULL);

  /*
   * Initializing connection/disconnection events.
   */
  cputs("Shell service started on SD1, SD2");
  cputs("  - Listening for connections on SD1");
  chEvtRegister(chnGetEventSource(&SD1), &sd1fel, 1);
  cputs("  - Listening for connections on SD2");
  chEvtRegister(chnGetEventSource(&SD2), &sd2fel, 2);

  /*
   * Events servicing loop.
   */
  while (!chThdShouldTerminate())
    chEvtDispatch(fhandlers, chEvtWaitOne(ALL_EVENTS));

  /*
   * Clean simulator exit.
   */
  chEvtUnregister(chnGetEventSource(&SD1), &sd1fel);
  chEvtUnregister(chnGetEventSource(&SD2), &sd2fel);
  return 0;
}