source: tags/confman-1.3.1/confman @ 111

Revision 111, 12.9 KB checked in by ccowart, 6 years ago (diff)

Rolling the next confman.

  • Property rc:mode set to 0555
  • Property svn:executable set to *
  • Property svn:keywords set to Id
Line 
1#! /bin/bash
2#
3# confman provides a command-line interface to Rescomp's server configuration
4# management system.
5#
6# confman --help
7#       Print help and usage information
8#
9# Author: Chris Cowart <ccowart@rescomp.berkeley.edu>
10# Date: 30 March 2006
11#
12# $Id$
13
14
15
16# Some global definitions. Defaults that can be overriden by options.
17GCONF="/usr/local/rescomp/etc/confman.conf"
18UCONF="${HOME}/.confmanrc"
19MYNAME=`basename $0`
20
21# First things first. Check to see if the logging fd is open. If it's not,
22# we re-spawn confman inside a pipe.
23if (true >&5) 2>/dev/null ; then
24        exec 4>&2 2>&5 >&3-
25else
26        exec 3>&1
27        exec $0 $* 5>&1 1>&3 | logger -t "$MYNAME ($USER)" -s
28        exit ${PIPESTATUS[0]}
29fi
30
31# Get the global config
32if [ -f $GCONF ] ; then
33        . $GCONF
34else
35        echo "Global config file couldn't be located" >&2
36        exit 1
37fi
38
39# Get the user config
40if [ -f $UCONF ] ; then
41        . $UCONF
42fi
43
44# Set debugging:
45if [ -z $DEBUG ] ; then
46        DEBUG="false"
47fi
48
49# Now, we source the library
50if [ -f $REPO_LIBRARY ] ; then
51        . $REPO_LIBRARY
52else
53        echo "Couldn't source the confman shell library" >&2
54        exit 1
55fi
56
57# And the documentation library
58if [ -f $REPO_DOCS ] ; then
59        . $REPO_DOCS
60else
61        echo "Couldn't source the confman shell library" >&2
62        exit 1
63fi
64
65# And we read in the layers that make this host
66if [ -f $RECIPE_PATH ] ; then
67        LAYERS=`cat $RECIPE_PATH | grep "^[^#]"`
68else
69        echo "Couldn't read the host's recipe!" >&2
70        exit 1
71fi
72
73# Set a default editor
74if [ -z ${EDITOR} ] ; then
75        if which vim >/dev/null 2>&1 ; then
76                EDITOR="vim"
77        else
78                EDITOR="vi"
79        fi
80fi
81
82# Let's make sure that only you can read your working copy
83# Have to make this less restrictive due to NFS home dirs.
84umask 022
85
86# And we'll set a trap:
87trap "conf_cleanexit" SIGINT SIGTERM
88
89
90# This function implements the setup subcommand. It is intended to be called
91# with no arguments, and will error if that's not the case.
92function setup {
93        local response
94        $DEBUG && echo "Running setup" >&4
95        if [ ! -z $* ] ; then
96                print_usage 1
97        elif [ -d ${WORK_PATH} ] ; then
98                echo "Looks like ${WORK_PATH} already exists."
99                echo "Start over by removing it? (y/N)"
100                read response
101                if [[ $response =~ '^[yY](es|ES)?' ]] ; then
102                        rm -rf ${WORK_PATH}
103                        setup
104                else
105                        echo "Setup failed." >&4
106                        exit 1
107                fi
108        else
109                conf_checkout_tree
110        fi
111}
112
113function create {
114        local module=$1
115        shift
116        if [ -z $* ] ; then
117                conf_create_module $module
118        else
119                print_usage 1
120        fi
121}
122
123function update {
124        if [ -z $* ] ; then
125                conf_update_tree || conf_cleanexit
126        else
127                print_usage 1
128        fi
129}
130
131function revert {
132        if [ -z $* ] ; then
133                print_usage 1
134        else
135                conf_revert $*
136        fi
137}
138
139function commit {
140        if [ -z $* ] ; then
141                local msg=`mktemp -t confman`
142                # Moved up per Ian's request.
143                echo "Change this file to your log message." > $msg
144                ${EDITOR} $msg
145                sudo -v
146                update || conf_cleanexit
147
148                echo "Commit operation started" >&2
149                for layer in $LAYERS ; do
150                        conf_commit $layer $msg || return $?
151                done
152                for layer in $LAYERS ; do
153                        echo "Rolling on $layer..."
154                        conf_rollout $layer || return $?
155                done
156                for file in $SINGULARITIES ; do
157                        conf_assemble_sing $file || return $?
158                done
159                echo "Commit operation finished successfully" >&2
160                rm -f $msg
161
162        else
163                print_usage 1
164        fi
165}
166
167# Short name intentional, don't want collision with real install.
168function inst {
169        local file livefile
170
171        if [ -z "$*" ] ; then
172                print_usage 1
173# This check is handled in the library. Calling on a non-existant file isn't
174# necessarily a syntax error.
175#       elif [ ! -e $1 ] ; then
176#               echo File $1 not found!
177#               print_usage 1
178        else
179                local msg=`mktemp -t confman`
180                # Moved up per Ian's request.
181                echo "Change this file to your log message." > $msg
182                ${EDITOR} $msg
183                sudo -v
184                update || conf_cleanexit
185
186                echo "Installation operation started." >&2
187                for layer in $LAYERS ; do
188                        $DEBUG && echo "Layer: $layer" >&4
189                        conf_commit $layer $msg || return $?
190                        conf_install $layer $*
191                done
192                for file in $SINGULARITIES ; do
193                        conf_assemble_sing $file || conf_cleanexit
194                done
195                echo "Installation operation succeeded." >&2
196        fi
197}
198       
199
200function import {
201       
202        # Check for a force
203        local item OPTIND
204        force=0
205        while getopts "f" opt ; do
206                case $opt in
207                        f)
208                        force=1
209                        shift
210                        ;;
211                        *)
212                        print_help 1
213                        ;;
214                esac
215        done
216
217        local module=$1
218        local response usefile suffix file layer
219        local mode=$DEFAULT_MODE_FILE
220        local owner=$DEFAULT_OWNER
221        local group=$DEFAULT_GROUP
222        local comment=$DEFAULT_COMMENT
223        shift
224        if [ -z $1 ] ; then
225                print_usage 1
226        fi
227
228        sudo -v
229        if [ -r $1 ] ; then
230                file=`abspath $1`
231        else
232                # If we can't enter the parent directory, this will help us
233                # get the info we need.
234                file=`sudo abspath $1`
235        fi
236        shift
237
238
239        # See if we're importing a singularity
240        if [[ "$SINGULARITIES" =~ "$file" ]] ; then
241                suffix="-$module"
242        fi
243
244        # Error out when trying to import a symbolic link.
245        if sudo [ -L $file ] ; then
246                echo "$file is a symbolic link!" >&4
247                conf_cleanexit
248        fi
249
250        if [ -f ${WORK_PATH}/${module}${file}${suffix} ] ; then
251                echo "$file already exists in your working copy of $module." >&4
252                conf_cleanexit
253        fi
254
255        if [ $force = 0 ] ; then
256                for layer in $LAYERS ; do
257                        if [ -f ${WORK_PATH}/${layer}${file}${suffix} ] ; then
258                                echo "$file already exists in the ${layer}" \
259                                     "module." >&4
260                                echo "Did you mean -f ?" >&4
261                                conf_cleanexit
262                        fi
263                done
264        fi
265
266        if sudo [ -f $file ] ; then
267                eval `sudo stat -f "mode=%Mp%Lp owner=%Su group=%Sg" $file`
268                # Let's make our best guess on the comment character:
269                local tmpfile=`mktemp -t confman`
270                local biggestcount=0
271                local count
272
273                # Let's see if we can read the file as ourself:
274                usefile=`mktemp -t confman`
275                if [ ! -r $file ] ; then
276                        sudo cat $file > $usefile
277                else
278                        cat $file > $usefile
279                fi
280
281                # Put all non-alphanumerics into a file
282                awk '{print $1}' $usefile | egrep -o \
283                        "^[^-_A-Za-z0-9]" > $tmpfile
284
285                for char in `cat $tmpfile | sort | uniq` ; do
286                        count=`egrep -o "\\$char" $tmpfile | wc -l`
287                        if [ $count -gt $biggestcount ] ; then
288                                biggestcount=$count
289                                comment="$char"
290                        fi
291                done
292                rm $tmpfile
293
294                # Convert mode string to base 10:
295                mode=`echo "obase=10;ibase=8;$mode" | bc`
296                # And use a bitmask to subtract off all write-access
297                # 3949d = 7555o
298                mode=$(($mode & 3949))
299                # And back to an octet:
300                mode=`printf '%04o\n' $mode`
301        else
302                # Prompt for file owner
303                echo "Who should be the file's owner? [ $owner ]"
304                read response
305                if [ ! -z $response ] ; then
306                        owner=$response
307                fi
308
309                # And file's group
310                echo "Who should be the file's group? [ $group ]"
311                read response
312                if [ ! -z $response ] ; then
313                        group=$response
314                fi
315
316                # now, the permissions
317                echo "What should the file's permissions be? [ $mode ]"
318                read response
319                if [ ! -z $response ] ; then
320                        mode=$response
321                fi
322
323                # now, the comment character
324                echo "What string starts comment lines? [ $comment ]"
325                read response
326                if [ ! -z $response ] ; then
327                        comment=$response
328                fi
329        fi
330
331        if [ ! -d "${WORK_PATH}/${module}`dirname $file`" ] ; then
332                newdir "${WORK_PATH}/${module}`dirname $file`"
333        fi
334
335        # Time to generate the file
336        conf_gen_file $module "${file}${suffix}" $owner $group \
337                $mode "$comment" $usefile
338
339        # Removing temporary files
340        if [ -f $usefile ] ; then
341                rm $usefile
342        fi
343
344        # Are there more files to import?
345        if [ ! -z $1 ] ; then
346                import $module $*
347        fi
348
349}
350
351function remove {
352        if [ -z $1 ] ; then print_usage 1 ; fi
353        conf_rm_file $*
354}
355
356function newdir {
357        local dir=$1
358        local response module realpath
359        local mode=$DEFAULT_MODE_DIRECTORY
360        local owner=$DEFAULT_OWNER
361        local group=$DEFAULT_GROUP
362        local comment="dir"
363        local workdir=`abspath .`
364        if [ -z $1 ] ; then
365                print_usage 1
366        fi
367
368        # Find the "real" directory's path
369        if [[ ! $dir =~ "^\/" ]] ; then
370                dir="${workdir}/${dir}"
371        fi
372        module=`echo ${dir#$WORK_PATH} | sed -E 's:/([^/]+)/.*:\1:'`
373        realpath=${dir#${WORK_PATH}/${module}}
374
375        if [ -d $realpath ] ; then
376                eval `sudo stat -f "mode=%Mp%Lp owner=%Su group=%Sg" $realpath`
377
378                # Convert mode string to base 10:
379                mode=`echo "obase=10;ibase=8;$mode" | bc`
380                # And use a bitmask to subtract off all write-access
381                # 3949d = 7555o
382                mode=$(($mode & 3949))
383                # And back to an octet:
384                mode=`printf '%04o\n' $mode`
385        else
386                # Prompt for file owner
387                echo "Who should be the directory's owner? [ $owner ]"
388                read response
389                if [ ! -z $response ] ; then
390                        owner=$response
391                fi
392
393                # And file's group
394                echo "Who should be the directory's group? [ $group ]"
395                read response
396                if [ ! -z $response ] ; then
397                        group=$response
398                fi
399
400                # now, the permissions
401                echo "What should the directory's permissions be? [ $mode ]"
402                read response
403                if [ ! -z $response ] ; then
404                        mode=$response
405                fi
406        fi
407
408        # Time to create the directory.
409        echo "Making directory $dir with ${owner}:${group}, $mode"
410        conf_mkdir $dir $owner $group $mode
411}
412
413function list {
414        local file item
415        if [ -z $1 ] ; then
416                file=`abspath .`
417        else
418                file=`abspath $1`
419        fi
420        echo -e "--------------------------------------------------------"
421        echo -e "Mode\tOwner\tGroup\tComment\t\tFilename"
422        echo -e "--------------------------------------------------------"
423        if [ -f "$file" ] ; then
424                conf_list $file
425        elif [ -d "$file" ] ; then
426                for item in `ls $file` ; do
427                        conf_list "$file/$item"
428                done
429        fi
430}
431
432function status {
433        conf_status $*
434}
435
436function chowner {
437        local recursive item OPTIND
438        while getopts "R" opt ; do
439                case $opt in
440                        R)
441                        recursive=1
442                        shift
443                        ;;
444                        *)
445                        print_help 1
446                        ;;
447                esac
448        done
449        local owner=$1
450        local file=$2
451        conf_set_prop $file owner $owner
452        if [ ! -z $recursive ] && [ -d $file ] ; then
453                for item in $file/* ; do
454                        chowner -R $owner $item
455                done
456        fi
457}
458
459function chgroup {
460        local recursive item OPTIND
461        while getopts "R" opt ; do
462                case $opt in
463                        R)
464                        recursive=1
465                        shift
466                        ;;
467                        *)
468                        print_help 1
469                        ;;
470                esac
471        done
472        local group=$1
473        local file=$2
474        conf_set_prop $file group $group
475        if [ ! -z $recursive ] && [ -d $file ] ; then
476                for item in $file/* ; do
477                        chgroup -R $group $item
478                done
479        fi
480}
481
482function chmode {
483        local recursive item OPTIND
484        while getopts "R" opt ; do
485                case $opt in
486                        R)
487                        recursive=1
488                        shift
489                        ;;
490                        *)
491                        print_help 1
492                        ;;
493                esac
494        done
495        local mode=$1
496        local file=$2
497        conf_set_prop $file mode $mode
498        if [ ! -z $recursive ] && [ -d $file ] ; then
499                for item in $file/* ; do
500                        chmode -R $mode $item
501                done
502        fi
503}
504
505function chcom {
506        local comment="$1"
507        local file=$2
508        conf_set_prop $file comment "$comment"
509}
510
511function checklook {
512        local module=$1
513        local chkdir=${WORK_PATH}/${REPO_CHECKPTS}/${module}
514        if [ -z $1 ] ; then
515                print_usage 1
516        elif [ -d $chkdir ] ; then
517                ls $chkdir
518        else
519                echo "There are no checkpoints for ${module}."
520        fi
521}
522
523function checknew {
524        local module=$1
525        local checkpoint=$2
526        if [ -z $2 ] ; then
527                print_usage 1
528        else
529                conf_new_checkpoint $module $checkpoint
530        fi
531}
532
533function checkclear {
534        local module=$1
535        local checkpoint=$2
536        if [ -z $2 ] ; then
537                print_usage 1
538        else
539                conf_rm_checkpoint $module $checkpoint
540        fi
541}
542
543function rollback {
544        local module=$1
545        local checkpoint=$2
546        local clock=$3
547        if [ -z $2 ] ; then
548                print_usage 1
549        else
550                echo "Rolling $module back to $checkpoint $clock" >&2
551                conf_rollback $module $checkpoint $clock || conf_cleanexit
552                for layer in $LAYERS ; do
553                        echo "Rolling on $layer..."
554                        conf_rollout $layer || conf_cleanexit
555                done
556
557                for file in $SINGULARITIES ; do
558                        conf_assemble_sing $file || conf_cleanexit
559                done
560                echo "Rollback succeeded." >&2
561        fi
562}
563
564function rmmod {
565        local module=$1
566        if [ -z $module ] ; then
567                print_usage 1
568        fi
569        conf_rmmod $module
570}
571
572function rename {
573        local oldmod=$1
574        local newmod=$2
575        if [ -z $newmod ] ; then
576                print_usage 1
577        fi
578        if [ ! -d "${WORK_PATH}/${oldmod}" ] ; then
579                echo "${MYNAME}: Error: ${WORK_PATH}/${oldmod} doesn't exist" >&4
580                conf_cleanexit
581        fi
582        if [ -e "${WORK_PATH}/${newmod}" ] ; then
583                echo "${MYNAME}: Error: ${WORK_PATH}/${newmod}: file exists" >&4
584                conf_cleanexit
585        fi
586        conf_rename $oldmod $newmod
587}
588
589function diff {
590        conf_diff $*
591}
592
593function log {
594        conf_log $*
595}
596
597function copy {
598        local src=$1
599        local dest=$2
600
601        if [ -z $2 ] ; then print_usage 1 ; fi
602
603        conf_cp $src $dest
604}
605
606function move {
607        local src=$1
608        local dest=$2
609
610        if [ -z $2 ] ; then print_usage 1 ; fi
611
612        conf_mv $src $dest
613}
614
615# Dubug mode?
616while getopts "d" opt ; do
617        case $opt in
618                d)
619                DEBUG="true"
620                shift
621                ;;
622                *)
623                print_help 1
624                ;;
625        esac
626done
627
628
629# Dispatch the subcommand. This must happen last and in the global context.
630subcommand=$1
631shift
632case $subcommand in
633        help )                                                  print_help $* ; exit 0 ;;
634        setup|se* )                                             setup $* ;;
635        status|st* )                                    status $* ;;
636        create|cr* )                                    create $* ;;
637        update|u* )                                             update $* ;;
638        commit|com* )                                   commit $* ;;
639        import|im* )                                    import $* ;;
640        install|in* )                                   inst $* ;;
641        remove|rem*|rm )                                remove $* ;;
642        rev* )                                                  revert $* ;;
643        ren* )                                                  rename $* ;;
644        rmmod )                                                 rmmod $* ;;
645        mkdir|mkd* )                                    newdir $* ;;
646        list|ls )                                               list $* ;;
647        move|mv )                                               move $* ;;
648        copy|cp )                                               copy $* ;;
649        diff )                                                  diff $* ;;
650        log )                                                   log $* ;;
651        chmod )                                                 chmode $* ;;
652        chown )                                                 chowner $* ;;
653        chcom )                                                 chcom $* ;;
654        chgrp )                                                 chgroup $* ;;
655        checklook|checklist|chls|chlk ) checklook $* ;;
656        checknew|chnw )                                 checknew $* ;;
657        checkclear|chcl|chrm )                  checkclear $* ;;
658        rollback|ro* )                                  rollback $* ;;
659        * )                                                             print_usage 1 ;;
660esac
661
662# We shouldn't be here.
663exit 1
664
665# vim:ts=4
666
Note: See TracBrowser for help on using the repository browser.