rpm-lua(7) — Linux manual page

NAME | SYNOPSIS | DESCRIPTION | MACROS | SCRIPTLETS | SPEC FILES | EXTENSIONS | EXTENDING AND CUSTOMIZING | SEE ALSO | COLOPHON

RPM-LUA(7)           Miscellaneous Information Manual          RPM-LUA(7)

NAME         top

       rpm-lua - RPM embedded Lua interpreter

SYNOPSIS         top

       %scriptlet -p <lua>

       %{lua:...}

DESCRIPTION         top

       Lua is a general purpose programming language specifically
       designed for embedding in other programs, and RPM includes an
       embedded Lua interpreter for use in advanced rpm-macros(7) and
       transaction scriptlets.

       The embedded Lua interpreter makes possible various things that
       are hard or impossible with plain macros or external shell
       scripts, such as help eliminate dependency loops from package
       scriptlets.

MACROS         top

   Accessing macros
       The rpm extension has various functions for dealing with macros,
       but the most convenient way to access rpm-macroproc(7) from the
       RPM Lua environment is via the global macros table.

       Lua makes no difference between table index and field name
       syntaxes so macros.foo and macros['foo'] are equivalent, use what
       better suits the purpose.

       Like any real Lua table, non-existent items are returned as nil,
       and assignment can be used to define or undefine macros.

       Example:
           if not macros.yours then
               macros.my = 'my macro'
           end

           local v = { '_libdir', '_bindir', '_xbindir' }
           for _, v in ipairs(v) do
               if not macros[v] then
                   macros[v] = 'default'
               end
           end

       All macros share the same global Lua execution environment.

   Calling parametric macros
       Parametric macros (including all built-in macros) can be called in
       a Lua native manner via the macros table, with either
       macros.name() or macros[name]() syntax.

       Arguments are passed through a single argument, which is either
       •   a single string, in which case it's expanded and split with
           the macro-native rules
       •   a table, in which case the table contents are used as literal
           arguments that are not expanded in any way

       Example 1:
           macros.with('foo')

       Example 2:
           macros.dostuff({'one', 'two', 'three'})

   Returning data
       By definition, anything print()'ed in Lua will end up in the macro
       expansion. Lua macros can also return their output, which makes
       programming helper macros look more natural.

       Example:
           %sum() %{lua:
              local v = 0
              for _, a in ipairs(arg) do
                  v = v + tonumber(a)
              end
              return v
           }

   Options and arguments
       Parametric Lua macros receive their options and arguments as two
       local tables opt and arg, where opt holds processed option values
       keyed by the option character, and arg contains arguments
       numerically indexed.

       These tables are always present regardless of whether options or
       arguments were actually passed to simplify use.

       Example:
           %foo(a:b) %{lua:
           if opt.b then
              print('do b')
           else
              print('or not')
           end
           if opt.a == 's' then
              print('do s')
           end
           if #arg == 0 then
              print('no arguments :(')
           else
              for i = 1, #arg do
                 print(arg[i])
              end
           end
           }

SCRIPTLETS         top

       The internal Lua can be used as the interpreter of RPM any
       transaction scriptlets, including triggers and file triggers:

       Example:
           %pre -p <lua>
           print('Hello from Lua')

       While the venerable /bin/sh is usually more convenient for
       packaging related scripting activities, the embedded Lua
       interpreter has some unique advantages for transaction scriptlets:
       they add no extra dependencies to the packages and so can help
       eliminate dependency loops. This can be a crucial difference in
       the early "bootstrap" package set in an initial install.

       In particular, an embedded Lua script is the only generally usable
       option in %pretrans scriplets during the initial installation of a
       system.

       Embedded Lua is also much faster than executing a potentially
       heavyweight interpreter just to run a couple of lines of shell
       script.

       Note: scriptlets using the internal Lua should not make
       assumptions about sharing the execution environment with other
       scriptlets.

   Arguments
       Scriptlet arguments are accessible from a global arg table.

       Note: in Lua, indexes customarily start at 1 (one) instead of 0
       (zero), and for the better or worse, the RPM implementation
       follows this practise. Thus the scriptlet arg indexes are off by
       one from general expectation based on traditional scriptlet
       arguments. The argument containing number of installed package
       instances is arg[2] and the similar argument for trigger targets
       is arg[3], vs the traditional $1 and $2 in shell scripts.

       Example:
           %postun -p <lua>
           if arg[2] == 0  then
               print("erasing")
           end

   Relocatable packages
       Scriptlets of relocatable packages additionally carry a global
       RPM_INSTALL_PREFIX table containing all the possible prefixes of
       the package.

       Added: 4.18.0

   Exit status
       While scriptlets shouldn't be allowed to fail normally, you can
       signal scriptlet failure status by using Lua's error(msg, [level])
       function if you need to.

   File triggers
       Other file triggers receive the triggering paths via standard
       input, but Lua scriplets need to call the rpm.next_line() function
       in a loop. This function only exists inside the file trigger
       running environment.

SPEC FILES         top

       In the context of a rpm-spec(5) file parse with rpmbuild(1) or
       rpmspec(1), the RPM Lua environment contains the following spec
       specific global tables:

       patches
           The filenames of the patches in the spec, in the order they
           appeared in the spec.

       patch_nums
           The numbers of the patches in the spec, in the order they
           appeared in the spec.

       sources
           The filenames of the sources in the spec, in the order they
           appeared in the spec.

       source_nums
           The numbers of the sources in the spec, in the order they
           appeared in the spec.

       Example:
           for i, p in ipairs(patches) do
               print(string.format("echo %d: %sn", patch_nums[i], patches[i]))
           end

EXTENSIONS         top

       In addition to Lua standard libraries (subject to the Lua version
       RPM is linked to), the following extensions are available in the
       RPM internal Lua interpreter. These can be used in all contexts
       where the internal Lua can be used.

   rpm extension
       The following RPM specific functions are available:

       b64decode(arg)
           Perform base64 decoding on argument. See also b64encode().

           Example:
               blob = 'binary data'
               print(blob)
               e = rpm.b64encode(blob)
               print(e)
               d = rpm.b64decode(e)
               print(d)

       b64encode(arg [, linelen])
           Perform base64 encoding on argument. Line length may be
           optionally specified via second argument. See also
           b64decode().

       define("name body")
           Define a global macro name with body.  See also MACROS.

           Example:
               rpm.define('foo 1')

       execute(path [, arg1 [,...])
           Execute an external command. This is handy for executing
           external helper commands without depending on the shell. path
           is the command to execute, followed by optional number of
           arguments to pass to the command.

           For a better control over the process execution and output,
           see rpm.spawn().

           Added: 4.15.0

           Example:
               rpm.execute('ls', '-l', '/')
       expand(arg)
           Perform RPM macro expansion on arg string. See also MACROS.

           Example:
               rpm.expand('%{_libdir}/mydir')

       glob(pattern, [flags])
           Return a table of pathnames matching pattern. If flags
           contains c, return pattern in case of no matches.

           Example:
               for i, p in ipairs(rpm.glob('*')) do
                   print(p)
               end

       interactive()
           Launch interactive session for testing and debugging. Use
           rpmlua(1) instead.

           Example:
               rpm --eval "%{lua: rpm.interactive()}"

       isdefined(name)
           Test whether a macro name is defined and whether it's
           parametric, returned in two booleans. See also MACROS. (Added:
           4.17.0)

           Example:
               if rpm.isdefined('_libdir') then
                   ...
               end

       load(path)
           Load a macro file from given path. Same as the built-in
           %{load:...} macro.

           Example:
               rpm.load('my.macros')

       open(path, [mode[.flags]])
           Open a file stream using RPM IO facilities, with support for
           transparent compression and decompression.

           path is filename string, optionally followed with mode string
           to specify open behavior:
           •   a: open for append
           •   w: open for writing, truncate
           •   r: open for reading (default)
           •   +: open for reading and writing
           •   x: fail if file exists

           and optionally followed by rpm-payloadflags(7) for compression
           and decompression.

           Added: 4.17.0

           Example:
               f = rpm.open('some.txt.gz', 'r.gzdio')
               print(f:read())

           The returned rpm.fd object has the following methods:

           fd:close()

           Close the file stream.

           Example:
               f = rpm.open('file')
               f:close()

           fd:flush()

           Flush the file stream.

           Example:
               f = rpm.open('file', 'w')
               f:write('foo')
               f:flush()
               f:close()

           fd:read([len])

           Read data from the file stream up to len bytes or if not
           specified, the entire file.

           Example:
               f = rpm.open('/some/file')
               print(f:read())

           fd:seek(mode, offset)

           Reposition the file offset of the stream. mode is one of set,
           cur and end, and offset is relative to the mode: absolute,
           relative to current or relative to end. Not all streams
           support seeking.

           Returns file offset after the operation.

           See also lseek(3).

           Example:
               f = rpm.open('newfile', 'w')
               f:seek('set', 555)
               f:close()

           fd:write(buf [, len])

           Write data in buf to the file stream, either in its entirety
           or up to len bytes if specified.

           Example:
               f = rpm.open('newfile', 'w')
               f:write('data data')
               f:close()

           fd:reopen(mode)

           Reopen a stream with a new mode (see rpm.open()).

           Example:
               rpm.open('some.txt.gz')
               f = f:reopen('r.gzdio')
               print(f:read())}

       redirect2null(fdno) (OBSOLETE)
           Redirect file descriptor fdno to /dev/null (prior to 4.16 this
           was known as posix.redirect2null())

           This function is obsolete and only available for RPM v4
           packages for backwards compatibility. Use `rpm.spawn()` or
           `rpm.execute()` instead.

               pid = posix.fork()
               if pid == 0 then
                   posix.redirect2null(2)
                   assert(posix.exec('/bin/awk'))
               elseif pid > 0 then
                   posix.wait(pid)
               end

       spawn({command} [, {actions}])
           Spawn, aka execute, an external program.

           {command} is a table consisting of the command and its
           arguments. An optional second table can be used to pass
           various actions related to the command execution, currently
           supported are:

               | Action  | Argument(s) | Description
               |---------|----------------------
               | *stdin* | path        | Redirect standard input to path
               | *stdout*| path        | Redirect standard output to path
               | *stderr*| path        | Redirect standard error to path

           Returns the command exit status: zero on success, or a tuplet
           of (nil, message, code) on failure.

           Added: 4.20

           Example:
               rpm.spawn({'systemctl', 'restart', 'httpd'}, {stderr='/dev/null'})

       undefine(name)
           Undefine a macro. See also MACROS.

           Note that this is only pops the most recent macro definition
           by the given name from stack, ie there may be still macro
           definitions by the same name after an undefine operation.

           Example:
               rpm.undefine('zzz')

       vercmp(v1, v2)
           Perform RPM version comparison on argument strings. Returns
           -1, 0 or 1 if v1 is smaller, equal or larger than v2. See
           rpm-version(7).

           Note: in RPM < 4.16 this operated on version segments only,
           which does not produce correct results on full EVR strings.

           Example:
               rpm.vercmp('1.2-1', '2.0-1')

       ver(evr), ver(e, v, r)
           Create RPM version object. This takes either an evr string
           which is parsed to it's components, or epoch, version and
           release in separate arguments (which can be either strings or
           numbers). The object has three attributes: e for epoch, v for
           version and r for release, can be printed in it's EVR form and
           supports native comparison in Lua.

           Added: 4.17.0

           Example:
               v1 = rpm.ver('5:1.0-2)
               v2 = rpm.ver(3, '5a', 1)
               if v1 < v2 then
                  ...
               end

               if v1.e then
                  ...
               end

   posix extension
       Lua standard library offers fairly limited set of io operations.
       The posix extension greatly enhances what can be done from Lua.

       The following functions are available in the posix namespace, ie
       to call them use posix.function(). This documentation concentrates
       on the Lua API conventions, for further information on the
       corresponding system calls refer to the system manual, eg
       access(3) for posix.access().

       access(path [, mode])
           Test accessibility of file/directory path. See access(3). If
           mode is omitted then existence is tested, otherwise it is a
           combination of the following tests:
           •   r: readable
           •   w: writable
           •   x: executable
           •   f: exists

           Example:
               if posix.access('/bin/rpm', 'x') then
                   ...
               end

       chdir(path)
           Change current working directory to path. See chdir(1).

           Example:
               posix.chdir('/tmp')

       chmod(path, mode)
           Change file/directory mode. Mode can be either an octal number
           as for chmod(2) system call, or a string presentation similar
           to chmod(1).

           Example:
               posix.chmod('aa', 600)
               posix.chmod('bb', 'rw-')
               posix.chmod('cc', 'u+x')

       chown(path, user, group)
           Change file/directory owner/group of path. The user and group
           arguments may be either numeric id values or user/groupnames.
           See chown(2) and chown(1).

           Note: This is a privileged operation.

           Example:
               posix.chown('aa', 0, 0)
               posix.chown('bb', 'nobody', 'nobody')

       ctermid()
           Get controlling terminal name. See ctermid(3).

           Example:
               print(posix.ctermid())

       dir([path])
           Get directory contents - like readdir(3). If path is omitted,
           current directory is used.

           Example:
               for i,p in pairs(posix.dir('/')) do
                   print(p..'n')
               end

       errno()
           Get strerror(3) message and the corresponding number for
           current errno(3).

           Example:
               f = '/zzz'
               if not posix.chmod(f, 100) then
                   s, n = posix.errno()
                   print(f, s)
               end

       exec(path [, args...]) (OBSOLETE)
           Execute a program. This may only be performed after
           posix.fork().

           This function is obsolete and only available for RPM v4
           packages for backwards compatibility. Use rpm.spawn() or
           rpm.execute() instead.

       files([path])
           Iterate over directory contents. If path is omitted, current
           directory is used.

           Example:
               for f in posix.files('/') do
                   print(f..'n')
               end

       fork() (OBSOLETE)
           Fork a new process. See fork(2).

           This function is obsolete and only available for RPM v4
           packages for backwards compatibility. Use rpm.spawn() or
           rpm.execute() instead.

           Example:
               pid = posix.fork()
               if pid == 0 then
                   posix.exec('/foo/bar')
               elseif pid > 0 then
                   posix.wait(pid)
               end

       getcwd()
           Get current directory. See getcwd(3).

           Example:
               if posix.getcwd() ~= '/' then
                   ...
               endif

       getenv(name)
           Get an environment variable. See getenv(3).

           Example:
               if posix.getenv('HOME') ~= posix.getcwd() then
                   print('not at home')
               end

       getgroup(group)
           Get group(5) information for a group. group may be either a
           numeric id or group name. If omitted, current group is used.
           Returns a table with fields name and gid set to group name and
           id respectively, and indexes from 1 onwards specifying group
           members.

           Example:
               print(posix.getgroup('wheel').gid)

       getlogin()
           Get login name. See getlogin(3).

           Example:
               n = posix.getlogin()

       getpasswd([user [, selector]])
           Get passwd(5) information for a user account. user may be
           either a numeric id or username. If omitted, current user is
           used. The optional selector argument may be one of:
           •   nameuidgiddirshellgecospasswd

           If omitted, a table with all these fields is returned.

           Example:
               pw = posix.getpasswd(posix.getlogin(), 'shell')|

       getprocessid([selector])
           Get information about current process. The optional selector
           argument may be one of
           •   egid: effective group id
           •   euid: effective user id
           •   gid: group id
           •   uid: user id
           •   pgrp: parent group id
           •   pid: process id
           •   ppid: parent pid

           If omitted, a table with all these fields is returned.

           Example:
               if posix.getprocessid('pid') == 1 then
                   ...
               end

       kill(pid [, signal])
           Send a signal(7) to a process. signal must be a numeric value,
           eg. 9 for SIGKILL.  If omitted, SIGTERM is used. See also
           kill(2).

           Example:
               posix.kill(posix.getprocessid('pid'))

       link(oldpath, newpath)
           Create a new name at newpath for a file at oldpath, aka hard
           link. See also link(2).

           Example:
               f = rpm.open('aaa', 'w')
               posix.link('aaa', 'bbb')

       mkdir(path)
           Create a new directory at path. See also mkdir(2).

           Example:
               posix.mkdir('/tmp')

       mkfifo(path)
           Create a FIFO aka named pipe at path. See also mkfifo(2).

           Example:
               posix.mkfifo('/tmp/badplace')

       pathconf(path [, selector])
           Get pathconf(3) information for path. The optional selector
           may be one of
           •   link_maxmax_canonmax_inputname_maxpath_maxpipe_bufchown_restrictedno_truncvdisable.

           If omitted, a table with all these fields is returned.

           Example:
               posix.pathconf('/', 'path_max')

       putenv(string)
           Change or add an environment variable. See also putenv(3).

           Example:
               posix.putenv('HOME=/me')

       readlink(path)
           Read value of the symbolic link at path. See also readlink(2).

           Example:
               posix.mkdir('aaa')
               posix.symlink('aaa', 'bbb')
               print(posix.readlink('bbb'))

       rmdir(path)
           Remove a directory path. See also rmdir(2).

           Example:
               posix.rmdir('/tmp')

       setgid(group)
           Set group identity. group may be specified either as a numeric
           id or group name. See also setgid(2).

           Note: This is a privileged operation.

       setuid(user)
           Set user identity. user may be specified either as a numeric
           id or username. See also setuid(2).

           Note: This is a privileged operation.

           Example:
               posix.setuid('nobody')

       sleep(seconds)
           Sleep for the duration of seconds. See also sleep(3).

           Example:
               posix.sleep(5)

       stat(path [, selector])
           Get file stat(3) information about a file at path. The
           optional selector may be one of
           •   modeinodevnlinkuidgidsizeatimemtimectimetype.

           If omitted, a table with all these fields is returned.

           Example:
               print(posix.stat('/tmp', 'mode'))|

               s1 = posix.stat('f1')
               s2 = posix.stat('f2')
               if s1.ino == s2.ino and s1.dev == s2.dev then
                   ...
               end

       symlink(oldpath, newpath)
           Create a symbolic link at newpath to oldpath. See also
           symlink(2).

           Example:
               posix.mkdir('aaa')
               posix.symlink('aaa', 'bbb')

       sysconf([selector])
           Get sysconf(3) information. The optional selector argument may
           be one of:
           •   arg_maxchild_maxclk_tckngroups_maxstream_maxtzname_maxopen_maxjob_controlsaved_idsversion.

           If omitted, a table with all these fields is returned.

           Example:
               posix.sysconf('open_max')|

       times([selector])
           Get process and waited-for child process times(2). The
           optional selector argument may be one of
           •   utimestimecutimecstimeelapsed

           If omitted, a table with all these fields is returned.

           Example:
               t = posix.times()
               print(t.utime, t.stime)

       ttyname([fd])
           Get name of a terminal associated with file descriptor fd. If
           fd is omitted, 0 (aka standard input) is used. See ttyname(3).

           Example:
               if not posix.ttyname() then
                   ...
               endif

       umask([mode])
           Get or set process umask(2). mode may be specified as an octal
           number or mode string similarly to posix.chmod().

           Example:
               print(posix.umask())
               posix.umask(222)
               posix.umask('ug-w')
               posix.umask('rw-rw-r--')

       uname(format)
           Get uname(2) information about the current system. The
           following format directives are supported:

           •   %m:  Name of the hardware type
           •   %n:  Name of this node
           •   %r:  Current release level of this implementation
           •   %s:  Name of this operation system
           •   %v:  Current version level of this implementation

           Example:
               print(posix.uname('%s %r'))

       utime(path [, mtime [, ctime]])
           Change last access and modification times. mtime and ctime are
           expressed seconds since epoch. See utime(2).

           If mtime or ctime are omitted, current time is used, similar
           to touch(1).

           Example:
               posix.mkdir('aaa')
               posix.utime('aaa', 0, 0)

       wait([pid]) (DEPRECATED)
           Wait for a child process. If pid is specified wait for that
           particular child. See also wait(2).

           This function is obsolete and only available for RPM v4
           packages for backwards compatibility. Use rpm.spawn() or
           rpm.execute() instead.

           Example:
               pid = posix.fork()
               if pid == 0 then
                   posix.exec('/bin/ls'))
               elseif pid > 0 then
                   posix.wait(pid)
               end

       setenv(name, value [, overwrite])
           Change or add environment variable name. The optional
           overwrite is a boolean which defines behavior when a variable
           by the same name already exists. See also setenv(3).

           Example:
               posix.setenv('HOME', '/me', true)

       unsetenv(name)
           Remove a variable name from environment. See also unsetenv(3).

           Example:
               posix.unsetenv('HOME')

EXTENDING AND CUSTOMIZING         top

       On initialization, RPM executes a global init.lua Lua
       initialization script from the directory %getconfdir expands to,
       typically /usr/lib/rpm/init.lua. This can be used to customize the
       rpm Lua environment without recompiling RPM.

       For the embedded Lua interpreter, module's loaded with require are
       primarily searched from %{getconfdir}/lua/. %_rpmluadir is a
       shorthand for this path.

SEE ALSO         top

       rpm-macros(7) rpm-payloadflags(7) rpmlua(1) rpm-version(7)

       https://www.lua.org/ 

COLOPHON         top

       This page is part of the rpm (RPM Package Manager) project.
       Information about the project can be found at 
       ⟨https://github.com/rpm-software-management/rpm⟩.  It is not known
       how to report bugs for this man page; if you know, please send a
       mail to [email protected].  This page was obtained from the
       project's upstream Git repository
       ⟨https://github.com/rpm-software-management/rpm.git⟩ on
       2026-01-16.  (At that time, the date of the most recent commit
       that was found in the repository was 2026-01-15.)  If you discover
       any rendering problems in this HTML version of the page, or you
       believe there is a better or more up-to-date source for the page,
       or you have corrections or improvements to the information in this
       COLOPHON (which is not part of the original manual page), send a
       mail to [email protected]

RPM 6.0.90                      2026-01-16                     RPM-LUA(7)

Pages that refer to this page: rpmlua(1)rpm-macros(7)rpm-scriptlets(7)