CentOS 7 learn used grub entry

With the major changes introduced in CentOS 7 from CentOS 6 (systemd, grub2, and more), determining exactly which grub menu entry will be used at next boot is a little more difficult than before.

I wrote a quick script that calculates this for you: learn-used-grub-entry

#!/bin/sh
# File: learn-used-grub-entry
# Location: /usr/bin
# Author: bgstack15
# Startdate: 2019-01-28 11:27
# Title: Script that Determines Which Grub Entry Will be Used
# Purpose:
# Package: bgscripts
# History:
# Usage:
#    for RHEL7/grub2
# Reference:
#    original research
# Improve:

test -z "${LUGE_GRUB_CFG}" && LUGE_GRUB_CFG=/boot/grub2/grub.cfg
test -z "${LUGE_ETC_DEFAULT_GRUB}" && LUGE_ETC_DEFAULT_GRUB=/etc/default/grub
# use option LUGE_OUTPUT which is one of ["kernel","","initram"]

grub_saved_name="$( grub2-editenv - list | awk -F'=' '{print $NF}' )"
use_number="$( awk -F'=' '/^GRUB_DEFAULT/{print $NF}' "${LUGE_ETC_DEFAULT_GRUB}" )"

use_entry=""
# calculate true value
if test "$( echo "${use_number}" | tr '[[:upper:]]' '[[:lower:]]' )" = "saved" ;
then
   # it is the saved value (which is same as last used)
   use_entry="${grub_saved_name}"
else
   # calculate used name from number
   use_entry="$( grep -E -e '^menuentry' "${LUGE_GRUB_CFG}" | sed -r -n -e "$(( use_number + 1 ))p" )"
fi

# calculate which value to display or just display name
LUGE_grep=1
case "${LUGE_OUTPUT:-${1}}" in

   "num" | "number" )
      # just show the number
      unset LUGE_grep
      echo "${use_number}"
      ;;

   "kernel"|"vmlinuz" )
      # show kernel
      LUGE_regex="linux(16|32|64)"
      LUGE_awk_val='$2'
      ;;

   "initram" | "initrd" | "initramfs" )
      # show initram
      LUGE_regex="initrd|initram"
      LUGE_awk_val='$2'
      ;;

   *)
      # DEFAULT VALUE, so mistyped or not defined
      unset LUGE_grep
      echo "${use_entry}"
      ;;
esac

# show complicated value if necessary
if test -n "${LUGE_grep}" ;
then
   sed -n -r -e "/${use_entry}/,/^\s*\}/p" "${LUGE_GRUB_CFG}" | awk "/${LUGE_regex}/{print ${LUGE_awk_val}}"
fi

# exit cleanly
true

And an ansible playbook for myself:

---
# File: luge-tasks.yml
# Purpose: provides common tasks for displaying output from learn-used-grub-entry.sh
# Dependencies:
#    vars:
#       luge_script: '/etc/ansible/files/learn-used-grub-entry.sh'

- name: LUGE - learn lvm.conf filter
  shell: grep -E -e "^\s*(global_)?filter" {{ lvm_conf_file | default('/etc/lvm/lvm.conf') }} ; true
  args:
    warn: no
  changed_when: false
  register: lvm_conf

- name: LUGE - learn /boot value in fstab
  shell: grep -hE -e '\/boot' {{ etc_fstab_file | default('/etc/fstab') }} | grep -viE '^\s*(#|$)' ; true
  args:
    warn: no
  changed_when: false
  register: etc_fstab

- name: LUGE - learn grub menuentry to be used
  script: "{{ luge_script | default('/etc/ansible/files/learn-used-grub-entry.sh') }}"
  environment:
    LUGE_OUTPUT: name
  changed_when: false
  register: luge_menuentry

- name: LUGE - learn grub menuentry initram to be used
  script: "{{ luge_script | default('/etc/ansible/files/learn-used-grub-entry.sh') }}"
  environment:
    LUGE_OUTPUT: initram
  changed_when: false
  register: luge_initram

# this one will fail if the file does not exist
- name: LUGE - fail if selected initram is not valid initram file
  shell: lsinitrd "/boot{{ luge_initram.stdout_lines[0] }}" 1>/dev/null
  args:
    warn: no
  changed_when: false

- name: LUGE - capture raw info
  shell: echo "{{ item }}"
  loop:
  - "lvm.conf: {{ lvm_conf.stdout }}"
  - "fstab: {{ etc_fstab.stdout }}"
  - "menuentry: {{ luge_menuentry.stdout }}"
  - "initram: {{ luge_initram.stdout }}"
  register: stdout1
  changed_when: false

- name: LUGE - show useful info
  debug:
    msg: "{{ stdout1.results|map(attribute='stdout_lines')|flatten(levels=1) }}"

# info that is useful that is generated by the above statements
# - "{{ lvm_conf.stdout }}"
# - "{{ etc_fstab.stdout }}"
# - "{{ luge_menuentry.stdout }}"
# - "{{ luge_initram.stdout }}"

Run game in dosbox and make nice menu icon for it

When I want to play an old-school DOS game, I use the emulator DOSBox. I discovered that DOSBox has its own icon and uses its title in the window, and not the name of the game running inside. I now have a solution to change the icon and title that I want.

First of all, I make my .desktop file call my shell script.

$ cat ~/.local/share/applications/st25.desktop
[Desktop Entry]
Version=1.0
Name=Star Trek 25th Anniversary
Comment=1993 DOS computer game
Keywords=Game;Star Trek;
Exec=/usr/share/st25/st25.sh
Terminal=false
X-MultipleArgs=false
Type=Application
Icon=/usr/share/st25/st25.png
Categories=Game;AdventureGame;

The shell script calls dosbox with the custom batch file (from the olden days of non-free operating systems)

$ cat /usr/share/st25/st25.sh
#!/bin/sh
# Star Trek: 25th Anniversary game
GAMEDIR=/usr/share/st25
ICONFILE="${GAMEDIR}/st25.png"
cd "${GAMEDIR}"
dosbox ST25.BAT &
sleep 1
tid="$( xwininfo -root -children -all | grep -iE "dosbox.*STARTREK" | awk '{print $1}' )"
echo "modifying id ${tid}"
xseticon -id "${tid}" "${ICONFILE}"
xdotool set_window --name "STARTREK" "${tid}"
xdotool search --name "STARTREK" set_window --classname "STARTREK" --class "STARTREK" windowunmap windowmap

The above shell script is where the magic happens. The main emulator is executed and placed in the background. After a short delay, some X tools are used to find the specific application’s window ID.
A custom application named xseticon (available in my Fedora copr) written by Paul Evans is used to change the icon used by the window.
The more easily available xdotool (probably already bundled by your distro) can change the window name.
Additionally, xdotool can hide and re-show the window, to make the window manager and panel recognize the new icon and name!

And just for completeness’s sake, here is the batch file.

$ cat /usr/share/st25/ST25.BAT
REM ST25.BAT
REM Star Trek: 25th Anniversary game

MOUNT C /usr/share/st25
C:
STARTREK.EXE
exit

Conclusion

This is my preferred way to run a DOS-based application: desktop file, shell script, batch file. Yes, it spawns the extra process with the shell script, but I want to be able to call an application from the command line easily.

How do you make your DOS programs accessible to users on cli or the desktop?

References

For a complete list of Internet resources used to build this process, see my other post, X11 change application titlebar and icon in window manager panel.

Ansible disable service fails if service is not defined

If you are trying to disable and stop a system service, and it fails out when the service is not defined, you probably just want to continue.

- name: disable service
  service:
    name: chronyd
    enabled: no
    state: stopped
  register: disable_service
  failed_when: "disable_service is failed and ('Could not find the requested service' not in disable_service.msg)"

Credit goes to Rebekah Hayes.

Ansible check if list is in list

Here’s my hack for how to check if a list’s items are all in another list.

  - name: learn current mounts
    shell: mount | grep -iE "cifs|nfs" | grep -viE '^\s*#|pipefs|proc\/fs\/nfsd' | awk '{print $3}' | sort
    args:
      warn: no
    register: mounts

  - name: learn requested mounts
    shell: grep -iE "cifs|nfs" /etc/fstab | grep -viE '^\s*#|pipefs|proc\/fs\/nfsd' | awk '{print $2}' | sort
    args:
      warn: no
    register: fstab_entries

  - name: fail when fstab_entries not in mounts
    debug:
      msg: "{{ item }}"
    failed_when:
    - 'item not in mounts.stdout_lines'
    loop: "{{ fstab_entries.stdout_lines | flatten(levels=1) }}"

I am just using a debug task that loops over all the items of the possibly shorter list, with a condition to fail when the item is not in the longer list.

Insert your own ca root certificates in RancherOS

Cloud-init is pretty great. It has a module for installing CA certificates, which RancherOS does not yet support.

So the solution for now, as shared by Gizmotronic at the rancherOS forums, is as follows.

write_files:
- content: |+
    #!/bin/sh
    cat << _EOF_ >> /etc/ssl/certs/ca-certificates.crt
    # subject=/DC=com/DC=example/DC=ad/CN=CA2
    -----BEGIN CERTIFICATE-----
    certificate contents belong here
    -----END CERTIFICATE-----
    _EOF_
  owner: root:root
  path: /opt/rancher/bin/start.sh
  permissions: "0755"

A Devuan guest in kvm and using spice-vdagentd

If you intend to use spice-vdagent in a devuan vm, you might be interested to know how to get the spice agent to actually work.

Symptoms

The option for “Scale Display -> Auto resize VM with window” is not functional in the spice viewer.
In the guest’s /var/log/syslog, you can see an error:

spice-vdagentd: error getting session for pid 2970: no such file or directory free

But that’s about it.

The fix

Make file /etc/default/spice-vdagentd with contents:

SPICE_VDAGENTD_EXTRA_ARGS=-X

Then restart the daemon.

sudo service spice-vdagentd restart

The -X flag on the invocation disables systemd-logind integration. This is key for a devuan install because devuan exists to be free of the requirement for systemd.

References

Internet searches

  1. https://duckduckgo.com/?q=spice-vdagentd%3A+Error+getting+session+for+pid+2970%3A+No+such+file+or+directory

Weblinks

  1. 14.04 – Systemd, cgroup, and LXC – Ask Ubuntu
  2. Bug #1633609 “spice-vdagentd does not work” : Bugs : spice-vdagent package : Ubuntu
  3. Configuration for spice-vdagentd – Ask Ubuntu