Centos自定义motd

之前在ArchLinux上弄个motd,最近在Centos上按之前的笔记操作一边,发现有很多不一样的地方。

步骤

首先,需要有用于显示的脚本文件,放在/etc/update_motd.d文件夹下,然后使用motd-update脚本执行/etc/update_motd.d文件夹下的脚本。最后,在pam中加入motd-update脚本。

motd-update

1
2
3
4
#!/bin/sh
# /usr/bin/update-motd
run-parts-debian --lsbsysinit /etc/update_motd.d
#run-parts /etc/update_motd.d

会发现没有run-parts-debian这个命令,其实这个是我拷贝网上的脚本实现的/usr/bin/run-parts-debian,因为Contos的run-parts没有--lsbsysinit参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
cat /usr/bin/run-parts-debian 
#!/usr/bin/env bash

# run-parts - concept taken from Debian
# http://www.unix.com/man-page/linux/8/run-parts/
# with extensions from Ubuntu
# http://manpages.ubuntu.com/manpages/trusty/man8/run-parts.8.html

# keep going when something fails
set +e
# pipefail is required for --report support
set -o pipefail

usage() {
echo "run-parts [--test] [--verbose] [--report] [--umask=umask] [--lsbsysinit] [--regex=REGEX]
[--arg=argument] [--exit-on-error] [--help] [--list] [--reverse] [--] DIRECTORY"
}

help() {
echo "
NAME
run-parts - run scripts or programs in a directory

SYNOPSIS
run-parts [--test] [--verbose] [--report] [--umask=umask] [--lsbsysinit] [--regex=REGEX]
[--arg=argument] [--exit-on-error] [--help] [--list] [--reverse] [--] DIRECTORY

DESCRIPTION
run-parts runs all the executable files named within constraints described below, found in
directory directory. Other files and directories are silently ignored.

If neither the --lsbsysinit option nor the --regex option is given then the names must
consist entirely of ASCII upper- and lower-case letters, ASCII digits, ASCII underscores,
and ASCII minus-hyphens.

If the --lsbsysinit option is given, then the names must not end in .dpkg-old or
.dpkg-dist or .dpkg-new or .dpkg-tmp, and must belong to one or more of the following
namespaces: the LANANA-assigned namespace (^[a-z0-9]+$); the LSB hierarchical and reserved
namespaces (^_?([a-z0-9_.]+-)+[a-z0-9]+$); and the Debian cron script namespace (^[a-zA-
Z0-9_-]+$).

If the --regex option is given, the names must match the custom extended regular
expression specified as that option's argument.

Files are run in the lexical sort order of their names unless the --reverse option is
given, in which case they are run in the opposite order.

OPTIONS
--test print the names of the scripts which would be run, but don't actually run them.

--list print the names of the all matching files (not limited to executables), but don't
actually run them. This option cannot be used with --test.

-v, --verbose
print the name of each script to stderr before running.

--report
similar to --verbose, but only prints the name of scripts which produce output.
The script's name is printed to whichever of stdout or stderr the script produces
output on. The script's name is not printed to stderr if --verbose also specified.

--reverse
reverse the scripts' execution order.

--exit-on-error
exit as soon as a script returns with a non-zero exit code.

--umask=umask
sets the umask to umask before running the scripts. umask should be specified in
octal. By default the umask is set to 022.

--lsbsysinit
filename must be in one or more of either the LANANA-assigned namespace, the LSB
namespaces - either hierarchical or reserved - or the Debian cron script namespace.

--regex=REGEX
validate filenames against custom extended regular expression REGEX

-a, --arg=argument
pass argument to the scripts. Use --arg once for each argument you want passed.

-- specifies that this is the end of the options. Any filename after -- will be not
be interpreted as an option even if it starts with a hyphen.

-h, --help
display usage information and exit.
"
}

report-and-pipe() {
rline="$1"
while IFS= read -r line; do
echo -en "$rline" ; echo "$line";
unset rline;
done;
}

if [ $# -lt 1 ]; then
usage
exit 1
fi

args=""
dir=""
umask=""

for i in "$@"; do
if [ ${append_arg:-0} = 1 ]; then
args="$args $i"
append_arg=0
continue
fi
case $i in
--list)
list=1
;;
--test)
test=1
;;
--verbose|-v)
verbose=1
;;
--report)
report=1
;;
--reverse)
reverse=1
;;
--lsbsysinit)
lsbsysinit=1
;;
--regex)
regex="${i#*=}"
;;
--arg=*)
args="$args ${i#*=}"
;;
-a)
append_arg=1
;;
--umask=*)
umask="${i#*=}"
;;
--help|-h)
help
exit 0
;;
--exit-on-error)
exit_on_error=1
;;
--)
# -- end of options
;;
-*)
echo Unknown argument: $i > /dev/stderr
echo Rest of arguments: $* > /dev/stderr
usage
exit 1
;;
*)
# directory
dir=$i
break
;;
esac
done

if [[ "x$dir" = "x" && ! -d "$dir" ]]; then
echo "Not a directory: '$dir'"
usage
exit 1
fi

# Ignore *~ and *, scripts
filelist=$(LC_ALL=C; ls -1 "${dir}" | grep -vEe '[~,]$')

if [ ${reverse:-0} = 1 ]; then
filelist=$(echo "$filelist" | sort -r)
fi

echo "$filelist" | while read bname ; do
fpath="${dir%/}/${bname}"
[ -d "${fpath}" ] && continue
# Don't run *.{disabled,rpmsave,rpmorig,rpmnew,swp,cfsaved} scripts
[ "${bname%.disabled}" != "${bname}" ] && continue
[ "${bname%.cfsaved}" != "${bname}" ] && continue
[ "${bname%.rpmsave}" != "${bname}" ] && continue
[ "${bname%.rpmorig}" != "${bname}" ] && continue
[ "${bname%.rpmnew}" != "${bname}" ] && continue
[ "${bname%.swp}" != "${bname}" ] && continue
[ "${bname%,v}" != "${bname}" ] && continue

if [ ${lsbsysinit:-0} = 1 ]; then
# Don't run *.{dpkg-old,dpkg-dist,dpkg-new,dpkg-tmp} scripts
[ "${bname%.dpkg-old}" != "${bname}" ] && continue
[ "${bname%.dpkg-dist}" != "${bname}" ] && continue
[ "${bname%.dpkg-new}" != "${bname}" ] && continue
[ "${bname%.dpkg-tmp}" != "${bname}" ] && continue
# Adhere to LANANA-assigned LSB (hierarchical and reserved) and the Debian cron script namespaces
[[ ! "${bname}" =~ ^[a-z0-9]+$ ]] && \
[[ ! "${bname}" =~ ^_?([a-z0-9_.]+-)+[a-z0-9]+$ ]] && \
[[ ! "${bname}" =~ ^[a-zA-Z0-9_-]+$ ]] && continue
fi

if [ "x$regex" != "x" ]; then
[[ ! "${bname}" =~ $regex ]] && continue
fi

if [ -e "${fpath}" ]; then
if [ -r $dir/whitelist ]; then
grep -q "^${bname}$" $dir/whitelist && continue
fi

if [ ${list:-0} = 1 ]; then
echo "${fpath}" $args;
continue
fi

if [ -x "${fpath}" ]; then
if [ ${test:-0} = 1 ]; then
echo "${fpath}" $args;
continue
fi
if [ "$RANDOMIZE" != "" ]; then
let "rtime = $RANDOM"
if [ "$RANDOMTIME" != "" ]; then
let "rtime %= $RANDOMTIME"
else
let "rtime %= 300"
fi
sleep $rtime
fi

# run executable files
if [ ${verbose:-0} = 1 ]; then
echo "${fpath}" $args > /dev/stderr
fi

if [ "x$umask" != "x" ]; then
umask $umask
fi

if [ ${report:-0} = 1 ]; then
oline="${fpath}\n"
# do not report script name over stderr in verbose mode
# no duplicates are needed
if [ ${verbose:-0} = 1 ]; then
eline=""
else
eline="${fpath}\n"
fi
{ "${fpath}" $args 2>&1 1>&3 3>&- |
# handle stderr redirected to stdout
report-and-pipe "$eline"
} 3>&1 1>&2 |
# handle stdout
report-and-pipe "$oline"
else
"${fpath}" $args
fi

rc=${PIPESTATUS[0]}

if [ ${verbose:-0} = 1 ]; then
echo "${fpath}" $args exit status $rc > /dev/stderr
fi

if [ ${rc:-0} != 0 ]; then
if [ ${exit_on_error:-0} = 1 ]; then
exit $rc
fi
fi
fi
fi
done

exit 0

pam

/etc/pam.d/sshd添加

1
session    optional     pam_exec.so   stdout /usr/bin/update-motd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#%PAM-1.0
#/etc/pam.d/sshd
auth required pam_sepermit.so
auth substack password-auth
auth include postlogin
# Used with polkit to reauthorize users in remote sessions
-auth optional pam_reauthorize.so prepare
account required pam_nologin.so
account include password-auth
password include password-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session required pam_namespace.so
session optional pam_keyinit.so force revoke
session include password-auth
session include postlogin
session optional pam_exec.so stdout /usr/bin/update-motd
# Used with polkit to reauthorize users in remote sessions
-session optional pam_reauthorize.so prepare

/etc/motd-update.d

新建/etc/update_motd.d文件夹

1
sudo mkdir /etc/update_motd.d

增加脚本

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
#/etc/update_motd.d/00-banner
color="\e[1;33m"
clear="\e[m"
# figlet -f chunky "ASRock"
echo -e "${color} ______ __
| |.-----.-----.| |_.-----.-----.
| ---|| -__| || _| _ |__ --|
|______||_____|__|__||____|_____|_____|"
echo -e ${clear}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/bin/bash
# /etc/update_motd.d/30-body
#
# GREETER SCRIPT FOR ARCHLINUX SRV
# https://github.com/Gazeka74/archserver-motd/blob/master/arch-greeter

#########################################
#
# VARIABLES
#
#########################################

# Kernel information
kernel="$(uname -sr)"

# Uptime
uptime="$(uptime -p | sed 's/up //;s/,//g')"

# Numbers of packages installed
# packages="$(pacman -Q | wc -l)"

# Numbers of updates pending
# updates_count="$(checkupdates | wc -l)"

# Numbers of IP bannedi

# f2b="$(sudo fail2ban-client status sshd | grep 'Currently banned' | rev | cut -f 1 | rev)"
# banned="$f2b IP banned"
# f2b="$(sudo fail2ban-client status sshd | grep 'Currently banned' | rev | cut -f 1 | rev)"
# banned="IP banned"

# Text to be displayed
# if (( $updates_count > 0 )); then
# updates="$updates_count updates pending"
# else
# updates="$updates_count update pending"
# fi

## Filesystem
# Number of '-' to be displayed on the filesystem occupation
number=30

# /boot
read boot_a boot_s boot_m boot_pcent <<< "$(df -h --output=avail,size,target,pcent /boot | tail -1)"

# /
read root_a root_s root_m root_pcent<<< "$(df -h --output=avail,size,target,pcent / | tail -1)"

# /home
read home_a home_s home_m home_pcent<<< "$(df -h --output=avail,size,target,pcent /home | tail -1)"

# get free memory
read USED FREE TOTAL <<<$(free -htm | grep "Mem" | awk {'print $3,$4,$2'})
read USEDSW FREESW TOTALSW <<<$(free -htm | grep "Swap" | awk {'print $3,$4,$2'})

# get processes
PROCESS=`ps -eo user=|sort|uniq -c | awk '{ print $2 " " $1 }'`
PROCESS_ALL=`echo "$PROCESS"| awk {'print $2'} | awk '{ SUM += $1} END { print SUM }'`
PROCESS_ROOT=`echo "$PROCESS"| grep root | awk {'print $2'}`
PROCESS_USER=`echo "$PROCESS"| grep -v root | awk {'print $2'} | awk '{ SUM += $1} END { print SUM }'`

## Colors
bold="\033[01;1m"
black="\033[01;36m"
red="\033[01;31m"
green="\033[01;32m"
yellow="\033[01;33m"
blue="\033[01;34m"
magenta="\033[01;35m"
cyan="\033[01;36m"
white="\033[01;37m"
reset="\033[0m"

beg="${c1} ${c0}" # in front of information
c0="${reset}${blue}${bold}" # logo + text 1 color
c1="${reset}${white}${bold}" # text 2 color
upd_color="" # updates based on amount

#########################################
#
# FUNCTIONS
#
#########################################

# Displays a progression bar of the FS depending on the available space and the total space
# $PARAM1 = percentage used
bar () {
temp1="${1%?}" # Remove last character
temp2=$(($temp1*$number/100)) # Number of #

str="[" # Initiate

# Add a color to the output
if (($temp1 > 75)); then
str+="${red}"
elif (($temp1 > 50)); then
str+="${yellow}"
elif (($temp1 > 25)); then
str+="${green}"
else
str+="${white}"
fi
# Fill with '#'
for i in $(seq 1 $temp2)
do
str+="="
done

# reset the color
str+="${white}"

# Fill with '-'
for i in $(seq $temp2 $number)
do
str+="-"
done
str+="]"
echo $str
}

boot_bar=$(bar $boot_pcent)
root_bar=$(bar $root_pcent)
home_bar=$(bar $home_pcent)

## Memory

while IFS=":" read -r a b; do
case $a in
"MemTotal") ((mem_used+=${b/kB})); mem_total="${b/kB}" ;;
"Shmem") ((mem_used+=${b/kB})) ;;
"MemFree" | "Buffers" | "Cached" | "SReclaimable")
mem_used="$((mem_used-=${b/kB}))"
;;
# Available since Linux 3.14rc (34e431b0ae398fc54ea69ff85ec700722c9da773).
# If detected this will be used over the above calculation for mem_used.
"MemAvailable")
mem_avail=${b/kB}
;;
esac
done < /proc/meminfo

if [[ $mem_avail ]]; then
mem_used=$(((mem_total - mem_avail) / 1024))
else
mem_used="$((mem_used / 1024))"
fi

mem_total="$((mem_total / 1024))"

mem_perc="$((mem_used * 100 / mem_total))"

mem_used=$(awk '{printf "%.2f", $1 / $2}' <<< "$mem_used 1024")
mem_total=$(awk '{printf "%.2f", $1 / $2}' <<< "$mem_total 1024")
mem_label=GiB

memory="${yellow}${mem_used}${mem_label:-MiB} ${white}/ ${blue}${mem_total}${mem_label:-MiB} ${white}${mem_perc:+(${mem_perc}%)}"

memory_bar="$(bar "${mem_perc}%")"


#########################################
#
# PROCESSING
#
#########################################

# Setting updates color
# if (( $updates_count > 15 )); then
# upd_color="${reset}${red}"
# elif (( $updates_count > 5 )); then
# upd_color="${reset}${yellow}"
# else
# upd_color="${reset}${white}"
# fi

cpu=`cat /proc/cpuinfo | grep "name" | uniq | cut -d ":" -f2 | sed 's/ //;s/(TM)//g;s/(R)//g;s/CPU//;s/ / /'`
proc="${yellow}$PROCESS_ROOT${c1} (r), ${yellow}$PROCESS_USER${c1} (u) | ${yellow}$PROCESS_ALL${c1} (t)"

echo -e "${white}${bold}--------------------------------------------------------------------------------
${c0} ${beg}KERNEL:${c1}${kernel}
${c0} ${beg}UPTIME:${c1}${uptime}
${c0} ${beg}Proc:${c1}${proc}
${c0} ${beg}CPU:${c1}${cpu}
${c0} ${beg}Memory:${memory}
${c0} ${beg}${c1}${memory_bar}
${white}${bold}--------------------------------------------------------------------------------
FILESYSTEM TOTAL AVAIL USED
$root_m $root_s $root_a $root_pcent ${root_bar}
$boot_m $boot_s $boot_a $boot_pcent ${boot_bar}
$home_m $home_s $home_a $home_pcent ${home_bar}
${white}${bold}--------------------------------------------------------------------------------"

Centos自定义motd
https://bubao.github.io/posts/c3249d60.html
作者
一念
发布于
2021年9月12日
许可协议