e6857adafd6b6a381b2e06f28a0b2626e79e13a2
[exim.git] / src / scripts / exim_install
1 #! /bin/sh
2
3 # Copyright (c) The Exim Maintainters 2022
4 # SPDX-License-Identifier: GPL-2.0-or-later
5
6 # Script to install Exim binaries in BIN_DIRECTORY, which is defined in
7 # the local Makefile. It expects to be run in a build directory. It needs
8 # to be run as root in order to make exim setuid to root. If exim runs setuid
9 # to (e.g.) exim, this script should be run as that user or root.
10
11 # This script also installs a default configuration file in CONFIGURE_FILE
12 # if there is no configuration file there, but only if CONFIGURE_FILE specifies
13 # single file. If it specifies a list, no action is taken.
14
15 # If a default configuration file is installed, the existence of the system
16 # aliases file is tested. A default, containing only comments, is installed if
17 # necessary.
18
19 # If INFO_DIRECTORY is defined in any of the local Makefiles, and the Exim doc
20 # directory contains the Texinfo documentation, this script also installs a
21 # the info files in INFO_DIRECTORY.
22
23 # If DESTDIR is defined, all file paths are prefixed with ${DESTDIR}, with the
24 # sole exception of the reference to the system aliases file in the default
25 # configuration, because it is assumed that Exim is not actually going to be
26 # run from this position. For backward compatibility, if DESTDIR is not
27 # defined, ROOT is used instead.
28
29 # The script can be made to output what it would do, without actually doing
30 # anything, by giving it the option "-n" (cf make). Arguments are the names
31 # of things to install. No arguments installs everything.
32
33 do_chown=yes
34 do_symlink=yes
35
36 while [ $# -gt 0 ] ; do
37   case "$1" in
38     -n)
39       real="true || "
40       ver="verification "
41       com=": "
42       echo $com ""
43       echo $com "*** Verification mode only: no commands will actually be obeyed"
44       echo $com "*** You can cut and paste the bits you want to a shell, etc"
45       echo $com ""
46       echo cd `pwd`
47       ;;
48
49     -no_chown)
50       do_chown=no
51       ;;
52
53     -no_symlink)
54       do_symlink=no
55       ;;
56
57     *)
58       break
59       ;;
60   esac
61   shift
62 done
63
64 # Get the values of BIN_DIRECTORY, CONFIGURE_FILE, INFO_DIRECTORY, NO_SYMLINK,
65 # SYSTEM_ALIASES_FILE, and EXE from the global Makefile (in the build
66 # directory). EXE is empty except in the Cygwin environment. In each case, keep
67 # the latest definition, thus respecting the Makefiles precedence. The sed
68 # sequences here are messy, but have to be very "basic" in order to work on
69 # Solaris, where the regular expressions in sed are primitive indeed. Modify at
70 # your peril.
71
72 BIN_DIRECTORY=`sed -n   -e '/^ *BIN_DIRECTORY *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
73 CONFIGURE_FILE=`sed -n -e '/^ *CONFIGURE_FILE *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
74 INFO_DIRECTORY=`sed -n -e '/^ *INFO_DIRECTORY *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
75 NO_SYMLINK=`sed -n         -e '/^ *NO_SYMLINK *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
76
77 CHOWN=`sed -n           -e '/^ *CHOWN_COMMAND *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
78 MV=`sed -n                 -e '/^ *MV_COMMAND *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
79
80 SYSTEM_ALIASES_FILE=`sed -n -e '/^ *SYSTEM_ALIASES_FILE *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
81 EXE=`sed -n                                 -e '/^ *EXE *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
82
83 # Set a default for SYSTEM_ALIASES_FILE
84
85 if [ "${SYSTEM_ALIASES_FILE}" = "" ] ; then
86   SYSTEM_ALIASES_FILE=/etc/aliases
87 fi
88
89 # Allow INST_xx to over-ride xx
90 case "$INST_BIN_DIRECTORY"       in ?*) BIN_DIRECTORY="$INST_BIN_DIRECTORY";; esac
91 case "$INST_CONFIGURE_FILE"      in ?*) CONFIGURE_FILE="$INST_CONFIGURE_FILE";; esac
92 case "$INST_INFO_DIRECTORY"      in ?*) INFO_DIRECTORY="$INST_INFO_DIRECTORY";; esac
93 case "$INST_SYSTEM_ALIASES_FILE" in ?*) SYSTEM_ALIASES_FILE="$INST_SYSTEM_ALIASES_FILE";; esac
94
95 case "$INST_CHOWN"               in ?*) CHOWN="$INST_CHOWN";; esac
96 case "$INST_MV"                  in ?*) MV="$INST_MV";; esac
97
98 case "$INST_UID"     in '') INST_UID=root;;    *) INST_UID="$INST_UID";; esac
99 case "$INST_CP"      in '') CP=cp;;            *) CP="$INST_CP";; esac
100 case "$INST_LN"      in '') LN=ln;;            *) LN="$INST_LN";; esac
101 case "$INST_CHMOD"   in '') CHMOD=chmod;;      *) CHMOD="$INST_CHMOD";; esac
102 case "$INST_DIRNAME" in '') DIRNAME=dirname;;  *) DIRNAME="$INST_DIRNAME";; esac
103 case "$INST_MKDIR"   in '') MKDIR=mkdir;;      *) MKDIR="$INST_MKDIR";; esac
104
105 # Allow the user to over-ride xx
106 case "$inst_dest"    in ?*) BIN_DIRECTORY="$inst_dest";; esac
107 case "$inst_conf"    in ?*) CONFIGURE_FILE="$inst_conf";; esac
108 case "$inst_info"    in ?*) INFO_DIRECTORY="$inst_info";; esac
109 case "$inst_aliases" in ?*) SYSTEM_ALIASES_FILE="$inst_aliases";; esac
110
111 # Insert ${DESTDIR} at the start of all paths so that the whole thing can be
112 # installed under a different file root. For backwards compatibility, use
113 # ${ROOT} if ${DESTDIR} is not set. However, we need to save the value of
114 # the real system aliases file, and use that in the default configuration.
115
116 ACTUAL_SYSTEM_ALIASES_FILE=${SYSTEM_ALIASES_FILE}
117 DESTDIR=${DESTDIR:-${ROOT}}
118
119 BIN_DIRECTORY=${DESTDIR}${BIN_DIRECTORY}
120 CONFIGURE_FILE=${DESTDIR}${CONFIGURE_FILE}
121 SYSTEM_ALIASES_FILE=${DESTDIR}${SYSTEM_ALIASES_FILE}
122
123 if [ "${INFO_DIRECTORY}" != "" ] ; then
124   INFO_DIRECTORY=${DESTDIR}${INFO_DIRECTORY}
125 fi
126
127 # Overrides of other things
128 case "$inst_uid"     in ?*) INST_UID="$inst_uid";; esac
129 case "$inst_cp"      in ?*) CP="$inst_cp";; esac
130 case "$inst_mv"      in ?*) MV="$inst_mv";; esac
131 case "$inst_ln"      in ?*) LN="$inst_ln";; esac
132 case "$inst_chown"   in ?*) CHOWN="$inst_chown";; esac
133 case "$inst_chmod"   in ?*) CHMOD="$inst_chmod";; esac
134 case "$inst_dirname" in ?*) DIRNAME="$inst_dirname";; esac
135 case "$inst_mkdir"   in ?*) MKDIR="$inst_mkdir";; esac
136
137 # chown is a special case; in at least one OS it is in /usr/etc instead
138 # of in /usr/bin, and therefore not likely to be on the path. Another OS
139 # has it in /usr/sbin. This fudge tries to cope with these variations.
140
141 # Otherwise, and for other commands, we assume that the normal PATH will
142 # give access to where they are on your operating system (normally /usr/bin
143 # or /bin).
144
145 if [ "${CHOWN}" = "chown" -a -x /usr/sbin/chown ] ; then
146   CHOWN=/usr/sbin/chown
147 fi
148
149 if [ "${CHOWN}" = "chown" -a ! -f /usr/bin/chown -a -f /usr/etc/chown ] ; then
150   CHOWN=/usr/etc/chown
151 fi
152
153 # The values of CHOWN and MV taken from the Makefile are sometimes set to
154 # "look_for_it", which causes a search of the usual suspects. This code is
155 # similar to that in exicyclog, but has to be fudged for upper/lower case
156 # distinctions.
157
158 for cmd in CHOWN MV ; do
159   eval "oldcmd=\$$cmd"
160   if [ "$oldcmd" != "look_for_it" ] ; then continue ; fi
161   if [ "$cmd" = "CHOWN" ] ; then cmdlc="chown" ; fi
162   if [ "$cmd" = "MV" ] ; then cmdlc="mv" ; fi
163   newcmd=$cmdlc
164   for dir in /bin /usr/bin /usr/sbin /usr/etc ; do
165     if [ -f $dir/$cmdlc ] ; then
166       newcmd=$dir/$cmdlc
167       break
168     fi
169   done
170   eval $cmd=$newcmd
171 done
172
173 # See if the exim monitor has been built
174
175 if [ -f eximon -a -f eximon.bin ]; then
176   exim_monitor="eximon eximon.bin"
177 fi
178
179 # If bin directory doesn't exist, try to create it
180
181 if [ ! -d "${BIN_DIRECTORY}" ]; then
182   echo mkdir -p ${BIN_DIRECTORY}
183   ${real} mkdir -p ${BIN_DIRECTORY}
184   if [ $? -ne 0 ]; then
185     echo $com ""
186     echo $com "*** Exim installation ${ver}failed ***"
187     exit 1
188   else
189     ${real} echo $com ${BIN_DIRECTORY} created
190   fi
191 fi
192
193 # If no arguments, install everything
194
195 if [ $# -gt 0 ]; then
196   set $@
197 else
198   set exim${EXE} ${exim_monitor} exim_dumpdb${EXE} exim_fixdb${EXE} \
199       exim_tidydb${EXE} exinext exiwhat exim_dbmbuild${EXE} exicyclog \
200       exigrep eximstats exipick exiqgrep exiqsumm exim_lock${EXE} \
201       exim_checkaccess exim_msgdate
202 fi
203
204 echo $com ""
205 echo $com Installation directory is ${BIN_DIRECTORY}
206 echo $com ""
207
208 while [ $# -gt 0 ]; do
209   name=$1
210   shift
211
212   if [ ! -s ${name} ]; then
213     echo $com ""
214     echo $com "*** `pwd`/${name} does not exist or is empty"
215     echo $com "*** Have you built Exim successfully?"
216     echo $com "*** Exim installation ${ver}failed ***"
217     exit 1
218   fi
219
220   # The exim binary is handled specially
221
222   if [ $name = exim${EXE} ]; then
223     exim="./exim -bV -C /dev/null"
224     version=exim-`$exim 2>/dev/null | \
225       awk '/Exim version/ { OFS=""; print $3,"-",substr($4,2,length($4)-1) }'`${EXE}
226
227     if [ "${version}" = "exim-${EXE}" ]; then
228       echo $com ""
229       echo $com "*** Could not run $exim to find version number ***"
230       echo $com "*** Exim installation ${ver}failed ***"
231       $exim
232       exit 1
233     fi
234
235     # Do something only if newer than existing file, or no existing file
236
237     if ../scripts/newer ${name} ${BIN_DIRECTORY}/${version}; then
238       echo ${CP} ${name} ${BIN_DIRECTORY}/${version}
239       ${real} ${CP} ${name} ${BIN_DIRECTORY}/${version}
240       if [ $? -ne 0 ]; then
241         echo $com ""
242         echo $com "*** Exim installation ${ver}failed ***"
243         exit 1
244       fi
245
246       # After copy, set ownership and permissions, unless disabled
247
248       if [ "$do_chown" != "no" ]; then
249         echo ${CHOWN} ${INST_UID} ${BIN_DIRECTORY}/${version}
250         ${real} ${CHOWN} ${INST_UID} ${BIN_DIRECTORY}/${version}
251         if [ $? -ne 0 ]; then
252           echo $com ""
253           echo $com "*** You must be ${INST_UID} to install exim ***"
254           exit 1
255         fi
256         echo ${CHMOD} a+x ${BIN_DIRECTORY}/${version}
257         ${real} ${CHMOD} a+x ${BIN_DIRECTORY}/${version}
258         if [ $? -ne 0 ]; then
259           echo $com ""
260           echo $com "*** Exim installation ${ver}failed ***"
261           exit 1
262         fi
263         echo ${CHMOD} u+s ${BIN_DIRECTORY}/${version}
264         ${real} ${CHMOD} u+s ${BIN_DIRECTORY}/${version}
265         if [ $? -ne 0 ]; then
266           echo $com ""
267           echo $com "*** Exim installation ${ver}failed ***"
268           exit 1
269         fi
270       else
271         echo $com "$CHOWN $INST_UID omitted: -no_chown was specified"
272         echo $com "$CHMOD u+s omitted: -no_chown was specified"
273       fi
274
275       # Now sort out the "exim" alias, unless NO_SYMLINK is set.
276
277       if [ "X$NO_SYMLINK" = "X" ] && [ "$do_symlink" != "no" ] ; then
278
279         #  First check whether "exim" exists in the directory.
280         if [ -f ${BIN_DIRECTORY}/exim ]; then
281
282           # If it's not a symbolic link, make a copy with the old version number
283           if [ `ls -l ${BIN_DIRECTORY}/exim | cut -c1-1` != 'l' ]; then
284             oldversion=exim-`${BIN_DIRECTORY}/exim -bV -C /dev/null | \
285               awk '/Exim version/ { OFS=""; print $3,"-",substr($4,2,length($4)-1) }'`${EXE}
286             if [ "${version}" = "${oldversion}" ] ; then
287               echo $com ""
288               echo $com "*** Existing file called exim has the same version and compile number ***"
289               echo $com "*** Exim installation ${ver}failed ***"
290               exit 1
291             fi
292             echo ${CP} ${BIN_DIRECTORY}/exim ${BIN_DIRECTORY}/${oldversion}
293             ${real} ${CP} ${BIN_DIRECTORY}/exim ${BIN_DIRECTORY}/${oldversion}
294             if [ $? -ne 0 ]; then
295               echo $com ""
296               echo $com "*** Exim installation ${ver}failed ***"
297               exit 1
298             fi
299           fi
300
301           # Now we can move the name "exim" to be a symbolic link to the new
302           # version, atomically.
303
304           echo \(cd ${BIN_DIRECTORY}\; ${LN} -s ${version} temporary_exim\)
305           (${real} cd ${BIN_DIRECTORY}; ${real} ${LN} -s ${version} temporary_exim)
306           if [ $? -ne 0 ]; then
307             echo $com ""
308             echo $com "*** Exim installation ${ver}failed ***"
309             exit 1
310           fi
311
312           echo ${MV} -f ${BIN_DIRECTORY}/temporary_exim ${BIN_DIRECTORY}/exim
313           ${real} ${MV} -f ${BIN_DIRECTORY}/temporary_exim ${BIN_DIRECTORY}/exim
314           if [ $? -ne 0 ]; then
315             echo $com ""
316             echo $com "*** Exim installation ${ver}failed ***"
317             exit 1
318           fi
319
320         # If "exim" does not already exist just create a symbolic link.
321
322         else
323           echo \(cd ${BIN_DIRECTORY}\; ${LN} -s ${version} exim\)
324           (${real} cd ${BIN_DIRECTORY}; ${real} ${LN} -s ${version} exim)
325           if [ $? -ne 0 ]; then
326             echo $com ""
327             echo $com "*** Exim installation ${ver}failed ***"
328             exit 1
329           fi
330         fi
331
332       else
333         echo $com "creation of symlink omitted"
334         if [ "X$NO_SYMLINK" != "X" ] ; then
335           echo $com "(NO_SYMLINK is specified in Local/Makefile)"
336         else
337           echo $com "(-no_symlink was specified)"
338         fi
339       fi
340
341     # New binary is not newer than the installed file
342
343     else
344       echo $com ${name} is not newer than ${BIN_DIRECTORY}/${version}
345     fi
346
347   # Handle everything other than the exim binary itself
348
349   else
350     if ../scripts/newer ${name} ${BIN_DIRECTORY}/${name}; then
351       if [ -f ${BIN_DIRECTORY}/${name} ]; then
352         echo ${CP} ${BIN_DIRECTORY}/${name} ${BIN_DIRECTORY}/${name}.O
353         ${real} ${CP} ${BIN_DIRECTORY}/${name} ${BIN_DIRECTORY}/${name}.O
354         if [ $? -ne 0 ]; then
355           echo $com ""
356           echo $com "*** Exim installation ${ver}failed ***"
357           exit 1
358         fi
359       fi
360       echo ${CP} ${name} ${BIN_DIRECTORY}
361       ${real} ${CP} ${name} ${BIN_DIRECTORY}
362       if [ $? -ne 0 ]; then
363         echo $com ""
364         echo $com "*** Exim installation ${ver}failed ***"
365         exit 1
366       fi
367     else
368       echo $com ${name} is not newer than ${BIN_DIRECTORY}/${name}
369     fi
370   fi
371
372 done
373
374
375
376 # If there is no configuration file, install the default, modifying it to refer
377 # to the configured system aliases file. If there is no setting for
378 # SYSTEM_ALIASES_FILE, use the traditional /etc/aliases. If the file does not
379 # exist, install a default (dummy) for that too.
380
381 # However, if CONFIGURE_FILE specifies a list of files, skip this code.
382
383 echo $com ""
384
385 if [ `expr -- "${CONFIGURE_FILE}" : ".*:"` -ne 0 ] ; then
386   echo $com Runtime configuration is specified as the following list:
387   echo $com ' ' ${CONFIGURE_FILE}
388   echo $com Therefore, skipping automatic installation.
389
390 elif [ ! -f ${CONFIGURE_FILE} ]; then
391   echo $com Installing default configuration in ${CONFIGURE_FILE}
392   echo $com because there is no existing configuration file.
393   if [ "${SYSTEM_ALIASES_FILE}" = "" ] ; then
394     SYSTEM_ALIASES_FILE=/etc/aliases
395     echo $com This configuration has system aliases in ${SYSTEM_ALIASES_FILE}.
396   fi
397
398   echo ${MKDIR} -p `${DIRNAME} ${CONFIGURE_FILE}`
399   ${real} ${MKDIR} -p `${DIRNAME} ${CONFIGURE_FILE}`
400
401   echo sed -e '\\'
402   echo "  \"/SYSTEM_ALIASES_FILE/ s'SYSTEM_ALIASES_FILE'${ACTUAL_SYSTEM_ALIASES_FILE}'\"" '\\'
403   echo "  ../src/configure.default > \${CONFIGURE_FILE}"
404
405   # I can't find a way of writing this using the ${real} feature because
406   # it seems that the output redirection always happens, even when -n was
407   # specified. So control it the hard way.
408
409   if [ "$real" = "" ] ; then
410     sed -e \
411       "/SYSTEM_ALIASES_FILE/ s'SYSTEM_ALIASES_FILE'${ACTUAL_SYSTEM_ALIASES_FILE}'" \
412       ../src/configure.default > ${CONFIGURE_FILE}
413   else
414     true
415   fi
416
417   if [ $? -ne 0 ]; then
418     echo $com ""
419     echo $com "*** Exim installation ${ver}failed ***"
420     exit 1
421   fi
422   if [ ! -f ${SYSTEM_ALIASES_FILE} ]; then
423     echo $com '****'
424     echo $com Installing a dummy ${SYSTEM_ALIASES_FILE} file because you do not have
425     echo $com one, and the default configuration requires it. You should
426     echo $com edit ${SYSTEM_ALIASES_FILE} and at least create an alias for postmaster.
427     echo $com '***'
428     echo ${CP} ../src/aliases.default ${SYSTEM_ALIASES_FILE}
429     ${real} ${CP} ../src/aliases.default ${SYSTEM_ALIASES_FILE}
430   fi
431
432 else
433   echo $com Configuration file ${CONFIGURE_FILE} already exists
434 fi
435
436 # Install info files if the directory is defined and the Texinfo
437 # source documentation is present.
438
439 if [ "${INFO_DIRECTORY}" != "" -a -f ../doc/spec.texinfo ] ; then
440   echo $com ""
441   if [ ! -d "${INFO_DIRECTORY}" ] ; then
442     echo mkdir -p ${INFO_DIRECTORY}
443     ${real} mkdir -p ${INFO_DIRECTORY}
444     if [ $? -ne 0 ]; then
445       echo $com ""
446       echo $com "*** Exim installation ${ver}failed ***"
447       exit 1
448     else
449       echo $com ${INFO_DIRECTORY} created
450     fi
451   fi
452
453   echo $com Info installation directory is ${INFO_DIRECTORY}
454   echo $com ""
455
456   ${real} makeinfo --no-split --output exim.info ../doc/spec.texinfo
457   echo ${CP} exim.info ${INFO_DIRECTORY}
458   ${real} ${CP} exim.info ${INFO_DIRECTORY}
459   ${real} install-info --section="Exim" \
460       --entry "* User guide: (exim).           Exim manual" \
461       ${INFO_DIRECTORY}/exim.info ${INFO_DIRECTORY}/dir
462   ${real} makeinfo --no-split --output exim_filter.info ../doc/filter.texinfo
463   echo ${CP} exim_filter.info ${INFO_DIRECTORY}
464   ${real} ${CP} exim_filter.info ${INFO_DIRECTORY}
465   ${real} install-info --section="Exim" \
466       --entry "* Filtering: (exim_filter).     Filtering mail with Exim" \
467       ${INFO_DIRECTORY}/exim_filter.info ${INFO_DIRECTORY}/dir
468 fi
469
470 # Everything OK
471
472 echo $com ""
473 echo $com Exim installation ${ver}complete
474
475 # End of exim_install