71d7061
-- This is intended to be run as an RPM scriptlet.
71d7061
-- Keep this file in sync with the convert-to-edition
71d7061
-- shell script
71d7061
71d7061
local VARIANT_FILE = "/usr/lib/variant"
71d7061
71d7061
-- Read in /usr/lib/variant and determine the edition
71d7061
local function read_variant()
71d7061
  local variant
60501f2
  local f = io.open(VARIANT_FILE, "r")
71d7061
  if f ~= nil then
71d7061
    while true do
71d7061
      local line = f:read()
71d7061
      if line == nil then
71d7061
        break
71d7061
      end
71d7061
      local m = line:match("^VARIANT_ID=([^\n]+)")
71d7061
      if m ~= nil then
71d7061
        variant = m
71d7061
      end
71d7061
    end
60501f2
    f:close()
71d7061
  end
71d7061
  return variant
71d7061
end
71d7061
71d7061
-- Atomically replace a file with new contents
71d7061
local function writefile(path, data)
71d7061
  local tmp = path .. ".convert-to-edition"
71d7061
  local f = io.open(tmp, "w+")
71d7061
  if f == nil then
71d7061
    return
71d7061
  end
71d7061
  f:write(data)
71d7061
  f:close()
71d7061
  if not os.rename(tmp, path) then
71d7061
    os.remove(tmp)
71d7061
  end
71d7061
end
71d7061
71d7061
-- Forcibly replace a symlink
71d7061
local function symlink(from, to)
71d7061
  os.remove(to)
71d7061
  assert(posix.symlink(from, to))
71d7061
end
71d7061
71d7061
-- Run a subroutine in a child process
71d7061
local function execute(...)
71d7061
  local pid = posix.fork()
71d7061
  if pid == 0 then
71d7061
    posix.exec(...)
71d7061
    posix.exit(1)
71d7061
  elseif pid ~= -1 then
71d7061
    local status = posix.wait(pid)
71d7061
    if status ~= 0 then
71d7061
      local program = ...
71d7061
      error(program .. " exited with status " .. status)
71d7061
    end
71d7061
  end
71d7061
end
71d7061
71d7061
-- Remove preset files for other editions
71d7061
-- This should never be necessary, but it's best to be safe
71d7061
local function clear_presets()
71d7061
  local path = "/usr/lib/systemd/system-preset"
71d7061
  for file in posix.files(path) do
58e4ecf
    if file:match("^80%-.*%.preset$") then
71d7061
      os.remove(path .. "/" .. file)
71d7061
    end
71d7061
  end
71d7061
end
71d7061
71d7061
71d7061
-- Get a list of presets that need to be enabled or disabled
71d7061
-- as part of the installation of this edition
71d7061
local function read_presets(path)
71d7061
  local result = {}
71d7061
  local f = assert(io.open(path))
71d7061
  if f ~= nil then
71d7061
    while true do
71d7061
      local line = f:read()
71d7061
      if line == nil then
71d7061
        break
71d7061
      end
71d7061
      local cmd, arg = line:match("^([^ \t]+)[ \t]+([^\n \t]+)")
71d7061
      if cmd == "enable" or cmd == "disable" then
71d7061
        result[#result + 1] = arg
71d7061
      end
71d7061
    end
60501f2
    f:close()
71d7061
  end
71d7061
  return result
71d7061
end
71d7061
71d7061
local function set_variant(variant)
71d7061
  writefile(VARIANT_FILE, "VARIANT_ID=" .. variant .. "\n")
71d7061
end
71d7061
71d7061
local function set_release(release)
71d7061
  symlink("./os.release.d/os-release-" .. release, "/usr/lib/os-release")
71d7061
end
71d7061
b2ee3bb
local function set_edition_swidtag(release)
b2ee3bb
  symlink("/usr/lib/os.release.d/Fedora-" .. release .. ".swidtag", "%{_swidtagdir}/org.fedoraproject.Fedora-edition.swidtag")
b2ee3bb
end
b2ee3bb
b2ee3bb
local function unset_edition_swidtag()
b2ee3bb
  os.remove("%{_swidtagdir}/org.fedoraproject.Fedora-edition.swidtag")
b2ee3bb
end
b2ee3bb
71d7061
-- release: the VARIANT_ID for os-release
71d7061
-- presets: whether this edition has extra presets beyond the
71d7061
--          defaults to enable or disable
71d7061
local variants = {
b3aef3c
  atomichost = {release = "atomichost", presets = false},
b3aef3c
  cloud = {release = "cloud", presets = false},
b3aef3c
  cinnamon = {release = "cinnamon", presets = false},
b3aef3c
  container = {release = "container", presets = false},
b3aef3c
  coreos = {release = "coreos", presets = false},
b3aef3c
  iot = {release = "iot", presets = true},
b3aef3c
  kde = {release = "kde", presets = false},
b3aef3c
  matecompiz = {release = "matecompiz", presets = false},
b3aef3c
  nonproduct = {release = "fedora", presets = false},
b3aef3c
  server = {release = "server", presets = true},
b3aef3c
  silverblue = {release = "silverblue", presets = false},
b3aef3c
  soas = {release = "soas", presets = false},
b3aef3c
  workstation = {release = "workstation", presets = true},
b3aef3c
  xfce = {release = "xfce", presets = false},
71d7061
}
71d7061
71d7061
-- Call out to systemctl to enable or disable presets
60501f2
local function set_presets(edition, apply_presets)
71d7061
  if variants[edition].presets then
71d7061
    local target = "/usr/lib/systemd/system-preset/80-" .. edition .. ".preset"
60501f2
    symlink("../../os.release.d/presets/80-" .. edition .. ".preset", target)
60501f2
60501f2
    if apply_presets then
60501f2
      local presets = read_presets(target)
60501f2
      local systemctl = "/usr/bin/systemctl"
60501f2
      if posix.access(systemctl, "x") then
18e38ac
        --fork off a systemctl call
18e38ac
        local pid = assert(posix.fork())
18e38ac
        if pid == 0 then
18e38ac
          -- Child
18e38ac
          posix.exec(systemctl, "preset", "-q", table.unpack(presets))
18e38ac
          -- In case exec() fails
18e38ac
          os.exit(17)
18e38ac
        else
18e38ac
          -- RPM
18e38ac
          assert(posix.wait(pid))
18e38ac
        end
60501f2
      end
60501f2
    end
71d7061
  end
71d7061
end
71d7061
60501f2
local function convert_to_edition(edition, apply_presets)
71d7061
  local variant = variants[edition]
71d7061
  if variant == nil then
71d7061
    error("undefined edition: " .. edition)
71d7061
  end
71d7061
  set_release(variant.release)
b2ee3bb
b2ee3bb
  -- Symlink the correct edition .swidtag for anything but nonproduct
b2ee3bb
  if edition == "nonproduct" then
b2ee3bb
    unset_edition_swidtag()
b2ee3bb
  else
b2ee3bb
    set_edition_swidtag(variant.release)
b2ee3bb
  end
71d7061
  clear_presets()
71d7061
60501f2
  set_presets(edition, apply_presets)
71d7061
end
71d7061
71d7061
local function install_edition(edition)
71d7061
  -- Create the variant file if it does not already exist. This needs
71d7061
  -- to be done on both installation and upgrade, to ensure that we
71d7061
  -- upgrade from F23 and earlier properly.
71d7061
  if not posix.access(VARIANT_FILE, "f") then
71d7061
    set_variant(edition)
71d7061
  end
71d7061
  if read_variant() == edition then
71d7061
    -- (On initial installation only), fix up after %%systemd_post
71d7061
    -- in packages possibly installed before our preset file was
71d7061
    -- added
71d7061
    -- On upgrades, do not enable or disable presets to avoid
71d7061
    -- surprising the user
60501f2
    local initial_install = arg[2] == 1
71d7061
    convert_to_edition(edition, initial_install)
71d7061
  end
71d7061
end
71d7061
71d7061
local function uninstall_edition(edition)
71d7061
  -- If we are uninstalling, we need to reset the variant file and
71d7061
  -- force the os-release file back to os-release-fedora.  We do this
71d7061
  -- in %%preun so that we don't have any time where the os-release
71d7061
  -- symlink is dangling (since in %%postun, the os-release-$EDITION
71d7061
  -- file will have already been removed)
60501f2
  if arg[2] == 0 then
71d7061
    if read_variant() == edition then
60501f2
      set_variant("nonproduct")
71d7061
      convert_to_edition("nonproduct", false)
71d7061
    end
71d7061
  end
71d7061
end