YAML config file? Pain? Try Lua

Several articles about using YAML (YAML Ain't Markup Language) for configuration have been making the rounds, yet rarely do I see Lua [1] being mentioned as an alternative for configuration files.

Yes, it's a language, but it started out life as a configuration format. It's also small for a language, easy to embed, and easy to sandbox for the paranoid. Here's an example:

lua_State *gL;

bool config_read(char const *conf)
{
  int rc;
  
  assert(conf != NULL);
  
  /*---------------------------------------------------
  ; Create the Lua state, which includes NO predefined
  ; functions or values.  This is literally an empty
  ; slate.  
  ;----------------------------------------------------*/
  
  gL = luaL_newstate();
  if (gL == NULL)
  {
    fprintf(stderr,"cannot create Lua state");
    return false;
  }
  
  /*-----------------------------------------------------
  ; For the truly paranoid about sandboxing, enable the
  ; following code, which removes the string library,
  ; which some people find problematic to leave un-sand-
  ; boxed. But in my opinion, if you are worried about
  ; such attacks in a configuration file, you have bigger
  ; security issues to worry about than this.
  ;------------------------------------------------------*/
  
#ifdef PARANOID
  lua_pushliteral(gL,"x");
  lua_pushnil(gL);
  lua_setmetatable(gL,-2);
  lua_pop(gL,1);
#endif
  
  /*-----------------------------------------------------
  ; Lua 5.2+ can restrict scripts to being text only,
  ; to avoid a potential problem with loading pre-compiled
  ; Lua scripts that may have malformed Lua VM code that
  ; could possibly lead to an exploit, but again, if you
  ; have to worry about that, you have bigger security
  ; issues to worry about.  But in any case, here I'm
  ; restricting the file to "text" only.
  ;------------------------------------------------------*/
  
  rc = luaL_loadfilex(gL,conf,"t");
  if (rc != LUA_OK)
  {
    fprintf(stderr,"Lua error: (%d) %s",rc,lua_tostring(gL,-1));
    return false;
  }
  
  rc = lua_pcall(gL,0,0,0);
  if (rc != LUA_OK)
  {
    fprintf(stderr,"Lua error: (%d) %s",rc,lua_tostring(gL,-1));
    return false;
  }
  
  /*--------------------------------------------
  ; the Lua state gL contains our configuration,
  ; we can now query it for values
  ;---------------------------------------------*/
  
  /* ... */
  return true;
}

Yes, it's all too possible for someone to write:

(function() while true do end end)()

in the configuration and block the process with 100% CPU (Central Processing Unit) utilization, but as I stated in the code example, if that's a worry, you have bigger security issues to worry about [2].

Another nice benefit of using Lua is string management. If you are only using Lua for the configuration file, and once read, don't execute any more Lua code, then there's no need to duplicate the strings for your codebase—just keep using the strings directly from Lua. As long as you close the Lua state at the end of the program, they'll be cleaned up for you. And speaking of strings, you'll also have Lua's “long strings:”

long_string = [[
This is a long Lua string that can
span several lines.  Escapes like '\n' don't work in this,
but then again,
you don't really need the '\n' here because they're part of the 
string.
]]

long_string_2 = [=[
And if you want to embed a literal ']]' in a long string,
you can, no problems here.
]=]

I use Lua for the configuration file for my blogging engine [3] (to see how I pull the configuration from Lua [4]) which looks like:

name        = "A Blog Grows in Cyberspace"
description = "A place where I talk about stuff in cyperspace."
class       = "blog, rants, random stuff, programming"
basedir     = "."
webdir      = "htdocs"
lockfile    = ".modblog.lock"
url         = "http://www.example.com/blog/"
adtag       = "programming"
conversion  = "html"
prehook     = "./prehook_script"
posthook    = "./posthook_script"

author =
{
  name   = "Joe Blog" ,
  email  = "joe@example.com",
}

templates =
{
  {
    template = "html",
    output   = webdir .. "/index.html",
    items    = "7d",
    reverse  = true,
    posthook = "posthook_template_script"
  },
  {
    template = "atom",
    output   = webdir .. "/index.atom",
    items    = 15,
    reverse  = true,
  },
}

But if you think it'll be too complicated to instruct devops as to when to use a comma and not, you can always include semicolons at the end of each line:

name        = "A Blog Grows in Cyberspace";
description = "A place where I talk about stuff in cyperspace.";
class       = "blog, rants, random stuff, programming";
basedir     = ".";
webdir      = "htdocs";
lockfile    = ".modblog.lock";
url         = "http://www.example.com/blog/";
adtag       = "programming";
conversion  = "html";
prehook     = "./prehook_script";
posthook    = "./posthook_script";

author =
{
  name   = "Joe Blog";
  email  = "joe@example.com";
};

templates =
{
  {
    template = "html";
    output   = webdir .. "/index.html";
    items    = "7d";
    reverse  = true;
    posthook = "posthook_template_script";
  };
  {
    template = "atom";
    output   = webdir .. "/index.atom";
    items    = 15;
    reverse  = true;
  };
};

to simplify the configuration instructions (“just add a semicolon to the end of each line … ”). One other benefit—comments. That's one of the biggest complaints about using JSON (JavaScript Object Notation) as a configuration file format—a lack of comments.

Also, you don't even have to mention you are using Lua as a configuration file—most likely, no one will really notice anyway. I used Lua to configure “Project: Sippy-Cup [5]” and “Project: Cleese [6]” at The Enterprise and no one said anything about the format. It was also used for “Project: Bradenburg [7]” (written by another team member) and there were no issues with that either.

[1] https://www.lua.org/

[2] /boston/2004/09/19.1

[3] https://github.com/spc476/mod_blog

[4] https://github.com/spc476/mod_blog/blob/20ec614b33a1e3d26893c2d3a70ff1bad4aa5c2d/src/blog.c#L695C8-L695C8

[5] /boston/2014/03/05.1

[6] /boston/2018/09/11.2

[7] /boston/2021/12/10.1

Discussions about this entry

YAML config file? Pain? Try Lua | Lobsters

YAML config file? Pain? Try Lua | Hacker News

Gemini Mention this post

Contact the author