source: tags/confman-1.0/confman @ 96

Revision 96, 12.4 KB checked in by ccowart, 6 years ago (diff)

Tagged confman-1.0 release.

  • Property rc:mode set to 0555
  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author 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 2>/dev/null ; 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                for layer in $LAYERS ; do
126                        conf_update_module $layer || conf_cleanexit
127                done
128                conf_update_module ${REPO_CHECKPTS} || conf_cleanexit
129        else
130                print_usage 1
131        fi
132}
133
134function revert {
135        if [ -z $* ] ; then
136                print_usage 1
137        else
138                conf_revert $*
139        fi
140}
141
142function commit {
143        if [ -z $* ] ; then
144                local msg=`mktemp -t confman`
145                # Moved up per Ian's request.
146                echo "Change this file to your log message." > $msg
147                ${EDITOR} $msg
148                update || conf_cleanexit
149
150                echo "Commit operation started" >&2
151                for layer in $LAYERS ; do
152                        conf_commit $layer $msg || return $?
153                done
154                for layer in $LAYERS ; do
155                        echo "Rolling on $layer..."
156                        conf_rollout $layer || return $?
157                done
158                for file in $SINGULARITIES ; do
159                        conf_assemble_sing $file || return $?
160                done
161                echo "Commit operation finished successfully" >&2
162                rm -f $msg
163
164        else
165                print_usage 1
166        fi
167}
168
169# Short name intentional, don't want collision with real install.
170function inst {
171        local file livefile
172
173        if [ -z "$*" ] ; then
174                print_usage 1
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                update || conf_cleanexit
184
185                echo "Installation operation started." >&2
186                for layer in $LAYERS ; do
187                        $DEBUG && echo "Layer: $layer" >&4
188                        conf_commit $layer $msg || return $?
189                        conf_install $layer $*
190                done
191                for file in $SINGULARITIES ; do
192                        conf_assemble_sing $file || conf_cleanexit
193                done
194                echo "Installation operation succeeded." >&2
195        fi
196}
197       
198
199function import {
200       
201        # Check for a force
202        local item OPTIND
203        force=0
204        while getopts "f" opt ; do
205                case $opt in
206                        f)
207                        force=1
208                        shift
209                        ;;
210                        *)
211                        print_help 1
212                        ;;
213                esac
214        done
215
216        local module=$1
217        local response usefile suffix file layer
218        local mode=$DEFAULT_MODE_FILE
219        local owner=$DEFAULT_OWNER
220        local group=$DEFAULT_GROUP
221        local comment=$DEFAULT_COMMENT
222        shift
223        if [ -z $1 ] ; then
224                print_usage 1
225        fi
226
227        if [ -r $1 ] ; then
228                file=`abspath $1`
229        else
230                # If we can't enter the parent directory, this will help us
231                # get the info we need.
232                file=`sudo abspath $1`
233        fi
234        shift
235
236
237        # See if we're importing a singularity
238        if [[ "$SINGULARITIES" =~ "$file" ]] ; then
239                suffix="-$module"
240        fi
241
242        # Error out when trying to import a symbolic link.
243        if sudo [ -L $file ] ; then
244                echo "$file is a symbolic link!" >&4
245                conf_cleanexit
246        fi
247
248        if [ -f ${WORK_PATH}/${module}${file}${suffix} ] ; then
249                echo "$file already exists in your working copy of $module." >&4
250                conf_cleanexit
251        fi
252
253        if [ $force = 0 ] ; then
254                for layer in $LAYERS ; do
255                        if [ -f ${WORK_PATH}/${layer}${file}${suffix} ] ; then
256                                echo "$file already exists in the ${layer}" \
257                                     "module." >&4
258                                echo "Did you mean -f ?" >&4
259                                conf_cleanexit
260                        fi
261                done
262        fi
263
264        if sudo [ -f $file ] ; then
265                eval `sudo stat -f "mode=%Mp%Lp owner=%Su group=%Sg" $file`
266                # Let's make our best guess on the comment character:
267                local tmpfile=`mktemp -t confman`
268                local biggestcount=0
269                local count
270
271                # Let's see if we can read the file as ourself:
272                usefile=`mktemp -t confman`
273                if [ ! -r $file ] ; then
274                        sudo cat $file > $usefile
275                else
276                        cat $file > $usefile
277                fi
278
279                # Put all non-alphanumerics into a file
280                awk '{print $1}' $usefile | egrep -o \
281                        "^[^-_A-Za-z0-9]" > $tmpfile
282
283                for char in `cat $tmpfile | sort | uniq` ; do
284                        count=`egrep -o "\\$char" $tmpfile | wc -l`
285                        if [ $count -gt $biggestcount ] ; then
286                                biggestcount=$count
287                                comment="$char"
288                        fi
289                done
290                rm $tmpfile
291
292                # Convert mode string to base 10:
293                mode=`echo "obase=10;ibase=8;$mode" | bc`
294                # And use a bitmask to subtract off all write-access
295                # 3949d = 7555o
296                mode=$(($mode & 3949))
297                # And back to an octet:
298                mode=`printf '%04o\n' $mode`
299        else
300                # Prompt for file owner
301                echo "Who should be the file's owner? [ $owner ]"
302                read response
303                if [ ! -z $response ] ; then
304                        owner=$response
305                fi
306
307                # And file's group
308                echo "Who should be the file's group? [ $group ]"
309                read response
310                if [ ! -z $response ] ; then
311                        group=$response
312                fi
313
314                # now, the permissions
315                echo "What should the file's permissions be? [ $mode ]"
316                read response
317                if [ ! -z $response ] ; then
318                        mode=$response
319                fi
320
321                # now, the comment character
322                echo "What string starts comment lines? [ $comment ]"
323                read response
324                if [ ! -z $response ] ; then
325                        comment=$response
326                fi
327        fi
328
329        if [ ! -d "${WORK_PATH}/${module}`dirname $file`" ] ; then
330                newdir "${WORK_PATH}/${module}`dirname $file`"
331        fi
332
333        # Time to generate the file
334        conf_gen_file $module "${file}${suffix}" $owner $group \
335                $mode "$comment" $usefile
336
337        # Removing temporary files
338        if [ -f $usefile ] ; then
339                rm $usefile
340        fi
341
342        # Are there more files to import?
343        if [ ! -z $1 ] ; then
344                import $module $*
345        fi
346
347}
348
349function remove {
350        if [ -z $1 ] ; then print_usage 1 ; fi
351        conf_rm_file $*
352}
353
354function newdir {
355        local dir=$1
356        local response module realpath
357        local mode=$DEFAULT_MODE_DIRECTORY
358        local owner=$DEFAULT_OWNER
359        local group=$DEFAULT_GROUP
360        local comment="dir"
361        local workdir=`abspath .`
362        if [ -z $1 ] ; then
363                print_usage 1
364        fi
365
366        # Find the "real" directory's path
367        if [[ ! $dir =~ "^\/" ]] ; then
368                dir="${workdir}/${dir}"
369        fi
370        module=`echo ${dir#$WORK_PATH} | sed -E 's:/([^/]+)/.*:\1:'`
371        realpath=${dir#${WORK_PATH}/${module}}
372
373        if [ -d $realpath ] ; then
374                eval `sudo stat -f "mode=%Mp%Lp owner=%Su group=%Sg" $realpath`
375
376                # Convert mode string to base 10:
377                mode=`echo "obase=10;ibase=8;$mode" | bc`
378                # And use a bitmask to subtract off all write-access
379                # 3949d = 7555o
380                mode=$(($mode & 3949))
381                # And back to an octet:
382                mode=`printf '%04o\n' $mode`
383        else
384                # Prompt for file owner
385                echo "Who should be the directory's owner? [ $owner ]"
386                read response
387                if [ ! -z $response ] ; then
388                        owner=$response
389                fi
390
391                # And file's group
392                echo "Who should be the directory's group? [ $group ]"
393                read response
394                if [ ! -z $response ] ; then
395                        group=$response
396                fi
397
398                # now, the permissions
399                echo "What should the directory's permissions be? [ $mode ]"
400                read response
401                if [ ! -z $response ] ; then
402                        mode=$response
403                fi
404        fi
405
406        # Time to create the directory.
407        echo "Making directory $dir with ${owner}:${group}, $mode"
408        conf_mkdir $dir $owner $group $mode
409}
410
411function list {
412        local file item
413        if [ -z $1 ] ; then
414                file=`abspath .`
415        else
416                file=`abspath $1`
417        fi
418        echo -e "--------------------------------------------------------"
419        echo -e "Mode\tOwner\tGroup\tComment\t\tFilename"
420        echo -e "--------------------------------------------------------"
421        if [ -f "$file" ] ; then
422                conf_list $file
423        elif [ -d "$file" ] ; then
424                for item in `ls $file` ; do
425                        conf_list "$file/$item"
426                done
427        fi
428}
429
430function status {
431        conf_status $*
432}
433
434function chowner {
435        local recursive item OPTIND
436        while getopts "R" opt ; do
437                case $opt in
438                        R)
439                        recursive=1
440                        shift
441                        ;;
442                        *)
443                        print_help 1
444                        ;;
445                esac
446        done
447        local owner=$1
448        local file=$2
449        conf_set_prop $file owner $owner
450        if [ ! -z $recursive ] && [ -d $file ] ; then
451                for item in $file/* ; do
452                        chowner -R $owner $item
453                done
454        fi
455}
456
457function chgroup {
458        local recursive item OPTIND
459        while getopts "R" opt ; do
460                case $opt in
461                        R)
462                        recursive=1
463                        shift
464                        ;;
465                        *)
466                        print_help 1
467                        ;;
468                esac
469        done
470        local group=$1
471        local file=$2
472        conf_set_prop $file group $group
473        if [ ! -z $recursive ] && [ -d $file ] ; then
474                for item in $file/* ; do
475                        chgroup -R $group $item
476                done
477        fi
478}
479
480function chmode {
481        local recursive item OPTIND
482        while getopts "R" opt ; do
483                case $opt in
484                        R)
485                        recursive=1
486                        shift
487                        ;;
488                        *)
489                        print_help 1
490                        ;;
491                esac
492        done
493        local mode=$1
494        local file=$2
495        conf_set_prop $file mode $mode
496        if [ ! -z $recursive ] && [ -d $file ] ; then
497                for item in $file/* ; do
498                        chmode -R $mode $item
499                done
500        fi
501}
502
503function chcom {
504        local comment="$1"
505        local file=$2
506        conf_set_prop $file comment "$comment"
507}
508
509function checklook {
510        local module=$1
511        local chkdir=${WORK_PATH}/${REPO_CHECKPTS}/${module}
512        if [ -z $1 ] ; then
513                print_usage 1
514        elif [ -d $chkdir ] ; then
515                ls $chkdir
516        else
517                echo "There are no checkpoints for ${module}."
518        fi
519}
520
521function checknew {
522        local module=$1
523        local checkpoint=$2
524        if [ -z $2 ] ; then
525                print_usage 1
526        else
527                conf_new_checkpoint $module $checkpoint
528        fi
529}
530
531function checkclear {
532        local module=$1
533        local checkpoint=$2
534        if [ -z $2 ] ; then
535                print_usage 1
536        else
537                conf_rm_checkpoint $module $checkpoint
538        fi
539}
540
541function rollback {
542        local module=$1
543        local checkpoint=$2
544        local clock=$3
545        if [ -z $2 ] ; then
546                print_usage 1
547        else
548                echo "Rolling $module back to $checkpoint $clock" >&2
549                conf_rollback $module $checkpoint $clock || conf_cleanexit
550                for layer in $LAYERS ; do
551                        echo "Rolling on $layer..."
552                        conf_rollout $layer || conf_cleanexit
553                done
554
555                for file in $SINGULARITIES ; do
556                        conf_assemble_sing $file || conf_cleanexit
557                done
558                echo "Rollback succeeded." >&2
559        fi
560}
561
562function rmmod {
563        local module=$1
564        if [ -z $module ] ; then
565                print_usage 1
566        fi
567        conf_rmmod $module
568}
569
570function diff {
571        conf_diff $*
572}
573
574function log {
575        conf_log $*
576}
577
578function copy {
579        local src=$1
580        local dest=$2
581
582        if [ -z $2 ] ; then print_usage 1 ; fi
583
584        conf_cp $src $dest
585}
586
587function move {
588        local src=$1
589        local dest=$2
590
591        if [ -z $2 ] ; then print_usage 1 ; fi
592
593        conf_mv $src $dest
594}
595
596# Dubug mode?
597while getopts "d" opt ; do
598        case $opt in
599                d)
600                DEBUG="true"
601                shift
602                ;;
603                *)
604                print_help 1
605                ;;
606        esac
607done
608
609
610# Dispatch the subcommand. This must happen last and in the global context.
611subcommand=$1
612shift
613case $subcommand in
614        help )
615                print_help $*
616                exit 0
617                ;;
618        setup|se* )
619                setup $*
620                ;;
621        status|st* )
622                status $*
623                ;;
624        create|cr* )
625                create $*
626                ;;
627        update|u* )
628                update $*
629                ;;
630        commit|com* )
631                commit $*
632                ;;
633        import|im* )
634                import $*
635                ;;
636        install|in* )
637                inst $*
638                ;;
639        remove|rem*|rm )
640                remove $*
641                ;;
642        rev* )
643                revert $*
644                ;;
645        rmmod )
646                rmmod $*
647                ;;
648        mkdir|mkd* )
649                newdir $*
650                ;;
651        list|ls )
652                list $*
653                ;;
654        move|mv )
655                move $*
656                ;;
657        copy|cp )
658                copy $*
659                ;;
660        diff )
661                diff $*
662                ;;
663        log )
664                log $*
665                ;;
666        chmod )
667                chmode $*
668                ;;
669        chown )
670                chowner $*
671                ;;
672        chcom )
673                chcom $*
674                ;;
675        chgrp )
676                chgroup $*
677                ;;
678        checklook|checklist|chls|chlk )
679                checklook $*
680                ;;
681        checknew|chnw )
682                checknew $*
683                ;;
684        checkclear|chcl|chrm )
685                checkclear $*
686                ;;
687        rollback|ro* )
688                rollback $*
689                ;;
690        * )
691                print_usage 1
692                ;;
693esac
694
695# We shouldn't be here.
696exit 1
697
Note: See TracBrowser for help on using the repository browser.