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