summaryrefslogtreecommitdiffstats
path: root/shop
blob: c2e01fe084685910e75de4c9dccfacc093166904 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/bin/bash
#
# shop - Show Permissions at all levels of a given path
#
#        With `tree(1)` you start at a trunk and show all leaves that
#        originate from that trunk, optionally showing permissions.
#        `shop` starts at a leaf and shows the permissions back to a
#        trunk.
#
# CREATED:  2009-09-03 17:30
# MODIFIED: 2009-11-17 11:05

_NAME=$(basename $0)
_VERSION=1.0

# DEFAULTS
unset octal               # use text mode instead of octal mode
level=-1                  # traverse all the way up to /
trunk='/'                 # traverse all the way up to /
pad=17                    # padding for pathname

usage() {
    cat <<EOT
Usage: $_NAME [-L N] [-o] [-t PATH] [PATH1..]

Options:
  -L, --level N      traverse N levels up the tree
  -o, --octal        show octal mode instead of human readable mode 
  -t, --trunk PATH   only traverse up to PATH instead of / (root)
                       - takes precedence over --level
  -p, --pad N        allow USER:GROUP N characters before directory name
                       default: 17

  -h, --help         show this message
      --version      show version info
EOT
}

_shop() {
    [ $octal ] && stat_str="%a" || stat_str="%A"

    stats=( $(stat -c "$stat_str %U:%G %n" "$1") )

    if [ $octal ]; then
        # `stat -c "%a"` only returns a 4 digit mode when the first digit is 
        # nonzero, yet `stat` always returns a 4 digit mode.  how annoying...
        [ ${#stats} -eq 3 ] && echo -n "0"
    fi    

    printf "%s %-${pad}s ${stats[@]:2}\n" "${stats[@]:0:2}"
}

main() {
    arg="$1"
    if [ -z "$arg" ]; then
        # user didn't supply an arg, use current working dir
        arg="$PWD"
    fi

    until [ -z "$arg" ]; do
        if ! [ -a "$arg" ]; then
             echo "error: $arg does not exist"
             return 1
        fi

        # if $arg is a directory, prime the directory stack, else use 
        # the parent dir of $arg to prime the stack
        if [ -d "$arg" ]; then
            cd "$arg" || return 1
            unset file_arg
        else
            cd $(dirname -- "$arg") || return 1
            file_arg=1
            let "level -=1"
        fi

        start_dir=$PWD

        # populate directory stack with $level levels on the path to
        # the $trunk
        while [ "$PWD" != "$trunk" ]; do
            if [ $level -gt 0 ] || [ $level -lt 0 ]; then
                let "level -= 1"
                pushd .. &> /dev/null 
            elif [ $level -eq 0 ]; then
                break;
            fi
        done

        # display the permissions for each level
        while [ "$PWD" != "$start_dir" ]; do
            _shop "$PWD"
            popd &> /dev/null
        done
        _shop "$PWD"

        # leaf was a file, run _shop on this file as well
        if [ $file_arg ]; then
            _shop "${PWD}/$(basename -- "$arg")"
        else
            cd .. || return 1
        fi

        # user passed multiple leafs, separate output for each leaf
        if [ $# -gt 1 ]; then
            echo
        fi

        shift
        arg="$1"
    done
}

declare -a args
until [ -z "$1" ]; do
    case "$1" in
        -L|--level) level="$2"
                    shift 2
                    ;;

        -o|--octal) octal=1
                    shift
                    ;;

        -t|--trunk) trunk="$(readlink -f $2)"
                    shift 2
                    ;;

        -p|--pad) pad="$2"
                  shift 2
                  ;;

        -h|--help) usage
                   exit
                   ;;

        --version) echo "$_NAME v$_VERSION"
                   exit
                   ;;

        --) shift
            args=( "${args[@]}" "$@" )
            break
            ;;

        -*) echo -e "$_NAME: unknown option: $1\n"
            usage
            exit
            ;;

        *) args[${#args[*]}]="$1"
           shift
           ;;
    esac
done

main "${args[@]}"