Project

General

Profile

setup_ncurses6x.sh

Roger Borrello, 06/25/2026 01:50 PM

Download (9.26 KB)

 
1
#!/bin/bash
2

    
3
#set -x # Set to help debug
4

    
5
show_usage()
6
{
7
   cat <<EOF
8
Usage: $0 [-p<path>] [-fsad] [-u<user>]
9
Where:
10
p	= Use specific path instead of current directory
11
f	= Override thread-safe dynamically linked version with statically linked patched version containing auto_getch_refresh
12
s	= Set system-wide environment instead of just current user
13
a	= Handle setup of /etc/apt/sources.list and restore when done (requires sudo)
14
u	= Update the given user's .bashrc instead of current running user. Typically for when run under sudo
15
d	= Dry run. Just show commands.
16
EOF
17
}
18

    
19
# True if the variable is already exported, or - for the per-user .bashrc, which we
20
# append to rather than rewrite - already present in the target file.
21
have_var()
22
{
23
   [ -n "${!1}" ] && return 0
24
   [[ "$system" != true ]] && [ -f "$rc_filename" ] && grep -q "$1" "$rc_filename"
25
}
26

    
27
# Defaults
28
user=$USER
29
homedir=$HOME
30

    
31
# process options
32
while getopts "h?p:fsadu:" opt; do
33
   case $opt in
34
      p  ) target_dir=$OPTARG ;;
35
      f  ) patch_ncurses=true ;;
36
      s  ) system=true ;;
37
      a  ) handle_apt=true ;;
38
      u  ) user=$OPTARG
39
           homedir=$(getent passwd "$OPTARG" | cut -d: -f6)
40
           [ -z "$homedir" ] && { echo "Unknown user: $OPTARG" >&2; exit 1; } ;;
41
      d  ) dry="echo" ;;
42
      h | \
43
      \? ) show_usage && exit 1
44
           exit 1 ;;
45
   esac
46
done
47
shift $(($OPTIND - 1))
48

    
49
# remove previous install, if any
50
$dry rm -rf ncurses*
51

    
52
# Learn the OS so that we can handle non-Ubuntu "kind of" gracefully
53
. /etc/os-release
54
codename="$VERSION_CODENAME"
55
case "$codename" in
56
   ulyana|ulyssa|uma|una)          release="focal" ;;   # Linux Mint 20.x
57
   vanessa|vera|victoria|virginia) release="jammy" ;;   # Linux Mint 21.x
58
   wilma|xia|zara|zena)            release="noble" ;;   # Linux Mint 22.x
59
   *)                              release="$codename" ;;
60
esac
61
if [ "$ID" = "rhel" ]; then
62
   is_rhel=true
63
fi
64

    
65
# get up to date version
66
if [[ "$handle_apt" == true ]]; then
67
   apt_backup=""   # original file saved under /tmp, restored when done
68
   apt_created=""  # new file we added, removed when done
69
   if [[ -f "/etc/apt/sources.list.d/ubuntu.sources" ]]; then
70
      # Deb822 format (Ubuntu 24.04 and newer): widen the Types line to add deb-src
71
      apt_backup="/etc/apt/sources.list.d/ubuntu.sources"
72
      $dry cp "$apt_backup" /tmp
73
      $dry sed -i 's/^Types: deb$/Types: deb deb-src/' "$apt_backup"
74
   elif [[ -f "/etc/apt/sources.list.d/official-package-repositories.list" ]]; then
75
      # Some Linux distros derive a separate deb-src list from the existing deb entries
76
      apt_src="/etc/apt/sources.list.d/official-package-repositories.list"
77
      apt_created="/etc/apt/sources.list.d/deb-src.list"
78
      if [ -n "$dry" ]; then
79
         echo "grep -q '^deb-src' $apt_src ||" \
80
              "sed -e 's|^deb |deb-src |' $apt_src >> $apt_created"
81
      else
82
         grep -q '^deb-src' "$apt_src" || \
83
         sed -e 's|^deb |deb-src |' "$apt_src" >> "$apt_created"
84
      fi
85
   else
86
      # Legacy one-line format (Ubuntu 22.04 / 20.04 and earlier)
87
      apt_backup="/etc/apt/sources.list"
88
      $dry cp "$apt_backup" /tmp
89
      if [ -n "$dry" ]; then
90
         echo "echo \"deb-src http://archive.ubuntu.com/ubuntu $release main restricted universe multiverse\" >> /etc/apt/sources.list"
91
      else
92
         echo "deb-src http://archive.ubuntu.com/ubuntu $release main restricted universe multiverse" >> /etc/apt/sources.list
93
      fi
94
   fi
95
   $dry apt-get update
96
fi
97

    
98
# install ncurses source code for this version
99
if [ -z "$is_rhel" ]; then
100
   $dry apt-get -q -y source ncurses
101
   src_rc=$?
102
else
103
   $dry yum install -y ncurses-devel
104
   src_rc=$?
105
fi
106

    
107
if [[ "$handle_apt" == true ]]; then
108
   [ -n "$apt_backup" ]  && $dry mv "/tmp/$(basename "$apt_backup")" "$apt_backup"
109
   [ -n "$apt_created" ] && $dry rm -f "$apt_created"
110
   $dry apt-get update
111
fi
112

    
113
# check if sources obtained
114
if [ "$src_rc" -ne 0 ] && [ -z "$dry" ]; then
115
   echo "+------------------------------------------------------------------------------+"
116
   echo "|                  Unable to get NCURSES source tree!                          |"
117
   echo "|       Check the available packages list in /etc/apt/sources.list.            |"
118
   echo "+------------------------------------------------------------------------------+"
119
   exit 1
120
fi
121

    
122
# patching the source files. Setup an array of the base configure parameters.
123
ncurses_configure_flags=(CFLAGS='-fPIC -O2' --with-termlib --with-abi-version=6 --disable-widec)
124
$dry pushd ncurses-6.* > /dev/null || { echo "Unable to enter NCURSES source directory (ncurses-6.*)!"; exit 1; }
125
if [[ "$patch_ncurses" == true ]]; then
126
   case "$release" in
127
      focal|jammy)   # Ubuntu 20.04 / 22.04 (ncurses 6.2 / 6.3)
128
          patch_h="ncurses_curses_h_in_v6.1_20200708.patch"
129
          patch_c="ncurses_lib_getch_c_v6.1_20200708.patch" ;;
130
      noble)         # Ubuntu 24.04 (ncurses 6.4)
131
          patch_h="ncurses_curses_h_in_v6.4+20240113.patch"
132
          patch_c="ncurses_lib_getch_c_v6.4+20240113.patch" ;;
133
      *)             # unknown / newer - assume newest, but say so
134
          echo "Warning: unrecognized release '$release'; using newest NCURSES patch set" >&2
135
          patch_h="ncurses_curses_h_in_v6.4+20240113.patch"
136
          patch_c="ncurses_lib_getch_c_v6.4+20240113.patch" ;;
137
   esac
138

    
139
   $dry wget https://proj.goldencode.com/downloads/ncurses/${patch_h} || { echo "Failed to download ${patch_h} patch!"; exit 1; }
140
   $dry wget https://proj.goldencode.com/downloads/ncurses/${patch_c} || { echo "Failed to download ${patch_c} patch!"; exit 1; }
141
   $dry patch include/curses.h.in "${patch_h}"
142
   $dry patch ncurses/base/lib_getch.c "${patch_c}"
143
else
144
   # Add configure flags for thread-safe dynamically linked ncurses
145
   ncurses_configure_flags+=(--with-pthread --enable-pthreads-eintr)
146
fi
147
$dry ./configure "${ncurses_configure_flags[@]}"
148
$dry make
149
make_rc=$?
150
if [ "$make_rc" -ne 0 ] && [ -z "$dry" ]; then
151
   echo "NCURSES build failed (make returned $make_rc); aborting before any environment changes." >&2
152
   exit 1
153
fi
154

    
155
# make valid reference to updated ncurses.h
156
$dry cd include
157
$dry ln -s curses.h ncurses.h
158
$dry cd ..
159

    
160
if [[ "$patch_ncurses" == true ]]; then
161
   echo "+------------------------------------------------------------------------------+"
162
   echo "|                 Patched NCURSES libraries update completed.                  |"
163
else
164
   echo "+------------------------------------------------------------------------------+"
165
   echo "|               Thread-safe NCURSES libraries build completed.                 |"
166
fi
167

    
168
# Position minimal files if path is specified
169
if [[ -n "$target_dir" ]]; then
170
   $dry mkdir -p "$target_dir"
171
   $dry cp -r include "$target_dir"
172
   $dry cp -r lib "$target_dir"
173
   $dry cd "$target_dir"
174
   $dry chown -R "$user:$user" "$target_dir"
175
fi
176

    
177
# Set up environment variable(s) if they are not set already.
178
# Pick the target file first so we can also skip entries already present in it.
179
if [[ "$system" == true ]]; then
180
   rc_filename='/etc/profile.d/10-ncurses.sh'
181
   msg="|         The environment has been changed! Reboot to activate changes         |"
182
   mode="644"
183
else
184
   rc_filename="${homedir}/.bashrc"
185
   msg="|   The .bashrc has been changed! Please open new console to activate setup!   |"
186
fi
187

    
188
env_update=""; sudo_update=""
189
if ! have_var NCURSES_FWD_STATIC; then
190
   if [[ "$patch_ncurses" == true ]]; then
191
      env_update+="# set up patched NCURSES root location"$'\n'
192
   else
193
      env_update+="# set up thread-safe NCURSES root location"$'\n'
194
   fi
195
   env_update+="export NCURSES_FWD_STATIC=\"$PWD\""$'\n'
196
   sudo_update+="Defaults env_keep += NCURSES_FWD_STATIC"$'\n'
197
fi
198
if ! have_var NCURSES_FWD_PTHREADS && [ "$patch_ncurses" != true ]; then
199
   env_update+="# and set up thread-safe NCURSES_FWD_PTHREADS variable"$'\n'
200
   env_update+="export NCURSES_FWD_PTHREADS=true"$'\n'
201
   sudo_update+="Defaults env_keep += NCURSES_FWD_PTHREADS"$'\n'
202
fi
203

    
204
if [ -n "$env_update" ]; then
205
   if [[ "$system" == true ]]; then
206
      # Ensure we are making the only entry in the profile.d script
207
      [ -f "$rc_filename" ] && $dry rm -f "$rc_filename"
208
      if [ -z "$dry" ]; then
209
         tmp_sudoers=$(mktemp)
210
         echo -n "$sudo_update" > "$tmp_sudoers"
211
         if visudo -cf "$tmp_sudoers"; then
212
            install -m 440 "$tmp_sudoers" /etc/sudoers.d/10-ncurses
213
         else
214
            echo "Generated sudoers snippet failed validation; not installing." >&2
215
         fi
216
         rm -f "$tmp_sudoers"
217
      fi
218
   fi
219
   if [[ -z "$dry" ]]; then
220
      echo '' >> "$rc_filename"
221
      echo -n "$env_update" >> "$rc_filename"
222
      [[ "$system" == true ]] && chmod "$mode" "$rc_filename"
223
   fi
224
   echo "|   ---------------------------   WARNING ! --------------------------------   |"
225
   echo "$msg"
226
   echo "|   ---------------------------   WARNING ! --------------------------------   |"
227
fi
228

    
229
echo "|              Please do FULL FWD rebuild to activate the changes.             |"
230
echo "+------------------------------------------------------------------------------+"
231

    
232
# back to the starting directory
233
$dry popd > /dev/null
234

    
235
# On a successful build, clean up the downloaded source artifacts. The extracted
236
# source tree is only disposable when -p copied the libraries elsewhere; otherwise
237
# NCURSES_FWD_STATIC points into it and it must be kept.
238
if [ "$make_rc" -eq 0 ]; then
239
   $dry rm -f ncurses_*.dsc ncurses_*.debian.tar.* ncurses_*.orig.tar.*
240
   [ -n "$target_dir" ] && $dry rm -rf ncurses-6.*
241
fi