xref: /titanic_44/usr/src/lib/libsecdb/common/i.rbac (revision ead1f93ee620d7580f7e53350fe5a884fc4f158a)
1*ead1f93eSLiane Praza#!/bin/sh
2*ead1f93eSLiane Praza#
3*ead1f93eSLiane Praza# CDDL HEADER START
4*ead1f93eSLiane Praza#
5*ead1f93eSLiane Praza# The contents of this file are subject to the terms of the
6*ead1f93eSLiane Praza# Common Development and Distribution License (the "License").
7*ead1f93eSLiane Praza# You may not use this file except in compliance with the License.
8*ead1f93eSLiane Praza#
9*ead1f93eSLiane Praza# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*ead1f93eSLiane Praza# or http://www.opensolaris.org/os/licensing.
11*ead1f93eSLiane Praza# See the License for the specific language governing permissions
12*ead1f93eSLiane Praza# and limitations under the License.
13*ead1f93eSLiane Praza#
14*ead1f93eSLiane Praza# When distributing Covered Code, include this CDDL HEADER in each
15*ead1f93eSLiane Praza# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*ead1f93eSLiane Praza# If applicable, add the following below this CDDL HEADER, with the
17*ead1f93eSLiane Praza# fields enclosed by brackets "[]" replaced with your own identifying
18*ead1f93eSLiane Praza# information: Portions Copyright [yyyy] [name of copyright owner]
19*ead1f93eSLiane Praza#
20*ead1f93eSLiane Praza# CDDL HEADER END
21*ead1f93eSLiane Praza#
22*ead1f93eSLiane Praza# i.rbac
23*ead1f93eSLiane Praza#
24*ead1f93eSLiane Praza# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25*ead1f93eSLiane Praza# Use is subject to license terms.
26*ead1f93eSLiane Praza#
27*ead1f93eSLiane Praza# class action script for "rbac" class files
28*ead1f93eSLiane Praza# installed by pkgadd
29*ead1f93eSLiane Praza#
30*ead1f93eSLiane Praza# Files in "rbac" class:
31*ead1f93eSLiane Praza#
32*ead1f93eSLiane Praza# /etc/security/{prof_attr,exec_attr,auth_attr}
33*ead1f93eSLiane Praza# /etc/user_attr
34*ead1f93eSLiane Praza#
35*ead1f93eSLiane Praza#  Allowable exit codes
36*ead1f93eSLiane Praza#
37*ead1f93eSLiane Praza# 0 - success
38*ead1f93eSLiane Praza# 2 - warning or possible error condition. Installation continues. A warning
39*ead1f93eSLiane Praza#     message is displayed at the time of completion.
40*ead1f93eSLiane Praza#
41*ead1f93eSLiane Praza
42*ead1f93eSLiane Prazaumask 022
43*ead1f93eSLiane Praza
44*ead1f93eSLiane Prazatmp_dir=${TMPDIR:-/tmp}
45*ead1f93eSLiane Praza
46*ead1f93eSLiane PrazaPATH="/usr/bin:/usr/sbin:${PATH}"
47*ead1f93eSLiane Prazaexport PATH
48*ead1f93eSLiane Praza
49*ead1f93eSLiane Prazabasename_cmd=basename
50*ead1f93eSLiane Prazacp_cmd=cp
51*ead1f93eSLiane Prazaegrep_cmd=egrep
52*ead1f93eSLiane Prazamv_cmd=mv
53*ead1f93eSLiane Prazanawk_cmd=nawk
54*ead1f93eSLiane Prazarm_cmd=rm
55*ead1f93eSLiane Prazased_cmd=sed
56*ead1f93eSLiane Prazasort_cmd=sort
57*ead1f93eSLiane Praza
58*ead1f93eSLiane Praza# $1 is the type
59*ead1f93eSLiane Praza# $2 is the "old/existing file"
60*ead1f93eSLiane Praza# $3 is the "new (to be merged)" file
61*ead1f93eSLiane Praza# $4 is the output file
62*ead1f93eSLiane Praza# returns 0 on success
63*ead1f93eSLiane Praza# returns 2 on failure if nawk fails with non-zero exit status
64*ead1f93eSLiane Praza#
65*ead1f93eSLiane Prazadbmerge() {
66*ead1f93eSLiane Praza#
67*ead1f93eSLiane Praza# Remove the ident lines.
68*ead1f93eSLiane Praza#
69*ead1f93eSLiane Praza	${egrep_cmd} -v '^#[pragma 	]*ident' $2 > $4.old 2>/dev/null
70*ead1f93eSLiane Praza#
71*ead1f93eSLiane Praza# If the new file has a Sun copyright, remove the Sun copyright from the old
72*ead1f93eSLiane Praza# file.
73*ead1f93eSLiane Praza#
74*ead1f93eSLiane Praza	newcr=`${egrep_cmd} '^# Copyright.*Sun Microsystems, Inc.' $3 \
75*ead1f93eSLiane Praza	    2>/dev/null`
76*ead1f93eSLiane Praza	if [ -n "${newcr}" ]; then
77*ead1f93eSLiane Praza		$sed_cmd -e '/^# Copyright.*Sun Microsystems, Inc./d' \
78*ead1f93eSLiane Praza		    -e '/^# All rights reserved./d' \
79*ead1f93eSLiane Praza		    -e '/^# Use is subject to license terms./d' \
80*ead1f93eSLiane Praza		    $4.old > $4.$$ 2>/dev/null
81*ead1f93eSLiane Praza		$mv_cmd $4.$$ $4.old
82*ead1f93eSLiane Praza	fi
83*ead1f93eSLiane Praza#
84*ead1f93eSLiane Praza# If the new file has the CDDL, remove it from the old file.
85*ead1f93eSLiane Praza#
86*ead1f93eSLiane Praza	newcr=`${egrep_cmd} '^# CDDL HEADER START' $3 2>/dev/null`
87*ead1f93eSLiane Praza	if [ -n "${newcr}" ]; then
88*ead1f93eSLiane Praza		$sed_cmd -e '/^# CDDL HEADER START/,/^# CDDL HEADER END/d' \
89*ead1f93eSLiane Praza		    $4.old > $4.$$ 2>/dev/null
90*ead1f93eSLiane Praza		$mv_cmd $4.$$ $4.old
91*ead1f93eSLiane Praza	fi
92*ead1f93eSLiane Praza#
93*ead1f93eSLiane Praza# Remove empty lines and multiple instances of these comments:
94*ead1f93eSLiane Praza#
95*ead1f93eSLiane Praza	$sed_cmd -e '/^# \/etc\/security\/exec_attr/d' -e '/^#$/d' \
96*ead1f93eSLiane Praza		-e '/^# execution attributes for profiles./d' \
97*ead1f93eSLiane Praza		-e '/^# See exec_attr(4)/d' \
98*ead1f93eSLiane Praza		-e '/^# \/etc\/user_attr/d' \
99*ead1f93eSLiane Praza		-e '/^# user attributes. see user_attr(4)/d' \
100*ead1f93eSLiane Praza		-e '/^# \/etc\/security\/prof_attr/d' \
101*ead1f93eSLiane Praza		-e '/^# profiles attributes. see prof_attr(4)/d' \
102*ead1f93eSLiane Praza		-e '/^# See prof_attr(4)/d' \
103*ead1f93eSLiane Praza		-e '/^# \/etc\/security\/auth_attr/d' \
104*ead1f93eSLiane Praza		-e '/^# authorizations. see auth_attr(4)/d' \
105*ead1f93eSLiane Praza		-e '/^# authorization attributes. see auth_attr(4)/d' \
106*ead1f93eSLiane Praza		    $4.old > $4.$$
107*ead1f93eSLiane Praza	$mv_cmd $4.$$ $4.old
108*ead1f93eSLiane Praza#
109*ead1f93eSLiane Praza# Retain old and new header comments.
110*ead1f93eSLiane Praza#
111*ead1f93eSLiane Praza	$sed_cmd -n -e '/^[^#]/,$d' -e '/^##/,$d' -e p $4.old > $4
112*ead1f93eSLiane Praza	$rm_cmd $4.old
113*ead1f93eSLiane Praza	$sed_cmd -n -e '/^[^#]/,$d' -e '/^##/,$d' -e p $3 >> $4
114*ead1f93eSLiane Praza#
115*ead1f93eSLiane Praza# Handle line continuations (trailing \)
116*ead1f93eSLiane Praza#
117*ead1f93eSLiane Praza 	$sed_cmd \
118*ead1f93eSLiane Praza 	    -e '/\\$/{N;s/\\\n//;}'  -e '/\\$/{N;s/\\\n//;}' \
119*ead1f93eSLiane Praza 	    -e '/\\$/{N;s/\\\n//;}'  -e '/\\$/{N;s/\\\n//;}' \
120*ead1f93eSLiane Praza 	    -e '/\\$/{N;s/\\\n//;}'  -e '/\\$/{N;s/\\\n//;}' \
121*ead1f93eSLiane Praza 	    $2 > $4.old
122*ead1f93eSLiane Praza 	$sed_cmd \
123*ead1f93eSLiane Praza 	    -e '/\\$/{N;s/\\\n//;}'  -e '/\\$/{N;s/\\\n//;}' \
124*ead1f93eSLiane Praza 	    -e '/\\$/{N;s/\\\n//;}'  -e '/\\$/{N;s/\\\n//;}' \
125*ead1f93eSLiane Praza 	    -e '/\\$/{N;s/\\\n//;}'  -e '/\\$/{N;s/\\\n//;}' \
126*ead1f93eSLiane Praza 	    $3 > $4.new
127*ead1f93eSLiane Praza#
128*ead1f93eSLiane Praza#!/usr/bin/nawk -f
129*ead1f93eSLiane Praza#
130*ead1f93eSLiane Praza#       dbmerge type=[auth|prof|user|exec] old-file new-file
131*ead1f93eSLiane Praza#
132*ead1f93eSLiane Praza#       Merge two versions of an RBAC database file. The output
133*ead1f93eSLiane Praza#       consists of the lines from the new-file, while preserving
134*ead1f93eSLiane Praza#       user customizations in the old-file. Specifically, the
135*ead1f93eSLiane Praza#       keyword/value section of each record contains the union
136*ead1f93eSLiane Praza#       of the entries found in both files. The value for each
137*ead1f93eSLiane Praza#       keyword is the value from the new-file, except for three
138*ead1f93eSLiane Praza#       keywords ("auths", "profiles", "roles") where the values
139*ead1f93eSLiane Praza#       from the old and new files are merged.
140*ead1f93eSLiane Praza#
141*ead1f93eSLiane Praza#	The output is run through sort except for the comments
142*ead1f93eSLiane Praza#	which will appear first in the output.
143*ead1f93eSLiane Praza#
144*ead1f93eSLiane Praza#
145*ead1f93eSLiane Praza	$nawk_cmd  '
146*ead1f93eSLiane Praza
147*ead1f93eSLiane PrazaBEGIN {
148*ead1f93eSLiane Praza	FS=":"
149*ead1f93eSLiane Praza}
150*ead1f93eSLiane Praza
151*ead1f93eSLiane Praza/^#/ || /^$/ {
152*ead1f93eSLiane Praza	continue;
153*ead1f93eSLiane Praza}
154*ead1f93eSLiane Praza
155*ead1f93eSLiane Prazatype == "auth" {
156*ead1f93eSLiane Praza	key = $1 ":" $2 ":" $3 ;
157*ead1f93eSLiane Praza	if (NR == FNR) {
158*ead1f93eSLiane Praza		short_comment[key] = $4 ;
159*ead1f93eSLiane Praza		long_comment[key] = $5;
160*ead1f93eSLiane Praza		record[key] = $6;
161*ead1f93eSLiane Praza	}
162*ead1f93eSLiane Praza	else {
163*ead1f93eSLiane Praza		if ( $4 != "" ) {
164*ead1f93eSLiane Praza			short_comment[key] = $4 ;
165*ead1f93eSLiane Praza		}
166*ead1f93eSLiane Praza		if ( $5 != "" ) {
167*ead1f93eSLiane Praza			long_comment[key] =  $5 ;
168*ead1f93eSLiane Praza		}
169*ead1f93eSLiane Praza		print key ":" short_comment[key] ":" long_comment[key] ":" \
170*ead1f93eSLiane Praza		    merge_attrs(record[key], $6);
171*ead1f93eSLiane Praza		delete record[key];
172*ead1f93eSLiane Praza	}
173*ead1f93eSLiane Praza}
174*ead1f93eSLiane Praza
175*ead1f93eSLiane Prazatype == "prof" {
176*ead1f93eSLiane Praza	key = $1 ":" $2 ":" $3 ;
177*ead1f93eSLiane Praza	if (NR == FNR) {
178*ead1f93eSLiane Praza		comment[key] = $4;
179*ead1f93eSLiane Praza		record[key] = $5;
180*ead1f93eSLiane Praza	}
181*ead1f93eSLiane Praza	else {
182*ead1f93eSLiane Praza		if ( $4 != "" ) {
183*ead1f93eSLiane Praza			comment[key] = $4 ;
184*ead1f93eSLiane Praza		}
185*ead1f93eSLiane Praza		if (key != "::") {
186*ead1f93eSLiane Praza			print key ":" comment[key] ":" \
187*ead1f93eSLiane Praza			    merge_attrs(record[key], $5);
188*ead1f93eSLiane Praza		}
189*ead1f93eSLiane Praza		delete record[key];
190*ead1f93eSLiane Praza	}
191*ead1f93eSLiane Praza}
192*ead1f93eSLiane Praza
193*ead1f93eSLiane Prazatype == "exec" {
194*ead1f93eSLiane Praza	key = $1 ":" $2 ":" $3 ":" $4 ":" $5 ":" $6 ;
195*ead1f93eSLiane Praza	# Substitute new entries, do not merge.
196*ead1f93eSLiane Praza	record[key] = $7;
197*ead1f93eSLiane Praza}
198*ead1f93eSLiane Praza
199*ead1f93eSLiane Prazatype == "user" {
200*ead1f93eSLiane Praza	key = $1 ":" $2 ":" $3 ":" $4 ;
201*ead1f93eSLiane Praza	if (NR == FNR)
202*ead1f93eSLiane Praza		record[key] = $5;
203*ead1f93eSLiane Praza	else {
204*ead1f93eSLiane Praza		print key ":" merge_attrs(record[key], $5);
205*ead1f93eSLiane Praza		delete record[key];
206*ead1f93eSLiane Praza	}
207*ead1f93eSLiane Praza}
208*ead1f93eSLiane Praza
209*ead1f93eSLiane PrazaEND {
210*ead1f93eSLiane Praza	for (key in record) {
211*ead1f93eSLiane Praza		if (type == "prof") {
212*ead1f93eSLiane Praza			if (key != "::") {
213*ead1f93eSLiane Praza				print key ":" comment[key] ":" record[key];
214*ead1f93eSLiane Praza			}
215*ead1f93eSLiane Praza		} else
216*ead1f93eSLiane Praza			if (type == "auth") {
217*ead1f93eSLiane Praza				print key ":" short_comment[key] ":"  \
218*ead1f93eSLiane Praza				    long_comment[key] ":" record[key];
219*ead1f93eSLiane Praza			} else
220*ead1f93eSLiane Praza				print key ":" record[key];
221*ead1f93eSLiane Praza		}
222*ead1f93eSLiane Praza}
223*ead1f93eSLiane Praza
224*ead1f93eSLiane Prazafunction merge_attrs(old, new, cnt, new_cnt, i, j, list, new_list, keyword)
225*ead1f93eSLiane Praza{
226*ead1f93eSLiane Praza	cnt = split(old, list, ";");
227*ead1f93eSLiane Praza	new_cnt = split(new, new_list, ";");
228*ead1f93eSLiane Praza	for (i = 1; i <= new_cnt; i++) {
229*ead1f93eSLiane Praza		keyword = substr(new_list[i], 1, index(new_list[i], "=")-1);
230*ead1f93eSLiane Praza		for (j = 1; j <= cnt; j++) {
231*ead1f93eSLiane Praza			if (match(list[j], "^" keyword "=")) {
232*ead1f93eSLiane Praza				list[j] = merge_values(keyword, list[j],
233*ead1f93eSLiane Praza				    new_list[i]);
234*ead1f93eSLiane Praza				break;
235*ead1f93eSLiane Praza			}
236*ead1f93eSLiane Praza		}
237*ead1f93eSLiane Praza		if (j > cnt)
238*ead1f93eSLiane Praza			list[++cnt] = new_list[i];
239*ead1f93eSLiane Praza	}
240*ead1f93eSLiane Praza
241*ead1f93eSLiane Praza	return unsplit(list, cnt, ";"); \
242*ead1f93eSLiane Praza}
243*ead1f93eSLiane Praza
244*ead1f93eSLiane Prazafunction merge_values(keyword, old, new, cnt, new_cnt, i, j, list, new_list, d)
245*ead1f93eSLiane Praza{
246*ead1f93eSLiane Praza	if (keyword != "auths" && keyword != "profiles")
247*ead1f93eSLiane Praza		return new;
248*ead1f93eSLiane Praza
249*ead1f93eSLiane Praza	cnt = split(substr(old, length(keyword)+2), list, ",");
250*ead1f93eSLiane Praza	new_cnt = split(substr(new, length(keyword)+2), new_list, ",");
251*ead1f93eSLiane Praza
252*ead1f93eSLiane Praza	# If the existing list contains "All", remove it and add it
253*ead1f93eSLiane Praza	# to the new list; that way "All" will appear at the only valid
254*ead1f93eSLiane Praza	# location, the end of the list.
255*ead1f93eSLiane Praza	if (keyword == "profiles") {
256*ead1f93eSLiane Praza		d = 0;
257*ead1f93eSLiane Praza		for (i = 1; i <= cnt; i++) {
258*ead1f93eSLiane Praza			if (list[i] != "All")
259*ead1f93eSLiane Praza				list[++d] = list[i];
260*ead1f93eSLiane Praza		}
261*ead1f93eSLiane Praza		if (cnt != d) {
262*ead1f93eSLiane Praza			new_list[++new_cnt] = "All";
263*ead1f93eSLiane Praza			cnt = d;
264*ead1f93eSLiane Praza		}
265*ead1f93eSLiane Praza	}
266*ead1f93eSLiane Praza	for (i = 1; i <= new_cnt; i++) {
267*ead1f93eSLiane Praza		for (j = 1; j <= cnt; j++) {
268*ead1f93eSLiane Praza			if (list[j] == new_list[i])
269*ead1f93eSLiane Praza				break;
270*ead1f93eSLiane Praza		}
271*ead1f93eSLiane Praza		if (j > cnt)
272*ead1f93eSLiane Praza			list[++cnt] = new_list[i];
273*ead1f93eSLiane Praza	}
274*ead1f93eSLiane Praza
275*ead1f93eSLiane Praza	return keyword "=" unsplit(list, cnt, ",");
276*ead1f93eSLiane Praza}
277*ead1f93eSLiane Praza
278*ead1f93eSLiane Prazafunction unsplit(list, cnt, delim, str)
279*ead1f93eSLiane Praza{
280*ead1f93eSLiane Praza	str = list[1];
281*ead1f93eSLiane Praza	for (i = 2; i <= cnt; i++)
282*ead1f93eSLiane Praza		str = str delim list[i];
283*ead1f93eSLiane Praza	return str;
284*ead1f93eSLiane Praza}' \
285*ead1f93eSLiane Praza	type=$1 $4.old $4.new > $4.unsorted
286*ead1f93eSLiane Praza	rc=$?
287*ead1f93eSLiane Praza	$sort_cmd < $4.unsorted >> $4
288*ead1f93eSLiane Praza	return $rc
289*ead1f93eSLiane Praza}
290*ead1f93eSLiane Praza
291*ead1f93eSLiane Praza# $1 is the merged file
292*ead1f93eSLiane Praza# $2 is the target file
293*ead1f93eSLiane Praza#
294*ead1f93eSLiane Prazacommit() {
295*ead1f93eSLiane Praza	# Make sure that the last mv uses rename(2) by first moving to
296*ead1f93eSLiane Praza	# the same filesystem.
297*ead1f93eSLiane Praza	$mv_cmd $1 $2.$$
298*ead1f93eSLiane Praza	$mv_cmd $2.$$ $2
299*ead1f93eSLiane Praza	return $?
300*ead1f93eSLiane Praza}
301*ead1f93eSLiane Praza
302*ead1f93eSLiane Prazaoutfile=""
303*ead1f93eSLiane Prazatype=""
304*ead1f93eSLiane Prazaset_type_and_outfile() {
305*ead1f93eSLiane Praza	#
306*ead1f93eSLiane Praza	# Assumes basename $1 returns one of
307*ead1f93eSLiane Praza	# prof_attr, exec_attr, auth_attr, or user_attr
308*ead1f93eSLiane Praza	#
309*ead1f93eSLiane Praza	fname=`$basename_cmd $1`
310*ead1f93eSLiane Praza	type=`echo $fname | $sed_cmd -e s'/^\([a-z][a-z]*\)_attr$/\1/' `
311*ead1f93eSLiane Praza	case "$type" in
312*ead1f93eSLiane Praza		"prof"|"exec"|"user"|"auth") ;;
313*ead1f93eSLiane Praza		*) return 2 ;;
314*ead1f93eSLiane Praza	esac
315*ead1f93eSLiane Praza
316*ead1f93eSLiane Praza	outfile=$tmp_dir/rbac_${PKGINST}_${fname}_merge.$$
317*ead1f93eSLiane Praza
318*ead1f93eSLiane Praza	return 0
319*ead1f93eSLiane Praza}
320*ead1f93eSLiane Praza
321*ead1f93eSLiane Prazacleanup() {
322*ead1f93eSLiane Praza	$rm_cmd -f $outfile $outfile.old $outfile.new $outfile.unsorted
323*ead1f93eSLiane Praza
324*ead1f93eSLiane Praza	return 0
325*ead1f93eSLiane Praza}
326*ead1f93eSLiane Praza
327*ead1f93eSLiane Prazaexit_status=0
328*ead1f93eSLiane Praza
329*ead1f93eSLiane Praza# main
330*ead1f93eSLiane Praza
331*ead1f93eSLiane Prazawhile read newfile oldfile ; do
332*ead1f93eSLiane Praza	if [ -n "$PKGINST" ]
333*ead1f93eSLiane Praza	then
334*ead1f93eSLiane Praza		# Install the file in the "fragment" directory.
335*ead1f93eSLiane Praza		mkdir -m 755 -p ${oldfile}.d
336*ead1f93eSLiane Praza		rm -f ${oldfile}.d/"$PKGINST"
337*ead1f93eSLiane Praza		cp $newfile ${oldfile}.d/"$PKGINST"
338*ead1f93eSLiane Praza
339*ead1f93eSLiane Praza		# Make sure that it is marked read-only.
340*ead1f93eSLiane Praza		chmod a-w,a+r ${oldfile}.d/"$PKGINST"
341*ead1f93eSLiane Praza
342*ead1f93eSLiane Praza		# We also execute the rest of the i.rbac script.
343*ead1f93eSLiane Praza	fi
344*ead1f93eSLiane Praza
345*ead1f93eSLiane Praza	if [ ! -f $oldfile ]; then
346*ead1f93eSLiane Praza		cp $newfile $oldfile
347*ead1f93eSLiane Praza	else
348*ead1f93eSLiane Praza		set_type_and_outfile $newfile ||
349*ead1f93eSLiane Praza			set_type_and_outfile $oldfile
350*ead1f93eSLiane Praza		if [ $? -ne 0 ]; then
351*ead1f93eSLiane Praza			echo "$0 : $newfile not one of" \
352*ead1f93eSLiane Praza			    " prof_attr, exec_attr, auth_attr, user_attr"
353*ead1f93eSLiane Praza			exit_status=2
354*ead1f93eSLiane Praza			continue
355*ead1f93eSLiane Praza		fi
356*ead1f93eSLiane Praza
357*ead1f93eSLiane Praza		dbmerge $type $oldfile $newfile $outfile
358*ead1f93eSLiane Praza		if [ $? -ne 0 ]; then
359*ead1f93eSLiane Praza			echo "$0 : failed to merge $newfile with $oldfile"
360*ead1f93eSLiane Praza			cleanup
361*ead1f93eSLiane Praza			exit_status=2
362*ead1f93eSLiane Praza			continue
363*ead1f93eSLiane Praza		fi
364*ead1f93eSLiane Praza
365*ead1f93eSLiane Praza		commit $outfile $oldfile
366*ead1f93eSLiane Praza		if [ $? -ne 0 ]; then
367*ead1f93eSLiane Praza			echo "$0 : failed to mv $outfile to $2"
368*ead1f93eSLiane Praza			cleanup
369*ead1f93eSLiane Praza			exit_status=2
370*ead1f93eSLiane Praza			continue
371*ead1f93eSLiane Praza		fi
372*ead1f93eSLiane Praza
373*ead1f93eSLiane Praza		cleanup
374*ead1f93eSLiane Praza	fi
375*ead1f93eSLiane Prazadone
376*ead1f93eSLiane Praza
377*ead1f93eSLiane Prazaif [ "$1" = "ENDOFCLASS" ]; then
378*ead1f93eSLiane Praza	exit 0
379*ead1f93eSLiane Prazafi
380*ead1f93eSLiane Praza
381*ead1f93eSLiane Prazaexit $exit_status
382