source: tags/confman-1.1/confman @ 102

Revision 102, 12.3 KB checked in by ccowart, 6 years ago (diff)

Bumped confman version.

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