iwm: Fix S:N reporting in ifconfig(8)
[dragonfly.git] / tools / pw-update.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2020 The DragonFly Project.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # 1. Redistributions of source code must retain the above copyright
11 #    notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 #    notice, this list of conditions and the following disclaimer in
14 #    the documentation and/or other materials provided with the
15 #    distribution.
16 # 3. Neither the name of The DragonFly Project nor the names of its
17 #    contributors may be used to endorse or promote products derived
18 #    from this software without specific, prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24 # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 # SUCH DAMAGE.
32 #
33
34 # Exit if any untested command fails in non-interactive mode
35 set -e
36 # Exit when an undefined variable is referenced
37 set -u
38
39 # Usage: add_users <etcdir> <master.passwd> <group>
40 #
41 # Add new users and groups in <etcdir> according to the given <master.passwd>
42 # and <group> files.
43 #
44 # NOTE: Existing users and groups are not modified.
45 #
46 add_users() {
47         local etcdir="$1"
48         local fpasswd="$2"
49         local fgroup="$3"
50         local _name _pw _uid _gid _gids _group item
51         local _class _change _expire _gecos _home _shell _members
52
53         echo "===> Adding new users ..."
54         _gids=""
55         while IFS=':' read -r _name _pw _uid _gid _class \
56                         _change _expire _gecos _home _shell; do
57                 case ${_name} in
58                 '' | \#*) continue ;;
59                 esac
60                 if pw -V ${etcdir} usershow ${_name} -q >/dev/null; then
61                         continue
62                 fi
63                 echo "   * ${_name}: ${_uid}, ${_gid}, ${_gecos}, ${_home}, ${_shell}"
64
65                 _group=${_gid}
66                 if ! pw -V ${etcdir} groupshow ${_gid} -q >/dev/null; then
67                         # Primary group doesn't exist yet, so first assign to
68                         # the 'nogroup' group, and then adjust it after
69                         # creating the group.
70                         _group="nogroup"
71                         _gids="${_gids} ${_name}:${_gid}"
72                 fi
73
74                 # NOTE: The shell field can be empty (e.g., user 'toor') and
75                 #       would default to '/bin/sh'.
76                 # NOTE: Use '-o' option to allow to create user of duplicate
77                 #       UID, which is required by the 'toor' user (same UID
78                 #       as 'root').
79                 pw -V ${etcdir} useradd ${_name} \
80                         -o \
81                         -u ${_uid} \
82                         -g ${_group} \
83                         -d "${_home}" \
84                         -s "${_shell}" \
85                         -L "${_class}" \
86                         -c "${_gecos}"
87         done < ${fpasswd}
88
89         echo "===> Adding new groups ..."
90         while IFS=':' read -r _name _pw _gid _members; do
91                 case ${_name} in
92                 '' | \#*) continue ;;
93                 esac
94                 if pw -V ${etcdir} groupshow ${_name} -q >/dev/null; then
95                         continue
96                 fi
97                 echo "   * ${_name}: ${_gid}, ${_members}"
98                 pw -V ${etcdir} groupadd ${_name} -g ${_gid} -M "${_members}"
99         done < ${fgroup}
100
101         echo "===> Adjusting the group of new users ..."
102         for item in ${_gids}; do
103                 _name=${item%:*}
104                 _gid=${item#*:}
105                 echo "   * ${_name}: ${_gid}"
106                 pw -V ${etcdir} usermod ${_name} -g ${_gid}
107         done
108 }
109
110 # Usage: update_user <user> <etcdir> <master.passwd>
111 #
112 # Update an existing user in <etcdir> according to the given <master.passwd>.
113 #
114 update_user() {
115         local user="$1"
116         local etcdir="$2"
117         local fpasswd="$3"
118         local _line
119         local _name _pw _uid _gid _class _change _expire _gecos _home _shell
120
121         _line=$(grep "^${user}:" ${fpasswd}) || true
122         if [ -z "${_line}" ]; then
123                 echo "ERROR: no such user '${user}'" >&2
124                 exit 1
125         fi
126
127         echo "${_line}" | {
128                 IFS=':' read -r _name _pw _uid _gid _class \
129                         _change _expire _gecos _home _shell
130                 echo "===> Updating user ${user} ..."
131                 echo "   * ${_name}: ${_uid}, ${_gid}, ${_gecos}, ${_home}, ${_shell}"
132                 pw -V ${etcdir} usermod ${user} \
133                         -u ${_uid} \
134                         -g ${_gid} \
135                         -d ${_home} \
136                         -s ${_shell} \
137                         -L "${_class}" \
138                         -c "${_gecos}"
139         }
140 }
141
142 # Usage: update_group <group> <etcdir> <group>
143 #
144 # Update an existing group in <etcdir> according to the given <group> file.
145 #
146 update_group() {
147         local group="$1"
148         local etcdir="$2"
149         local fgroup="$3"
150         local _line
151         local _name _pw _gid _members
152
153         _line=$(grep "^${group}:" ${fgroup}) || true
154         if [ -z "${_line}" ]; then
155                 echo "ERROR: no such group '${group}'" >&2
156                 exit 1
157         fi
158
159         echo "${_line}" | {
160                 IFS=':' read -r _name _pw _gid _members
161                 echo "===> Updating group ${group} ..."
162                 echo "   * ${_name}: ${_gid}, ${_members}"
163                 pw -V ${etcdir} groupmod ${group} -g ${_gid} -M "${_members}"
164         }
165 }
166
167 usage() {
168         cat > /dev/stderr << _EOF_
169 Add/update users and groups.
170
171 Usage: ${0##*/} -d <etc-dir> -g <group-file> -p <master.passwd-file>
172         [-G group] [-U user]
173
174 _EOF_
175
176         exit 1
177 }
178
179 ETC_DIR=
180 GROUP_FILE=
181 PASSWD_FILE=
182 UPDATE_GROUP=
183 UPDATE_USER=
184
185 while getopts :d:G:g:hp:U: opt; do
186         case ${opt} in
187         d)
188                 ETC_DIR=${OPTARG}
189                 ;;
190         G)
191                 UPDATE_GROUP=${OPTARG}
192                 ;;
193         g)
194                 GROUP_FILE=${OPTARG}
195                 ;;
196         p)
197                 PASSWD_FILE=${OPTARG}
198                 ;;
199         U)
200                 UPDATE_USER=${OPTARG}
201                 ;;
202         h | \? | :)
203                 usage
204                 ;;
205         esac
206 done
207
208 shift $((OPTIND - 1))
209 [ $# -eq 0 ] || usage
210 [ -n "${ETC_DIR}" ] || usage
211 [ -n "${GROUP_FILE}" ] || usage
212 [ -n "${PASSWD_FILE}" ] || usage
213
214 if [ -z "${UPDATE_GROUP}" ] && [ -z "${UPDATE_USER}" ]; then
215         add_users "${ETC_DIR}" "${PASSWD_FILE}" "${GROUP_FILE}"
216 else
217         if [ -n "${UPDATE_GROUP}" ]; then
218                 update_group "${UPDATE_GROUP}" "${ETC_DIR}" "${GROUP_FILE}"
219         fi
220         if [ -n "${UPDATE_USER}" ]; then
221                 update_user "${UPDATE_USER}" "${ETC_DIR}" "${PASSWD_FILE}"
222         fi
223 fi