1 #! /usr/bin/ksh -p
2 #
3 # CDDL HEADER START
4 #
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
8 #
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22
23 #
24 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 # Use is subject to license terms.
26 #
27 # uid_proc.ksh
28 # The file contains global variables and support functions uidmapping tests.
29 # It contains three sections to help other scrips set up an initial
30 # scripting environment:
31 #
32 # 1) The 1st section sources necessary files
33 # 2) The 2nd section defines variables
34 # 3) The 3rd section defines functions
35 #
36 # All other ksh scripts under "uidmapping" directory are expected to source
37 # this file only.
38 #
39 # Note on temporary file management:
40 # This file defines a ERRLOG variable, which is used by all scripts
41 # under "uidmapping" directory as a temporary file to store error message.
42 # If a process creates that file(surely it will), it SHOULD remove that
43 # file when it exits no matter if it exits normally or it is interrupted.
44 #
45 # However, for simplicity purpose, a function might exits without cleaning
46 # up the temporary file it created. An example if set_local_domain() in
47 # this file and setup() in runtests.ksh file. If some commands failed
48 # within those functions, they just return without any cleanup. That
49 # won't cause any problem since we have a per-process file clean up
50 # solution described above.
51
52 [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
53
54 #
55 # source necessary files
56 #
57
58 NAME=$(basename $0)
59 CDIR=$(pwd)
60 TESTROOT=${TESTROOT:-"$CDIR/../../"}
61 TESTSH="$TESTROOT/testsh"
62
63 # sourcing framework global environment variables created after go_setup
64 # and for this purpose only this file should be sourced
65 CONFIGFILE=/var/tmp/nfsv4/config/config.suite
66 if [[ ! -f $CONFIGFILE ]]; then
67 echo "$NAME: CONFIGFILE[$CONFIGFILE] not found;"
68 echo "\texit UNINITIATED."
69 exit 6
70 fi
71 . $CONFIGFILE
72
73 # source useful functions
74 if [[ ! -f $TESTSH ]]; then
75 echo "$NAME: TESTSH[$TESTSH] not found; test UNINITIATED."
76 exit $UNINITIATED
77 fi
78
79 . $TESTSH
80
81 #
82 # "Global" variables used by all scripts or functions
83 #
84
85 # test directory
86 TESTDIR=$ZONE_PATH/uidmapping
87
88 # testfile name.
89 TESTFILE=uidmapping.$$.test
90
91 # positions of own and group fields in "ls -l" output
92 OWN=3
93 GRP=4
94
95 # temporary output file
96 ERRLOG=$TMPDIR/uidmapping.$$.err
97
98 #
99 # Functions
100 #
101
102 # variables for backup files, used by set/restore_local_domain() functions
103 NFSCFG_BACKUP=$TMPDIR/uidmapping.nfscfg.backup
104 DNSCFG_BACKUP=$TMPDIR/uidmapping.dnscfg.backup
105 DNS_NOTCONFIGURED=$TMPDIR/uidmapping.dns_notconfigured
106 NIS_DOMAIN=$TMPDIR/uidmapping.nis_domain
107
108 # restart_mapid_service
109 # The function restarts mapid service and verifies it has been
110 # restarted successfully. The function is designed to replace
111 # the usual "svcadm restart" command.
112 # usage:
113 # restart_mapid_service
114 # return value:
115 # 0 on success; 1 on error
116
117 function restart_mapid_service
118 {
119 [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
120
121 orig_pid=$(pgrep -z $(zonename) nfsmapid)
122
123 svcadm restart svc:/network/nfs/mapid:default
124 (( $? == 0)) || return 1
125
126 # check daemon pid
127 wait_now 10 "new_pid=\$(pgrep -z $(zonename) nfsmapid); \
128 [[ \$new_pid != $orig_pid ]]" || return 1
129 # check service status
130 wait_now 10 "st=\$(svcprop -p restarter/state nfs/mapid); \
131 [[ \$st == 'online' ]]" || return 1
132
133 sleep 2
134 }
135
136 # set_local_domain
137 # The function takes one argument and sets localhost's mapid domain
138 # to it. If the argument is not null, it modifies /etc/default/nfs file;
139 # or else, it removes /etc/default/nfs and /etc/resolv.conf files and
140 # unsets nis domain.
141 #
142 # The original environment changed by this function can be
143 # restored by call of restore_local_domain(). These two functions are
144 # supposed to be used together.
145 # usage:
146 # set_local_domain <new_domain>
147 # return value:
148 # 0 on success; 1 on error
149
150 function set_local_domain
151 {
152 [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
153
154 # check arguments
155 if (( $# != 1 )); then
156 echo "Usage: set_local_domain <new_domain>"
157 return 1
158 fi
159
160 typeset new_domain=$1
161
162 # Back up /etc/default/nfs
163 cp -p /etc/default/nfs $NFSCFG_BACKUP 2>$ERRLOG
164 ckreturn $? "could not back up /etc/default/nfs" $ERRLOG "ERROR" \
165 || return 1
166
167 if [[ -n $new_domain ]]; then
168 orig_pid=$(pgrep -z $(zonename) nfsmapid)
169 # Set mapid domain
170 sharectl set -p NFSMAPID_DOMAIN=$new_domain nfs 1>$ERRLOG 2>&1
171 ckreturn $? "could not set domain for client" $ERRLOG "ERROR" \
172 || return 1
173 wait_now 10 "[[ \$(sharectl get -p NFSMAPID_DOMAIN nfs | \
174 awk -F= '{print \$2}') == $new_domain ]]"
175 ckreturn $? "the nfs domain has not been updated even after \
176 10 seconds" "ERROR" || return 1
177 # check daemon pid
178 wait_now 10 "new_pid=\$(pgrep -z $(zonename) nfsmapid); \
179 [[ \$new_pid != $orig_pid ]]" || return 1
180 # check service status
181 wait_now 10 "st=\$(svcprop -p restarter/state nfs/mapid); \
182 [[ \$st == 'online' ]]" || return 1
183 sleep 2
184 else
185 # Back up DNS setting
186 if [[ -f /etc/resolv.conf ]]; then
187 # DNS was configured and thus needs to be backed up.
188 cp -p /etc/resolv.conf $DNSCFG_BACKUP 2>$ERRLOG
189 ckreturn $? "could not back up /etc/resolv.conf" \
190 $ERRLOG "ERROR" || return 1
191 else
192 # DNS wasn't configured. Mark that with a file
193 touch $DNS_NOTCONFIGURED 2>$ERRLOG
194 ckreturn $? \
195 "could not generate $DNS_NOTCONFIGURED" \
196 $ERRLOG "ERROR" || return 1
197 fi
198
199 # Back up NIS domain
200 domainname | cat > $NIS_DOMAIN
201 ckreturn $? "could not back up nis domain" "ERROR" || return 1
202
203 # Set mapid domain
204 grep -v "NFSMAPID_DOMAIN" /etc/default/nfs \
205 > $TMPDIR/uidmapping.$$.tmp 2>$ERRLOG \
206 && mv $TMPDIR/uidmapping.$$.tmp /etc/default/nfs 2>$ERRLOG \
207 && rm -f /etc/resolv.conf 2>$ERRLOG \
208 && domainname "" 2>$ERRLOG \
209 && restart_mapid_service 2>$ERRLOG
210 ckreturn $? "could not set mapid domain to null" $ERRLOG \
211 "ERROR" || return 1
212 fi
213
214 # This function may exit on various errors, so it may fail to reach
215 # the following line and thus leave temporary error file unremoved.
216 # However, it doesn't matter. Since this function is always supposed
217 # to be used together with restore_local_domain() function, which
218 # can help to do that if needed.
219 rm -f $ERRLOG
220 }
221
222 # restore_local_domain
223 # the function restores the original environment changed by call of
224 # setup_local_domain().
225 # usage:
226 # restore_local_domain
227 # return value:
228 # 0 on success; non-zero on error
229
230 function restore_local_domain
231 {
232 [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
233
234 typeset ret=0
235
236 # Restore /etc/default/nfs
237 if [[ -f $NFSCFG_BACKUP ]]; then
238 # Restore the file
239 mv $NFSCFG_BACKUP /etc/default/nfs 2>$ERRLOG
240 ckreturn $? "could not restore /etc/default/nfs" $ERRLOG \
241 "WARNING" || ret=$((ret + 1))
242 fi
243
244 # Restore DNS configuration if necessary
245 if [[ -f $DNS_NOTCONFIGURED ]]; then
246 # no dns configuration at all
247 rm -f $DNS_NOTCONFIGURED 2>$ERRLOG
248 ckreturn $? "could not remove $DNS_NOTCONFIGURED" \
249 $ERRLOG "WARNING" || ret=$((ret + 1))
250 elif [[ -f $DNSCFG_BACKUP ]]; then
251 # Restore /etc/resolv.conf
252 mv $DNSCFG_BACKUP /etc/resolv.conf 2>$ERRLOG
253 ckreturn $? "could not restore /etc/resolv.conf" \
254 $ERRLOG "WARNING" || ret=$((ret + 1))
255 fi
256
257 # Restore NIS domain if necessary
258 if [[ -f $NIS_DOMAIN ]]; then
259 domainname $(cat $NIS_DOMAIN) 2>$ERRLOG \
260 && rm -f $NIS_DOMAIN
261 ckreturn $? "could not restore NIS domain" $ERRLOG "WARNING" \
262 || ret=$((ret + 1))
263 fi
264
265 # Restart nfsmapid
266 restart_mapid_service 1>$ERRLOG 2>&1
267 ckreturn $? "could not restart nfsmapid" $ERRLOG "WARNING" \
268 || ret=$((ret + 1))
269
270 rm -f $ERRLOG
271
272 return $ret
273 }
274
275 # get_free_id
276 # This function returns a uid or gid which is unknown on
277 # both client and server. It does that by first trying an value
278 # large enough and check if it is mappable or not on server and client.
279 # If yes, it increases the value by one and try it again until the max
280 # try number is exceeded.
281 # Usage: get_free_id "UID"|"GID"
282 # Return Values:
283 # On success, it returns 0 and outputs uid/gid on stdout;
284 # On failure, it returns 1.
285
286 function get_free_id
287 {
288 [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
289
290 # check arguments
291 if (( $# != 1 )); then
292 echo "Usage: get_free_id \"UID\"|\"GID\""
293 return 1
294 fi
295
296 # select different database based on query type
297 idtype=$1
298 case $idtype in
299 UID )
300 database="passwd"
301 ;;
302 GID )
303 database="group"
304 ;;
305 * )
306 echo "Usage: get_free_id \"UID\"|\"GID\""
307 return 1
308 ;;
309 esac
310
311 #
312 # The following code looks for an uid or gid unknown on both
313 # client and server. It picks up a number large enough(5000000)
314 # and tries it first. If the number is not free, increases it by one
315 # and tries again until the maximum retry number(100) is met.
316 #
317
318 val=4999999
319 st_server=0
320 st_client=0
321
322 while (( st_server != 2 || st_client != 2 ))
323 do
324 val=$((val + 1))
325 if (( val >= 5000100 )); then
326 # if not in the first 100 ids, assume other problem
327 rm -f $ERRLOG
328 return 1
329 fi
330
331 # check it on server side
332 execute $SERVER root "getent $database $val" 1>/dev/null \
333 2> $ERRLOG
334 st_server=$?
335 [[ $DEBUG != 0 ]] && cat $ERRLOG >&2
336
337 # check it on client side
338 getent $database $val 1>/dev/null 2>$ERRLOG
339 st_client=$?
340 [[ $DEBUG != 0 ]] && cat $ERRLOG >&2
341 done
342
343 echo $val
344
345 rm -f $ERRLOG
346 return 0
347 }
348
349 # print_state
350 # This function prints the configuration of the test system, which can
351 # be used to help to debug command failures. It currently does the
352 # following and might be enhanced when necessary.
353 # - print /var/run/nfs4_domain on client and server
354 # - print users in /etc/passwd on client and server
355 # Usage: print_state
356 # Return Values:
357 # it always returns 0.
358
359 function print_state
360 {
361 echo "\n===================== DEBUG INFORMATION ====================="
362 echo "nfs domain on client: $(cat /var/run/nfs4_domain)"
363 echo "nfs domain on server: $(execute $SERVER root cat /var/run/nfs4_domain)"
364 typeset MAPID_FMRI="svc:/network/nfs/mapid:default"
365 echo "nfs/mapid on client:"
366 svcs $MAPID_FMRI
367 echo "nfs/mapid on server:"
368 execute $SERVER root svcs $MAPID_FMRI
369 users_on_client=$(cut -d: -f1 /etc/passwd)
370 echo "users on client: " $users_on_client
371 users_on_server=$(execute $SERVER root cut -d: -f1 /etc/passwd)
372 echo "users on server: " $users_on_server
373 echo "============================ END =============================\n"
374 }