Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1530 dpurdie 1
#!/bin/ksh -hp
2
#set -x
3
#
4
# @(#) patchrm.ksh 2.4 99/04/06 SMI
5
#
6
# 
7
# Copyright (c) 1996-1999 Sun Microsystems, Inc.  All Rights Reserved. Sun 
8
# considers its source code as an unpublished, proprietary trade secret, and 
9
# it is available only under strict license provisions.  This copyright 
10
# notice is placed here only to protect Sun in the event the source is 
11
# deemed a published work.  Dissassembly, decompilation, or other means of 
12
# reducing the object code to human readable form is prohibited by the 
13
# license agreement under which this code is provided to the user or company 
14
# in possession of this copy. 
15
# 
16
# RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the Government 
17
# is subject to restrictions as set forth in subparagraph (c)(1)(ii) of the 
18
# Rights in Technical Data and Computer Software clause at DFARS 52.227-7013 
19
# and in similar clauses in the FAR and NASA FAR Supplement. 
20
# 
21
# Exit Codes:
22
#		0	No error
23
#		1	Usage error
24
#		2	Attempt to backout a patch that hasn't been applied
25
#		3	Effective UID is not root
26
#		4	No saved files to restore
27
#		5	pkgrm failed
28
#		6	Attempt to back out an obsoleted patch
29
#		7	Attempt to restore CPIO archived files failed
30
#		8	Invalid patch id format
31
#		9	Prebackout script failed
32
#		10	Postbackout script failed
33
#		11	Suspended due to administrative defaults
34
#		12	Patchrm could not locate the backout data
35
#	   13	The relative directory supplied can't be found
36
#	   14	Patchadd has been interrupted, re-invoke patchadd 
37
#	   15	This patch is required by a patch already installed, can't back it out
38
#
39
 
40
# Set up the path to use with this script.
41
 
42
PATH=/usr/sadm/bin:/usr/sbin:/usr/bin:$PATH
43
export PATH
44
 
45
umask 007
46
 
47
# Global Files
48
 
49
TMPSOFT=/tmp/soft.$$
50
ADMINFILE=/tmp/admin.$$
51
LOGFILE=/tmp/backoutlog.$$
52
RESPONSE_FILE=/tmp/response.$$
53
TEMP_REMOTE=/tmp/temp_remote.$$
54
INSTPATCHES_FILE=/tmp/MyShowrevFile.$$
55
 
56
force=no
57
pkginstlist=
58
pkglist=
59
ret=
60
curdir=
61
diPatch="no"
62
ObsoletedBy="none"
63
ThisPatchFnd="no"
64
PatchedPkgs=""
65
InstPkgs=""
66
RebootRqd="no"
67
netImage="none"
68
compatsAlreadyChecked="no"
69
unReqAlreadyChecked="no"
70
 
71
typeset -i dbSum=0
72
 
73
ROOTDIR="/"
74
PATCHDB="/var/sadm/patch"
75
PATCH_UNDO_ARCHIVE="none"
76
OBS_PATCH_UNDO_ARCHIVE="none"
77
TEMP_PATCH_UNDO_ARCHIVE="none"
78
PKGDB="/var/sadm/pkg"
79
SOFTINFO="/var/sadm/softinfo"
80
NEW_SOFTINFO="/var/sadm/system/admin/INST_RELEASE"
81
OLD_SOFTINFO="/var/sadm/softinfo/INST_RELEASE"
82
MGRSOFTINFO="none"
83
TRGSOFTINFO="none"
84
CONTENTS="/var/sadm/install/contents"
85
TMP_LIB_DIR="/tmp/TmpLibDir.$$"
86
PKGDBARG=""
87
PATCH_PID=""
88
DASHB_SUPPLIED="no"
89
 
90
# This tells pkgadd to not check mounted FS's. Used in the mini-root.
91
MOPTION=""
92
 
93
# Version string of the patch data base file. Change this
94
# anytime the format of the .patchDB file changes. Also
95
# needs to be changed in patchadd.
96
PATCHDBVER="1.0"
97
 
98
# Needed utilities
99
DF=/usr/sbin/df
100
RM=/usr/bin/rm
101
MV=/usr/bin/mv
102
SED=/usr/bin/sed
103
AWK=/usr/bin/awk
104
NAWK=/usr/bin/nawk
105
CAT=/usr/bin/cat
106
LS=/usr/bin/ls
107
EGREP=/usr/bin/egrep
108
GREP=/usr/bin/grep
109
FGREP=/usr/bin/fgrep
110
CP=/usr/bin/cp
111
FIND=/usr/bin/find
112
UNAME=/usr/bin/uname
113
MOUNT=/sbin/mount
114
UMOUNT=/sbin/umount
115
SUM=/usr/bin/sum
116
 
117
recreatePatchDB="no"
118
 
119
PatchIdFormat='^[A-Z]*[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]$'
120
 
121
#
122
# Description:
123
#	Execute the prebackout script if it is executable. Fail if the
124
#	return code is not 0.
125
#
126
# Parameters:
127
#	$1	- package database directory
128
#	$2	- patch number
129
# Globals Set:
130
#	none
131
function execute_prebackout
132
{
133
	typeset -i retcode=0
134
	if [ -x $1/$2/prebackout ]
135
	then
136
		/usr/bin/gettext "Executing prebackout script...\n"
137
		$1/$2/prebackout
138
		retcode=$?
139
		if (( retcode != 0 ))
140
		then
141
			/usr/bin/gettext "prebackout script exited with return code $retcode.\n"
142
			/usr/bin/gettext "Patchrm is exiting.\n\n"
143
			exit 9
144
		fi
145
	fi
146
}
147
 
148
#
149
# Description:
150
#   Check to see if patchadd was interrupted, prompt
151
#	usr to reinvoke patchadd. 
152
#
153
# Globals Set:
154
#   RECOVERDIR
155
 
156
function check_file_recovery
157
{
158
	if [[ -f "$RECOVERDIR/.$PatchNum" ]]
159
	then
160
		/usr/bin/gettext "The installation of patch $PatchNum was interrupted.\nPatchadd needs to be re-invoked to ensure proper installation of the patch.\n"
161
		patch_quit 14
162
	fi
163
}
164
 
165
#
166
# Description:
167
#	Execute the postbackout script if it is executable. Fail if the
168
#	return code is not 0.
169
#
170
# Parameters:
171
#	$1	- package database directory
172
#	$2	- patch number
173
# Globals Set:
174
#	none
175
function execute_postbackout
176
{
177
	typeset -i retcode=0
178
	if [ -x $1/$2/postbackout ]
179
	then
180
		/usr/bin/gettext "Executing postbackout script...\n"
181
		$1/$2/postbackout
182
		retcode=$?
183
		if (( retcode != 0 ))
184
		then
185
			/usr/bin/gettext "postbackout script exited with return code $retcode.\nPatchrm exiting.\n\n"
186
			exit 10
187
		fi
188
	fi
189
}
190
 
191
# Quit patchrm and clean up any remaining temporary files.
192
function patch_quit {   # exit code
193
	if [[ $1 -ne 0 ]]
194
	then
195
		/usr/bin/gettext "\nPatchrm is terminating.\n"
196
	fi
197
 
198
	exit $1
199
}
200
 
201
#
202
# Description:
203
#	Return the base code of the provided patch. The base code
204
#	returned will include the version prefix token (usu "-").
205
#
206
# Parameters Used:
207
#	$1	- patch number
208
#
209
function get_base_code {
210
	ret_value=${1:%[0-9]}
211
	last_value=$1
212
 
213
	while [[ $ret_value != $last_value ]]
214
	do
215
		last_value=$ret_value
216
		ret_value=${last_value%[0-9]}
217
	done
218
 
219
	cur_base_code=${ret_value%?}
220
}
221
 
222
#
223
# Description:
224
#	Return the version number of the provided patch.
225
#
226
# Parameters Used:
227
#	$1	- patch number
228
#	$2	- base code
229
#
230
function get_vers_no {
231
	cur_vers_no=${1:#$2?}
232
}
233
 
234
#
235
# Description:
236
#	Give a list of applied patches similar in format to the showrev -p
237
#	command. Had to write my own because the showrev command won't take
238
#	a -R option.
239
#
240
# Parameters:
241
#	$1	- package database directory
242
#
243
# Globals used
244
#	PatchNum
245
#
246
# Globals Set:
247
#	diPatch
248
#	ObsoletedBy
249
#	ThisPatchFnd
250
#	PatchedPkgs
251
#
252
# Revision History
253
#	1995-08-01	Added PATCH_OBSOLETES and expanded the tests for
254
#			direct instance patches since all necessary
255
#			is reviewed at this time, this function also
256
#			tests for obsolescence, dependencies and
257
#			incompatibilities.
258
#
259
function eval_inst_patches
260
{
261
	typeset -i TestCount=0
262
	typeset -i ArrayCount=0
263
	typeset -i PatchFound=0
264
	typeset -i req_count=0
265
	typeset -i sr_count=0
266
 
267
	set -A PkgArrElem
268
	set -A ObsArrElem
269
	set -A ReqsArrElem
270
	set -A IncsArrElem
271
	set -A PatchArrElem
272
 
273
	# Use the file /var/sadm/patch/.patchDB instead of
274
	# gathering the information
275
 
276
	if [[ -s "$PATCHDBFILE" && "$recreatePatchDB" = "no" ]]; then
277
		$GREP -v "Version" $PATCHDBFILE
278
		return
279
	elif [[ "$is_an_instpatches" = "yes" ]]
280
	then
281
		cat $INSTPATCHES_FILE
282
		return
283
	fi
284
 
285
	olddir=$(pwd)
286
 
287
	#
288
	# First get the old-style patches and obsoletions
289
	#
290
	if [ -d $1 -a -d $PATCHDB ]
291
	then
292
		cd $1
293
		patches=
294
		patches=$(grep -l SUNW_PATCHID ./*/pkginfo | \
295
			xargs $SED -n 's/^SUNW_PATCHID=//p' | sort -u)
296
 
297
		if [ "$patches" != "" ]
298
		then
299
			for apatch in $patches
300
			do
301
				outstr="Patch: $apatch Obsoletes: "
302
 
303
				# Scan all the installed packages for this
304
				# patch number and return the effected
305
				# package instances
306
				patchvers=$(grep -l "SUNW_PATCHID=$apatch" \
307
					./*/pkginfo | $SED 's,^./\(.*\)/pkginfo$,\1,' )
308
 
309
				# If there's a PATCH_INFO entry then this
310
				# is really a direct instance patch
311
				for package in $patchvers
312
				do
313
					break;
314
				done
315
 
316
				$(grep "PATCH_INFO_$apatch" $package/pkginfo 1>/dev/null 2>&1)
317
				if [[ $? -eq 0 ]]
318
				then
319
					continue
320
				fi
321
 
322
				PatchFound=1
323
 
324
				obsoletes_printed="n"
325
				for vers in $patchvers
326
				do
327
					if [ "$obsoletes_printed" = "n" ]
328
					then
329
						outstr="$outstr$($SED -n \
330
							's/SUNW_OBSOLETES=//p' \
331
							./$vers/pkginfo) Packages: "
332
						outstr="$outstr$vers $($SED -n \
333
							's/VERSION=//p' \
334
							./$vers/pkginfo)"
335
						obsoletes_printed="y"
336
					else
337
						outstr="$outstr, $vers $($SED \
338
							-n 's/VERSION=//p' \
339
							./$vers/pkginfo)"
340
					fi
341
				done
342
 
343
				# The current patch is a progressive
344
				# instance patch
345
				if [[ $apatch = "$PatchNum" ]]
346
				then
347
					diPatch="no"
348
					ThisPatchFnd="yes"
349
				fi
350
 
351
				echo $outstr | tee -a $INSTPATCHES_FILE
352
			done
353
		fi
354
	fi
355
 
356
	#
357
	# Now get the direct instance patches
358
	#
359
	# DIPatches is a non-repeating list of all patches applied
360
	# to the system.
361
	#
362
	typeset -i TempCount=0
363
 
364
	InstPkgs=$(pkginfo -R $ROOTDIR | $NAWK ' { print $2; } ')
365
 
366
	for package in $InstPkgs
367
	do
368
		DIPatches=$(pkgparam -R $ROOTDIR $package PATCHLIST)
369
		for patch in $DIPatches
370
		do
371
			get_base_code $patch
372
			patch_base=$cur_base_code
373
 
374
			get_vers_no $patch $patch_base
375
			patch_vers=$cur_vers_no
376
 
377
			PatchFound=1;
378
 
379
			# Get the obsoletes from each installed package
380
 
381
			tmpStr=""
382
			tmpStr=$(pkgparam -R $ROOTDIR $package PATCH_INFO_$patch)
383
			obsoletes=${tmpStr##*Obsoletes:}
384
			obsoletes=${obsoletes%%Requires:*}
385
 
386
			#obsoletes=$(echo $tmpStr | $GREP Obsoletes: | $NAWK ' \
387
			  #{ print substr($0, match($0, "Obsoletes:")+11) } ' | \
388
			  #$SED 's/Requires:.*//g')
389
 
390
			# Get the requires from each installed package
391
 
392
			reqs=${tmpStr##*Requires:}
393
			reqs=${reqs%%Incompatibles:*}
394
 
395
			#reqs=$(echo $tmpStr | $GREP Requires: | $NAWK ' \
396
			  #{ print substr($0, match($0, "Requires:")+10) } ' | \
397
			  #$SED 's/Incompatibles:.*//g')
398
 
399
			# Get the incompatibles from each installed package
400
 
401
			incs=${tmpStr##*Incompatibles:}
402
 
403
			#incs=$(echo $tmpStr | $GREP Incompatibles: | $NAWK ' \
404
			  #{ print substr($0, match($0, "Incompatibles:")+15) } ')
405
 
406
			if [[ -n "$obsoletes" ]]
407
			then
408
				for obs in $obsoletes;
409
				do
410
					PatchArrElem[$ArrayCount]=$patch;
411
					ObsArrElem[$ArrayCount]=$obs;
412
					PkgArrElem[$ArrayCount]=$package;
413
					ArrayCount=ArrayCount+1;
414
				done
415
			else
416
				PatchArrElem[$ArrayCount]=$patch;
417
				ObsArrElem[$ArrayCount]="";
418
				PkgArrElem[$ArrayCount]=$package;
419
				ArrayCount=ArrayCount+1;
420
			fi
421
 
422
			if [[ -n "$reqs" ]]
423
			then
424
				for req in $reqs;
425
				do
426
					PatchArrElem[$ArrayCount]=$patch;
427
					ReqsArrElem[$ArrayCount]=$req;
428
					PkgArrElem[$ArrayCount]=$package;
429
					ArrayCount=ArrayCount+1;
430
				done
431
			else
432
				PatchArrElem[$ArrayCount]=$patch;
433
				ReqsArrElem[$ArrayCount]="";
434
				PkgArrElem[$ArrayCount]=$package;
435
				ArrayCount=ArrayCount+1;
436
			fi
437
 
438
			if [[ -n "$incs" ]]
439
			then
440
				for inc in $incs;
441
				do
442
					PatchArrElem[$ArrayCount]=$patch;
443
					IncsArrElem[$ArrayCount]=$inc;
444
					PkgArrElem[$ArrayCount]=$package;
445
					ArrayCount=ArrayCount+1;
446
				done
447
			else
448
				PatchArrElem[$ArrayCount]=$patch;
449
				IncsArrElem[$ArrayCount]="";
450
				PkgArrElem[$ArrayCount]=$package;
451
				ArrayCount=ArrayCount+1;
452
			fi
453
 
454
			# Check for already installed
455
			if [[ "$patch" = "$PatchNum" ]]
456
			then
457
				ThisPatchFnd="yes"
458
				diPatch="yes"
459
			fi
460
 
461
			CheckInstallingCompats $patch $patch_base $patch_vers
462
			compatsAlreadyChecked="yes"
463
		done
464
	done
465
 
466
	CheckUninstalledReqs
467
	unReqAlreadyChecked="yes"
468
 
469
	while [[ $TestCount -lt $ArrayCount ]]
470
	do
471
		typeset -i TempCount=TestCount+1
472
 
473
		# Scan all entries matching the current one
474
		PatchArrEntry=${PatchArrElem[$TestCount]}   # Current one
475
		ObsArrEntry=${ObsArrElem[$TestCount]}
476
		PkgArrEntry=${PkgArrElem[$TestCount]}
477
		ReqsArrEntry=${ReqsArrElem[$TestCount]}
478
		IncsArrEntry=${IncsArrElem[$TestCount]}
479
 
480
		if [[ "$PatchArrEntry" = "used" ]]
481
		then
482
			TestCount=TestCount+1
483
			continue
484
		fi
485
 
486
		while [[ $TempCount -lt $ArrayCount ]]
487
		do
488
			typeset -i dont_use;
489
			#
490
			# If this is another line describing this patch
491
			#
492
			if [[ ${PatchArrElem[$TempCount]} = $PatchArrEntry ]]
493
			then
494
				dont_use=0;
495
 
496
				PatchArrElem[$TempCount]="used"
497
				for pkg in $PkgArrEntry
498
				do
499
					if [[ $pkg = ${PkgArrElem[$TempCount]} ]]
500
					then
501
						dont_use=1;
502
						break;
503
					fi
504
				done
505
 
506
				if [[ $dont_use = 0 ]]
507
				then
508
					PkgArrEntry="$PkgArrEntry ${PkgArrElem[$TempCount]}"
509
				fi
510
 
511
				dont_use=0;
512
 
513
				for obs in $ObsArrEntry
514
				do
515
					if [[ $obs = ${ObsArrElem[$TempCount]} ]]
516
					then
517
						dont_use=1;
518
						break;
519
					fi
520
				done
521
 
522
				if [[ $dont_use = 0 ]]
523
				then
524
					ObsArrEntry="$ObsArrEntry ${ObsArrElem[$TempCount]}"
525
				fi
526
 
527
				dont_use=0;
528
 
529
				for inc in $IncsArrEntry
530
				do
531
					if [[ $inc = ${IncsArrElem[$TempCount]} ]]
532
					then
533
						dont_use=1;
534
						break;
535
					fi
536
				done
537
 
538
				if [[ $dont_use = 0 ]]
539
				then
540
					IncsArrEntry="$IncsArrEntry ${IncsArrElem[$TempCount]}"
541
				fi
542
 
543
				dont_use=0;
544
 
545
				for req in $ReqsArrEntry
546
				do
547
					if [[ $req = ${ReqsArrElem[$TempCount]} ]]
548
					then
549
						dont_use=1;
550
						break;
551
					fi
552
				done
553
 
554
				if [[ $dont_use = 0 ]]
555
				then
556
					ReqsArrEntry="$ReqsArrEntry ${ReqsArrElem[$TempCount]}"
557
				fi
558
 
559
			fi
560
			TempCount=TempCount+1
561
		done
562
 
563
		if [[ $PatchArrEntry = "$PatchNum" ]]; then
564
			export PatchedPkgs="$PkgArrEntry"
565
		fi
566
 
567
		# Now make it comma separated lists
568
		PkgArrEntry=$(echo $PkgArrEntry | $SED s/\ /,\ /g)
569
		ObsArrEntry=$(echo $ObsArrEntry | $SED s/\ /,\ /g)
570
		ReqsArrEntry=$(echo $ReqsArrEntry | $SED s/\ /,\ /g)
571
		IncsArrEntry=$(echo $IncsArrEntry | $SED s/\ /,\ /g)
572
 
573
		outstr="Patch: $PatchArrEntry Obsoletes: $ObsArrEntry \
574
		  Requires: $ReqsArrEntry Incompatibles: $IncsArrEntry \
575
		  Packages: $PkgArrEntry"
576
 
577
		echo $outstr | tee -a $INSTPATCHES_FILE
578
 
579
		TestCount=TestCount+1
580
	done
581
 
582
	if [[ ! -f "$PATCHDBFILE" || "$recreatePatchDB" == "yes" ]]; then
583
		pkginfoParamSum
584
		echo "Version $PATCHDBVER $dbSum" > $PATCHDBFILE
585
		cat $INSTPATCHES_FILE >> $PATCHDBFILE
586
		chmod 600 $PATCHDBFILE > /dev/null 2>&1
587
	fi
588
 
589
	cd $olddir;
590
}
591
 
592
# Description:
593
#	Export variables that prebackout or postbackout may need.
594
 
595
function exportVars
596
{
597
	export PatchNum="$PatchNum"
598
	export ROOTDIR="$ROOTDIR"
599
}
600
 
601
#
602
# Description:
603
#	Get the sum of the PATCHID and the PATCHLIST parameters.
604
#
605
 
606
function pkginfoParamSum
607
{
608
	dbSum=$($NAWK '/PATCHID/ {print} /PATCHLIST/ {print}' \
609
		$PKGDB/*/pkginfo 2>/dev/null | $SUM | $NAWK '{print $1}')
610
}
611
 
612
#
613
# Description
614
#	
615
function CheckUninstalledReqs
616
{
617
	req_count=0;
618
	for req in $Requires; do
619
		if [[ ${ReqArrElem[$req_count]} = "no" ]]
620
		then
621
			ReqdPatchCnt=ReqdPatchCnt+1
622
			UninstReqs="$UninstReqs $req"
623
		fi
624
		req_count=req_count+1;
625
	done
626
 
627
	if [[ $validate = "no" ]]
628
	then
629
		ReqdPatchCnt=0
630
	fi
631
}
632
 
633
# Description:
634
#   Find installing compatibility issues.
635
#
636
# Parameters
637
# 	$1 - installing patch
638
#	$2 - installed patch base code
639
#	$3 - installed patch version
640
#
641
function CheckInstallingCompats
642
{
643
	# Check for incompatible patches
644
	for incompat in $Incompat
645
	do
646
		get_base_code $incompat
647
 
648
		if [[ "$2" = "$cur_base_code" ]]
649
		then
650
			get_vers_no $incompat $cur_base_code
651
			if [[ $3 -ge $cur_vers_no ]]
652
			then
653
				InstIncompat=$1
654
			fi
655
		fi
656
	done
657
 
658
	# Check for required patches
659
	req_count=0;
660
 
661
	for required in $Requires; do
662
		get_base_code $required
663
 
664
		if [[ "$2" = "$cur_base_code" ]]
665
		then
666
			get_vers_no $required $cur_base_code
667
 
668
			if [[ $3 -ge $cur_vers_no ]]
669
			then
670
				ReqArrElem[$req_count]="yes"
671
			fi
672
		fi
673
		req_count=req_count+1
674
	done
675
 
676
	for obs_entry in $obsoletes
677
	do
678
		get_base_code $obs_entry
679
 
680
		if [[ "$cur_base_code" = "$PatchBase" ]]
681
		then
682
			get_vers_no $obs_entry $cur_base_code
683
			if [[ $cur_vers_no -ge $PatchVers ]]
684
			then
685
				ObsoletedBy=$1
686
			else
687
				ObsoletePast=$PatchBase
688
				ObsoletedBy=$1
689
			fi
690
		fi
691
	done
692
}
693
 
694
# Description:
695
#	Print out the usage message to the screen
696
# Parameters:
697
#	none
698
 
699
function print_usage
700
{
701
cat<<EOF
702
 
703
   Usage: patchrm [-f] [-B backout_dir] [-R <client_root_path> | -S <service>]
704
			[-C <net_install_image>] <patch_id>
705
 
706
EOF
707
 
708
# This line gets inserted after Usage message.
709
# [-C <net_install_image>]
710
}
711
 
712
# Description:
713
#	Patch obsolecense message, printed if the patch being backed
714
#	out was superceded by other patches 
715
# Parameters:
716
#	$1	- patch ID
717
#	$2	- patch revision number
718
#
719
function print_obsolete_msg
720
{
721
	outstr="This patch was obsoleted by patch $1"
722
	if [[ "$2" = "none" ]]
723
	then
724
		outstr="$outstr."
725
	else
726
		outstr="$outstr-$2."
727
	fi
728
	/usr/bin/gettext "$outstr\n\nPatches must be backed out in the reverse order in\nwhich they were installed.\n\nPatchrm exiting.\n\n"
729
}
730
 
731
# Description:
732
#	   Find the appropriate softinfo files for the manager and the target.
733
# Parameters:
734
#	   $1	  ROOT of target filesystem
735
# Globals set:
736
#	   TRGSOFTINFO
737
#	   MGRSOFTINFO
738
# Globals used:
739
#	   OLD_SOFTINFO
740
#	   NEW_SOFTINFO
741
function find_softinfos
742
{
743
	if [[ "$netImage" = "boot" ]]
744
	then
745
		return
746
	fi
747
 
748
	if [[ -f $NEW_SOFTINFO ]]
749
	then
750
		MGRSOFTINFO=$NEW_SOFTINFO
751
	elif [[ -f $OLD_SOFTINFO ]]
752
	then
753
		MGRSOFTINFO=$OLD_SOFTINFO
754
	fi
755
 
756
	if [[ "$1" = "/" || "$1" = "" ]]
757
	then
758
		TRGSOFTINFO=MGRSOFTINFO
759
	elif [[ -f $1$NEW_SOFTINFO ]]
760
	then
761
		TRGSOFTINFO=$1$NEW_SOFTINFO
762
	elif [[ -f $1$OLD_SOFTINFO ]]
763
	then
764
		TRGSOFTINFO=$1$OLD_SOFTINFO
765
	fi
766
}
767
 
768
# Description:
769
#   Check the host system for 2.6 existence.
770
#
771
function check_for_2_6
772
{
773
	# Only the managing hosts OS is checked for now
774
	# 9/21/96
775
 
776
	mgrOS=
777
	mgrOS=$($UNAME -r)
778
	if [[ "$mgrOS" -le "5.5.1" ]]
779
	then
780
		/usr/bin/gettext "WARNING: patchrm must be executed from a 2.6 or later system.\n\n"
781
		exit $?
782
	fi
783
}
784
 
785
# Description:
786
#	Parse the arguments and set all affected global variables
787
# Parameters:
788
#	Arguments to patchrm
789
# Globals Set:
790
#	force
791
#	PatchNum
792
#	ROOTDIR
793
#	PATCHDB
794
#	PKGDB
795
#	PKGDBARG
796
#	CONTENTS
797
# Globals used:
798
#	Mgrprodver
799
#	MGRSOFTINO
800
#	TRGSOFTINFO
801
#
802
 
803
function parse_args
804
{
805
	# Inserted for readability reasons
806
	echo ""
807
	service_specified="n"
808
	rootdir_specified="n"
809
	origdir=$(pwd)
810
	while [[ "$1" != "" ]]
811
	do
812
		case $1 in
813
		-f)	force="yes"
814
			shift;;
815
		-B)	shift
816
			if [[ -d $1 ]]
817
			then
818
				determine_directory $1
819
				if [[ $ret = 0 ]]
820
				then
821
					PATCH_UNDO_ARCHIVE=$1
822
				else
823
					PATCH_UNDO_ARCHIVE=$curdir
824
				fi
825
				DASHB_SUPPLIED="yes"
826
				TEMP_PATCH_UNDO_ARCHIVE=$PATCH_UNDO_ARCHIVE
827
			else
828
				/usr/bin/gettext "Specified backout directory $1 cannot be found.\n"
829
				exit 1
830
			fi
831
			shift;;
832
				-V) echo "@(#) patchrm.ksh 2.4 99/04/06"
833
			exit 0
834
			shift;;
835
		-S)	shift
836
			if [[ "$service_specified" != "n" ]]
837
			then
838
				/usr/bin/gettext "Only one service may be defined.\n"
839
				print_usage
840
				exit 1
841
			elif [[ "$rootdir_specified" != "n" ]]
842
			then
843
				/usr/bin/gettext "The -S and -R options are mutually exclusive.\n"
844
				print_usage
845
				exit 1
846
			fi
847
			find_softinfos /export/$1
848
 
849
			get_OS_version "$TRGSOFTINFO" "$MGRSOFTINFO" "$1"
850
 
851
			if [ "$1" != "$Mgrprodver" ]
852
			then
853
				if [ -d "/export/$1$PKGDB" ]
854
				then
855
					ROOTDIR=/export/$1
856
					PATCHDB=$ROOTDIR$PATCHDB
857
					PKGDB=$ROOTDIR$PKGDB
858
					SOFTINFO=$ROOTDIR$SOFTINFO
859
					PKGDBARG="-R $ROOTDIR"
860
					CONTENTS=$ROOTDIR$CONTENTS
861
					service_specified="y"
862
				else
863
					/usr/bin/gettext "The $1 service cannot be found on this system.\n"
864
					print_usage
865
					patch_quit 1
866
				fi
867
			fi
868
			shift;;
869
		-R)	shift
870
			if [[ "$rootdir_specified" != "n" ]]
871
			then
872
				/usr/bin/gettext "Only one client may be defined.\n"
873
				print_usage
874
				exit 1
875
			elif [[ "$service_specified" != "n" ]]
876
			then
877
				/usr/bin/gettext "The -S and -R options are mutually exclusive.\n"
878
				print_usage
879
				exit 1
880
			fi
881
			if [[ -d "$1" ]]
882
			then
883
				determine_directory $1
884
			if [[ $ret = 0 ]]
885
			then
886
				ROOTDIR=$1
887
			else
888
				ROOTDIR=$curdir
889
			fi
890
				PATCHDB=$ROOTDIR/var/sadm/patch
891
				PKGDB=$ROOTDIR/var/sadm/pkg
892
				SOFTINFO=$ROOTDIR$SOFTINFO
893
				PKGDBARG="-R $ROOTDIR"
894
				CONTENTS=$ROOTDIR$CONTENTS
895
				rootdir_specified="y"
896
			else
897
				/usr/bin/gettext "The $1 directory cannot be found on this system.\n"
898
				print_usage
899
				exit 1
900
			fi
901
			shift;;
902
		-C) shift
903
			if [[ "$service_specified" = "y" || "$rootdir_specified" = "y" ]]
904
			then 
905
				/usr/bin/gettext "The -S, -R and -C arguments are mutually exclusive.\n"
906
				print_usage
907
				patch_quit 1
908
			fi 
909
			if [ ! -d "$1" ]
910
			then 
911
				/usr/bin/gettext "The path to the net install image $1 cannot be found on this disk.\n"
912
				print_usage
913
				patch_quit 1
914
			else 
915
				determine_directory $1
916
				if [[ $ret = 0 ]]
917
				then
918
					ROOTDIR=$1
919
				else
920
					ROOTDIR=$curdir
921
				fi
922
				PATCHDB=$ROOTDIR$PATCHDB
923
				PKGDB=$ROOTDIR$PKGDB
924
				PKGDBARG="-R $ROOTDIR"
925
				netImage="boot"
926
			fi
927
			shift;;
928
 
929
		-*)	print_usage
930
			exit 1;;
931
		 *)	break;;
932
		esac
933
	done
934
	PatchNum=$1
935
 
936
	PATCHDBFILE=$ROOTDIR/var/sadm/patch/.patchDB
937
	RECOVERDIR=$ROOTDIR/var/sadm/.patchRec
938
 
939
	#
940
	# If there is no patch number specified, exit with an error.
941
	#
942
	if [[ "$PatchNum" = "" ]]
943
	then
944
		/usr/bin/gettext "No patch number was specified.\n"
945
		print_usage
946
		exit 1
947
	fi
948
}
949
 
950
# Description:
951
# 	Derive the full path name from a (possibly) relative path name.
952
# Parameters:
953
#	   $1	  - command line argument
954
#
955
# Globals Used:
956
#	ret
957
#	   curdir
958
 
959
function determine_directory
960
{
961
	$(valpath -a $1)
962
	ret=$?
963
	if [[ $ret != 0 ]]
964
	then
965
		cd $1 3>/dev/null
966
		if [[ $? = 0 ]]
967
		then
968
			curdir=$(pwd)
969
			cd $origdir
970
		else
971
			/usr/bin/gettext "Can not determine relative directory.\n"
972
			patch_quit 13
973
		fi
974
	else
975
		return
976
	fi
977
}
978
 
979
# Description:
980
#	Make sure the effective UID is '0'
981
# Parameters:
982
#	none
983
function validate_uid
984
{
985
	typeset -i uid
986
	uid=$(id | $SED 's/uid=\([0-9]*\)(.*/\1/')
987
	if (( uid != 0 ))
988
	then
989
		/usr/bin/gettext "You must be root to execute this script.\n"
990
		exit 3
991
	fi
992
}
993
 
994
# Description:
995
#	   Get the product version <name>_<version> of local Solaris installation
996
# Parameters:
997
#	   $1	  target host softinfo directory path
998
#	   $2	  managing host softinfo directory path
999
#	   $3	  root of the target host
1000
# Globals Set:
1001
#	   prodver
1002
#
1003
function get_OS_version
1004
{
1005
	# If this a patch to a net install image we don't care about
1006
	# the managing and target host we know it will be a 2.6 or
1007
	# beyond OS.
1008
	if [[ "$netImage" = "boot" ]]
1009
	then
1010
		MgrProduct="Solaris"
1011
		MgrOSVers="2.6"
1012
		Mgrprodver=$MgrProduct"_"$MgrOSVers
1013
		TrgOSVers=$MgrOSVers
1014
		Product=$MgrProduct
1015
		prodver=$Mgrprodver
1016
		return
1017
	fi
1018
 
1019
	if [[ "$2" != "none" ]]
1020
	then
1021
		MgrProduct=$($SED -n 's/^OS=\(.*\)/\1/p' $2)
1022
		MgrOSVers=$($SED -n 's/^VERSION=\(.*\)/\1/p' $2)
1023
		Mgrprodver=$MgrProduct"_"$MgrOSVers
1024
	else
1025
		MgrProduct="Solaris"
1026
		MgrOSVers=$(uname -r | $SED -n -e 's/5\./2\./p' -e 's/4\./1\./p')
1027
		Mgrprodver=$MgrProduct"_"$MgrOSVers
1028
	fi
1029
 
1030
	if [[ $3 = "/" ]]	   # If there's not a client
1031
	then
1032
		Product=$MgrProduct
1033
		TrgOSVers=$MgrOSVers
1034
		prodver=$Mgrprodver
1035
 
1036
	# OK, there is a client
1037
	elif [[ "$1" = "none" ]]		# but no softinfo file
1038
	then
1039
		/usr/bin/gettext "patchrm is unable to find the INST_RELEASE file for the target\nfilesystem.  This file must be present for patchrm to function correctly.\n"
1040
		patch_quit 11
1041
	else
1042
		Product=$($SED -n 's/^OS=\(.*\)/\1/p' $1)
1043
		TrgOSVers=$($SED -n 's/^VERSION=\(.*\)/\1/p' $1)
1044
		prodver=$Product"_"$TrgOSVers
1045
	fi
1046
}
1047
 
1048
# Description:
1049
#	Build the admin script for pkgadd
1050
# Parameters:
1051
#	none
1052
# Globals Used:
1053
#	ADMINFILE
1054
function build_admin
1055
{
1056
	if [[ "$PatchMethod" = "direct" && -f /var/sadm/install/admin/patch ]]
1057
	then
1058
		ADMINFILE=/var/sadm/install/admin/patch
1059
	else
1060
		cat >$ADMINFILE <<EOF
1061
mail=
1062
instance=unique
1063
partial=nocheck
1064
runlevel=nocheck
1065
idepend=nocheck
1066
rdepend=nocheck
1067
space=quit
1068
setuid=nocheck
1069
conflict=nocheck
1070
action=nocheck
1071
basedir=default
1072
EOF
1073
fi
1074
}
1075
 
1076
# Description:
1077
# 	Restore old versions of files
1078
# Parameters:
1079
#	$1	- patch database directory
1080
#	$2	- patch number
1081
#	$3	- package command relocation argument
1082
#	$4	- path name of contents file
1083
#	
1084
 
1085
function restore_orig_files
1086
{
1087
	olddir=
1088
	file=
1089
	ownerfound=
1090
	srch=
1091
	cfpath=
1092
	instlist=
1093
	filelist=
1094
 
1095
	if [[ ! -f $1/$2/.nofilestosave ]]
1096
	then
1097
		/usr/bin/gettext "Restoring previous version of files...\n"
1098
		if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
1099
		then
1100
			olddir=$PATCH_UNDO_ARCHIVE
1101
		else
1102
			olddir=$(pwd)
1103
			olddir=$olddir/save
1104
		fi
1105
		cd $ROOTDIR
1106
		# Must retain backwards compatibility to restore
1107
		# archives which were not stored as files
1108
		if [[ -f $olddir/archive.cpio ]]
1109
		then 
1110
			filelist=$(cat $olddir/archive.cpio | cpio -it 2>/dev/null)
1111
			cpio -idumv -I $olddir/archive.cpio
1112
		else 
1113
			if [[ -f $olddir/archive.cpio.Z ]]
1114
			then
1115
				filelist=$(zcat $olddir/archive.cpio.Z | \
1116
							cpio -it 2>/dev/null)
1117
				zcat $olddir/archive.cpio.Z | cpio -idumv
1118
			else
1119
				filelist=$($FIND . -print | $SED "s/^.//")
1120
				$FIND  . -print | cpio -pdumv / 
1121
			fi
1122
		fi
1123
		if [[ $? -ne 0 ]]
1124
		then
1125
			/usr/bin/gettext "Restore of old files failed.\nSee Install.info file for instructions.\n"
1126
			$RM -f /tmp/*.$$
1127
			remove_libraries
1128
			exit 7
1129
		fi
1130
		/usr/bin/gettext "Making package database consistent with restored files:\n"
1131
		$RM -f /tmp/fixfile.$$ > /dev/null 2>&1
1132
		for file in $filelist
1133
		do
1134
			if [[ ! -f $file || -h $file ]]
1135
			then
1136
				continue
1137
			fi
1138
			# if file failed validation when the patch was 
1139
			# installed, don't do an installf on it.  It should 
1140
			# continue to fail validation after the patch is 
1141
			# backed out.
1142
			file1=$(expr $file : '\(\/.*\)')
1143
			if [[ "$file1" = "" ]]
1144
			then
1145
				file1="/"$file
1146
			fi
1147
			srch="^$file1\$"
1148
			if [[ -f $1/$2/.validation.errors ]] && \
1149
				grep "$srch" $1/$2/.validation.errors >/dev/null 2>&1
1150
			then 
1151
				continue
1152
			fi
1153
 
1154
			# The following commands find the file's entry in the
1155
			# contents file, and return the first field of the 
1156
			# entry. If the file is a hard link, the first field 
1157
			# will contain an "=".  This will cause the -f test to 
1158
			# fail and we won't try to installf the file.
1159
			srch="^$file1[ =]"
1160
			cfpath=$(grep "$srch" $CONTENTS | $SED 's/ .*//')
1161
			if [[ "$cfpath" = "" || ! -f "$ROOTDIR$cfpath" ]]
1162
			then
1163
				continue
1164
			fi
1165
			ownerfound=no
1166
			# Parsing pkgchk output is complicated because all text
1167
			# may be localized. Currently the only line in the 
1168
			# output which contains a tab is the line of packages 
1169
			# owning the file, so we search for lines containing a 
1170
			# tab.  This is probably reasonably safe. If any of the
1171
			# text lines end up with tabs due to localization, the 
1172
			# pkginfo check should protect us from calling installf
1173
			# with a bogus package instance argument.
1174
			pkgchk $3 -lp $file1 | grep '	' | \
1175
			while read instlist
1176
			do
1177
				for i in $instlist
1178
				do
1179
					pkginfo $3 $i >/dev/null 2>&1
1180
					if [[ $? -eq 0 ]]
1181
					then
1182
						echo $i $file1 >> /tmp/fixfile.$$
1183
						ownerfound=yes
1184
						break
1185
					fi
1186
				done
1187
				if [[ $ownerfound = "yes" ]]
1188
				then
1189
					break
1190
				fi
1191
			done
1192
		done
1193
		if [[ -s /tmp/fixfile.$$ ]]
1194
		then
1195
			$SED 's/^\([^ ]*\).*/\1/' /tmp/fixfile.$$ | sort -u | \
1196
			while read pkginst
1197
			do
1198
				grep "^${pkginst} " /tmp/fixfile.$$ | \
1199
				$SED 's/^[^ ]* \(.*\)/\1/' | \
1200
				if [[ "$ROOTDIR" != "/" ]]
1201
				then
1202
					installf $PKGDBARG $pkginst -
1203
					installf $PKGDBARG -f $pkginst
1204
				else
1205
					installf $pkginst -
1206
					installf -f $pkginst
1207
				fi
1208
			done
1209
		fi
1210
		cd $olddir
1211
	fi
1212
}
1213
 
1214
#
1215
# Description:
1216
#	Change directory to location of patch
1217
# Parameters:
1218
#	$1	- patch database directory
1219
#	$2	- patch number
1220
# Globals Set:
1221
#	patchdir
1222
#	PatchBase
1223
#	PatchVers
1224
function activate_patch
1225
{
1226
	result=""
1227
 
1228
	if [[ "$recreatePatchDB" = "yes" || ! -f "$PATCHDBFILE" ]]; then
1229
		eval_inst_patches $PKGDB > /dev/null 2>&1
1230
	else # New style patch data base
1231
		result=$($GREP "Patch: $PatchNum" $PATCHDBFILE)
1232
		if [[ -n $result ]]; then
1233
			ThisPatchFnd="yes"
1234
			PatchedPkgs=$($GREP "Patch: $PatchNum" $PATCHDBFILE | \
1235
			  $NAWK ' {print substr($0, match($0, "Packages:")+10) }' | \
1236
			  $SED 's/,//g')
1237
 
1238
			for p in $PatchedPkgs; do 
1239
				pList=""
1240
				pList=$(pkgparam -f $PKGDB/$p/pkginfo PATCHLIST | \
1241
					$GREP $PatchNum)
1242
				if [[ -n "$pList" ]]; then
1243
					diPatch="yes"  
1244
					break
1245
				else   
1246
					diPatch="no"
1247
				fi
1248
			done 
1249
		fi
1250
	fi
1251
 
1252
	if [[ $ThisPatchFnd = "yes" ]]
1253
	then
1254
		patchdir=$1/$2
1255
 
1256
		# For direct instance patches, this may not be here
1257
		if [[ -d $patchdir ]]
1258
		then
1259
			cd $patchdir
1260
		fi
1261
 
1262
		#
1263
		# Get the patch base code (the number up to the version prefix) 
1264
		# and the patch revision number (the number after the version prefix).
1265
		#
1266
		get_base_code $PatchNum
1267
		PatchBase=$cur_base_code
1268
		get_vers_no $PatchNum $cur_base_code
1269
		PatchVers=$cur_vers_no
1270
	else
1271
		/usr/bin/gettext "Patch $2 has not been applied to this system.\n"
1272
 		if [[ -d $1/$2 ]]
1273
		then
1274
 			/usr/bin/gettext "Will remove directory $1/$2\n"
1275
 			$RM -r $1/$2
1276
 		fi
1277
 
1278
		patch_quit 2
1279
	fi
1280
 
1281
}
1282
 
1283
# Description:
1284
#	Find the package instances for this patch
1285
# Parameters:
1286
#	$1	- package database directory
1287
#	$2	- patch number
1288
# Globals Set:
1289
#	pkginstlist
1290
 
1291
function get_pkg_instances
1292
{
1293
	pkginst=
1294
	j=
1295
	for j in $1/*
1296
	do
1297
		if grep -s "SUNW_PATCHID *= *$2" $j/pkginfo > /dev/null 2>&1
1298
		then
1299
			pkginst=$(basename $j)
1300
			pkginstlist="$pkginstlist $pkginst"
1301
		fi
1302
	done
1303
}
1304
 
1305
# Description:
1306
# 	Check to see if this patch was obsoleted by another patch.
1307
# Parameters:
1308
#	$1	- patch database directory
1309
#	$2	- patch ID
1310
#	$3	- patch revision
1311
 
1312
function check_if_obsolete
1313
{
1314
	if [[ "$diPatch" = "yes" ]]
1315
	then
1316
		if [[ "$ObsoletedBy" = "none" ]]
1317
		then
1318
			return
1319
		else
1320
			print_obsolete_msg "$ObsoletedBy" "none"
1321
			exit 6
1322
		fi
1323
	else
1324
		Patchid=
1325
		oldbase=
1326
		oldrev=
1327
		opatchid=
1328
		obase=
1329
		obsoletes=
1330
		i=
1331
		j=
1332
		if [[ -d $1 ]]
1333
		then
1334
			cd $1
1335
			for i in * X
1336
			do
1337
				if [[ $i = X || "$i" = "*" ]]
1338
				then
1339
					break
1340
				elif [[ ! -d $i ]]
1341
				then
1342
					continue
1343
				fi
1344
				cd $i
1345
				for j in */pkginfo X
1346
				do
1347
					if [[ "$j" = "X" || "$j" = "*/pkginfo" ]]
1348
					then
1349
						break
1350
					fi
1351
					Patchid=$($SED -n 's/^[ 	]*SUNW_PATCHID[ 	]*=[ 	]*\([^ 	]*\)[	 ]*$/\1/p' $j)
1352
					if [[ "$Patchid" = "" ]]
1353
					then
1354
						continue
1355
					fi
1356
					oldbase=${Patchid%-*}
1357
					oldrev=${Patchid#*-}
1358
					if [[ $oldbase = $2 && $3 -lt $oldrev ]]
1359
					then
1360
						print_obsolete_msg "$2" "$oldrev"
1361
						exit 6
1362
					fi
1363
					obsoletes=$($SED -n 's/^[	 ]*SUNW_OBSOLETES[ 	]*=[ 	]*\([^ 	]*\)[ 	]*$/\1/p' $j)
1364
					while [ "$obsoletes" != "" ]
1365
					do
1366
						opatchid=$(expr $obsoletes : '\([0-9\-]*\).*')
1367
						obsoletes=$(expr $obsoletes : '[0-9\-]*[ ,]*\(.*\)')
1368
						# patchrevent infinite loop.  If we couldn't
1369
						# find a valid patch id, just quit.
1370
						if [[ "$opatchid" = "" ]]
1371
						then
1372
							break;
1373
						fi
1374
						obase=$(expr $opatchid : '\(.*\)-.*')
1375
						if [[ "$obase" = "" ]]
1376
						then
1377
							# no revision field in opatchid,
1378
							# might be supported someday 
1379
							# (we don't use the revision 
1380
							# field for obsoletion testing)
1381
							obase=$opatchid
1382
						fi
1383
						if [[ $obase = $2 && $2 != $oldbase ]]
1384
						then
1385
							print_obsolete_msg "$Patchid" "none"
1386
							exit 6
1387
						fi
1388
					done
1389
				done
1390
				cd $1
1391
			done
1392
		fi
1393
	fi
1394
}
1395
 
1396
# Description:
1397
#	Check to see if originally modified files were saved. If not,
1398
#	the patch cannot be backed out.
1399
# Parameters:
1400
#	$1	- patch database directory
1401
#	$2	- patch number
1402
 
1403
function check_if_saved
1404
{
1405
	if [[ ! -f $1/$2/.oldfilessaved && ! -f $1/$2/.nofilestosave ]]
1406
	then
1407
		/usr/bin/gettext "Patch $2 was installed without backing up the original files.\nIt cannot be backed out.\n"
1408
		exit 4
1409
	fi
1410
}
1411
 
1412
# Description:
1413
#	Get the list of packages 
1414
# Parameters:
1415
#	$1	- patch database directory
1416
#	$2	- patch number
1417
# Globals Set:
1418
#	pkglist
1419
 
1420
function get_package_list
1421
{
1422
	pkg=
1423
	i=
1424
	cd $1/$2
1425
	for i in */pkgmap
1426
	do
1427
		pkg=`expr $i : '\(.*\)/pkgmap'`
1428
		pkglist="$pkglist $pkg"
1429
	done
1430
}
1431
 
1432
# Description:
1433
# Parameters:
1434
#	$1	- patch database directory
1435
#	$2	- patch number
1436
#	$3	- softinfo directory
1437
#	$4	- product version
1438
# Globals Used:
1439
#	TMPSOFT
1440
 
1441
function cleanup
1442
{
1443
	$RM -f /tmp/*.$$
1444
 
1445
	if [[ -d $1 ]]
1446
	then
1447
		cd $1
1448
		if [[ -f softinfo_sed ]]
1449
		then
1450
			sed -f softinfo_sed $3/$4 > $TMPSOFT
1451
			$MV $3/$4 $3/sav.$4
1452
			$CP $TMPSOFT $3/$4
1453
		fi
1454
		$RM -fr ./$2/*
1455
		$RM -fr $2
1456
 
1457
		if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
1458
		then
1459
			PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)
1460
			$RM -fr $PATCH_UNDO_ARCHIVE/$2
1461
		fi
1462
	fi
1463
 
1464
	if [[ "$netImage" = "boot" && -d $ROOTDIR/mnt/root ]]
1465
	then
1466
		restore_net_image
1467
	fi
1468
 
1469
	if [[ -f "$PATCHDBFILE" ]]; then
1470
		InsertPkgDBSum
1471
	fi
1472
}
1473
 
1474
# Description:
1475
#	Insert the sum of all the PATCHLIST and PATCHID parameters
1476
#	to determine if the PATCHDBFILE needs to be recreated.
1477
 
1478
function InsertPkgDBSum
1479
{
1480
	pkgDBSum=$($NAWK '/PATCHID/ {print} /PATCHLIST/ {print}' \
1481
		$PKGDB/*/pkginfo 2>/dev/null | $SUM | $NAWK '{print $1}')
1482
 
1483
	$NAWK -v ps="$pkgDBSum" '
1484
		$1 ~ /Version/ { printf("%s %s %s\n", $1, $2, ps); next } 
1485
		{ print } ' $PATCHDBFILE > $PATCHDBFILE.tmp
1486
	$MV -f $PATCHDBFILE.tmp $PATCHDBFILE
1487
}
1488
 
1489
# Description:
1490
#	Remove appropriate patch packages from the system 
1491
#	NOTE: this will not restore the overwritten or removed files, but will
1492
#		  remove any files which were added by the patch.
1493
# Parameters:
1494
#	$1	- patch database directory
1495
#	$2	- patch number
1496
#	$3	- packaging command relocation argument 
1497
# Globals Used:
1498
#	ADMINFILE
1499
#	pkginstlist
1500
 
1501
function remove_patch_pkgs
1502
{
1503
	pkgrmerr=
1504
	i=
1505
	if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
1506
	then
1507
		if [[ ! -d $PATCH_UNDO_ARCHIVE ]]
1508
		then
1509
			/usr/bin/gettext "The backout data has been moved. Please supply\npatchrm with the new location of the archive.\n"
1510
			patch_quit 12
1511
		fi
1512
	fi
1513
 
1514
	for i in $pkginstlist
1515
	do
1516
		/usr/bin/gettext "\nRemoving patch package for $i:\n"
1517
		echo pkgrm $3 -a $ADMINFILE -n $i $LOGFILE
1518
		pkgrm $3 -a $ADMINFILE -n $i>$LOGFILE 2>&1
1519
		pkgrmerr=$?
1520
		cat $LOGFILE >>$1/$2/log
1521
		cat $LOGFILE | grep -v "^$"
1522
		$RM -f $LOGFILE
1523
		if [[ $pkgrmerr != 0 && $pkgrmerr != 2 && $pkgrmerr != 10 && $pkgrmerr != 20 ]]
1524
		then
1525
			/usr/bin/gettext "pkgrm of $i package failed with return code $pkgrmerr.\nSee $1/$2/log for details.\n"
1526
			$RM -fr /tmp/*.$$
1527
			remove_libraries
1528
			exit 5
1529
		fi
1530
	done
1531
}
1532
 
1533
# Description:
1534
#	Copy required libraries to TMP_LIB_DIR, set and
1535
#	export LD_PRELOAD.
1536
# Parameters:
1537
#	none
1538
# Environment Variables Set:
1539
#	LD_PRELOAD
1540
#
1541
function move_libraries
1542
{
1543
	typeset -i Rev
1544
	Rev=$(uname -r | $SED -e 's/\..*$//')
1545
	if (( Rev >= 5 ))
1546
	then
1547
 
1548
		if [[ ! -d $TMP_LIB_DIR ]]
1549
		then
1550
			mkdir -p -m755 $TMP_LIB_DIR
1551
		fi
1552
 
1553
		LD_PRELOAD=
1554
		for Lib in libc libdl libelf libintl libw libgen libadm
1555
		do
1556
			if [[ ! -f /usr/lib/${Lib}.so.1 ]]; then
1557
				continue
1558
			fi
1559
 
1560
			$CP /usr/lib/${Lib}.so.1 ${TMP_LIB_DIR}/${Lib}.so.1
1561
 
1562
			chown bin ${TMP_LIB_DIR}/${Lib}.so.1
1563
			chgrp bin ${TMP_LIB_DIR}/${Lib}.so.1
1564
			chmod 755 ${TMP_LIB_DIR}/${Lib}.so.1
1565
 
1566
			LD_PRELOAD="${LD_PRELOAD} ${TMP_LIB_DIR}/${Lib}.so.1"
1567
		done
1568
		export LD_PRELOAD
1569
	fi
1570
}
1571
 
1572
# Description:
1573
#	remove the TMP_LIB_DIR directory
1574
# Parameters:
1575
#	none
1576
# Environment Variables Set:
1577
#	LD_PRELOAD
1578
#
1579
function remove_libraries
1580
{
1581
	LD_PRELOAD=
1582
	export LD_PRELOAD
1583
	$RM -rf $TMP_LIB_DIR
1584
}
1585
 
1586
# Description:
1587
#	unobsolete direct instance patches that this one obsoleted
1588
# Parameters:
1589
#	none
1590
# Environment Variables Used:
1591
#	ROOTDIR
1592
#	InstPkgs
1593
#	PatchNum
1594
#
1595
function di_unobsolete
1596
{
1597
	cd $ROOTDIR
1598
	cd var/sadm/pkg
1599
	if [[ "$recreatePatchDB" = "no" ]]; then
1600
		InstPkgs=$(pkginfo -R $ROOTDIR | $NAWK ' { print $2; } ')
1601
	fi
1602
	for pkg in $InstPkgs; do
1603
		PATCHLIST=$(pkgparam -R $ROOTDIR $pkg PATCHLIST)
1604
		for Patchno in $PATCHLIST; do
1605
			check_remote_file $pkg $Patchno
1606
				archive_path=$pkg/save/$Patchno
1607
 
1608
			if [[ -f $archive_path/obsolete || -f $archive_path/obsolete.Z || -f $archive_path/remote ]]
1609
			then
1610
				if [[ -f $archive_path/obsoleted_by ]]
1611
				then
1612
					egrep -s $PatchNum $archive_path/obsoleted_by
1613
					if [[ $? -eq 0 ]]
1614
					then
1615
						cat $archive_path/obsoleted_by | $NAWK -v patchno=$PatchNum '
1616
							$0 ~ patchno	{ next; }
1617
							{ print; } ' > $archive_path/obsoleted_by.new
1618
 
1619
						if [[ -f $archive_path/remote ]]
1620
						then
1621
							restore_remote_state $pkg $Patchno
1622
						fi
1623
 
1624
						if [[ -s $archive_path/obsoleted_by.new ]]
1625
						then
1626
							$MV $archive_path/obsoleted_by.new $archive_path/obsoleted_by
1627
						else
1628
							$RM -f $archive_path/obsoleted_by.new $archive_path/obsoleted_by
1629
							if [[ -f $archive_path/remote ]]
1630
							then
1631
								continue
1632
							fi
1633
 
1634
							if [[ -f $archive_path/obsolete ]]
1635
							then
1636
								$MV $archive_path/obsolete $archive_path/undo
1637
							else
1638
								$MV $archive_path/obsolete.Z $archive_path/undo.Z
1639
							fi
1640
						fi
1641
					fi
1642
				fi
1643
			fi
1644
		done
1645
	done
1646
}
1647
 
1648
# Description:
1649
#	Load the patch compatibility arrays.
1650
#
1651
# Parameters:
1652
#	$1 - The line from the .patchDB.
1653
function LoadPtchArrays
1654
{
1655
	installedPtch[$insPs]=""
1656
	installedObs[$insPs]=""
1657
	installedReq[$insPs]=""
1658
	installedInc[$insPs]=""
1659
	installedPkgs[$insPs]=""
1660
 
1661
	while (( "$#" != "0" ))
1662
	do
1663
		case $1 in
1664
			"Patch:"|"Obsoletes:"|"Requires:"| \
1665
			"Incompatibles:"|"Packages:" )
1666
				mode=$1
1667
				shift;;
1668
			"Version" )
1669
				break;;
1670
			* ) 
1671
 
1672
			case $mode in
1673
				"Patch:" )
1674
					 installedPtch[$insPs]=$1
1675
					 shift;;
1676
		 		"Obsoletes:" )
1677
					 installedObs[$insPs]="${installedObs[$insPs]} $1" 
1678
					 shift;;  
1679
		 		"Requires:" )
1680
					 installedReq[$insPs]="${installedReq[$insPs]} $1"
1681
					 shift;;  
1682
		 		"Incompatibles:" )
1683
					 installedInc[$insPs]="${installedInc[$insPs]} $1"
1684
					 shift;;  
1685
		 		"Packages:" )
1686
					 installedPkgs[$insPs]="${installedPkgs[$insPs]} $1"
1687
					 shift;;  
1688
			esac
1689
		esac
1690
	done
1691
}
1692
 
1693
# Description:
1694
#	Check to see if any pkginfo files have changed since the last
1695
#	patchadd or patchrm. If so, recreate the patch database.  
1696
#	NOTE: There will be times when the database is considered out 
1697
#	of sync due to a pkg command. 
1698
#
1699
function check_PatchDBs
1700
{
1701
	typeset -i pdbSum=0
1702
 
1703
	if [[ -f $PATCHDBFILE ]]; then
1704
		pkginfoParamSum
1705
		pdbSum=$($NAWK ' $1 ~ /Version/ { print $3 } ' $PATCHDBFILE)
1706
		if (( dbSum != pdbSum )); then
1707
			recreatePatchDB="yes"
1708
			$RM -f $PATCHDBFILE
1709
		fi
1710
	else
1711
		pkginfoParamSum
1712
		recreatePatchDB="yes"
1713
	fi
1714
}
1715
 
1716
# Description:
1717
#	Check to see if the patch being backed out has other patches 
1718
#	installed that require it to be there.
1719
# Parameters:
1720
#	none
1721
# Locals Used
1722
#	tmp
1723
#	list
1724
#	requires
1725
#	obsPatch
1726
#	pkg
1727
#
1728
function check_REQUIRE
1729
{
1730
	set -A installedPtch
1731
	set -A installedObs
1732
	set -A installedReq
1733
	set -A installedInc
1734
	set -A installedPkgs
1735
 
1736
	typeset -i ctr=0
1737
	typeset -i outctr=0
1738
	typeset -i inctr=0
1739
	typeset -i obctr=0
1740
	typeset -i insPs=0
1741
	typeset -i ptch=0
1742
	typeset -i outPtch=0
1743
	typeset -i reqStillMet=0
1744
 
1745
	requires=
1746
	list=
1747
	obsPatch=
1748
	pkg=
1749
	instBase=
1750
	instVers=
1751
 
1752
	patchFile=""
1753
	patchFileStripped=/tmp/patchDBstripped.$$
1754
 
1755
	# If the user doesn't care about the consequences
1756
	# of not removing required patches first then we
1757
	# skip this check.
1758
 
1759
	if [[ "$force" = "yes" ]]
1760
	then
1761
		return
1762
	fi
1763
 
1764
	if [[ -s "$PATCHDBFILE" ]]; then
1765
		patchFile=$PATCHDBFILE
1766
	elif [[ ! -s $INSTPATCHES_FILE ]]; then
1767
		return
1768
	else
1769
		patchFile=$INSTPATCHES_FILE
1770
	fi
1771
 
1772
	$SED 's/,//g' $patchFile > $patchFileStripped
1773
 
1774
	while read line
1775
	do
1776
		LoadPtchArrays $line
1777
		insPs=insPs+1
1778
	done < $patchFileStripped
1779
 
1780
	#cd $PKGDB
1781
 
1782
	obsPatch=""
1783
 
1784
	ctr=1
1785
 
1786
	while (( ctr < insPs ))
1787
	do
1788
		get_base_code $patch
1789
		instBase=$cur_base_code
1790
 
1791
		get_vers_no $patch $patch_base
1792
		instVers=$cur_vers_no
1793
 
1794
		if [[ "$compatsAlreadyChecked" == "no" ]]; then
1795
			CheckInstallingCompats ${installedPtch[$ctr]} $instBase $instVers
1796
		fi
1797
		ctr=ctr+1
1798
	done
1799
 
1800
	if [[ "$unReqAlreadyChecked" == "no" ]]; then
1801
		CheckUninstalledReqs
1802
	fi
1803
 
1804
	ctr=1
1805
 
1806
	while (( ctr < insPs ))
1807
	do
1808
		# We're only concerned about the patch being backed
1809
		# out. If it obsoletes another patch we need to 
1810
		# check to see if the patch is required to be 
1811
		# installed.
1812
 
1813
		if [[ -n ${installedObs[$ctr]} ]]
1814
		then
1815
			for ob in ${installedObs[$ctr]}
1816
			do
1817
				# Only concerned with the patch that
1818
				# is being backed out.
1819
 
1820
				if [[ ${installedPtch[$ctr]} != "$PatchNum" ]]
1821
				then
1822
					continue
1823
				fi
1824
 
1825
				get_base_code $ob
1826
				obBase=$cur_base_code
1827
 
1828
				obctr=0
1829
 
1830
				# We need to check every patch to see if
1831
				# this patch obsoletes any patch that requires
1832
				# it to be installed.
1833
 
1834
				while (( obctr < insPs ))
1835
				do
1836
					for obReq in ${installedReq[$obctr]}
1837
					do
1838
						get_base_code $obReq
1839
						obPatchBase=$cur_base_code
1840
 
1841
						if [[ "$obBase" = "$obPatchBase" ]]
1842
						then
1843
							# If the requirement is still met
1844
							# with a lower revision of an 
1845
							# installed patch then continue
1846
 
1847
 							get_vers_no $ob $obBase
1848
 							obVers=$cur_vers_no   
1849
 
1850
							ptch=0
1851
 
1852
							while (( ptch < insPs ))
1853
							do
1854
								# If there is only one patch
1855
								# in the $obReq list there 
1856
								# will be an extra ' ' at the end
1857
								# of the patch.
1858
 
1859
							 	get_base_code ${installedPtch[$ptch]}
1860
								ptBase=$cur_base_code
1861
								get_vers_no ${installedPtch[$ptch]} \
1862
								  $cur_base_code
1863
								ptVers=$cur_vers_no
1864
 
1865
								ptch=ptch+1
1866
 
1867
								if [[ "$ptBase" != "$obBase" ]]
1868
								then
1869
									continue
1870
								fi
1871
								if [[ "$ptVers" -le "$obVers" ]]
1872
								then
1873
									# requirement still met
1874
									reqStillMet=1
1875
									break
1876
								fi
1877
							done
1878
							if (( reqStillMet == 0 ))
1879
							then
1880
								print_require_msg ${installedPtch[$obctr]}
1881
							fi
1882
							reqStillMet=0
1883
						fi
1884
					done
1885
					obctr=obctr+1
1886
				done
1887
			done
1888
		fi
1889
 
1890
		# Check any patch that has an require patch
1891
		# contained in is PATCH_INFO line.
1892
 
1893
		if [[ -n ${installedReq[$ctr]} ]]
1894
		then
1895
			for req in ${installedReq[$ctr]}
1896
			do
1897
				get_base_code $req
1898
				reqBase=$cur_base_code
1899
				get_vers_no $req $cur_base_code
1900
				reqVers=$cur_vers_no
1901
 
1902
				if [[ "$reqBase" = "$PatchBase" && \
1903
				  "$reqVers" -le "$PatchVers" || -n $obsPatch ]]
1904
				then
1905
 
1906
					# We need to check all installed
1907
					# patches incase a lower rev 
1908
					# is installed that still meets 
1909
					# the requirement. (sigh)
1910
 
1911
					ptch=0
1912
 
1913
					while (( ptch < insPs ))
1914
					do
1915
						get_base_code ${installedPtch[$ptch]}
1916
						ptBase=$cur_base_code
1917
						get_vers_no ${installedPtch[$ptch]} $cur_base_code
1918
						ptVers=$cur_vers_no
1919
 
1920
						ptch=ptch+1
1921
 
1922
						if [[ "$ptBase" != "$reqBase" ]]
1923
						then
1924
							continue
1925
						fi
1926
 
1927
						if [[ "$ptVers" -ge "$reqVers" && \
1928
						  "$PatchVers" != "$ptVers" ]]
1929
						then
1930
							# requirement still met
1931
							reqStillMet=1
1932
							break
1933
						fi
1934
					done
1935
 
1936
					if (( reqStillMet == 0 ))
1937
					then
1938
						print_require_msg ${installedPtch[$ctr]}
1939
					fi
1940
					reqStillMet=0
1941
				fi
1942
			done
1943
		fi
1944
		ctr=ctr+1
1945
	done
1946
}
1947
 
1948
# Description:
1949
#   Patch requires message.
1950
#   out was superceded by other patches
1951
# Parameters:
1952
#   $1  - required patch ID
1953
#
1954
function print_require_msg
1955
{
1956
	/usr/bin/gettext "Patch $PatchNum is required to be installed by patch $1\nit cannot be backed out until patch $1 is backed out.\n"
1957
	patch_quit 15
1958
}
1959
 
1960
# Description:
1961
#	Detect if there have been any implicit or explicit obsoletions.
1962
# Parameters:
1963
#	none
1964
# Environment Variable Set:
1965
#
1966
function detect_obs
1967
{
1968
	cd $ROOTDIR
1969
	cd var/sadm/pkg
1970
	if [[ $ThisPatchFnd = "no" ]]
1971
	then
1972
		/usr/bin/gettext "Patch $PatchNum has not been applied to this system.\n"
1973
		exit 2
1974
	fi
1975
 
1976
	#
1977
	# First scan for the undo and remote files and make sure, none of them have
1978
	# been obsoleted
1979
	#
1980
	for pkg in $PatchedPkgs; do
1981
		if [[ -f $pkg/pkginfo ]]
1982
		then
1983
			if [[ -d $pkg/save/$PatchNum ]]
1984
			then
1985
				if [[ -f $pkg/save/$PatchNum/remote ]]
1986
				then
1987
				   	check_remote_file $pkg $PatchNum
1988
					if [[ ! -f $PATCH_UNDO_ARCHIVE/undo && ! -f $PATCH_UNDO_ARCHIVE/undo.Z ]]
1989
					then
1990
		   				/usr/bin/gettext "The backout archive has been moved.\nSupply the -B option to back out the patch.\n"
1991
						patch_quit 12
1992
					 elif [[ -f $pkg/save/$PatchNum/obsoleted_by ]]
1993
					 then
1994
						ObsoletedBy=$(cat $pkg/save/$PatchNum/obsoleted_by)
1995
						print_obsolete_msg "$ObsoletedBy" "none"
1996
						exit 6
1997
					fi
1998
				else
1999
					if [[ -f $pkg/save/$PatchNum/obsolete || -f $pkg/save/$PatchNum/obsolete.Z ]]
2000
					then
2001
						ObsoletedBy=$(cat $pkg/save/$PatchNum/obsoleted_by)
2002
						print_obsolete_msg "$ObsoletedBy" "none"
2003
						exit 6
2004
 
2005
					elif [[ ! -f $pkg/save/$PatchNum/undo && ! -f $pkg/save/$PatchNum/undo.Z ]]
2006
					then
2007
						/usr/bin/gettext "Patch $PatchNum was installed without backing up the original files.\nIt cannot be backed out.\n"
2008
						exit 4 
2009
					fi
2010
				fi
2011
			else
2012
				/usr/bin/gettext "Patch $PatchNum was installed without backing up the original files.\nIt cannot be backed out.\n"
2013
				exit 4 
2014
 
2015
			fi
2016
		else
2017
			/usr/bin/gettext "Patch $PatchNum was installed without backing up the original files.\nIt cannot be backed out.\n"
2018
			exit 4 
2019
		fi
2020
	done
2021
}
2022
 
2023
# Description:
2024
#	If backing out a patch in the mini-root invoke pkgadd with the -M option.
2025
# Parameters:
2026
#	none
2027
# Globals Set:
2028
#	MOPTION
2029
#
2030
function check_pkgadd_M_option {
2031
 
2032
	[[ "$mgrOS" > "5.5.1" ]] &&  [[ "$ROOTDIR" != "/" ]] && MOPTION="-M"
2033
}
2034
 
2035
# Description:
2036
#	backout a patch applied using direct instance patching
2037
# Parameters:
2038
#	none
2039
# Environment Variable Set:
2040
#
2041
function di_backout
2042
{
2043
	typeset -i Something_Backedout=0
2044
	typeset -i exit_code=0
2045
 
2046
	cd $ROOTDIR
2047
	cd var/sadm/pkg
2048
 
2049
	# The following is done since pkgadd will unpack the undo pkg in
2050
	# /var/tmp. If backing out in the mini-root a writable scratch dir
2051
	# needs to exist. /var/tmp is read only in the mini-root environment.
2052
 
2053
	#if [[ "$ROOTDIR" != "/" ]]; then
2054
		#export TMPDIR="$ROOTDIR/var/sadm/patch/.tmp"
2055
	#fi
2056
 
2057
	#
2058
	# With no obsoletions detected, we pkgadd the undo packages.
2059
	#
2060
	for pkg in $PatchedPkgs; do
2061
			   	check_remote_file $pkg $PatchNum
2062
		if [[ "$PATCH_UNDO_ARCHIVE" != "none" && -f $PATCH_UNDO_ARCHIVE/undo.Z ]]
2063
		then
2064
						uncompress $PATCH_UNDO_ARCHIVE/undo.Z 1> $LOGFILE 2>&1
2065
		elif [[ -f $pkg/save/$PatchNum/undo.Z ]]
2066
		then
2067
			uncompress $pkg/save/$PatchNum/undo.Z 1> $LOGFILE 2>&1
2068
		fi
2069
 
2070
		# Get the prior patch list since the checkinstall script
2071
		# doesn't have permission to make this enquiry.
2072
		OLDLIST=$(pkgparam -R $ROOTDIR $pkg PATCHLIST)
2073
 
2074
		echo OLDLIST=\'$OLDLIST\' > $RESPONSE_FILE
2075
 
2076
		if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
2077
		then
2078
			pkgadd $MOPTION -n -r $RESPONSE_FILE -R $ROOTDIR \
2079
				-a $ADMINFILE -d $PATCH_UNDO_ARCHIVE/undo all \
2080
				1>> $LOGFILE </dev/null 2>&1
2081
		else
2082
			pkgadd $MOPTION -n -r $RESPONSE_FILE -R $ROOTDIR \
2083
				-a $ADMINFILE -d $pkg/save/$PatchNum/undo all \
2084
				1>> $LOGFILE </dev/null 2>&1
2085
		fi
2086
 
2087
		exit_code=$?
2088
 
2089
		# Check for an apostrphe in the pkginfo file. This is needed
2090
		# since pkgparam inserts '"'"' for any ' it finds.
2091
		# This is a workaround for a bug in pkgparam. Pkgparam
2092
		# is used in the generic preinstall script. 
2093
 
2094
		$SED s,ApOsTrOpHe,\',g \
2095
		  $ROOTDIR/var/sadm/pkg/$pkg/pkginfo > /tmp/pkginfo.$$
2096
		rm -f $ROOTDIR/var/sadm/pkg/$pkg/pkginfo 1>/dev/null 2>&1
2097
		mv /tmp/pkginfo.$$ $ROOTDIR/var/sadm/pkg/$pkg/pkginfo \
2098
		  1>/dev/null 2>&1
2099
		chmod 644 $ROOTDIR/var/sadm/pkg/$pkg/pkginfo
2100
		rm -f /tmp/pkginfo.$$
2101
 
2102
		# If it's a suspend (exit code 4), then the
2103
		# message type is the appropriate patchrm 
2104
		# exit code and the appropriate message follows.
2105
		# A suspend means, nothing has been installed.
2106
		if (( exit_code == 4 ))	# suspend
2107
		then
2108
			Message=$(egrep PaTcH_MsG $LOGFILE | $SED s/PaTcH_MsG\ //)
2109
			if [[ $Message = "" ]]
2110
			then
2111
				exit_code=5
2112
			else
2113
				Msg_Type=$(echo $Message | $NAWK ' { print $1 } ')
2114
				Message=$(echo $Message | $SED s/$Msg_Type\ //)
2115
				/usr/bin/gettext "$Message\n" >> $LOGFILE
2116
				/usr/bin/gettext "$Message\n"
2117
				exit $Msg_Type
2118
			fi
2119
		fi
2120
 
2121
		if ((exit_code == 5 ))
2122
		then	# administration
2123
			/usr/bin/gettext "Backout has been halted due to administrative defaults.\n"
2124
			cat $LOGFILE
2125
			exit 11
2126
		elif (( exit_code == 10 || exit_code == 20 ))
2127
		then
2128
			/usr/bin/gettext "NOTE: After backout the target host will need to be rebooted.\n"
2129
			RebootRqd="yes"
2130
		elif (( exit_code != 0 ))
2131
		then
2132
			egrep ERROR $LOGFILE
2133
			exit 7
2134
		else
2135
			Something_Backedout=1
2136
		fi
2137
	done
2138
 
2139
	if (( Something_Backedout == 1 ))
2140
	then
2141
		di_unobsolete
2142
		update_patchDB
2143
		if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
2144
		then
2145
			PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)
2146
			PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)
2147
			$RM -r $PATCH_UNDO_ARCHIVE/$PatchNum
2148
		fi
2149
	else
2150
		/usr/bin/gettext "Patch number $PatchNum backout packages were not found.\n"
2151
	fi
2152
}
2153
 
2154
# Description
2155
#	Update the new patch data base,
2156
 
2157
function update_patchDB
2158
{
2159
	if [[ ! -f $PATCHDBFILE ]]; then
2160
		return
2161
	fi
2162
 
2163
	$FGREP -v "Patch: $PatchNum" $PATCHDBFILE > $PATCHDBFILE.tmp
2164
	$MV -f $PATCHDBFILE.tmp $PATCHDBFILE
2165
}
2166
 
2167
# Description:
2168
#	   check to see if the backout data is saved remotely
2169
# Parameters:
2170
#	   $1	  - package associated with the patch
2171
#	   $2	  - the patch number
2172
#
2173
# Environment Variable Set:
2174
#
2175
#	PATCH_UNDO_ARCHIVE
2176
#	OBS_PATCH_UNDO_ARCHIVE
2177
 
2178
function check_remote_file
2179
{
2180
	if [[ "$diPatch" = "yes" ]]
2181
	then
2182
			if [[ ! -f $PKGDB/$1/save/$2/remote ]]
2183
			then
2184
			return
2185
		fi
2186
 
2187
		if [[ "$DASHB_SUPPLIED" = "yes" ]]
2188
		then
2189
			if [[ $2 != "$PatchNum" ]]
2190
			then
2191
							OBS_PATCH_UNDO_ARCHIVE=$TEMP_PATCH_UNDO_ARCHIVE/$2/$1			
2192
			else
2193
				PATCH_UNDO_ARCHIVE=$TEMP_PATCH_UNDO_ARCHIVE/$2/$1
2194
			fi
2195
		elif [[ $2 != "$PatchNum" ]]
2196
		then
2197
						OBS_PATCH_UNDO_ARCHIVE=$(grep "FIND_AT" $PKGDB/$1/save/$2/remote | $AWK -F= '{print $2}')
2198
						OBS_PATCH_UNDO_ARCHIVE=$(dirname $OBS_PATCH_UNDO_ARCHIVE)
2199
		else
2200
						PATCH_UNDO_ARCHIVE=$(grep "FIND_AT" $PKGDB/$1/save/$2/remote | $AWK -F= '{print $2}')
2201
						PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)
2202
		fi
2203
	# progressive instance logic
2204
	else
2205
			if [[ ! -f $PATCHDB/$2/save/remote ]]
2206
			then
2207
			return
2208
		fi
2209
 
2210
		if [[ "$DASHB_SUPPLIED" = "yes" ]]
2211
		then
2212
				PATCH_UNDO_ARCHIVE=$TEMP_PATCH_UNDO_ARCHIVE/$2/archive.cpio
2213
		else
2214
				PATCH_UNDO_ARCHIVE=$(grep "FIND_AT" $PATCHDB/$2/save/remote | $AWK -F= '{print $2}')
2215
		fi
2216
		PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)
2217
 
2218
	fi
2219
}
2220
 
2221
# Description:
2222
#	   restore the STATE parameter back to the proper
2223
#	state in the remote file
2224
# Parameters:
2225
#	   $1	  - package associated with the patch
2226
#	   $2	  - the patch number
2227
#
2228
# Environment Variable Set:
2229
#
2230
function restore_remote_state
2231
{
2232
	$(grep . $PKGDB/$1/save/$2/remote | $SED 's/STATE=.*/STATE=active/' > $TEMP_REMOTE)
2233
	$RM -f $PKGDB/$1/save/$2/remote
2234
	$MV $TEMP_REMOTE $PKGDB/$1/save/$2/remote
2235
	$RM -f $TEMP_REMOTE
2236
	chmod 644 $PKGDB/$1/save/$2/remote
2237
}
2238
 
2239
# Description:
2240
#	   Call check_remote_file if the remote file is found
2241
#	   for progressive instance patches
2242
# Parameters:
2243
#	   $1	  - patch database
2244
#	   $2	  - the patch number
2245
#
2246
# Globals Set:
2247
#	none
2248
 
2249
function set_archive_path
2250
{
2251
	if [[ ! -f $1/$2/remote ]]
2252
	then
2253
		check_remote_file $1 $2
2254
	fi
2255
}
2256
 
2257
# Description:
2258
#   Setup the net install boot image to look like an installed system.
2259
# Parameters:
2260
#   none
2261
# Globals Set:
2262
#   none
2263
#
2264
function setup_net_image {
2265
 
2266
	if [[ "$netImage" != "boot" ]]
2267
	then
2268
		return
2269
	fi
2270
 
2271
	# Check to see if there was an interruption that left the loop back
2272
	# mounts mounted for Net Install Patching.
2273
 
2274
	if [[ -d $ROOTDIR/mnt/root ]]
2275
	then
2276
		restore_net_image
2277
	fi
2278
 
2279
	# The .../Boot/.tmp_proto/root needs to be re-mapped to
2280
	# .../Boot/tmp in order for the boot image to be patched
2281
	# successfully.
2282
 
2283
	$MOUNT -F lofs -O $ROOTDIR/tmp $ROOTDIR/mnt
2284
	$MOUNT -F lofs -O $ROOTDIR/.tmp_proto $ROOTDIR/tmp
2285
	$MOUNT -F lofs -O $ROOTDIR/mnt/root/var $ROOTDIR/tmp/root/var
2286
 
2287
	# At this point patchrm thinks the net install image
2288
	#is just like an installed image.
2289
}
2290
 
2291
# Description:
2292
#	Restore the net image to the way it was before mucking
2293
#	with it in the setup_net_image function.
2294
# Parameters:
2295
#   none
2296
# Globals Set:
2297
#   none
2298
#
2299
function restore_net_image {
2300
 
2301
	if [[ "$netImage" != "boot" ]]
2302
	then
2303
		return
2304
	fi
2305
 
2306
	cd $origdir
2307
	$UMOUNT $ROOTDIR/tmp/root/var
2308
	$UMOUNT $ROOTDIR/tmp
2309
	$UMOUNT $ROOTDIR/mnt
2310
}
2311
 
2312
#########################################################
2313
#					
2314
# 			Main routine
2315
#				
2316
#########################################################
2317
 
2318
# -	Parse the argument list and set globals accordingly
2319
# -	Make sure the user is running as 'root'
2320
# -	Get the product version <name>_<version> of the local
2321
#	Solaris installation
2322
# - 	activate the patch
2323
 
2324
Cmd=$0
2325
CmdArgs=$*
2326
 
2327
validate_uid
2328
 
2329
parse_args $*
2330
 
2331
check_for_2_6
2332
 
2333
find_softinfos $ROOTDIR
2334
 
2335
get_OS_version $TRGSOFTINFO $MGRSOFTINFO $ROOTDIR
2336
 
2337
check_file_recovery
2338
 
2339
setup_net_image
2340
 
2341
check_PatchDBs
2342
 
2343
/usr/bin/gettext "Checking installed packages and patches...\n\n"
2344
 
2345
activate_patch "$PATCHDB" "$PatchNum"
2346
 
2347
exportVars
2348
 
2349
if [[ "$diPatch" != "yes" ]]
2350
then
2351
	echo $PatchNum | grep $PatchIdFormat >/dev/null
2352
	if [[ $? -ne 0 ]]
2353
	then
2354
		/usr/bin/gettext "Invalid patch id format: $PatchNum\n"
2355
		exit 8
2356
	fi
2357
fi
2358
 
2359
#
2360
# Check to see if this patch was obsoleted by another patch
2361
#
2362
if [[ "$force" = "no" || "$diPatch" = "yes" ]]
2363
then
2364
	check_if_obsolete "$PATCHDB" "$PatchBase" "$PatchVers"
2365
fi
2366
execute_prebackout "$PATCHDB" "$PatchNum"
2367
 
2368
# -	Check to see if original files were actually saved
2369
# -	Generate list of packages to be removed
2370
# -	Find the package instances for this patch
2371
# -	Build admin file for later use by pkgrm
2372
# -	pkgrm patch packages
2373
# -	Restore the original files which were overwritten by the patch
2374
# -	Update the prodver file & cleanup tmp files
2375
 
2376
build_admin
2377
 
2378
# If we're in the mini-root, invoke pkgadd with -M
2379
# or if the managing host is 2.6 or later.
2380
check_pkgadd_M_option
2381
 
2382
if [[ "$diPatch" = "yes" ]]
2383
then
2384
	detect_obs
2385
	check_REQUIRE
2386
 
2387
	/usr/bin/gettext "Backing out patch $PatchNum...\n\n"
2388
 
2389
	di_backout
2390
	$RM -f $RESPONSE_FILE
2391
else
2392
	set_archive_path "$PATCHDB" "$PatchNum" 
2393
 
2394
	check_if_saved "$PATCHDB" "$PatchNum"
2395
 
2396
	get_package_list "$PATCHDB" "$PatchNum"
2397
 
2398
	get_pkg_instances "$PKGDB" "$PatchNum"
2399
 
2400
	trap 'remove_libraries' HUP INT QUIT TERM
2401
	move_libraries
2402
 
2403
	remove_patch_pkgs "$PATCHDB" "$PatchNum" "$PKGDBARG"
2404
 
2405
	update_patchDB
2406
 
2407
	restore_orig_files "$PATCHDB" "$PatchNum" "$PKGDBARG" "$CONTENTS"
2408
 
2409
	remove_libraries
2410
 
2411
fi
2412
 
2413
execute_postbackout "$PATCHDB" "$PatchNum"
2414
 
2415
cleanup "$PATCHDB" "$PatchNum" "$SOFTINFO" "$prodver"
2416
 
2417
/usr/bin/gettext "Patch $PatchNum has been backed out.\n\n"
2418
 
2419
exit 0