config_language: rely on console-setup for keyboard + font handling
[grml-autoconfig.git] / bin / save-config
1 #!/bin/zsh
2 # Filename:      save-config
3 # Purpose:       generate grml configuration archive and store it anywhere
4 # Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
5 # Bug-Reports:   see http://grml.org/bugs/
6 # License:       This file is licensed under the GPL v2.
7 ################################################################################
8
9 # some zsh-stuff {{{
10   autoload colors ; colors
11   setopt nonomatch
12   . /etc/grml/sh-lib
13   . /etc/grml/script-functions
14 # }}}
15
16 # set variables  {{{
17   LANG=C
18   LC_ALL=C
19   [[ $UID != 0 ]] && runas='sudo' # important for /etc
20
21   if [ -d /lib/live/mount/overlay ] ; then # since around December 2012
22     CHANGE_DIR='/lib/live/mount/overlay'
23   elif [ -d /live/overlay ] ; then  # until around December 2012
24     CHANGE_DIR='/live/overlay'
25   elif [ -d /live/image ] ; then # old version
26     CHANGE_DIR='/live/image'
27   else
28     echo "Error: no overlay directories found (like /lib/live/mount/overlay or /live/overlay)." >&2
29     bailout; exit 1
30   fi
31
32   if [ -d /live/rofs ] ; then
33     ORIG_DIR="$(find /live/rofs/ -maxdepth 1 -name \*.squashfs | head -1)"
34   else # old version
35     ORIG_DIR="/GRML"
36   fi
37
38   check4progs mutt &>/dev/null || echo "Warning, mutt not available for mail handling.">&2
39   check4progs tar || { echo "Sorry, can't continue. Exiting.">&2 ; bailout ; exit 1 }
40
41   CONFIG=/etc/grml/saveconfig
42   [ -r "$CONFIG" ] && . $CONFIG
43
44   PROGRAMNAME=${0##*/}
45   HOSTNAME=$(hostname)
46   DATE=$(date)
47   GRML_VERSION=$(awk '{print $1}' /etc/grml_version 2>/dev/null || print "not a grml system")
48   KERNEL=$(uname -a)
49
50   TMPDIR='/tmp'
51   MAILFILE="${TMPDIR}/mail.txt"
52
53   [ -n "$FILELIST" ] || FILELIST=$(mktemp $TMPDIR/filelist.XXXXXX)
54 # }}}
55
56 # functions {{{
57 debug(){
58   if [[ $DEBUG -gt 0 ]] ; then
59     echo "debug: $*"
60   fi
61 # setopt xtrace
62 # set -x
63 }
64
65 bailout(){
66   rm -f "$FILELIST"
67   rm -f "$MAILFILE"
68 }
69
70 trap bailout 1 2 3 15
71
72 findchanged() {
73   if [ -d "$1" ]; then
74     for i in `(cd "$1"; find . -type f 2>/dev/null | sed 's,^\./,,g' | grep -v ' ' )`; do
75       cmp -s "$1/$i" "$2/$i" || echo "$1/$i"
76     done
77   elif [ -e "$1" ]; then
78     cmp -s "$1" "$2" || echo "$1"
79   fi
80 }
81 # }}}
82
83 # usage information {{{
84 usage()
85 {
86   print 1>&2 "
87 $bg[black]$fg[green]${boldcolor}${PROGRAMNAME} - save configuration of grml system${reset_color}
88
89 $bg[black]$fg[blue]${boldcolor}Usage:${reset_color}
90   $PROGRAMNAME [-target_options] -{all,home,etc,configdir}
91
92 $bg[black]$fg[blue]${boldcolor}Target options:${reset_color}
93   -ssh user@host:/path/to/file  copy configuration via ssh/scp to remote host
94   -mail <recipient>             send configuration via mail
95   -file foo_bar_config.tbz      save configuration in specified file
96
97   Notice: if no option is specified the default is assumed:
98           create file config.tbz in current directory
99
100 $bg[black]$fg[blue]${boldcolor}Files-to-store options:${reset_color}
101   -home                         store hidden files from \$HOME (\$HOME/.*)
102   -grmlhome                     store hidden files from \$HOME (\$HOME/.*) of user grml [use as user root]
103   -etc                          store modified files from /etc
104   -configdir                    store \$HOME/config
105   -all                          store all configuration files (:= -home, -configdir and -etc)
106
107   Notice: it is also possible to use environment variables:
108           \$SAVE_HOME, \$SAVE_GRMLHOME, \$SAVE_ETC, \$SAVE_CONFIGDIR and \$SAVE_ALL
109
110 $bg[black]$fg[blue]${boldcolor}Usage examples:${reset_color}
111   $PROGRAMNAME -all                                  => store all configuration files in config.tbz in current dir
112   $PROGRAMNAME -home -mail  devnull@grml.org         => store \$HOME/.* in config.tbz and send it via mail
113   $PROGRAMNAME -etc  -ssh   devnull@grml.org:/path/  => store /etc in config.tbz and scp it to specified host
114   $PROGRAMNAME -all  -file  foo.tbz                  => store all configuration files in foo.tbz
115   SAVE_ALL=yes $PROGRAMNAME -file /path/foo.tbz      => store all configuration files in /path/foo.tbz
116
117 More information on save-config can be found in the manual page: man save-config
118
119 See also: restore-config(1), bootoptions: myconfig=/dev/ice, extract=PATH,
120           netconfig=server.tld/path/to/config.tbz
121
122 Report bugs, send wishes and feedback to the grml team:
123 http://grml.org/bugs/ - contact (at) grml.org
124 "
125 }
126 # }}}
127
128 # what do we want to store? {{{
129 save_home(){
130   debug "save home"
131   for i in $HOME/.* ; do findchanged "$i" /etc/skel/$(basename "$i"); done >> $FILELIST
132   debug "debug: $FILELIST"
133 }
134
135 save_grmlhome(){
136   debug "save grmlhome"
137   if [ -d /home/grml/ ] ; then
138      for i in /home/grml/.* ; do findchanged "$i" /etc/skel/$(basename "$i"); done >> $FILELIST
139   fi
140   debug "debug: $FILELIST"
141 }
142
143 save_etc(){
144   debug "save etc"
145   if [ -n "$NEWLAYOUT" ] ; then
146      $runas find "${CHANGE_DIR}/etc" | sed -e "s#${CHANGE_DIR}## ; /etc$/d" >> $FILELIST
147   else
148      $runas findchanged /etc "${ORIG_DIR}/etc" >> $FILELIST
149   fi
150 }
151
152 save_configdir(){
153   debug "save configdir"
154   if [ -d $HOME/config ] ; then
155      ls $HOME/config/*  >> $FILELIST 2>/dev/null
156      ls $HOME/config/.* >> $FILELIST 2>/dev/null
157   fi
158 }
159 # }}}
160
161 # create configuration file {{{
162 create_config(){
163   if ! [ -r "$FILELIST" ]; then
164     echo "Filelist $FILELIST could not be read." >&2
165     echo "Error when generating $FILENAME." >&2
166     bailout ; exit 1
167   else
168     # GNU tar sucks so much, really. Avoid the "file changed as we read it":
169     tar cf /dev/null /etc
170     # now really execute the according tar command:
171     if BZIP2=-9 $runas tar -T - -cpPjf "$FILENAME" <"$FILELIST" ; then
172       echo "Successfully stored configuration in file $FILENAME"
173     else
174       echo "Error when generating $FILENAME." >&2
175       bailout ; exit 1
176     fi
177   fi
178 }
179 # }}}
180
181 # commandline parsing {{{
182 parse_options()
183 {
184    zparseopts -K -- help=o_help mail:=o_mail \
185                     file:=o_file home=o_home grmlhome=o_grmlhome etc=o_etc \
186                     configdir=o_configdir all=o_all ssh:=o_ssh
187
188    if [[ "$#" == 0 || "$o_help" != "" || "$1" == '-h' || "$1" == '--help' ]]; then
189       usage ; exit
190    fi
191
192    if [[ "$o_file" != "" ]]; then
193      FILENAME="$o_file[2]"
194    else
195      FILENAME="config.tbz"
196    fi
197
198    if [[ "$o_home" != "" ]]; then
199       debug "home is set"
200       SAVE_HOME="yes"
201    fi
202
203    if [[ "$o_grmlhome" != "" ]]; then
204       debug "grmlhome is set"
205       SAVE_GRMLHOME="yes"
206    fi
207
208    if [[ "$o_etc" != "" ]]; then
209       debug "etc is set"
210       SAVE_ETC="yes"
211    fi
212
213    if [[ "$o_configdir" != "" ]]; then
214       debug "configdir is set"
215       SAVE_CONFIGDIR="yes"
216    fi
217
218    if [[ "$o_all" != "" ]]; then
219       debug "home, grmlhome, etc and configdir are set"
220       SAVE_HOME="yes"
221       SAVE_GRMLHOME="yes"
222       SAVE_ETC="yes"
223       SAVE_CONFIGDIR="yes"
224    fi
225
226    if [[ "$o_ssh" != "" ]]; then
227       debug "scp $FILENAME $o_ssh[2]"
228       scp $FILENAME $o_ssh[2]
229    fi
230
231    if [[ "$o_mail" != "" ]]; then
232       check4progs mutt || { echo "Sorry, mutt not available for sending mail. Exiting.">&2 ; exit 1 }
233       recipient=$o_mail[2]
234       debug "send mail to $recipient"
235       echo "Created on $DATE on host $HOSTNAME running grml $GRML_VERSION" > $MAILFILE
236       mutt -s "configuration of $HOSTNAME ($DATE)" -a $FILENAME $recipient < $MAILFILE
237    fi
238 }
239 parse_options $*
240 # }}}
241
242 # execution wrapper {{{
243 runit(){
244    if [[ $SAVE_HOME == "yes" ]]; then
245      debug "running save_home"
246      save_home
247      SETSAVE=1
248    fi
249    if [[ $SAVE_GRMLHOME == "yes" ]]; then
250      debug "running save_grmlhome"
251      save_grmlhome
252      SETSAVE=1
253    fi
254    if [[ $SAVE_ETC == "yes" ]] ; then
255      debug "running save_etc"
256      save_etc
257      SETSAVE=1
258    fi
259    if [[ $SAVE_CONFIGDIR == "yes" ]] ; then
260      debug "running save_configdir"
261      save_configdir
262      SETSAVE=1
263    fi
264    if [ -z $SETSAVE ] ; then
265      echo "Sorry, you did not select any configuration which should be saved. Exiting."
266      bailout ; exit 1
267    fi
268 }
269 # }}}
270
271 # now run it
272   runit
273   create_config
274   bailout
275
276 ## END OF FILE #################################################################
277 # vim:foldmethod=marker