#!/bin/bash # ################################################################################ # Unix Tools / Homework assignment number 3 # # # # simplestore maintains a database of elements # # # ###############################################################################/ # FUNCTIONS ########### tokenize(){ ########## SPLITS KEY TO ITS COMPONENTS PUT IN ARRAY key2=$1; i=0; unset key_comp; if [ -z "$key2" ]; then # NO KEY WAS PROVIDED return 0 fi keypath=`echo "$key2" | sed 's/\(.*\)\/.*/\1/'` echo "$key2" | grep -v '/' > /dev/null && key_comp[i]=$key2 echo "$key2" | grep '/' > /dev/null while [ $? -eq 0 ] ; do component=`echo "$key2" | sed 's/\([^/]*\)\/.*/\1/'` temp=`echo "$key2" | sed 's/[^/]*\/\(.*\)/\1/'` key2=$temp key_comp[i]=$component i=$(( i+1)) echo "$key2" | grep '/' > /dev/null if [ $? -gt 0 ] ; then key_comp[i]=$key2 break fi done last=$((${#key_comp[@]})) l=0 # CHECK IF CONSECUTIVE SLASHES IN KEY while [ "$l" -lt "$last" ]; do # THAT'S AN ILLEGAL KEY if [ ${#key_comp[l]} -eq 0 ]; then echo "ILLEGAL KEY. CANNOT HAVE A SLASH IN THE KEY NAME" >&2 exit 1 fi l=$((l+1)) done s1=$((last-1)) file=${key_comp[s1]} return $last } ################################################################################ isint() ##### CHECKS IF A NUMBER IS AN INTEGRER. RETURNS 0 IF IT IS { num="$1" if [ -z "$num" ] ; then # CHECK FOR NULL INPUT return 1 fi if [ "${num%${num#?}}" = "-" ] ; then # CHECK NEGATIVE stripval="${num#?}" # STRIP OFF FIRST CHAR else stripval="$num" fi if [ -z "$stripval" ] ; then # CHECK FOR NULL INPUT return 1 fi otherthandig="$(echo $stripval | sed 's/[0-9]//g')" if [ ! -z "$otherthandig" ] ; then # NOT A DIGIT return 1 fi return 0 # VALID INTEGER } ################################################################################ permission1(){ ########### RULES: IF YOU ARE THE OWNER OF THE DB (DIR) AND YOU HAVE w and x ########### OR IF YOU ARE IN THE GROUP AND THE GROUP HAS w and x, OR ########### IF YOU BELONG TO "other" AND OTHER HAS w and x ########### ==> WRITING KEY IS PERMITTED, OTHERWISE IT IS PROHIBITED ### FIRST GET TO THE DIRECTORY, TO WHICH THE KEY IS ATTEMPTED TO BE WRITTEN last_dir=$((last-1)); k1=0 while [ "$k1" -lt "$last_dir" ]; do if [ ! -d "${key_comp[k1]}" ]; then # IF NEW DIR, STOP break fi cd "${key_comp[k1]}" k1=$((k1+1)) done perm=`ls -ld` perm_string=$(echo "$perm" | sed 's/\(.\{10\}\).*/\1/') dbuser=$(echo "$perm" | cut -d" " -f5) dbgroup=$(echo "$perm" | cut -d" " -f8) owner_w=$(echo "$perm_string" | awk '{print substr($0,3,1)}') owner_x=$(echo "$perm_string" | awk '{print substr($0,4,1)}') group_w=$(echo "$perm_string" | awk '{print substr($0,6,1)}') group_x=$(echo "$perm_string" | awk '{print substr($0,7,1)}') other_w=$(echo "$perm_string" | awk '{print substr($0,9,1)}') other_x=$(echo "$perm_string" | awk '{print substr($0,10,1)}') if [ "$USER" = "$dbuser" -a "$owner_w" = "w" -a "$owner_x" = "x" ] || [ "$GROUP" = "$dbgroup" -a "$group_w" = "w" -a "$group_x" = "x" ] || [ "$other_w" = "w" -a "$other_x" = "x" ] then cd ~/.simplestore # BECAUSE THIS FUNCTION CHG THE CURR. DIR return 0 # WE SWAP IT BACK TO 'HOME' # else # return 1 else ### PERHAPS PERMISSIONS ARE TOO STRICT cd ~/.simplestore # BECAUSE THIS FUNCTION CHG THE CURR. DIR return 0 # WE SWAP IT BACK TO 'HOME' fi } ################################################################################ write(){ ##### WRITING A KEY TO THE DB (ADD/REPLACE) # VALIDATE THAT THE KEY NAME AND VALUE WERE GIVEN EITHER THRU THE ARGS OR STDIN if [ -z "$1" ]; then echo "NO KEY SPECIFIED" >&2 exit 1 fi key=`echo "$1" | sed 's/[^/]*\/\(.*\)/\1/'` # DROP COMPONENT SID if [ -n "$2" ]; then value=$2 else echo "PLEASE PROVIDE VALUE FOR KEY AND HIT ENTER AFTER EVERY LINE,\ WHEN DONE HOLD DOWN KEY AND HIT d" value=`cat /dev/stdin` # STANDARD INPUT if [ ${#value} -eq 0 ]; then echo "NO VALUE PROVIDED FOR KEY" >&2 exit 1 fi fi tokenize "$key" cd ~/.simplestore if [ $last -lt 2 ]; then # SINGLE COMPONENT KEY if [ -f "$key" ]; then if permission1 ; then # CHECK PERMISSIONS echo "$value" > "$key" # REPLACE EXISTING KEY return 0 else echo " YOU HAVE NO PERMISSION TO WRITE THIS KEY" >&2 exit 1 fi elif [ -d "$key" ]; then echo " CANNOT USE A KEY THAT IS SHORTER THAN EXISTING KEY" >&2 exit 1 else # ATTEMPT TO WRITE BRAND NEW KEY # CHECK PERMISSIONS if permission1 ; then echo "$value" > "$key" return 0 else echo " YOU HAVE NO PERMISSION TO WRITE THIS KEY" >&2 exit 1 fi fi else # KEY WITH MULTIPLE COMPONENTS if [ -f "$key" ]; then # CHECK PERMISSION TO WRITE if permission1 ; then echo "$value" > "$key" # REPLACE EXISTING KEY return 0 else echo " YOU HAVE NO PERMISSION TO REPLACE THIS KEY" exit 1 fi elif [ -d "$key" ]; then # IF KEY IS EXISTING DIRECTORY, LONGER KEY EXISTS echo "CANNOT USE A KEY THAT IS SHORTER THAN EXISTING KEY" >&2 exit 1 else ## KEY DOES NOT EXIST, CHECK IF USED IN EXISTING KEY AS A PREFIX j=0; last_dir=$((last-1)); found=1; sub_key=${key_comp[0]} while [ $j -le $last_dir ]; do if [ -f "$sub_key" ]; then found=0 break else j=$((j+1)) sub_key=`echo "$sub_key""/""${key_comp[j]}"` fi done if [ $found -eq 0 ]; then echo "CANNOT USE KEY THAT IS LONGER THAN EXISTING KEY" exit 1 else # CHECK PERMISSIONS if permission1 ; then # ADD NEW KEY (BY BUILDING THE STRUCTURE & WRITING THE KEY) cd ~/.simplestore j=0 while [ $j -lt $last_dir ]; do ## CHECK IF SUB-DIRECTORY EXIST ONLY AT CURRENR DIRECTORY dirrs=`find * -name "${key_comp[j]}" -type d -print -o -type d -prune\ | wc -l` if [ $dirrs -eq 0 ]; then mkdir "${key_comp[j]}" ## IF IT DOESN'T EXIST, MAKE IT fi cd "${key_comp[j]}" j=$((j+1)) done ## i.e a/b/c/d ==> last=4, last_dir=3, array last dir=2 echo "$value" > "$file" # WRITE NEW KEY (FILE) return 0 else echo " YOU HAVE NO PERMISSION TO WRITE THIS KEY" >&2 exit 1 fi fi fi fi # END MULTIPLE COMPONENT PROCESSING return 0 } ################################################################################ delete(){ ##### GETS ONE PARM: KEY TO DELETE keydel=`echo "$1" | sed 's/[^/]*\/\(.*\)/\1/'` # DROP COMPONENT SID tokenize "$keydel" cd ~/.simplestore if [ "$last" -eq 1 ]; then # KEY HAS ONE COMPONENT rows_found=`find . -name "$keydel" \( -type f -o -type d \) | wc -l` if [ $rows_found -ne 0 ]; then cd ~/.simplestore rm -rf "$keydel" return 0 else echo "KEY: $1 DOES NOT EXIST" >&2 exit 1 fi else # MULTI COMPONENT KEY rows_found=`find . -type f -name "$file" | wc -l` if [ $rows_found -gt 0 ]; then cd "$keypath" if [ $? -eq 0 ]; then rm "$file" return 0 else echo "KEY: $1 DOES NOT EXIST" >&2 exit 1 fi else # CHECK IF A PREFIX rows_found=`find . -type d -name "$file" | wc -l` if [ $rows_found -gt 0 ]; then rm -rf "$key" # DROP PREFIX AND ITS KEYS return 0 else echo "KEY: $1 DOES NOT EXIST" >&2 exit 1 fi fi fi return 0 } ################################################################################ lookup(){ ###### LIST KEY VALUE, OR LIST OF KEY ELEMENTS default=$2 exists=1 key=`echo "$1" | sed 's/[^/]*\/\(.*\)/\1/'` # DROP COMPONENT SID tokenize "$key" cd ~/.simplestore if [ $last -lt 2 ]; then # SINGLE COMPONENT KEY kf=`find . -type f -name "$key" | sed 's/\.\///'` if [ -n "$kf" ]; then cat "$kf" return 0 else kd=`find . -type d -name "$key" | head -1 | sed 's/\.\///'` if [ -n "$kd" ]; then if [ "$kd" = "$key" ]; then cd "$key" for compo in * ; do echo "$compo" done return 0 else echo "YOU HAVE ENTERED A PARTIAL KEY, PLEASE CORRECT" fi else if [ -z "$default" ]; then echo "KEY DOES NOT EXIST" >&2 # NO DEFAULT PROVIDED exit 1 else echo "$default" return 0 fi fi fi else # MULTI-COMPONENT KEY last_comp=$file kf=`find . -type f -name "$file" | sed 's/\.\///'` kd=`find . -type d -name "$file" | grep "$key" | sort -r | head -1 | sed 's/\.\///'` if [ -z "$kf" ] && [ -z "$kd" ] && [ -z "$default" ]; then echo "KEY DOES NOT EXIST" >&2 exit 1 fi if [ ${#kf} -gt 0 ]; then # DISPLAY FILE CONTENT (KEY VALUE) cd $keypath cat "$file" return 0 elif [ ${#kd} -gt 0 ]; then # PREFIX (LIST ALL KEYS FOR IT) cd "$key" for compo in * ; do echo "$compo" done return 0 else exists=0 # NO SUCH KEY OR PREFIX FOR A KEY fi if [ $exists -eq 0 ]; then if [ -n $default ]; then echo "$default" exit 1 fi fi fi return 0 } ################################################################################ increment(){ amount=$2 keyinc=`echo "$1" | sed 's/[^/]*\/\(.*\)/\1/'` # DROP COMPONENT SID if [ -z "$keyinc" ]; then echo "KEY TO INCREMENT HAS NOT BEEN PROVIDED" >&2 exit 1 fi if [ -n "$amount" ]; then # IF AMOUNT PROVIDED IT MUST BE INTEGER isint $amount if [ $? -ne 0 ]; then echo "VALUE ARGUMENT NOT INTEGER" >&2 exit 1 fi fi fullpath=`echo ~/.simplestore/"$keyinc"` if [ -f "$fullpath" ]; then stored=`cat "$fullpath"` isint $stored if [ $? -ne 0 ]; then echo "STORED VALUE NOT INTEGER" >&2 exit 1 else new_val=$((stored+amount)) echo "$new_val" > "$fullpath" return 0 fi else ### KEY TO INCREMENT DOES NOT EXIST; TRY TO CREATE IT WITH ### THE FUNCTION WRITE, AND VALUE OF ZERO AS A DEFAULT write "$1" 0 fi return 0 } ################################################################################ import(){ while read line; do key1="" value1="" key1=`echo $line | sed 's/\([^,]*\).*/\1/'` value1=`echo $line | sed 's/[^,]*,\(.*\)/\1/'` # key2=`echo "$key1" | sed 's/[^/]*\/\(.*\)/\1/'` # DROP COMPONENT SID if [ ${#key1} -eq 0 -o ${#value1} -eq 0 ]; then # KEY OR VALUE MISSING echo " BAD INPUT FOR IMPORT " exit 1 fi write "$key1" "$value1" done } ################################################################################ export(){ key1="$1" if [ -n "$key1" -a ! -f "$key1" -a ! -d "$key1" ]; then echo " CANNOT EXPORT, KEY DOES NOT EXIST" exit 1 fi if [ -z "$key1" ]; then # DEFAULT IS ROOT, EXPORT ALL KEYS (WHEN NO KEY) cd ~/.simplestore list=$(find . -type f | sed 's/\.\///') elif [ -f "$key1" ]; then line1=$(echo "$key1,"$(cat "$key1")) if [ ${#line1} -gt 80 ]; then # RESTRICT OUTPUT LINE TO 80 CHARS o_line=$(echo "$line1" | awk '{print substr($0,1,80)}') else o_line=$(echo "$line1") fi printf "%-80s\n" "$o_line" exit 0 elif [ -d "$key1" ]; then list=`find "$key1" -type f` fi for ln in $list; do value1=`cat $ln` line1=$(echo "$ln,"$(cat "$ln")) if [ ${#line1} -gt 80 ]; then o_line=$(echo "$line1" | awk '{print substr($0,1,80)}') else o_line=$(echo "$line1") fi printf "%-80s\n" "$o_line" done return 0 } ########### END OF FUNCTIONS ################################################### ########### MAIN SCRIPT LOGIC (DRIVER)######################################### # GENERAL VALIDATION OF ARGUMENTS count_simp=$(find ~/ -type d -name ".simplestore" | wc -l) if [ "$count_simp" -eq 0 ]; then mkdir ~/.simplestore # CREATE .simplesstore IF IT DOESN'T EXIST chmod 755 ~/.simplestore fi if [ $# -lt 1 ] || [ $# -gt 3 ] ; then echo " WRONG NUMBER OF ARGUMENTS" >&2 echo "Usage is: simplestore option [args] " >&2 echo " " >&2 echo "Options: write/increment/lookup take up to 2 ARGS, export up to 1" >&2 echo " and import reads from STDIN" >&2 exit 1 fi # PARSE ARGUMENTS FOR INITIAL ERROR DETECTION echo "$2" | grep ',' > /dev/null && { echo "Key: $2 cannont contain comma" >&2; exit 1;} option=`echo "$1" | tr '[A-Z]' '[a-z]'` case "$option" in # CHOOSE FUNCTION BY OPTION "increment") increment "$2" "$3";; "write" ) write "$2" "$3";; "lookup" ) lookup "$2" "$3";; "delete" ) delete "$2" ;; "import" ) import ;; "export" ) export "$2" ;; * ) echo "Option : $option NOT RECOGNIZED" >&2 echo "use: write, lookup, delete, import, export or increment" >&2;; esac