Example #1
0
/* Store exclude directory containing  info */
static void store_excludedir(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
{

   if (exclude) {
      scan_err0(lc, _("ExcludeDirContaining directive not permitted in Exclude.\n"));
      /* NOT REACHED */
   }
   lex_get_token(lc, T_NAME);
   if (pass == 1) {
      res_incexe.ignoredir = bstrdup(lc->str);
   }
   scan_to_eol(lc);
}
Example #2
0
/*
 *
 * Store FileSet Include/Exclude info
 *  new style includes are handled in store_newinc()
 */
void store_inc(LEX *lc, RES_ITEM *item, int index, int pass)
{
   int token;

   /*
    * Decide if we are doing a new Include or an old include. The
    *  new Include is followed immediately by open brace, whereas the
    *  old include has options following the Include.
    */
   token = lex_get_token(lc, T_SKIP_EOL);
   if (token == T_BOB) {
      store_newinc(lc, item, index, pass);
      return;
   }
   scan_err0(lc, _("Old style Include/Exclude not supported\n"));
}
Example #3
0
/*
 * Come here when Options seen in Include/Exclude
 */
static void options_res(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
{
   int token, i;

   if (exclude) {
      scan_err0(lc, _("Options section not permitted in Exclude\n"));
      /* NOT REACHED */
   }
   token = lex_get_token(lc, T_SKIP_EOL);
   if (token != T_BOB) {
      scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
   }

   if (pass == 1) {
      setup_current_opts();
   }

   while ((token = lex_get_token(lc, T_ALL)) != T_EOF) {
      if (token == T_EOL) {
         continue;
      }
      if (token == T_EOB) {
         break;
      }
      if (token != T_IDENTIFIER) {
         scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
      }
      for (i=0; options_items[i].name; i++) {
         if (bstrcasecmp(options_items[i].name, lc->str)) {
            token = lex_get_token(lc, T_SKIP_EOL);
            if (token != T_EQUALS) {
               scan_err1(lc, _("expected an equals, got: %s"), lc->str);
            }
            /* Call item handler */
            options_items[i].handler(lc, &options_items[i], i, pass);
            i = -1;
            break;
         }
      }
      if (i >=0) {
         scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
      }
   }
}
Example #4
0
/*
 * Store Filename info. Note, for minor efficiency reasons, we
 * always increase the name buffer by 10 items because we expect
 * to add more entries.
 */
static void store_plugin_name(LEX *lc, RES_ITEM2 *item, int index, int pass, bool exclude)
{
   int token;
   INCEXE *incexe;

   if (exclude) {
      scan_err0(lc, _("Plugin directive not permitted in Exclude\n"));
      /* NOT REACHED */
   }
   token = lex_get_token(lc, T_SKIP_EOL);
   if (pass == 1) {
      /* Pickup Filename string
       */
      switch (token) {
      case T_IDENTIFIER:
      case T_UNQUOTED_STRING:
         if (strchr(lc->str, '\\')) {
            scan_err1(lc, _("Backslash found. Use forward slashes or quote the string.: %s\n"), lc->str);
            /* NOT REACHED */
         }
      case T_QUOTED_STRING:
         if (res_all.res_fs.have_MD5) {
            MD5Update(&res_all.res_fs.md5c, (unsigned char *)lc->str, lc->str_len);
         }
         incexe = &res_incexe;
         if (incexe->plugin_list.size() == 0) {
            incexe->plugin_list.init(10, true);
         }
         incexe->plugin_list.append(bstrdup(lc->str));
         Dmsg1(900, "Add to plugin_list %s\n", lc->str);
         break;
      default:
         scan_err1(lc, _("Expected a filename, got: %s"), lc->str);
         /* NOT REACHED */
      }
   }
   scan_to_eol(lc);
}
Example #5
0
/*
 * Store Schedule Run information
 *
 * Parse Run statement:
 *
 *  Run <keyword=value ...> [on] 2 january at 23:45
 *
 *   Default Run time is daily at 0:0
 *
 *   There can be multiple run statements, they are simply chained
 *   together.
 *
 */
void store_run(LEX *lc, RES_ITEM *item, int index, int pass)
{
   char *p;
   int i, j;
   int options = lc->options;
   int token, state, state2 = 0, code = 0, code2 = 0;
   bool found;
   utime_t utime;
   RES *res;
   RUNRES **run = (RUNRES **)(item->value);
   URES *res_all = (URES *)my_config->m_res_all;

   lc->options |= LOPT_NO_IDENT;      /* Want only "strings" */

   /*
    * Clear local copy of run record
    */
   memset(&lrun, 0, sizeof(lrun));

   /*
    * Scan for Job level "full", "incremental", ...
    */
   for (found = true; found; ) {
      found = false;
      token = lex_get_token(lc, T_NAME);
      for (i = 0; !found && RunFields[i].name; i++) {
         if (bstrcasecmp(lc->str, RunFields[i].name)) {
            found = true;
            if (lex_get_token(lc, T_ALL) != T_EQUALS) {
               scan_err1(lc, _("Expected an equals, got: %s"), lc->str);
               /* NOT REACHED */
            }
            switch (RunFields[i].token) {
            case 's':                 /* Data spooling */
               token = lex_get_token(lc, T_NAME);
               if (bstrcasecmp(lc->str, "yes") || bstrcasecmp(lc->str, "true")) {
                  lrun.spool_data = true;
                  lrun.spool_data_set = true;
               } else if (bstrcasecmp(lc->str, "no") || bstrcasecmp(lc->str, "false")) {
                  lrun.spool_data = false;
                  lrun.spool_data_set = true;
               } else {
                  scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str);
               }
               break;
            case 'L':                 /* Level */
               token = lex_get_token(lc, T_NAME);
               for (j = 0; joblevels[j].level_name; j++) {
                  if (bstrcasecmp(lc->str, joblevels[j].level_name)) {
                     lrun.level = joblevels[j].level;
                     lrun.job_type = joblevels[j].job_type;
                     j = 0;
                     break;
                  }
               }
               if (j != 0) {
                  scan_err1(lc, _("Job level field: %s not found in run record"), lc->str);
                  /* NOT REACHED */
               }
               break;
            case 'p':                 /* Priority */
               token = lex_get_token(lc, T_PINT32);
               if (pass == 2) {
                  lrun.Priority = lc->pint32_val;
               }
               break;
            case 'P':                 /* Pool */
            case 'f':                 /* FullPool */
            case 'v':                 /* VFullPool */
            case 'i':                 /* IncPool */
            case 'd':                 /* DiffPool */
            case 'n':                 /* NextPool */
               token = lex_get_token(lc, T_NAME);
               if (pass == 2) {
                  res = GetResWithName(R_POOL, lc->str);
                  if (res == NULL) {
                     scan_err1(lc, _("Could not find specified Pool Resource: %s"),
                                lc->str);
                     /* NOT REACHED */
                  }
                  switch(RunFields[i].token) {
                  case 'P':
                     lrun.pool = (POOLRES *)res;
                     break;
                  case 'f':
                     lrun.full_pool = (POOLRES *)res;
                     break;
                  case 'v':
                     lrun.vfull_pool = (POOLRES *)res;
                     break;
                  case 'i':
                     lrun.inc_pool = (POOLRES *)res;
                     break;
                  case 'd':
                     lrun.diff_pool = (POOLRES *)res;
                     break;
                  case 'n':
                     lrun.next_pool = (POOLRES *)res;
                     break;
                  }
               }
               break;
            case 'S':                 /* Storage */
               token = lex_get_token(lc, T_NAME);
               if (pass == 2) {
                  res = GetResWithName(R_STORAGE, lc->str);
                  if (res == NULL) {
                     scan_err1(lc, _("Could not find specified Storage Resource: %s"),
                                lc->str);
                     /* NOT REACHED */
                  }
                  lrun.storage = (STORERES *)res;
               }
               break;
            case 'M':                 /* Messages */
               token = lex_get_token(lc, T_NAME);
               if (pass == 2) {
                  res = GetResWithName(R_MSGS, lc->str);
                  if (res == NULL) {
                     scan_err1(lc, _("Could not find specified Messages Resource: %s"),
                                lc->str);
                     /* NOT REACHED */
                  }
                  lrun.msgs = (MSGSRES *)res;
               }
               break;
            case 'm':                 /* Max run sched time */
               token = lex_get_token(lc, T_QUOTED_STRING);
               if (!duration_to_utime(lc->str, &utime)) {
                  scan_err1(lc, _("expected a time period, got: %s"), lc->str);
                  return;
               }
               lrun.MaxRunSchedTime = utime;
               lrun.MaxRunSchedTime_set = true;
               break;
            case 'a':                 /* Accurate */
               token = lex_get_token(lc, T_NAME);
               if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
                  lrun.accurate = true;
                  lrun.accurate_set = true;
               } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
                  lrun.accurate = false;
                  lrun.accurate_set = true;
               } else {
                  scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str);
               }
               break;
            default:
               scan_err1(lc, _("Expected a keyword name, got: %s"), lc->str);
               /* NOT REACHED */
               break;
            } /* end switch */
         } /* end if bstrcasecmp */
      } /* end for RunFields */

      /*
       * At this point, it is not a keyword. Check for old syle
       * Job Levels without keyword. This form is depreciated!!!
       */
      if (!found) {
         for (j = 0; joblevels[j].level_name; j++) {
            if (bstrcasecmp(lc->str, joblevels[j].level_name)) {
               lrun.level = joblevels[j].level;
               lrun.job_type = joblevels[j].job_type;
               found = true;
               break;
            }
         }
      }
   } /* end for found */

   /*
    * Scan schedule times.
    * Default is: daily at 0:0
    */
   state = s_none;
   set_defaults();

   for (; token != T_EOL; (token = lex_get_token(lc, T_ALL))) {
      int len;
      bool pm = false;
      bool am = false;
      switch (token) {
      case T_NUMBER:
         state = s_mday;
         code = atoi(lc->str) - 1;
         if (code < 0 || code > 30) {
            scan_err0(lc, _("Day number out of range (1-31)"));
         }
         break;
      case T_NAME:                    /* This handles drop through from keyword */
      case T_UNQUOTED_STRING:
         if (strchr(lc->str, (int)'-')) {
            state = s_range;
            break;
         }
         if (strchr(lc->str, (int)':')) {
            state = s_time;
            break;
         }
         if (strchr(lc->str, (int)'/')) {
            state = s_modulo;
            break;
         }
         if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') &&
             is_an_integer(lc->str+1)) {
            code = atoi(lc->str+1);
            if (code < 0 || code > 53) {
               scan_err0(lc, _("Week number out of range (0-53)"));
              /* NOT REACHED */
            }
            state = s_woy;            /* Week of year */
            break;
         }
         /*
          * Everything else must be a keyword
          */
         for (i = 0; keyw[i].name; i++) {
            if (bstrcasecmp(lc->str, keyw[i].name)) {
               state = keyw[i].state;
               code   = keyw[i].code;
               i = 0;
               break;
            }
         }
         if (i != 0) {
            scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
            /* NOT REACHED */
         }
         break;
      case T_COMMA:
         continue;
      default:
         scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
         /* NOT REACHED */
         break;
      }
      switch (state) {
      case s_none:
         continue;
      case s_mday:                    /* Day of month */
         if (!have_mday) {
            clear_bits(0, 30, lrun.mday);
            have_mday = true;
         }
         set_bit(code, lrun.mday);
         break;
      case s_month:                   /* Month of year */
         if (!have_month) {
            clear_bits(0, 11, lrun.month);
            have_month = true;
         }
         set_bit(code, lrun.month);
         break;
      case s_wday:                    /* Week day */
         if (!have_wday) {
            clear_bits(0, 6, lrun.wday);
            have_wday = true;
         }
         set_bit(code, lrun.wday);
         break;
      case s_wom:                     /* Week of month 1st, ... */
         if (!have_wom) {
            clear_bits(0, 4, lrun.wom);
            have_wom = true;
         }
         set_bit(code, lrun.wom);
         break;
      case s_woy:
         if (!have_woy) {
            clear_bits(0, 53, lrun.woy);
            have_woy = true;
         }
         set_bit(code, lrun.woy);
         break;
      case s_time:                    /* Time */
         if (!have_at) {
            scan_err0(lc, _("Time must be preceded by keyword AT."));
            /* NOT REACHED */
         }
         if (!have_hour) {
            clear_bits(0, 23, lrun.hour);
         }
//       Dmsg1(000, "s_time=%s\n", lc->str);
         p = strchr(lc->str, ':');
         if (!p)  {
            scan_err0(lc, _("Time logic error.\n"));
            /* NOT REACHED */
         }
         *p++ = 0;                    /* Separate two halves */
         code = atoi(lc->str);        /* Pick up hour */
         code2 = atoi(p);             /* Pick up minutes */
         len = strlen(p);
         if (len >= 2) {
            p += 2;
         }
         if (bstrcasecmp(p, "pm")) {
            pm = true;
         } else if (bstrcasecmp(p, "am")) {
            am = true;
         } else if (len != 2) {
            scan_err0(lc, _("Bad time specification."));
            /* NOT REACHED */
         }
         /*
          * Note, according to NIST, 12am and 12pm are ambiguous and
          *  can be defined to anything.  However, 12:01am is the same
          *  as 00:01 and 12:01pm is the same as 12:01, so we define
          *  12am as 00:00 and 12pm as 12:00.
          */
         if (pm) {
            /*
             * Convert to 24 hour time
             */
            if (code != 12) {
               code += 12;
            }
         } else if (am && code == 12) {
            /*
             * AM
             */
            code -= 12;
         }
         if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
            scan_err0(lc, _("Bad time specification."));
            /* NOT REACHED */
         }
         set_bit(code, lrun.hour);
         lrun.minute = code2;
         have_hour = true;
         break;
      case s_at:
         have_at = true;
         break;
      case s_last:
         lrun.last_set = true;
         if (!have_wom) {
            clear_bits(0, 4, lrun.wom);
            have_wom = true;
         }
         break;
      case s_modulo:
         p = strchr(lc->str, '/');
         if (!p) {
            scan_err0(lc, _("Modulo logic error.\n"));
         }
         *p++ = 0;                 /* Separate two halves */

         if (is_an_integer(lc->str) && is_an_integer(p)) {
            /*
             * Check for day modulo specification.
             */
            code = atoi(lc->str) - 1;
            code2 = atoi(p);
            if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
               scan_err0(lc, _("Bad day specification in modulo."));
            }
            if (code > code2) {
               scan_err0(lc, _("Bad day specification, offset must always be <= than modulo."));
            }
            if (!have_mday) {
               clear_bits(0, 30, lrun.mday);
               have_mday = true;
            }
            /*
             * Set the bits according to the modulo specification.
             */
            for (i = 0; i < 31; i++) {
               if (i % code2 == 0) {
                  set_bit(i + code, lrun.mday);
               }
            }
         } else if (strlen(lc->str) == 3 && strlen(p) == 3 &&
                   (lc->str[0] == 'w' || lc->str[0] == 'W') &&
                   (p[0] == 'w' || p[0] == 'W') &&
                    is_an_integer(lc->str + 1) &&
                    is_an_integer(p + 1)) {
            /*
             * Check for week modulo specification.
             */
            code = atoi(lc->str + 1);
            code2 = atoi(p + 1);
            if (code < 0 || code > 53 || code2 < 0 || code2 > 53) {
               scan_err0(lc, _("Week number out of range (0-53) in modulo"));
            }
            if (code > code2) {
               scan_err0(lc, _("Bad week number specification in modulo, offset must always be <= than modulo."));
            }
            if (!have_woy) {
               clear_bits(0, 53, lrun.woy);
               have_woy = true;
            }
            /*
             * Set the bits according to the modulo specification.
             */
            for (i = 0; i < 54; i++) {
               if (i % code2 == 0) {
                  set_bit(i + code - 1, lrun.woy);
               }
            }
         } else {
            scan_err0(lc, _("Bad modulo time specification. Format for weekdays is '01/02', for yearweeks is 'w01/w02'."));
         }
         break;
      case s_range:
         p = strchr(lc->str, '-');
         if (!p) {
            scan_err0(lc, _("Range logic error.\n"));
         }
         *p++ = 0;                    /* Separate two halves */

         if (is_an_integer(lc->str) && is_an_integer(p)) {
            /*
             * Check for day range.
             */
            code = atoi(lc->str) - 1;
            code2 = atoi(p) - 1;
            if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
               scan_err0(lc, _("Bad day range specification."));
            }
            if (!have_mday) {
               clear_bits(0, 30, lrun.mday);
               have_mday = true;
            }
            if (code < code2) {
               set_bits(code, code2, lrun.mday);
            } else {
               set_bits(code, 30, lrun.mday);
               set_bits(0, code2, lrun.mday);
            }
         } else if (strlen(lc->str) == 3 && strlen(p) == 3 &&
                   (lc->str[0] == 'w' || lc->str[0] == 'W') &&
                   (p[0] == 'w' || p[0] == 'W') &&
                    is_an_integer(lc->str + 1) &&
                    is_an_integer(p + 1)) {
            /*
             * Check for week of year range.
             */
            code = atoi(lc->str + 1);
            code2 = atoi(p + 1);
            if (code < 0 || code > 53 || code2 < 0 || code2 > 53) {
               scan_err0(lc, _("Week number out of range (0-53)"));
            }
            if (!have_woy) {
               clear_bits(0, 53, lrun.woy);
               have_woy = true;
            }
            if (code < code2) {
               set_bits(code, code2, lrun.woy);
            } else {
               set_bits(code, 53, lrun.woy);
               set_bits(0, code2, lrun.woy);
            }
         } else {
            /*
             * lookup first half of keyword range (week days or months).
             */
            lcase(lc->str);
            for (i = 0; keyw[i].name; i++) {
               if (bstrcmp(lc->str, keyw[i].name)) {
                  state = keyw[i].state;
                  code = keyw[i].code;
                  i = 0;
                  break;
               }
            }
            if (i != 0 || (state != s_month && state != s_wday && state != s_wom)) {
               scan_err0(lc, _("Invalid month, week or position day range"));
               /* NOT REACHED */
            }

            /*
             * Lookup end of range.
             */
            lcase(p);
            for (i = 0; keyw[i].name; i++) {
               if (bstrcmp(p, keyw[i].name)) {
                  state2 = keyw[i].state;
                  code2 = keyw[i].code;
                  i = 0;
                  break;
               }
            }
            if (i != 0 || state != state2 || code == code2) {
               scan_err0(lc, _("Invalid month, weekday or position range"));
               /* NOT REACHED */
            }
            if (state == s_wday) {
               if (!have_wday) {
                  clear_bits(0, 6, lrun.wday);
                  have_wday = true;
               }
               if (code < code2) {
                  set_bits(code, code2, lrun.wday);
               } else {
                  set_bits(code, 6, lrun.wday);
                  set_bits(0, code2, lrun.wday);
               }
            } else if (state == s_month) {
               if (!have_month) {
                  clear_bits(0, 11, lrun.month);
                  have_month = true;
               }
               if (code < code2) {
                  set_bits(code, code2, lrun.month);
               } else {
                  /*
                   * This is a bit odd, but we accept it anyway
                   */
                  set_bits(code, 11, lrun.month);
                  set_bits(0, code2, lrun.month);
               }
            } else {
               /*
                * Must be position
                */
               if (!have_wom) {
                  clear_bits(0, 4, lrun.wom);
                  have_wom = true;
               }
               if (code < code2) {
                  set_bits(code, code2, lrun.wom);
               } else {
                  set_bits(code, 4, lrun.wom);
                  set_bits(0, code2, lrun.wom);
               }
            }
         }
         break;
      case s_hourly:
         have_hour = true;
         set_bits(0, 23, lrun.hour);
         break;
      case s_weekly:
         have_mday = have_wom = have_woy = true;
         set_bits(0, 30, lrun.mday);
         set_bits(0, 4,  lrun.wom);
         set_bits(0, 53, lrun.woy);
         break;
      case s_daily:
         have_mday = true;
         set_bits(0, 6, lrun.wday);
         break;
      case s_monthly:
         have_month = true;
         set_bits(0, 11, lrun.month);
         break;
      default:
         scan_err0(lc, _("Unexpected run state\n"));
         /* NOT REACHED */
         break;
      }
   }

   /* Allocate run record, copy new stuff into it,
    * and append it to the list of run records
    * in the schedule resource.
    */
   if (pass == 2) {
      RUNRES *tail;

      /* Create new run record */
      RUNRES *nrun = (RUNRES *)malloc(sizeof(RUNRES));
      memcpy(nrun, &lrun, sizeof(RUNRES));
      nrun ->next = NULL;

      if (!*run) {                       /* If empty list */
         *run = nrun;                    /* Add new record */
      } else {
         for (tail = *run; tail->next; tail=tail->next)
            {  }
         tail->next = nrun;
      }
   }

   lc->options = options;                /* Restore scanner options */
   set_bit(index, res_all->res_sch.hdr.item_present);
   clear_bit(index, res_all->hdr.inherit_content);
}
Example #6
0
bool CONFIG::parse_config()
{
   LEX *lc = NULL;
   int token, i, pass;
   int res_type = 0;
   enum parse_state state = p_none;
   RES_ITEM *items = NULL;
   int level = 0;
   static bool first = true;
   int errstat;
   const char *cf = m_cf;
   LEX_ERROR_HANDLER *scan_error = m_scan_error;
   int err_type = m_err_type;

   if (first && (errstat=rwl_init(&res_lock)) != 0) {
      berrno be;
      Jmsg1(NULL, M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
            be.bstrerror(errstat));
   }
   first = false;

   char *full_path = (char *)alloca(MAX_PATH + 1);

   if (!find_config_file(cf, full_path, MAX_PATH +1)) {
      Jmsg0(NULL, M_ABORT, 0, _("Config filename too long.\n"));
   }
   cf = full_path;

   /* Make two passes. The first builds the name symbol table,
    * and the second picks up the items.
    */
   Dmsg0(900, "Enter parse_config()\n");
   for (pass=1; pass <= 2; pass++) {
      Dmsg1(900, "parse_config pass %d\n", pass);
      if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
         berrno be;
         /* We must create a lex packet to print the error */
         lc = (LEX *)malloc(sizeof(LEX));
         memset(lc, 0, sizeof(LEX));
         if (scan_error) {
            lc->scan_error = scan_error;
         } else {
            lex_set_default_error_handler(lc);
         }
         lex_set_error_handler_error_type(lc, err_type) ;
         bstrncpy(lc->str, cf, sizeof(lc->str));
         lc->fname = lc->str;
         scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
            lc->str, be.bstrerror());
         free(lc);
         return 0;
      }
      lex_set_error_handler_error_type(lc, err_type) ;
      while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
         Dmsg3(900, "parse state=%d pass=%d got token=%s\n", state, pass,
              lex_tok_to_str(token));
         switch (state) {
         case p_none:
            if (token == T_EOL) {
               break;
            } else if (token == T_UTF8_BOM) {
               /* We can assume the file is UTF-8 as we have seen a UTF-8 BOM */
               break;
            } else if (token == T_UTF16_BOM) {
               scan_err0(lc, _("Currently we cannot handle UTF-16 source files. "
                   "Please convert the conf file to UTF-8\n"));
               return 0;
            } else if (token != T_IDENTIFIER) {
               scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
               return 0;
            }
            for (i=0; resources[i].name; i++) {
               if (strcasecmp(resources[i].name, lc->str) == 0) {
                  items = resources[i].items;
                  if (!items) {
                     break;
                  }
                  state = p_resource;
                  res_type = resources[i].rcode;
                  init_resource(this, res_type, items, pass);
                  break;
               }
            }
            if (state == p_none) {
               scan_err1(lc, _("expected resource name, got: %s"), lc->str);
               return 0;
            }
            break;
         case p_resource:
            switch (token) {
            case T_BOB:
               level++;
               break;
            case T_IDENTIFIER:
               if (level != 1) {
                  scan_err1(lc, _("not in resource definition: %s"), lc->str);
                  return 0;
               }
               for (i=0; items[i].name; i++) {
                  if (strcasecmp(items[i].name, lc->str) == 0) {
                     /* If the ITEM_NO_EQUALS flag is set we do NOT
                      *   scan for = after the keyword  */
                     if (!(items[i].flags & ITEM_NO_EQUALS)) {
                        token = lex_get_token(lc, T_SKIP_EOL);
                        Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
                        if (token != T_EQUALS) {
                           scan_err1(lc, _("expected an equals, got: %s"), lc->str);
                           return 0;
                        }
                     }
                     Dmsg1(800, "calling handler for %s\n", items[i].name);
                     /* Call item handler */
                     items[i].handler(lc, &items[i], i, pass);
                     i = -1;
                     break;
                  }
               }
               if (i >= 0) {
                  Dmsg2(900, "level=%d id=%s\n", level, lc->str);
                  Dmsg1(900, "Keyword = %s\n", lc->str);
                  scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
                     "Perhaps you left the trailing brace off of the previous resource."), lc->str);
                  return 0;
               }
               break;

            case T_EOB:
               level--;
               state = p_none;
               Dmsg0(900, "T_EOB => define new resource\n");
               if (res_all.hdr.name == NULL) {
                  scan_err0(lc, _("Name not specified for resource"));
                  return 0;
               }
               save_resource(res_type, items, pass);  /* save resource */
               break;

            case T_EOL:
               break;

            default:
               scan_err2(lc, _("unexpected token %d %s in resource definition"),
                  token, lex_tok_to_str(token));
               return 0;
            }
            break;
         default:
            scan_err1(lc, _("Unknown parser state %d\n"), state);
            return 0;
         }
      }
      if (state != p_none) {
         scan_err0(lc, _("End of conf file reached with unclosed resource."));
         return 0;
      }
      if (debug_level >= 900 && pass == 2) {
         int i;
         for (i=m_r_first; i<=m_r_last; i++) {
            dump_resource(i, m_res_head[i-m_r_first], prtmsg, NULL);
         }
      }
      lc = lex_close_file(lc);
   }
   Dmsg0(900, "Leave parse_config()\n");
   return 1;
}
Example #7
0
/*
 *
 * Get the next token from the input
 *
 */
int lex_get_token(LEX *lf, int expect)
{
   int ch;
   int token = T_NONE;
   bool esc_next = false;
   /* Unicode files, especially on Win32, may begin with a "Byte Order Mark"
      to indicate which transmission format the file is in. The codepoint for
      this mark is U+FEFF and is represented as the octets EF-BB-BF in UTF-8
      and as FF-FE in UTF-16le(little endian) and  FE-FF in UTF-16(big endian).
      We use a distinct state for UTF-8 and UTF-16le, and use bom_bytes_seen
      to tell which byte we are expecting. */
   int bom_bytes_seen = 0;

   Dmsg0(dbglvl, "enter lex_get_token\n");
   while (token == T_NONE) {
      ch = lex_get_char(lf);
      switch (lf->state) {
      case lex_none:
         Dmsg2(dbglvl, "Lex state lex_none ch=%d,%x\n", ch, ch);
         if (B_ISSPACE(ch))
            break;
         if (B_ISALPHA(ch)) {
            if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
               lf->state = lex_string;
            } else {
               lf->state = lex_identifier;
            }
            begin_str(lf, ch);
            break;
         }
         if (B_ISDIGIT(ch)) {
            if (lf->options & LOPT_STRING) {
               lf->state = lex_string;
            } else {
               lf->state = lex_number;
            }
            begin_str(lf, ch);
            break;
         }
         Dmsg0(dbglvl, "Enter lex_none switch\n");
         switch (ch) {
         case L_EOF:
            token = T_EOF;
            Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
            break;
         case '#':
            lf->state = lex_comment;
            break;
         case '{':
            token = T_BOB;
            begin_str(lf, ch);
            break;
         case '}':
            token = T_EOB;
            begin_str(lf, ch);
            break;
         case '"':
            lf->state = lex_quoted_string;
            begin_str(lf, 0);
            break;
         case '=':
            token = T_EQUALS;
            begin_str(lf, ch);
            break;
         case ',':
            token = T_COMMA;
            begin_str(lf, ch);
            break;
         case ';':
            if (expect != T_SKIP_EOL) {
               token = T_EOL;      /* treat ; like EOL */
            }
            break;
         case L_EOL:
            Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
            if (expect != T_SKIP_EOL) {
               token = T_EOL;
            }
            break;
         case '@':
            /* In NO_EXTERN mode, @ is part of a string */
            if (lf->options & LOPT_NO_EXTERN) {
               lf->state = lex_string;
               begin_str(lf, ch);
            } else {
               lf->state = lex_include;
               begin_str(lf, 0);
            }
            break;
         case 0xEF: /* probably a UTF-8 BOM */
         case 0xFF: /* probably a UTF-16le BOM */
         case 0xFE: /* probably a UTF-16be BOM (error)*/
            if (lf->line_no != 1 || lf->col_no != 1)
            {
               lf->state = lex_string;
               begin_str(lf, ch);
            } else {
               bom_bytes_seen = 1;
               if (ch == 0xEF) {
                  lf->state = lex_utf8_bom;
               } else if (ch == 0xFF) {
                  lf->state = lex_utf16_le_bom;
               } else {
                  scan_err0(lf, _("This config file appears to be in an "
                     "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
                  return T_ERROR;
               }
            }
            break;
         default:
            lf->state = lex_string;
            begin_str(lf, ch);
            break;
         }
         break;
      case lex_comment:
         Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
         if (ch == L_EOL) {
            lf->state = lex_none;
            if (expect != T_SKIP_EOL) {
               token = T_EOL;
            }
         } else if (ch == L_EOF) {
            token = T_ERROR;
         }
         break;
      case lex_number:
         Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
         if (ch == L_EOF) {
            token = T_ERROR;
            break;
         }
         /* Might want to allow trailing specifications here */
         if (B_ISDIGIT(ch)) {
            add_str(lf, ch);
            break;
         }

         /* A valid number can be terminated by the following */
         if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
            token = T_NUMBER;
            lf->state = lex_none;
         } else {
            lf->state = lex_string;
         }
         lex_unget_char(lf);
         break;
      case lex_ip_addr:
         if (ch == L_EOF) {
            token = T_ERROR;
            break;
         }
         Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
         break;
      case lex_string:
         Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
         if (ch == L_EOF) {
            token = T_ERROR;
            break;
         }
         if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
             ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
            lex_unget_char(lf);
            token = T_UNQUOTED_STRING;
            lf->state = lex_none;
            break;
         }
         add_str(lf, ch);
         break;
      case lex_identifier:
         Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
         if (B_ISALPHA(ch)) {
            add_str(lf, ch);
            break;
         } else if (B_ISSPACE(ch)) {
            break;
         } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
                    ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
            lex_unget_char(lf);
            token = T_IDENTIFIER;
            lf->state = lex_none;
            break;
         } else if (ch == L_EOF) {
            token = T_ERROR;
            lf->state = lex_none;
            begin_str(lf, ch);
            break;
         }
         /* Some non-alpha character => string */
         lf->state = lex_string;
         add_str(lf, ch);
         break;
      case lex_quoted_string:
         Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
         if (ch == L_EOF) {
            token = T_ERROR;
            break;
         }
         if (ch == L_EOL) {
            esc_next = false;
            break;
         }
         if (esc_next) {
            add_str(lf, ch);
            esc_next = false;
            break;
         }
         if (ch == '\\') {
            esc_next = true;
            break;
         }
         if (ch == '"') {
            token = T_QUOTED_STRING;
            /*
             * Since we may be scanning a quoted list of names,
             *  we get the next character (a comma indicates another
             *  one), then we put it back for rescanning.
             */
            lex_get_char(lf);
            lex_unget_char(lf);
            lf->state = lex_none;
            break;
         }
         add_str(lf, ch);
         break;
      case lex_include_quoted_string:
         if (ch == L_EOF) {
            token = T_ERROR;
            break;
         }
         if (esc_next) {
            add_str(lf, ch);
            esc_next = false;
            break;
         }
         if (ch == '\\') {
            esc_next = true;
            break;
         }
         if (ch == '"') {
            /* Keep the original LEX so we can print an error if the included file can't be opened. */
            LEX* lfori = lf;
            /* Skip the double quote when restarting parsing */
            lex_get_char(lf);

            lf->state = lex_none;
            lf = lex_open_file(lf, lf->str, lf->scan_error, lf->scan_warning);
            if (lf == NULL) {
               berrno be;
               scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
                  lfori->str, be.bstrerror());
               return T_ERROR;
            }
            break;
         }
         add_str(lf, ch);
         break;
      case lex_include:            /* scanning a filename */
         if (ch == L_EOF) {
            token = T_ERROR;
            break;
         }
         if (ch == '"') {
            lf->state = lex_include_quoted_string;
            break;
         }


         if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
             ch == ';' || ch == ','   || ch == '"' || ch == '#') {
            /* Keep the original LEX so we can print an error if the included file can't be opened. */
            LEX* lfori = lf;

            lf->state = lex_none;
            lf = lex_open_file(lf, lf->str, lf->scan_error, lf->scan_warning);
            if (lf == NULL) {
               berrno be;
               scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
                  lfori->str, be.bstrerror());
               return T_ERROR;
            }
            break;
         }
         add_str(lf, ch);
         break;
      case lex_utf8_bom:
         /* we only end up in this state if we have read an 0xEF
            as the first byte of the file, indicating we are probably
            reading a UTF-8 file */
         if (ch == 0xBB && bom_bytes_seen == 1) {
            bom_bytes_seen++;
         } else if (ch == 0xBF && bom_bytes_seen == 2) {
            token = T_UTF8_BOM;
            lf->state = lex_none;
         } else {
            token = T_ERROR;
         }
         break;
      case lex_utf16_le_bom:
         /* we only end up in this state if we have read an 0xFF
            as the first byte of the file -- indicating that we are
            probably dealing with an Intel based (little endian) UTF-16 file*/
         if (ch == 0xFE) {
            token = T_UTF16_BOM;
            lf->state = lex_none;
         } else {
            token = T_ERROR;
         }
         break;
      }
      Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
        lex_tok_to_str(token), ch);
   }
   Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
   lf->token = token;

   /*
    * Here is where we check to see if the user has set certain
    *  expectations (e.g. 32 bit integer). If so, we do type checking
    *  and possible additional scanning (e.g. for range).
    */
   switch (expect) {
   case T_PINT16:
      lf->u.pint16_val = (scan_pint(lf, lf->str) & 0xffff);
      lf->u2.pint16_val = lf->u.pint16_val;
      token = T_PINT16;
      break;

   case T_PINT32:
      lf->u.pint32_val = scan_pint(lf, lf->str);
      lf->u2.pint32_val = lf->u.pint32_val;
      token = T_PINT32;
      break;

   case T_PINT32_RANGE:
      if (token == T_NUMBER) {
         lf->u.pint32_val = scan_pint(lf, lf->str);
         lf->u2.pint32_val = lf->u.pint32_val;
         token = T_PINT32;
      } else {
         char *p = strchr(lf->str, '-');
         if (!p) {
            scan_err2(lf, _("expected an integer or a range, got %s: %s"),
               lex_tok_to_str(token), lf->str);
            token = T_ERROR;
            break;
         }
         *p++ = 0;                       /* terminate first half of range */
         lf->u.pint32_val  = scan_pint(lf, lf->str);
         lf->u2.pint32_val = scan_pint(lf, p);
         token = T_PINT32_RANGE;
      }
      break;

   case T_INT16:
      if (token != T_NUMBER || !is_a_number(lf->str)) {
         scan_err2(lf, _("expected an integer number, got %s: %s"),
               lex_tok_to_str(token), lf->str);
         token = T_ERROR;
         break;
      }
      errno = 0;
      lf->u.int16_val = (int16_t)str_to_int64(lf->str);
      if (errno != 0) {
         scan_err2(lf, _("expected an integer number, got %s: %s"),
               lex_tok_to_str(token), lf->str);
         token = T_ERROR;
      } else {
         token = T_INT16;
      }
      break;

   case T_INT32:
      if (token != T_NUMBER || !is_a_number(lf->str)) {
         scan_err2(lf, _("expected an integer number, got %s: %s"),
               lex_tok_to_str(token), lf->str);
         token = T_ERROR;
         break;
      }
      errno = 0;
      lf->u.int32_val = (int32_t)str_to_int64(lf->str);
      if (errno != 0) {
         scan_err2(lf, _("expected an integer number, got %s: %s"),
               lex_tok_to_str(token), lf->str);
         token = T_ERROR;
      } else {
         token = T_INT32;
      }
      break;

   case T_INT64:
      Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
      if (token != T_NUMBER || !is_a_number(lf->str)) {
         scan_err2(lf, _("expected an integer number, got %s: %s"),
               lex_tok_to_str(token), lf->str);
         token = T_ERROR;
         break;
      }
      errno = 0;
      lf->u.int64_val = str_to_int64(lf->str);
      if (errno != 0) {
         scan_err2(lf, _("expected an integer number, got %s: %s"),
               lex_tok_to_str(token), lf->str);
         token = T_ERROR;
      } else {
         token = T_INT64;
      }
      break;

   case T_PINT64_RANGE:
      if (token == T_NUMBER) {
         lf->u.pint64_val = scan_pint64(lf, lf->str);
         lf->u2.pint64_val = lf->u.pint64_val;
         token = T_PINT64;
      } else {
         char *p = strchr(lf->str, '-');
         if (!p) {
            scan_err2(lf, _("expected an integer or a range, got %s: %s"),
               lex_tok_to_str(token), lf->str);
            token = T_ERROR;
            break;
         }
         *p++ = 0;                       /* terminate first half of range */
         lf->u.pint64_val  = scan_pint64(lf, lf->str);
         lf->u2.pint64_val = scan_pint64(lf, p);
         token = T_PINT64_RANGE;
      }
      break;

   case T_NAME:
      if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
         scan_err2(lf, _("expected a name, got %s: %s"),
               lex_tok_to_str(token), lf->str);
         token = T_ERROR;
      } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
         scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
            lf->str_len, MAX_RES_NAME_LENGTH);
         token = T_ERROR;
      }
      break;

   case T_STRING:
      if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
         scan_err2(lf, _("expected a string, got %s: %s"),
               lex_tok_to_str(token), lf->str);
         token = T_ERROR;
      } else {
         token = T_STRING;
      }
      break;


   default:
      break;                          /* no expectation given */
   }
   lf->token = token;                 /* set possible new token */
   return token;
}
Example #8
0
/*
 * Store network addresses.
 *
 *   my tests
 *   positiv
 *   = { ip = { addr = 1.2.3.4; port = 1205; } ipv4 = { addr = 1.2.3.4; port = http; } }
 *   = { ip = {
 *         addr = 1.2.3.4; port = 1205; }
 *     ipv4 = {
 *         addr = 1.2.3.4; port = http; }
 *     ipv6 = {
 *       addr = 1.2.3.4;
 *       port = 1205;
 *     }
 *     ip = {
 *       addr = 1.2.3.4
 *       port = 1205
 *     }
 *     ip = {
 *       addr = 1.2.3.4
 *     }
 *     ip = {
 *       addr = 2001:220:222::2
 *     }
 *     ip = {
 *       addr = bluedot.thun.net
 (     }
 *   }
 *   negativ
 *   = { ip = { } }
 *   = { ipv4 { addr = doof.nowaytoheavenxyz.uhu; } }
 *   = { ipv4 { port = 4711 } }
 */
void store_addresses(LEX * lc, RES_ITEM * item, int index, int pass)
{
   int token;
   int exist;
   int family = 0;
   char errmsg[1024];
   char port_str[128];
   char hostname_str[1024];
   enum {
      EMPTYLINE = 0x0,
      PORTLINE = 0x1,
      ADDRLINE = 0x2
   } next_line = EMPTYLINE;
   int port = str_to_int32(item->default_value);

   token = lex_get_token(lc, T_SKIP_EOL);
   if (token != T_BOB) {
      scan_err1(lc, _("Expected a block begin { , got: %s"), lc->str);
   }
   token = lex_get_token(lc, T_SKIP_EOL);
   if (token == T_EOB) {
      scan_err0(lc, _("Empty addr block is not allowed"));
   }
   do {
      if (!(token == T_UNQUOTED_STRING || token == T_IDENTIFIER)) {
         scan_err1(lc, _("Expected a string, got: %s"), lc->str);
      }
      if (bstrcasecmp("ip", lc->str) || bstrcasecmp("ipv4", lc->str)) {
         family = AF_INET;
#ifdef HAVE_IPV6
      } else if (bstrcasecmp("ipv6", lc->str)) {
         family = AF_INET6;
      } else {
         scan_err1(lc, _("Expected a string [ip|ipv4|ipv6], got: %s"), lc->str);
      }
#else
      } else {
         scan_err1(lc, _("Expected a string [ip|ipv4], got: %s"), lc->str);
      }
#endif
      token = lex_get_token(lc, T_SKIP_EOL);
      if (token != T_EQUALS) {
         scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
      }
      token = lex_get_token(lc, T_SKIP_EOL);
      if (token != T_BOB) {
         scan_err1(lc, _("Expected a block begin { , got: %s"), lc->str);
      }
      token = lex_get_token(lc, T_SKIP_EOL);
      exist = EMPTYLINE;
      port_str[0] = hostname_str[0] = '\0';
      do {
         if (token != T_IDENTIFIER) {
            scan_err1(lc, _("Expected a identifier [addr|port], got: %s"), lc->str);
         }
         if (bstrcasecmp("port", lc->str)) {
            next_line = PORTLINE;
            if (exist & PORTLINE) {
               scan_err0(lc, _("Only one port per address block"));
            }
            exist |= PORTLINE;
         } else if (bstrcasecmp("addr", lc->str)) {
            next_line = ADDRLINE;
            if (exist & ADDRLINE) {
               scan_err0(lc, _("Only one addr per address block"));
            }
            exist |= ADDRLINE;
         } else {
            scan_err1(lc, _("Expected a identifier [addr|port], got: %s"), lc->str);
         }
         token = lex_get_token(lc, T_SKIP_EOL);
         if (token != T_EQUALS) {
            scan_err1(lc, _("Expected a equal =, got: %s"), lc->str);
         }
         token = lex_get_token(lc, T_SKIP_EOL);
         switch (next_line) {
         case PORTLINE:
            if (!(token == T_UNQUOTED_STRING || token == T_NUMBER || token == T_IDENTIFIER)) {
               scan_err1(lc, _("Expected a number or a string, got: %s"), lc->str);
            }
            bstrncpy(port_str, lc->str, sizeof(port_str));
            break;
         case ADDRLINE:
            if (!(token == T_UNQUOTED_STRING || token == T_IDENTIFIER)) {
               scan_err1(lc, _("Expected an IP number or a hostname, got: %s"),
                         lc->str);
            }
            bstrncpy(hostname_str, lc->str, sizeof(hostname_str));
            break;
         case EMPTYLINE:
            scan_err0(lc, _("State machine missmatch"));
            break;
         }
         token = lex_get_token(lc, T_SKIP_EOL);
      } while (token == T_IDENTIFIER);
      if (token != T_EOB) {
         scan_err1(lc, _("Expected a end of block }, got: %s"), lc->str);
      }
      if (pass == 1 && !add_address((dlist **)(item->value), IPADDR::R_MULTIPLE,
          htons(port), family, hostname_str, port_str, errmsg, sizeof(errmsg))) {
           scan_err3(lc, _("Can't add hostname(%s) and port(%s) to addrlist (%s)"),
                   hostname_str, port_str, errmsg);
      }
      token = scan_to_next_not_eol(lc);
   } while ((token == T_IDENTIFIER || token == T_UNQUOTED_STRING));
Example #9
0
/*
 * Store a size in bytes
 */
static void store_int_unit(LEX *lc, RES_ITEM *item, int index, int pass,
                           bool size32, enum store_unit_type type)
{
   int token;
   uint64_t uvalue;
   char bsize[500];

   Dmsg0(900, "Enter store_unit\n");
   token = lex_get_token(lc, T_SKIP_EOL);
   errno = 0;
   switch (token) {
   case T_NUMBER:
   case T_IDENTIFIER:
   case T_UNQUOTED_STRING:
      bstrncpy(bsize, lc->str, sizeof(bsize));  /* save first part */
      /*
       * If terminated by space, scan and get modifier
       */
      while (lc->ch == ' ') {
         token = lex_get_token(lc, T_ALL);
         switch (token) {
         case T_NUMBER:
         case T_IDENTIFIER:
         case T_UNQUOTED_STRING:
            bstrncat(bsize, lc->str, sizeof(bsize));
            break;
         }
      }

      switch (type) {
      case STORE_SIZE:
         if (!size_to_uint64(bsize, &uvalue)) {
            scan_err1(lc, _("expected a size number, got: %s"), lc->str);
            return;
         }
         break;
      case STORE_SPEED:
         if (!speed_to_uint64(bsize, &uvalue)) {
            scan_err1(lc, _("expected a speed number, got: %s"), lc->str);
            return;
         }
         break;
      default:
         scan_err0(lc, _("unknown unit type encountered"));
         return;
      }

      if (size32) {
         *(uint32_t *)(item->value) = (uint32_t)uvalue;
      } else {
         *(uint64_t *)(item->value) = uvalue;
      }
      break;
   default:
      scan_err2(lc, _("expected a %s, got: %s"),
                (type == STORE_SIZE)?_("size"):_("speed"), lc->str);
      return;
   }
   if (token != T_EOL) {
      scan_to_eol(lc);
   }
   set_bit(index, res_all.hdr.item_present);
   Dmsg0(900, "Leave store_unit\n");
}
Example #10
0
bool CONFIG::parse_config_file(const char *cf, void *caller_ctx, LEX_ERROR_HANDLER *scan_error,
                               LEX_WARNING_HANDLER *scan_warning, int32_t err_type)
{
   bool result = true;
   LEX *lc = NULL;
   int token, i, pass;
   int res_type = 0;
   enum parse_state state = p_none;
   RES_TABLE *res_table = NULL;
   RES_ITEM *items = NULL;
   RES_ITEM *item = NULL;
   int level = 0;

   /*
    * Make two passes. The first builds the name symbol table,
    * and the second picks up the items.
    */
   Dmsg0(900, "Enter parse_config()\n");
   for (pass = 1; pass <= 2; pass++) {
      Dmsg1(900, "parse_config pass %d\n", pass);
      if ((lc = lex_open_file(lc, cf, scan_error, scan_warning)) == NULL) {
         berrno be;

         /*
          * We must create a lex packet to print the error
          */
         lc = (LEX *)malloc(sizeof(LEX));
         memset(lc, 0, sizeof(LEX));

         if (scan_error) {
            lc->scan_error = scan_error;
         } else {
            lex_set_default_error_handler(lc);
         }

         if (scan_warning) {
            lc->scan_warning = scan_warning;
         } else {
            lex_set_default_warning_handler(lc);
         }

         lex_set_error_handler_error_type(lc, err_type) ;
         scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
            cf, be.bstrerror());
         free(lc);

         return 0;
      }
      lex_set_error_handler_error_type(lc, err_type);
      lc->error_counter = 0;
      lc->caller_ctx = caller_ctx;

      while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
         Dmsg3(900, "parse state=%d pass=%d got token=%s\n", state, pass,
               lex_tok_to_str(token));
         switch (state) {
         case p_none:
            if (token == T_EOL) {
               break;
            } else if (token == T_UTF8_BOM) {
               /*
                * We can assume the file is UTF-8 as we have seen a UTF-8 BOM
                */
               break;
            } else if (token == T_UTF16_BOM) {
               scan_err0(lc, _("Currently we cannot handle UTF-16 source files. "
                               "Please convert the conf file to UTF-8\n"));
               goto bail_out;
            } else if (token != T_IDENTIFIER) {
               scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
               goto bail_out;
            }
            res_table = get_resource_table(lc->str);
            if(res_table && res_table->items) {
               items = res_table->items;
               state = p_resource;
               res_type = res_table->rcode;
               init_resource(res_type, items, pass);
            }
            if (state == p_none) {
               scan_err1(lc, _("expected resource name, got: %s"), lc->str);
               goto bail_out;
            }
            break;
         case p_resource:
            switch (token) {
            case T_BOB:
               level++;
               break;
            case T_IDENTIFIER:
               if (level != 1) {
                  scan_err1(lc, _("not in resource definition: %s"), lc->str);
                  goto bail_out;
               }
               i = get_resource_item_index(items, lc->str);
               if (i>=0) {
                  item = &items[i];
                  /*
                   * If the CFG_ITEM_NO_EQUALS flag is set we do NOT
                   *   scan for = after the keyword
                   */
                  if (!(item->flags & CFG_ITEM_NO_EQUALS)) {
                     token = lex_get_token(lc, T_SKIP_EOL);
                     Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
                     if (token != T_EQUALS) {
                        scan_err1(lc, _("expected an equals, got: %s"), lc->str);
                        goto bail_out;
                     }
                  }

                  /*
                   * See if we are processing a deprecated keyword if so warn the user about it.
                   */
                  if (item->flags & CFG_ITEM_DEPRECATED) {
                     scan_warn2(lc, _("using deprecated keyword %s on line %d"), item->name, lc->line_no);
                     /*
                      * As we only want to warn we continue parsing the config. So no goto bail_out here.
                      */
                  }

                  Dmsg1(800, "calling handler for %s\n", item->name);

                  /*
                   * Call item handler
                   */
                  if (!store_resource(item->type, lc, item, i, pass)) {
                     /*
                      * None of the generic types fired if there is a registered callback call that now.
                      */
                     if (m_store_res) {
                        m_store_res(lc, item, i, pass);
                     }
                  }
               } else {
                  Dmsg2(900, "level=%d id=%s\n", level, lc->str);
                  Dmsg1(900, "Keyword = %s\n", lc->str);
                  scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
                                  "Perhaps you left the trailing brace off of the previous resource."), lc->str);
                  goto bail_out;
               }
               break;

            case T_EOB:
               level--;
               state = p_none;
               Dmsg0(900, "T_EOB => define new resource\n");
               if (((URES *)m_res_all)->hdr.name == NULL) {
                  scan_err0(lc, _("Name not specified for resource"));
                  goto bail_out;
               }
               /* save resource */
               if (!save_resource(res_type, items, pass)) {
                  scan_err0(lc, _("save_resource failed"));
                  goto bail_out;
               };
               break;

            case T_EOL:
               break;

            default:
               scan_err2(lc, _("unexpected token %d %s in resource definition"),
                  token, lex_tok_to_str(token));
               goto bail_out;
            }
            break;
         default:
            scan_err1(lc, _("Unknown parser state %d\n"), state);
            goto bail_out;
         }
      }
      if (state != p_none) {
         scan_err0(lc, _("End of conf file reached with unclosed resource."));
         goto bail_out;
      }
      if (debug_level >= 900 && pass == 2) {
         int i;
         for (i = m_r_first; i <= m_r_last; i++) {
            dump_resource(i, m_res_head[i-m_r_first], prtmsg, NULL, false);
         }
      }

      if (lc->error_counter > 0) {
         result = false;
      }

      lc = lex_close_file(lc);
   }
   Dmsg0(900, "Leave parse_config_file()\n");

   return result;

bail_out:
   if (lc) {
      lc = lex_close_file(lc);
   }

   return false;
}