]> CyberLeo.Net >> Repos - CDN/bash-config.git/blob - share/fixuser
Add fixusers script to handle bash-config symlinks in user directories
[CDN/bash-config.git] / share / fixuser
1 #!/bin/sh
2
3 pebkac() {
4   [ "${*}" ] && printf "%s\n\n" "${*}"
5   cat <<EOF
6 Usage: fixuser [-c|-i|-r] <user> [user ...]
7
8  -c    Check symlinks for sanity
9  -i    Install symlinks
10  -r    Remove symlinks
11
12 This script will adjust the bash-config symlinks in the homedir of
13 the supplied user, or all users if unspecified.
14
15 This script will avoid tampering with files that it thinks are
16 manually added. Use -c to check, and verify the files manually
17 afterwards.
18
19 EOF
20   exit "${#}"
21 }
22
23 files="bash_profile bashrc"
24
25 userlist() {
26   # Ignore users with shell not in /etc/shells
27   # Ignore users with invalid homedir
28   # Ignore subsequent users with the same homedir (root, toor, daemon, etc)
29   # List all remaining usernames
30   local _home_cache
31   getent passwd | while IFS=: read user pass uid gid gecos home shell extra
32   do
33     getent shells "${shell}" >&- || continue
34     [ -d "${home}" ] || continue
35     echo "${_home_cache}" | grep -q " ${home} " && continue
36     _home_cache="${_home_cache} ${home} "
37     echo "${user}"
38   done
39 }
40
41 userdir() {
42   [ "${1}" ] || return 1
43   # This is a loop because read will not work after pipe due to subshell isolation
44   getent passwd "${1}" | while IFS=: read user pass uid gid gecos home shell extra
45   do
46     echo "${home}"
47     break
48   done
49 }
50
51 mine() {
52   [ "${1}" ] || return 1
53   user="${1}"; shift
54   [ "${#}" -eq 0 ] && set - ${files}
55   while [ "${1}" ]
56   do
57     file="${1}"
58     link="$(userdir "${user}")/.${file}"
59     real="/usr/local/etc/bash-config/${file}"
60     if [ ! -L "${link}" ] || [ "$(realpath "$(readlink "${link}")")" != "${real}" ]
61     then
62       return 1
63     fi
64     shift
65   done
66   return 0
67 }
68
69 gone() {
70   [ "${1}" ] || return 1
71   user="${1}"; shift
72   [ "${#}" -eq 0 ] && set - ${files}
73   while [ "${1}" ]
74   do
75     file="${1}"
76     link="$(userdir "${user}")/.${file}"
77     [ -f "${link}" ] && return 1
78     shift
79   done
80   return 0
81 }
82
83 check() {
84   [ "${1}" ] || return 1
85   user="${1}"; shift
86   [ "${#}" -eq 0 ] && set - ${files}
87   echo "Checking user ${user}..."
88   while [ "${1}" ]
89   do
90     file="${1}"
91     if gone "${user}" "${file}"
92     then
93       echo " File ${file} does not exist."
94     else
95       if mine "${user}" "${file}"
96       then
97         echo " File ${file} is mine."
98       else
99         echo " File ${file} exists, but is not mine."
100       fi
101     fi
102     shift
103   done
104 }
105
106 install() {
107   [ "${1}" ] || return 1
108   user="${1}"
109   if mine "${user}"
110   then
111     echo "User symlinks appear to be correct"
112     return 0
113   fi
114   
115   if ! gone "${user}"
116   then
117     echo "User files (${files}) appear to exist, and are not mine"
118     echo "Refusing to molest them"
119     return 1
120   fi
121   
122   for file in ${files}
123   do
124     link="$(userdir "${user}")/.${file}"
125     real="/usr/local/etc/bash-config/${file}"
126     [ "${link%%.${file}}" = "/" ] && return 1
127     su "${user}" -c "ln -s '${real}' '${link}'" || return $?
128   done
129   return 0
130 }
131
132 remove() {
133   [ "${1}" ] || return 1
134   user="${1}"
135   if gone "${user}"
136   then
137     echo "User symlinks already removed"
138     return 0
139   fi
140   
141   if ! mine "${user}"
142   then
143     echo "User files (${files}) appear to exist, and are not mine"
144     echo "Refusing to molest them"
145     return 1
146   fi
147   
148   for file in ${files}
149   do
150     link="$(userdir "${user}")/.${file}"
151     [ "${link%%.${file}}" = "/" ] && return 1
152     rm -f "${link}" || return $?
153   done
154   return 0
155 }
156
157 state() {
158   [ -z "${cmd}" ] || pebkac "Only specify one of -c -i -r"
159   cmd="${1}"
160 }
161
162 cmd=""
163
164 while getopts "cir" opt
165 do
166   case "${opt}" in
167   c)  state check ;;
168   i)  state install ;;
169   r)  state remove ;;
170   [?]) pebkac "Unrecognized option ${OPTARG}" ;;
171   esac
172 done
173 shift $(( $OPTIND - 1 ))
174
175 [ "${cmd}" ] || pebkac
176
177 # Default to current user if not root
178 if [ "$(id -u)" -gt 0 ]
179 then
180   if [ "${*}" -a "${*}" != "${USER}" ]
181   then
182     echo "Mortal users can only modify themselves" >&2
183     exit 1
184   fi
185   [ "${#}" -eq 0 ] && set - ${USER}
186 else
187   [ "${#}" -eq 0 ] && set - $(userlist)
188 fi
189
190 printf "Working on user(s) "
191 echo "${@}"
192
193 while [ "${1}" ]
194 do
195   "${cmd}" "${1}"
196   shift
197 done