Is there a simple way to report any systemd-based service whose configuration is is non-standard/non-default?
All systemd defaults are in /lib/systemd/system
All overrides, i.e. non-standard config or changes are in /etc/systemd/system
That said, if you want to report any systemd-based service whose configuration is non-standard, one way to do that would be:
ls -l /etc/systemd/system |grep service
Theoretically, this could be empty since all defaults are in /lib/.
As you can see, Ubuntu already comes with a non-standard/non-default configuration. It looks like a lot but most of these are just alternative names in the form of symlinks. The real files here are the services which configuration has changed or added by ubuntu or installed packages. List them like:
find /etc/systemd/system -type f -name '*\.service'
Then we have also the runlevels (or ātargetsā as systemd tends to call them).
These targets are directories containing symlinks to services (quite like init with its runlevels actually )
You can get a nice formatted list of non-standard or changed targets with their services like this:
ls -l /etc/systemd/system/*.target.wants
And ofcourse the default ones:
ls -l /lib/systemd/system/*.target.wants
The non-standard configurationfiles of these targets are here
find /etc/systemd/system -maxdepth 1 -name '*\.target'
And the default ones are here:
find /lib/systemd/system -maxdepth 1 -name '*\.target'
As you can see I havenāt used any systemd commands for this.
There are probably systemd commands to do this but Iām not aware of any ![]()
Hope this answers your question a bit.
Also, probably systemd-delta.
It shows you every unit where the config has been overridden, extended, masked, or redirected from the vendor default.
Run it on its own or filter with --type= if you only care about specific kinds (overridden, extended, masked, etc).
If you want to see the actual diff for a specific unit, systemctl cat foo.service will show the full effective config including any drop-ins, and systemd-delta foo.service will highlight just what changed.
Not perfect since it only catches stuff under the standard systemd search paths, but for spotting ānon-standard/non-defaultā it covers most cases.
Thank you, Thom.
Should that, instead, be limited to the following, to ignore the symlinks?
ls -l /etc/systemd/system | grep -v '^lr' | grep 'service$'
The report I get is this:
-rw-r--r-- 1 root root 593 Apr 30 14:55 snap.canonical-livepatch.canonical-livepatchd.service
-rw-r--r-- 1 root root 496 May 7 19:41 snap.chromium.daemon.service
-rw-r--r-- 1 root root 596 Apr 16 20:04 snap.cups.cups-browsed.service
-rw-r--r-- 1 root root 561 Apr 16 20:04 snap.cups.cupsd.service
-rw-r--r-- 1 root root 537 Mar 16 19:07 snap.mesa-2404.component-monitor.service
What is curious about those is that they are all SNAP-related!!!
I also checked under /snap, and those Applications are all installed SNAP packages!!!
Now, I will ābuyā the results to be the reporting of non-standard (post-distro-install) packages, except for that first one, but I donāt see those results as reporting what are deviations from a ādefaultā installation for each of those packages individually!
To everyone following this discussion ā¦
Being SNAP-averse, is there an existing tool that
-
identifies non-OS-critical SNAP packages,
-
determines existence of equivalent Debian package,
-
downloads (without installing) the required Debian packages,
-
creates the necessary āconfigā files giving the proper directives to the APT packaging system,
-
extracts and preserves the appropriate local-customization files relevant to each of the packages that have a downloaded(a.k.a. verified) Debian package,
-
purges the SNAP packages for which those Debian packages were downloaded,
-
installs the Debian-based packages that were downloaded, and
-
re-integrates the saved local-customization files for proper functioning of the Debian-based Applications?
Thank you, Hayden.
systemd-delta gives me the following:
# systemd-delta
[EXTENDED] /usr/lib/systemd/system/lightdm.service ā /etc/systemd/system/lightdm.service.d/override.conf
[EXTENDED] /usr/lib/systemd/system/networking.service ā /etc/systemd/system/networking.service.d/timeout.conf
[EXTENDED] /usr/lib/systemd/system/rc-local.service ā /usr/lib/systemd/system/rc-local.service.d/debian.conf
[EXTENDED] /usr/lib/systemd/system/sysinit.target ā /etc/systemd/system/sysinit.target.d/override.conf
[EXTENDED] /usr/lib/systemd/system/systemd-localed.service ā /usr/lib/systemd/system/systemd-localed.service.d/locale-gen.conf
[EXTENDED] /usr/lib/systemd/system/[email protected] ā /usr/lib/systemd/system/[email protected]/timeout.conf
6 overridden configuration files found.
but when I run the command systed-delta ${serviceName}, I get ā0 overridden configuration files found.ā for every one of them!
That reporting leaves me with questions because I do have a custom version of rc.local, which contains the following:
#!/bin/bash
/DB001_F2/Oasis/bin/HW_Admin__Power_SetFreqCPU.sh --default --service
and that calls the following script:
#!/bin/bash
####################################################################################################
###
### Script to make it easier to learn how to control the CPU 'governor' and CPU clock frequencies
###
### 2024-11-18 -- Version 5.1 -- Eric Marceau, Ottawa, Ontario, Canada
###
### Related discussion: https://ubuntu-mate.community/t/setting-up-boot-time-service-for-local-custom-cpu-frequency-governor-script-cpupower/28349
###
####################################################################################################
#23456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+
dbg=0
test "${1}" = "--debug1" && { dbg=1 ; shift ; }
test "${1}" = "--debug2" && { dbg=2 ; shift ; }
###
### Edit this script to assign preset defaults appropriate for your local Desktop CPU
###
doMode=59 # userspace
doFreq=2 # 1900MHz
doDefault=0
doStatus=0
doCron=0
doService=0
shopt -s extglob
identifyGovernors()
{
test ${dbg} -gt 0 && echo " >>> ENTERING identifyGovernors ..." >&2
#governors=$(echo "userspace performance ondemand conservative powersave schedutil junker" |
governors=$(grep 'available cpufreq governors:' ${tmp} |
sed 's+\:\ +\:+' |
cut -f2 -d":" |
awk -v dbg="${dbg}" 'BEGIN{
split("", plist) ;
plist[1,1]="userspace";
plist[2,1]="performance";
plist[3,1]="ondemand";
plist[4,1]="conservative";
plist[5,1]="powersave";
plist[6,1]="schedutil";
c=6 ;
for( i=1 ; i <= c ; i++ ){
plist[i,2]=0 ;
} ;
if( dbg == 2 ){
for( j=1 ; j <= c ; j++ ){
printf("plist[%s] = %s\n", j, plist[j,1] ) | "cat 1>&2" ;
} ;
} ;
}{
for( k=1 ; k <= NF ; k++ ){
if( dbg == 2 ){ printf("\t $%d = %s\n", k, $k ) | "cat 1>&2" ; } ;
valid=0 ;
for( m=1 ; m <= c ; m++ ){
if( dbg == 2 ){ printf("\t\t plist[%d,1] = %s\n", m, plist[m,1] ) | "cat 1>&2" ; } ;
if( $k == plist[m,1] ){
plist[m,2]=1
valid=1
break ;
} ;
} ;
if( valid == 0 ){
printf("\n NOTE: Reported governor mode \"%s\" is not currently handled by programmed logic.\n", $k ) | "cat 1>&2" ;
} ;
} ;
}END{
for( n=1 ; n <= c ; n++ ){
if( plist[n,2] == 1 ){
printf("%s\n", plist[n,1] ) ;
} ;
} ;
}'
)
}
getGov()
{
test ${dbg} -gt 0 && echo " >>> ENTERING getGov ..." >&2
case ${doMode} in
1 ) governor="performance" ;;
2 ) governor="conservative" ;;
3 ) governor="powersave" ;;
4 ) governor="ondemand" ;;
5 ) governor="schedutil" ;;
58 ) ;; ### governor specified on command line
59 ) governor="userspace" ;;
esac
}
identifyFrequencies()
{
test ${dbg} -gt 0 && echo " >>> ENTERING identifyFrequencies ..." >&2
steps=$(grep 'Pstate-' ${tmp} |
sed 's+\:\ \ +\:+' |
cut -f2 -d":" |
awk '{
n=split($0, vals, ",") ;
for( i=1 ; i <= n ; i++ ){
printf("%s\n", vals[i] ) ;
} ;
}'
)
}
getFreq()
{
test ${dbg} -gt 0 && echo " >>> ENTERING getFreq ..." >&2
case ${doMode} in
[1-5] ) return ;; ### No need to so set frequency for these modes
* ) ;;
esac
fmax=$(echo "${steps}" | head -1 )
fmidhi=$(echo "${steps}" | head -2 | tail -1 )
fmidlo=$(echo "${steps}" | tail -2 | head -1 )
fmin=$(echo "${steps}" | tail -1 )
test -n "${fmin}" || fmin=$(echo "${steps}" | tail -2 | head -1 )
fopt=( $(echo ${steps} ) )
len=${#fopt[*]}
test ${dbg} -gt 0 && echo -e "\n Number of clock speeds identified: ${len}" >&2
test ${dbg} -gt 1 && echo "doFreq = ${doFreq}" >&2
case ${doFreq} in
#(!+[0-9]) ) frequency="NULL" ;;
80 )
case "${frequency}" in
+([0-9])"MHz" ) ;;
#[0-9]"."+([0-9])"GHz" | [0-9]"."[0-9][0-9]"GHz" )
[0-9]"."+([0-9])"GHz" )
fval=$(echo "${frequency}" | sed 's+GHz++' )
#fval=$(echo "scale=0 ; 1000 * ${fval}" | bc ) ### This form doesn't work
#fval=$(echo "1000 * ${fval}" | bc | cut -f1 -d\. ) ### Kludgy fix
fval=$(echo "1000 * ${fval}" / 1 | bc ) ### Elegant fix
frequency="${fval}MHz"
;;
esac
return ;;
96 ) frequency="${fmin}" ; return ;;
97 ) frequency="${fmidlo}" ; return ;;
98 ) frequency="${fmidhi}" ; return ;;
99 ) frequency="${fmax}" ; return ;;
+([0-9]) )
test ${doFreq} -gt ${len} && { printf "\n\t ERROR: User has specified frequncy index which is out of range. Max positional choices = 4.\n Bye!\n\n" ; exit 1 ; }
frequency="${fopt[$(expr ${doFreq} - 1)]}" ; return ;;
#'([:alpha:])' )
* ) printf "\n\t ERROR: User has specified frequency index which is invalid. Re-run with no options to obtain report of choices available.\n Bye!\n\n" ; exit 1 ;;
esac
}
reportOptions()
{
test ${dbg} -gt 0 && echo " >>> ENTERING reportOptions ..." >&2
printf "\n Choices Available for 'CPU Frequency Governor' labels:\n\n"
echo "${governors}" | awk '{ printf("\t %s\n", $0 ); }'
printf "\n Choices Available for 'userspace' fixed CPU 'frequency':\n\n"
echo "${steps}" | awk '{ printf("\t %7s\n", $0 ); }'
printf "\n Syntax: $(basename $0 )\n\
\t\t[\t--list |\n\
\t\t\t--detail |\n\
\t\t\t--default |\n\
\t\t\t[ --mode {governor_label} |\n\
\t\t\t --max |\n\
\t\t\t --min |\n\
\t\t\t --laptop |\n\
\t\t\t --load |\n\
\t\t\t --adaptive ]\n\
\t\t\t[ --freq {frequency} ]\n\
\t\t]\n\n"
printf "\n View detailed report generated by 'cpupower' ? [y/N] => " ; read ans ; test -n "$ans" || ans="N"
case "${ans}" in
y* | Y* )
printf "\n Contents of raw report from 'cpupower' (${tmp}):\n\n"
awk '{ printf("\t|%s\n", $0 ) ; }' <"${tmp}"
echo ""
ls -l "${tmp}"
echo ""
rm -i "${tmp}"
;;
* ) rm -f "${tmp}" ;;
esac
}
setGovernor()
{
test ${dbg} -gt 0 && echo " >>> ENTERING setGovernor ..." >&2
test -n "${governor}" || { printf "\n ERROR: No 'governor' label specified. Unable to proceed.\n\n" ; exit 1 ; }
#testor=$(grep 'available cpufreq governors:' ${tmp} | grep "${governor}" )
testor=$(echo "${governors}" | grep "${governor}" )
test -n "${testor}" || { printf "\n ERROR: Governor '${governor}' is available for your hardware. Unable to proceed.\n\n" ; exit 1 ; }
### Set CPU frequency under USER-defined control
COM="${command} --cpu 'all' frequency-set --governor '${governor}'"
printf "\n COMMAND: ${COM}\n"
eval ${COM}
}
setFrequency()
{
test ${dbg} -gt 0 && echo " >>> ENTERING setFrequency ..." >&2
test -n "${frequency}" || { printf "\n ERROR: No CPU frequency value specified. Unable to proceed.\n\n" ; exit 1 ; }
testor=$(grep 'Pstate-' ${tmp} | grep "${frequency}" )
test -n "${testor}" || { printf "\n ERROR: Frequency '${frequency}' is not available for your hardware. Unable to proceed.\n\n" ; exit 1 ; }
### Can ONLY set frequency by itself; no other parameters allowed
COM="${command} --cpu 'all' frequency-set --freq '${frequency}'"
printf "\n COMMAND: ${COM}\n"
eval ${COM}
}
reportStatus()
{
now=$( date '+%Y-%m-%d %H:%M:%S' )
for cpu in 0 1 2 3
do
fmax=$(cat /sys/devices/system/cpu/cpu${cpu}/cpufreq/scaling_max_freq )
fmin=$(cat /sys/devices/system/cpu/cpu${cpu}/cpufreq/scaling_min_freq )
govr=$(cat /sys/devices/system/cpu/cpu${cpu}/cpufreq/scaling_governor )
freq=$(cat /sys/devices/system/cpu/cpu${cpu}/cpufreq/scaling_cur_freq )
printf "${now}| CPU ${cpu}: %s %4s MHz [%s <-> %s]\n" ${govr} $( expr ${freq} / 1000 ) $( expr ${fmin} / 1000 ) $( expr ${fmax} / 1000 )
done
}
command=$(which "cpupower" )
test -n "${command}" || { printf "\n ERROR: Unable to locate command 'cpupower'. Unable to proceed.\n\n" ; exit 1 ; }
tmp=/tmp/$(basename "$0" ".sh" ).report
### get details report to parse for available governor labels and CPU frequencies
${command} frequency-info --debug >${tmp}
test -s "${tmp}" || { printf "\n ERROR: ${command} did not generate the required details report. Unable to proceed.\n\n" ; exit 1 ; }
identifyGovernors
identifyFrequencies
test ${dbg} -gt 0 && echo " >>> START parsing ..." >&2
### always report safely and informatively, if no parameters provided
if [ $# -eq 0 ]
then
set - '--list'
fi
while [ $# -gt 0 ]
do
case "${1}" in
"--list" )
reportOptions ; echo "" ; exit 0 ; ;;
"--detail" )
${command} frequency-info --debug ; echo "" ; exit 0 ;;
"--mode" )
doMode=58 ;
governor="${2}" ; shift ; shift ;;
"--max" )
doMode=1 ; shift ;;
"--min" )
doMode=2 ; shift ;;
"--laptop" )
doMode=3 ; shift ;;
"--load" )
doMode=4 ; shift ;;
"--adaptive" )
doMode=5 ; shift ;;
"--freq" )
doMode=59 ;
doFreq=80 ;
frequency="${2}" ; shift ; shift ;;
"--fmax" )
doFreq=99 ; shift ;;
"--fmidhi" )
doFreq=98 ; shift ;;
"--fmidlo" )
doFreq=97 ; shift ;;
"--fmin" )
doFreq=96 ; shift ;;
"--f"+([0-9]) )
doFreq=$(echo "$1" | cut -c4- ) ; shift ;;
"--default" )
doDefault=1 ; shift ;;
"--status" )
doStatus=1 ; shift ;;
"--cron" )
doCron=1 ; shift ;;
"--service" )
doService=1 ; shift ;;
* )
echo "ERROR: Invalid argument '${1}' on command line." ; exit 1 ;;
esac
done
test ${dbg} -gt 0 && echo " >>> END parsing ..." >&2
if [ ${doService} -eq 1 ]
then
rm -f /var/log/cpufreq.log
fi
if [ ${doStatus} -eq 1 ]
then
if [ ${doCron} -eq 1 ]
then
{ reportStatus ; echo "" ; } >>/var/log/cpufreq.log
else
reportStatus
fi
exit
fi
getGov
getFreq
test ${dbg} -gt 1 && echo frequency = ${frequency} >&2
test ${doDefault} -eq 1 \
&& { printf "\n Will use hard-coded presets:\n\t governor = '${governor}'\n\t frequency = '${frequency}'\n\n" ; } \
|| { printf "\n Will use selected governor: '${governor}' ...\n" ; }
setGovernor
if [ "${governor}" = "userspace" ]
then
test ${doDefault} -eq 0 \
&& { printf "\n Will use selected frequency: '${frequency}' ...\n" ; }
setFrequency
fi
echo ""
test ${doService} -eq 0 && rm -i ${tmp}
exit 0
Yes, either that or this:
find /etc/systemd/system -type f -name '*\.service'
But donāt forget that symlinks are part of this ! Donāt brush them aside too fast.
Remember that systemctl mask unneeded.service is exactly the same as:
ln -s /dev/null /etc/systemd/system/unneeded.service
Which is a change from the default and will prevent unneeded.service from starting.
Thank you, Thom. I figured that any symlink pointint to a system default configuration is deemed non-modified.
Is that not the case?
If so, I could tweak that one-liner as follows:
ls -l /etc/systemd/system | grep -v ' -> /lib/systemd/system/' | grep 'service$'
Is that not correct? If not, can you help me understand?
That is correct.
That is correct ![]()