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
# @(#) patchadd.ksh 2.5 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 apply a patch that's already been applied
25
#		3	Effective UID is not root
26
#		4	Attempt to save original files failed
27
#		5	pkgadd failed
28
#		6	Patch is obsoleted
29
#		7	Invalid package directory
30
#		8	Attempting to patch a package that is not installed
31
#		9	Cannot access /usr/sbin/pkgadd (client problem)
32
#		10	Package validation errors
33
#		11	Error adding patch to root template
34
#		12	Patch script terminated due to signal
35
#		13	Symbolic link included in patch
36
#		14	NOT USED
37
#		15	The prepatch script had a return code other than 0.
38
#		16	The postpatch script had a return code other than 0.
39
#		17	Mismatch of the -d option between a previous patch
40
#			install and the current one.
41
#		18	Not enough space in the file systems that are targets
42
#			of the patch.
43
#		19	$SOFTINFO/INST_RELEASE file not found
44
#		20	A direct instance patch was required but not found
45
#		21	The required patches have not been installed on the manager
46
#		22	A progressive instance patch was required but not found
47
#		23	A restricted patch is already applied to the package
48
#		24	An incompatible patch is applied
49
#		25	A required patch is not applied
50
#		26	The user specified backout data can't be found
51
#		27	The relative directory supplied can't be found
52
#		28	A pkginfo file is corrupt or missing
53
#		29	Bad patch ID format
54
#		30	Dryrun failure(s)
55
#		31	Path given for -C option is invalid
56
#		32	Must be running Solaris 2.6 or greater
57
#		33	Bad formatted patch file or patch file not found
58
#
59
 
60
# Set the path for use with these scripts.
61
PATH=/usr/sadm/bin:/usr/sbin:/usr/bin:$PATH
62
export PATH
63
 
64
umask 022
65
 
66
# Global Files
67
 
68
# Needed utilities
69
DF=/usr/sbin/df
70
MV=/usr/bin/mv
71
RM=/usr/bin/rm
72
SED=/usr/bin/sed
73
AWK=/usr/bin/awk
74
NAWK=/usr/bin/nawk
75
GREP=/usr/bin/grep
76
EGREP=/usr/bin/egrep
77
LS=/usr/bin/ls
78
CP=/usr/bin/cp
79
WC=/usr/bin/wc
80
FIND=/usr/bin/find
81
MD=/usr/bin/mkdir
82
TOUCH=/usr/bin/touch
83
DIFF=/usr/bin/diff
84
TAIL=/usr/bin/tail
85
MOUNT=/sbin/mount
86
UMOUNT=/sbin/umount
87
UNAME=/usr/bin/uname
88
VALPATH=/usr/sadm/bin/valpath
89
FGREP=/usr/bin/fgrep
90
SUM=/usr/bin/sum
91
 
92
multiPtchInstall="no"
93
multiPtchList=
94
multiPtchStatus=
95
lastPtchInList=
96
patchdir=
97
olddir=
98
validate="yes"
99
saveold="yes"
100
netImage="none"
101
dryrunDir="none"
102
 
103
ROOTDIR="/"
104
PATCHDB="/var/sadm/patch"
105
PKGDB="/var/sadm/pkg"
106
NEW_SOFTINFO="/var/sadm/system/admin/INST_RELEASE"
107
OLD_SOFTINFO="/var/sadm/softinfo/INST_RELEASE"
108
MGRSOFTINFO="none"
109
TRGSOFTINFO="none"
110
PKGDBARG=""
111
INSTALL_PATCHDIR=""
112
 
113
# This tells pkgadd to not check mounted FS's. Used in the mini-root.
114
MOPTION=""
115
 
116
PatchIdFormat='^[A-Z]*[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]$'
117
 
118
# Version string of the patch data base file. Change this 
119
# anytime the format of the .patchDB file changes. Also needs
120
# to be changed in patchrm.
121
PATCHDBVER="1.0" 
122
 
123
# response file keywords
124
PATCH_UNCONDITIONAL="false"
125
PATCH_PROGRESSIVE="true"
126
PATCH_NO_UNDO="false"
127
PATCH_BUILD_DIR="none"
128
PATCH_UNDO_ARCHIVE="none"
129
INTERRUPTION="no"
130
DRYRUN="no"
131
 
132
typeset -i Root_Kbytes_Needed=0
133
typeset -i Kbytes_Required=0
134
typeset -i Opt_Kbytes_Needed=0
135
typeset -i Openwin_Kbytes_Needed=0
136
typeset -i Usr_Kbytes_Needed=0
137
typeset -i Var_Kbytes_Needed=0
138
typeset -i ReqArrCount=0
139
typeset -i ReqdPatchCnt=0
140
typeset -i Something_Installed=0
141
typeset -i interactive=0
142
typeset -i req_count=0
143
typeset -i dbSum=0
144
typeset -i pdbSum=0
145
 
146
# List of required commands
147
REQD_CMDS="/usr/sbin/removef /usr/sbin/installf /usr/sbin/pkgadd \
148
	/usr/bin/pkgparam /usr/bin/pkginfo"
149
 
150
# Description:
151
#   Set the pid specific globals for use with multiple patch installation.
152
# Parameters:
153
#   none
154
#
155
function set_globals
156
{
157
	EXISTFILES=/tmp/existfiles.$$
158
	PATCHFILES=/tmp/patchfiles.$$
159
	PKGCOFILE=/tmp/pkgchk.out.$$
160
	VALERRFILE=/tmp/valerr.$$
161
	VALWARNFILE=/tmp/valwarn.$$
162
	ADMINTFILE=/tmp/admin.tmp.$$
163
	ADMINFILE=/tmp/admin.$$
164
	LOGFILE=/tmp/pkgaddlog
165
	TMP_ARCHIVE=/tmp/TmpArchive.$$
166
	TMP_FILELIST=/tmp/FileList.$$
167
	TMP_LIB_DIR=/tmp/TmpLibDir.$$
168
	INSTPATCHES_FILE=/tmp/MyShowrevFile.$$
169
	PARAMS_FILE=/tmp/ParamsFile.$$
170
	RESPONSE_FILE=/tmp/response.$$
171
	TEMP_REMOTE=/tmp/temp_remote.$$
172
 
173
	Obsoletes=
174
	Incompat=
175
	Requires=
176
	ObsoletePast=""
177
	UninstReqs=
178
	InstIncompat=
179
	Product=
180
	MgrProduct=
181
 
182
	OpenwinFS=
183
	OptFS=
184
	UsrFS=
185
	VarFS=
186
	ClientFS=
187
	pkglist=
188
	newpkglist=
189
 
190
	client="no"
191
	is_a_root_pkg="no"
192
	is_an_instpatches="no"
193
	ret=
194
	curdir=
195
	PatchNum=
196
	PatchBase=
197
	PatchVers=
198
	PatchMethod=
199
	PatchType=
200
	printpatches="no"
201
	ThisPatchFnd="no"
202
	ObsoletedBy="none"
203
	ReqdOSPatch="none"
204
	rootlist=
205
	isapplied="no"
206
	libs_are_moved="no"
207
	useRecFiles="no"
208
	recreatePatchDB="no"
209
	reapplied="no"
210
 
211
	Root_Kbytes_Needed=0
212
	Kbytes_Required=0
213
	Opt_Kbytes_Needed=0
214
	Openwin_Kbytes_Needed=0
215
	Usr_Kbytes_Needed=0
216
	Var_Kbytes_Needed=0
217
	ReqArrCount=0
218
	ReqdPatchCnt=0
219
	Something_Installed=0
220
	compatsAlreadyChecked="no"
221
	unReqAlreadyChecked="no"
222
}
223
 
224
# Description:
225
#   Usage message
226
# Parameters:
227
#   none
228
#
229
function print_usage
230
{
231
cat << EOF
232
 
233
Usage: patchadd [-u] [-d] [-B <backout_dir>]
234
                    [-S <service> | -R <client_root_path>]
235
                    [-C <net_install_image>] <patch>
236
 
237
       patchadd [-u] [-d] [-B <backout_dir>]
238
                    [-S <service> | -R <client_root_path>] 
239
                    [-C <net_install_image>]
240
                    -M patch_dir patch_id... | patch_dir patch_list
241
 
242
       patchadd [-S <service> | -R <client_root_path>] 
243
                    [-C <net_install_image>] -p
244
EOF
245
 
246
# This line is part of the usage msg
247
}
248
 
249
#
250
# Description:
251
# 	Quit patchadd and clean up any remaining temporary files.
252
#
253
# Parameters:
254
#	$1 - exitcode
255
#	$2 - Quit the entire installation 
256
 
257
function patch_quit {	# exit code
258
	if [[ "$lastPtchInList" != "$PatchNum" && $2 = "no" ]]
259
	then
260
		/usr/bin/gettext "WARNING: Skipping patch $PatchNum \n\n"
261
		return
262
	elif [[ $1 -ne 0 ]]
263
	then
264
		/usr/bin/gettext "\nPatchadd is terminating.\n"
265
	fi
266
 
267
	if [[ "$netImage" != "none"  && -d "$ROOTDIR/mnt/root" ]]
268
	then
269
		restore_net_image
270
	fi
271
 
272
	remove_files
273
 
274
	exit $1
275
}
276
 
277
#
278
# Description:
279
#	Remove the patch recovery directory if installation
280
#	was successful and any other files needing to be removed.
281
#
282
# Globals Used:
283
#	RECOVERDIR
284
#	Something_Installed	
285
 
286
function remove_files {
287
 
288
	if (( Something_Installed == 1 ))
289
	then
290
		$RM -fr $RECOVERDIR
291
	fi
292
 
293
	if [[ $libs_are_moved = "yes" ]]
294
	then
295
		remove_libraries
296
	fi
297
 
298
	$RM -f $INSTPATCHES_FILE
299
	$RM -f /tmp/*.$$.1
300
	$RM -f /tmp/archive.cpio*
301
	$RM -fr /tmp/*.$$
302
	$RM -f $patchFileStripped
303
}
304
 
305
#
306
# Description:
307
#	Return the base code of the provided patch. The base code
308
#	returned will include the version prefix token (usu "-").
309
#
310
# Parameters Used:
311
#	$1	- patch number
312
#
313
function get_base_code {
314
	ret_value=${1:%[0-9]}
315
	last_value=$1
316
 
317
	while [[ $ret_value != $last_value ]]
318
	do
319
		last_value=$ret_value
320
		ret_value=${last_value%[0-9]}
321
	done
322
 
323
	cur_base_code=${ret_value%?}
324
}
325
 
326
#
327
# Description:
328
#	Return the version number of the provided patch.
329
#
330
# Parameters Used:
331
#	$1	- patch number
332
#	$2	- base code
333
#
334
function get_vers_no {
335
	cur_vers_no=${1:#$2?}
336
}
337
 
338
#
339
# Description:
340
#	This function is an extension to the patch arch.
341
#	It allows patch/pkg engineers to include a script
342
#	that will execute before installpatch evaluates
343
#	dependencies. This is very risky and hopefully
344
#	this prePatch script is not malignent.
345
#
346
# Parameters:
347
#	$1 - patch directory.
348
#	$2 - ROOTDIR
349
# Globals Set:
350
#   none
351
#
352
function execute_prePatch
353
{
354
	typeset -i retcode=0
355
 
356
	if [[ -x "$1/prePatch" ]]
357
	then
358
		/usr/bin/gettext "Executing prePatch script...\n"
359
		$1/prePatch "$1" "$2"
360
		retcode=$?
361
		if (( retcode != 0 ))
362
		then
363
			/usr/bin/gettext "The prePatch script exited with return code $retcode.\n"
364
			patch_quit 15 "no"
365
			return 0
366
		fi
367
	fi
368
	return 1
369
}
370
 
371
#
372
# Description:
373
#	If a prepatch executable exists in the $1 directory, execute it.
374
#	If the return code is 0, continue. Otherwise, exit with code 15.
375
#
376
# Parameters:
377
#	$1	- patch directory.
378
# Globals Set:
379
#	none
380
#
381
function execute_prepatch
382
{
383
	typeset -i retcode=0
384
	if [[ -x "$1/prepatch" ]]
385
	then
386
		/usr/bin/gettext "Executing prepatch script...\n"
387
		$1/prepatch
388
		retcode=$?
389
		if (( retcode != 0 ))
390
		then
391
			/usr/bin/gettext "The prepatch script exited with return code $retcode.\n"
392
			patch_quit 15 "no"
393
			return 0
394
		fi
395
	fi
396
	return 1
397
}
398
 
399
#
400
# Description:
401
#	If a postpatch executable exists in the $1 directory, execute it.
402
#	If the return code is 0, continue. Otherwise, if this is not
403
#	a re-installation of the patch, execute the 
404
#	patchrm script and exit with a return code 16.
405
#	If this is a re-installation, don't backout the patch. Instead,
406
#	send a message to the user.
407
#
408
# Parameters:
409
#	$1	- patch database directory
410
#	$2	- patch number
411
#	$3	- patch directory.
412
# Globals Set:
413
#	none
414
#
415
function execute_postpatch
416
{
417
        # 31-July-2002 VC: added additional postpatch script location.
418
        #
419
        m_postpatch_List="$3/postpatch $1/$2/postpatch"
420
 
421
        for i in $m_postpatch_List
422
        do
423
 
424
	    typeset -i retcode=0
425
	    if [[ -x "$i" ]]
426
	    then
427
		    /usr/bin/gettext "Executing postpatch script...\n"
428
                    $i
429
		    retcode=$?
430
		    if (( retcode != 0 ))
431
		    then
432
			    /usr/bin/gettext "The postpatch script exited with return code $retcode.\n"
433
			    if [[ "$isapplied" = "no" ]]
434
			    then
435
				    $CP $1/$2/log /tmp/log.$2
436
				    /usr/bin/gettext "Backing out patch:\n"
437
				    cd $3
438
				    if [[ "$ROOTDIR" != "/" ]]
439
				    then
440
					    /usr/sbin/patchrm $PKGDBARG $2
441
				    else
442
					    /usr/sbin/patchrm $2
443
				    fi
444
				    /usr/bin/gettext "See /tmp/log.$2 for more details.\n"
445
			    else
446
				    /usr/bin/gettext "Not backing out patch because this is a re-installation.\nThe system may be in an unstable state!\nSee $1/$2/log for more details.\n"  |tee -a $1/$2/log
447
			    fi
448
			    patch_quit 16 "no"
449
			    return 0
450
		    fi
451
	    fi
452
        done
453
 
454
	return 1
455
}
456
 
457
# Description:
458
#       Check to see if the pkginfo command reports an error
459
#       before using it to evaluate the installed pkgs.
460
#
461
# Parameters:
462
#       none
463
#
464
# Globals used
465
#       PKGDB
466
#
467
function chk_pkginfo_cmd
468
{
469
	if [[ "$netImage" != "none" ]]
470
	then
471
		return
472
	fi
473
	prevDir=$(pwd)
474
	cd $PKGDB
475
	for pkg in *
476
	do
477
		pkginfo -R $ROOTDIR $pkg > /dev/null 2>&1
478
		if [[ $? -ne 0 ]]
479
		then
480
			/usr/bin/gettext "The pkginfo file for package: $pkg is either corrupt or missing.\nA fsck of the file system or re-installing $pkg\nis recommended before installing any patches!\n"
481
			patch_quit 28 "yes"
482
		fi
483
	done
484
	cd $prevDir
485
}
486
 
487
# Description
488
#	Add the installing patches information into the patch data base.
489
#
490
# Parameters:
491
#	$1 - patch number
492
 
493
function update_patchDB
494
{
495
	# At this point the patch has installed and we now update
496
	# the new patch database.
497
 
498
	if [[ "$reapplied" = "yes" ]]; then
499
		if (( Something_Installed == 1 )); then
500
			$RM -f $PATCHDBFILE
501
			return
502
		fi
503
	fi
504
 
505
	reallyNotThere=""
506
 
507
	pkginfoParamSum
508
 
509
	if [[ ! -f $PATCHDBFILE ]]; then
510
		echo "Version $PATCHDBVER $dbSum" > $PATCHDBFILE
511
		chmod 644 $PATCHDBFILE > /dev/null 2>&1
512
	else
513
		$NAWK -v ps="$dbSum" '
514
			$1 ~ /Version/ { printf("%s %s %s\n", $1, $2, ps); next }
515
			{ print } ' $PATCHDBFILE > $PATCHDBFILE.tmp
516
		$MV -f $PATCHDBFILE.tmp $PATCHDBFILE
517
	fi
518
 
519
	reallyNotThere=$($GREP "Patch:[ 	]*$1" $PATCHDBFILE)
520
	if [[ -z "$reallyNotThere" ]]; then
521
		if [[ -n "$Requires" && -n "$Incompat" ]]; then
522
			echo "Patch: $1 Obsoletes: $Obsoletes Requires: $Requires Incompatibles: $Incompat Packages: $pkgDispList" >> $PATCHDBFILE
523
		elif [[ -n "$Requires" ]]; then
524
			echo "Patch: $1 Obsoletes: $Obsoletes Requires: $Requires Incompatibles: $Incompat Packages: $pkgDispList" >> $PATCHDBFILE
525
		elif [[ -n "$Incompat" ]]; then
526
			echo "Patch: $1 Obsoletes: $Obsoletes Requires: $Requires Incompatibles: $Incompat Packages: $pkgDispList" >> $PATCHDBFILE
527
		else
528
			echo "Patch: $1 Obsoletes: $Obsoletes Requires: Incompatibles: Packages: $pkgDispList" >> $PATCHDBFILE
529
		fi
530
	fi
531
}
532
 
533
# Description:
534
#	Give a list of applied patches similar in format to the showrev -p
535
#	command. Had to write my own because the showrev command won't take
536
#	a -R option.
537
#
538
# Parameters:
539
#	$1	- package database directory
540
#
541
# Locals used
542
#	arg
543
#	tmpStr
544
#
545
# Globals used
546
#	PatchNum
547
#	force
548
#
549
# Globals Set:
550
#	ObsoletedBy
551
#	ThisPatchFnd
552
#	PatchedPkgs
553
#	ReqdOSPatchFnd	The patch that this OS release requires was found
554
#
555
# Revision History
556
#	1995-08-01	Added PATCH_OBSOLETES and expanded the tests for
557
#			direct instance patches since all necessary
558
#			is reviewed at this time, this function also
559
#			tests for obsolescence, dependencies and
560
#			incompatibilities.
561
#
562
function eval_inst_patches
563
{
564
	typeset -i TestCount=0
565
	typeset -i ArrayCount=0
566
	typeset -i PatchFound=0
567
	typeset -i sr_count=0
568
 
569
	set -A PkgArrElem
570
	set -A ObsArrElem
571
	set -A ReqsArrElem
572
	set -A IncsArrElem
573
	set -A PatchArrElem
574
 
575
	instPtchs=""
576
	fnd=""
577
 
578
	# Use the file /var/sadm/patch/.patchDB instead of
579
	# gathering the information
580
 
581
	if [[ -s "$PATCHDBFILE" && "$recreatePatchDB" = "no" ]]; then
582
		if [[ "$printpatches" = "yes" ]]; then
583
			instPtchs=$($GREP -v "Version" $PATCHDBFILE)
584
			if [[ -n "$instPtchs" ]]; then
585
				/usr/bin/gettext "$instPtchs\n\n"
586
			else
587
				/usr/bin/gettext "No patches installed\n\n"
588
			fi
589
			return
590
		fi
591
 
592
		fnd=$($GREP "^Patch:[ 	]*$PatchNum" $PATCHDBFILE)
593
 
594
		if [[ -n "$fnd" ]]; then
595
			ThisPatchFnd="yes"
596
		fi
597
 
598
		$GREP -v "Version" $PATCHDBFILE
599
		return
600
 
601
	elif [[ "$is_an_instpatches" = "yes" ]]
602
	then
603
		cat $INSTPATCHES_FILE
604
		return
605
	fi
606
 
607
	olddir=$(pwd)
608
	#
609
	# First get the old-style patches and obsoletions
610
	#
611
	if [[ -d $1 && -d $PATCHDB && $netImage != "product" ]]
612
	then
613
		cd $1
614
		patches=""
615
 
616
		# This gets old and new style patches
617
		patches=$($GREP -l SUNW_PATCHID ./*/pkginfo 2>/dev/null | \
618
		    xargs $SED -n 's/^SUNW_PATCHID=//p' | sort -u)
619
 
620
		if [[ "$patches" != "" ]]
621
		then
622
			for apatch in $patches
623
			do
624
				outstr="Patch: $apatch Obsoletes: "
625
 
626
				# Scan all the installed packages for this
627
				# patch number and return the effected
628
				# package instances
629
				patchvers=$($GREP -l "SUNW_PATCHID=$apatch" \
630
				    ./*/pkginfo 2>/dev/null | \
631
				    $SED 's,^./\(.*\)/pkginfo$,\1,' )
632
 
633
				# If there's a PATCH_INFO entry then this
634
				# is really a direct instance patch
635
				for package in $patchvers
636
				do
637
					break;
638
				done
639
 
640
				$($GREP -b "PATCH_INFO_$apatch" $package/pkginfo 1>/dev/null 2>&1)
641
				if [[ $? -eq 0 ]]
642
				then
643
					continue
644
				fi
645
 
646
				PatchFound=1
647
 
648
				# Get the obsoletes list
649
				obsoletes_printed="n"
650
				for vers in $patchvers
651
				do
652
					if [[ "$obsoletes_printed" = "n" ]]
653
					then
654
						outstr="$outstr$($SED -n 's/SUNW_OBSOLETES=//p' \
655
						    ./$vers/pkginfo) Packages: "
656
						outstr="$outstr$vers $($SED -n 's/VERSION=//p' \
657
						    ./$vers/pkginfo)"
658
						obsoletes_printed="y"
659
					else
660
						outstr="$outstr, $vers $($SED -n 's/VERSION=//p' \
661
						    ./$vers/pkginfo)"
662
					fi
663
				done
664
 
665
				# The current patch is a direct instance patch
666
				if [[ $apatch = "$PatchNum" ]]
667
				then
668
					ThisPatchFnd="yes"
669
				fi
670
 
671
				if [[ "$printpatches" = "yes" ]]
672
				then
673
					echo $outstr  | tee -a $INSTPATCHES_FILE
674
				else
675
					echo $outstr | tee -a $INSTPATCHES_FILE
676
					is_an_instpatches="yes"
677
				fi
678
			done
679
		fi
680
	fi
681
 
682
	#
683
	# Now get the direct instance patches
684
	#
685
	# DIPatches is a non-repeating list of all patches applied
686
	# to the system.
687
	#
688
	if [[ "$netImage" = "product" ]]
689
	then
690
		arg="-d"
691
	else
692
		arg="-R"
693
	fi
694
 
695
	pkginfo $arg  $ROOTDIR | $NAWK ' { print $2; } ' | while read pkg
696
	do
697
		DIPatches=$(pkgparam $arg $ROOTDIR $pkg PATCHLIST)
698
		for patch in $DIPatches
699
		do
700
			get_base_code $patch
701
			patch_base=$cur_base_code
702
 
703
			get_vers_no $patch $patch_base
704
			patch_vers=$cur_vers_no
705
 
706
			PatchFound=1;
707
 
708
			# Get the obsoletes from each installed package
709
 
710
			tmpStr=""
711
			tmpStr=$(pkgparam $arg $ROOTDIR $pkg PATCH_INFO_$patch)
712
			obsoletes=${tmpStr##*Obsoletes:}
713
			obsoletes=${obsoletes%%Requires:*}
714
 
715
			#obsoletes=$(echo $tmpStr | $GREP Obsoletes: | $NAWK ' \
716
			  #{ print substr($0, match($0, "Obsoletes:")+11) } ' | \
717
			  #$SED 's/Requires:.*//g')
718
 
719
			# Get the requires from each installed package
720
 
721
			reqs=${tmpStr##*Requires:}
722
			reqs=${reqs%%Incompatibles:*}
723
 
724
			#reqs=$(echo $tmpStr | $GREP Requires: | $NAWK ' \
725
			  #{ print substr($0, match($0, "Requires:")+10) } ' | \
726
			  #$SED 's/Incompatibles:.*//g')
727
 
728
			# Get the incompatibles from each installed package
729
 
730
			incs=${tmpStr##*Incompatibles:}
731
 
732
			#incs=$(echo $tmpStr | $GREP Incompatibles: | $NAWK ' \
733
			  #{ print substr($0, match($0, "Incompatibles:")+15) } ')
734
 
735
			if [[ -n "$obsoletes" ]]
736
			then
737
				for obs in $obsoletes;
738
				do
739
					PatchArrElem[$ArrayCount]=$patch;
740
					ObsArrElem[$ArrayCount]=$obs;
741
					PkgArrElem[$ArrayCount]=$pkg;
742
					ArrayCount=ArrayCount+1;
743
				done
744
			else
745
				PatchArrElem[$ArrayCount]=$patch;
746
				ObsArrElem[$ArrayCount]="";
747
				PkgArrElem[$ArrayCount]=$pkg;
748
				ArrayCount=ArrayCount+1;
749
			fi
750
 
751
			if [[ -n "$reqs" ]]
752
			then
753
				for req in $reqs;
754
				do
755
					PatchArrElem[$ArrayCount]=$patch;
756
					ReqsArrElem[$ArrayCount]=$req;
757
					PkgArrElem[$ArrayCount]=$pkg;
758
					ArrayCount=ArrayCount+1;
759
				done
760
			else
761
				PatchArrElem[$ArrayCount]=$patch;
762
				ReqsArrElem[$ArrayCount]="";
763
				PkgArrElem[$ArrayCount]=$pkg;
764
				ArrayCount=ArrayCount+1;
765
			fi
766
 
767
			if [[ -n "$incs" ]]
768
			then
769
				for inc in $incs;
770
				do
771
					PatchArrElem[$ArrayCount]=$patch;
772
					IncsArrElem[$ArrayCount]=$inc;
773
					PkgArrElem[$ArrayCount]=$pkg;
774
					ArrayCount=ArrayCount+1;
775
				done
776
			else
777
				PatchArrElem[$ArrayCount]=$patch;
778
				IncsArrElem[$ArrayCount]="";
779
				PkgArrElem[$ArrayCount]=$pkg;
780
				ArrayCount=ArrayCount+1;
781
			fi
782
 
783
			# Check for already installed
784
			if [[ "$patch" = "$PatchNum" ]]
785
			then
786
				ThisPatchFnd="yes"
787
			fi
788
 
789
			if [[ $printpatches != "yes" ]]
790
			then
791
				compatsAlreadyChecked="yes"
792
				CheckInstallingCompats $patch $patch_base $patch_vers
793
			fi
794
		done
795
	done
796
 
797
	CheckUninstalledReqs
798
	unReqAlreadyChecked="yes"
799
 
800
	while [[ $TestCount -lt $ArrayCount ]]
801
	do
802
		typeset -i TempCount=TestCount+1
803
 
804
		# Scan all entries matching the current one
805
		PatchArrEntry=${PatchArrElem[$TestCount]}	# Current one
806
		ObsArrEntry=${ObsArrElem[$TestCount]}
807
		PkgArrEntry=${PkgArrElem[$TestCount]}
808
		ReqsArrEntry=${ReqsArrElem[$TestCount]}
809
		IncsArrEntry=${IncsArrElem[$TestCount]}
810
 
811
		if [[ "$PatchArrEntry" = "used" ]]
812
		then
813
			TestCount=TestCount+1
814
			continue
815
		fi
816
 
817
		while [[ $TempCount -lt $ArrayCount ]]
818
		do
819
			typeset -i dont_use;
820
			#
821
			# If this is another line describing this patch
822
			#
823
			if [[ ${PatchArrElem[$TempCount]} = $PatchArrEntry ]]
824
			then
825
				dont_use=0;
826
 
827
				PatchArrElem[$TempCount]="used"
828
				for pkg in $PkgArrEntry
829
				do
830
					if [[ $pkg = ${PkgArrElem[$TempCount]} ]]
831
					then
832
						dont_use=1;
833
						break;
834
					fi
835
				done
836
 
837
				if [[ $dont_use = 0 ]]
838
				then
839
					PkgArrEntry="$PkgArrEntry ${PkgArrElem[$TempCount]}"
840
				fi
841
 
842
				dont_use=0;
843
 
844
				for obs in $ObsArrEntry
845
				do
846
					if [[ $obs = ${ObsArrElem[$TempCount]} ]]
847
					then
848
						dont_use=1;
849
						break;
850
					fi
851
				done
852
 
853
				if [[ $dont_use = 0 ]]
854
				then
855
					ObsArrEntry="$ObsArrEntry ${ObsArrElem[$TempCount]}"
856
				fi
857
 
858
				dont_use=0;
859
 
860
				for inc in $IncsArrEntry
861
				do
862
					if [[ $inc = ${IncsArrElem[$TempCount]} ]]
863
					then
864
						dont_use=1;
865
						break;
866
					fi
867
				done
868
 
869
				if [[ $dont_use = 0 ]]
870
				then
871
					IncsArrEntry="$IncsArrEntry ${IncsArrElem[$TempCount]}"
872
				fi
873
 
874
				dont_use=0;
875
 
876
				for req in $ReqsArrEntry
877
				do
878
					if [[ $req = ${ReqsArrElem[$TempCount]} ]]
879
					then
880
						dont_use=1;
881
						break;
882
					fi
883
				done
884
 
885
				if [[ $dont_use = 0 ]]
886
				then
887
					ReqsArrEntry="$ReqsArrEntry ${ReqsArrElem[$TempCount]}"
888
				fi
889
 
890
			fi
891
			TempCount=TempCount+1
892
		done
893
 
894
		if [[ $PatchArrEntry = "$PatchNum" ]]; then
895
			export PatchedPkgs="$PkgArrEntry"
896
		fi
897
 
898
		# Now make it comma separated lists
899
		PkgArrEntry=$(echo $PkgArrEntry | $SED s/\ /,\ /g)
900
		ObsArrEntry=$(echo $ObsArrEntry | $SED s/\ /,\ /g)
901
		ReqsArrEntry=$(echo $ReqsArrEntry | $SED s/\ /,\ /g)
902
		IncsArrEntry=$(echo $IncsArrEntry | $SED s/\ /,\ /g)
903
 
904
		outstr="Patch: $PatchArrEntry Obsoletes: $ObsArrEntry \
905
		  Requires: $ReqsArrEntry Incompatibles: $IncsArrEntry \
906
		  Packages: $PkgArrEntry"
907
 
908
		if [[ "$printpatches" = "yes" ]]
909
		then
910
			echo $outstr | tee -a $INSTPATCHES_FILE
911
		else
912
			echo $outstr | tee -a $INSTPATCHES_FILE
913
			is_an_instpatches="yes"
914
		fi
915
 
916
		TestCount=TestCount+1
917
	done
918
 
919
	pkginfoParamSum
920
 
921
	if [[ ! -d $PATCHDB ]]; then
922
		$MD -p $PATCHDB
923
	fi
924
 
925
	echo "Version $PATCHDBVER $dbSum" > $PATCHDBFILE
926
 
927
	if [[ -s "$INSTPATCHES_FILE" ]]; then
928
		cat $INSTPATCHES_FILE >> $PATCHDBFILE
929
		chmod 644 $PATCHDBFILE > /dev/null 2>&1
930
	fi
931
 
932
	if [[ $PatchFound = 0 && $printpatches = "yes" ]]
933
	then
934
		print " No patches installed."
935
	fi
936
 
937
	cd $olddir;
938
}
939
 
940
#
941
# Description
942
#	
943
function CheckUninstalledReqs
944
{
945
	req_count=0;
946
	for req in $Requires; do
947
		if [[ ${ReqArrElem[$req_count]} = "no" ]]
948
		then
949
			ReqdPatchCnt=ReqdPatchCnt+1
950
			UninstReqs="$UninstReqs $req"
951
		fi
952
		req_count=req_count+1;
953
	done
954
 
955
	if [[ $validate = "no" ]]
956
	then
957
		ReqdPatchCnt=0
958
	fi
959
}
960
 
961
#
962
# Description:
963
#	Validate the patch directory, and parse out the patch number and
964
#	patch revision from the first pkginfo file found in the patch
965
#	packages.
966
# Parameters:
967
#	$1	- patch directory
968
# Globals Set:
969
#	PatchNum
970
#	PatchBase
971
#	PatchVers
972
function activate_patch
973
{
974
	cd $1
975
	for i in */pkginfo
976
	do
977
		#
978
		# Find the patch number in one of the pkginfo files. If there is 
979
		# no pkginfo file having a SUNW_PATCHID=xxxxxx entry, send an 
980
		# error to the user and exit.
981
		#
982
		tmp=$($GREP PATCHID $i)
983
		if [[ -n $tmp ]]; then
984
			PatchNum=$(pkgparam -f $i ${tmp:%=*})
985
			if [[ "$multiPtchInstall" = "no" ]]
986
			then
987
				lastPtchInList=$PatchNum
988
			fi
989
		else
990
			/usr/bin/gettext "The packages in $1\n"
991
			/usr/bin/gettext "are not proper patch packages.\n"
992
			/usr/bin/gettext "See instructions for applying the patch in patchadd(1M).\n"
993
			patch_quit 7 "no"
994
			return 0
995
		fi
996
	done
997
 
998
	#
999
	# Get the patch base code (the number up to the version prefix) 
1000
	# and the patch revision number (the number after the version prefix).
1001
	#
1002
	get_base_code $PatchNum
1003
	PatchBase=$cur_base_code
1004
	get_vers_no $PatchNum $cur_base_code
1005
	PatchVers=$cur_vers_no
1006
 
1007
	return 1
1008
}
1009
 
1010
 
1011
# Description:
1012
#   Check to see if there are any files leftover from a previous
1013
#	installation. Set the unconditional flag if there are.
1014
# Parameters:
1015
#   none
1016
# Globals Used:
1017
#   PatchNum
1018
 
1019
function check_file_recovery_dir
1020
{
1021
	if [[ -f $RECOVERDIR/.$PatchNum && "$PatchMethod" = "direct" ]]
1022
	then
1023
		PATCH_UNCONDITIONAL="true"
1024
	fi
1025
 
1026
}
1027
 
1028
# Description:
1029
#	Build the admin file for later use by non-interactive pkgadd
1030
# Parameters:
1031
#	none
1032
# Globals Used:
1033
#	ADMINTFILE
1034
 
1035
function build_admin_file
1036
{
1037
	if [[ "$PatchMethod" = "direct" && -f /var/sadm/install/admin/patch ]]
1038
	then
1039
		ADMINTFILE="patch"
1040
	else
1041
		cat > $ADMINTFILE << EOF
1042
mail=
1043
instance=unique
1044
partial=nocheck
1045
runlevel=nocheck
1046
idepend=nocheck
1047
rdepend=nocheck
1048
space=quit
1049
setuid=nocheck
1050
conflict=nocheck
1051
action=nocheck
1052
EOF
1053
	fi
1054
}
1055
 
1056
# Description:
1057
#	create a response file if it is necessary
1058
# Parameters:
1059
#	$1	patch type
1060
#	$2	patch method
1061
function build_response_file
1062
{
1063
	if [[ "$1" != "piPatch" ]]
1064
	then
1065
		if [[ "$2" = "progressive" ]]
1066
		then
1067
			cat > $RESPONSE_FILE << EOF
1068
PATCH_PROGRESSIVE=$PATCH_PROGRESSIVE
1069
EOF
1070
		else
1071
			cat > $RESPONSE_FILE << EOF
1072
PATCH_PROGRESSIVE=$PATCH_PROGRESSIVE
1073
PATCH_UNCONDITIONAL=$PATCH_UNCONDITIONAL
1074
PATCH_NO_UNDO=$PATCH_NO_UNDO
1075
PATCH_BUILD_DIR=$PATCH_BUILD_DIR
1076
PATCH_UNDO_ARCHIVE=$PATCH_UNDO_ARCHIVE
1077
INTERRUPTION=$INTERRUPTION
1078
EOF
1079
 
1080
		fi
1081
	fi
1082
}
1083
 
1084
# Description:
1085
#	See if there is any work to be done. If none of the packages to
1086
#	which the patch applies are installed and there is no spooling work
1087
#	to do for the client root templates, then you're done.
1088
#	NEW:
1089
#	If SUNWcar, SUNWcsd or SUNWcsr is included in the patch,
1090
#	but the package is not on the list to be patched, then print an
1091
#	error message and die. At least one instance of these packages
1092
#	should be patched if included in the patch.
1093
# Parameters:
1094
#	$1	- client status
1095
#	$2	- were any of the packages root packages?
1096
# Globals Used:
1097
#	pkglist
1098
#	rootlist
1099
#	patchdir
1100
 
1101
function check_for_action
1102
{
1103
	if [[ "$pkglist" = "" && "$rootlist" = "" ]]
1104
	then
1105
          echo "check for action $pkglist- $rootlist"
1106
		#
1107
		# In the first case, the system is not a client, however, 
1108
		# there are still no packages to patch. This will only 
1109
		# occur if the packages in question have not been installed 
1110
		# on the system.
1111
		#
1112
		if [[ $1 = "no" || $2 = "yes" ]]
1113
		then
1114
 			/usr/bin/gettext "One or more patch packages included in\n$PatchNum are not installed on this system.\n"
1115
			patch_quit 8 "no"
1116
			return 0
1117
		else
1118
			#
1119
			# In the second case, the system is a client system. 
1120
			# There are two types of packages for client systems: 
1121
			# root packages (those packages installed on the client 
1122
			# machines) and packages installed only on the server. 
1123
			# Patchadd will exit if the machine is a client, and 
1124
			# there are no root packages to be patched.
1125
			#
1126
			/usr/bin/gettext "This patch is not applicable to client systems.\n"
1127
			patch_quit 0 "no"
1128
			return 0
1129
		fi
1130
	fi
1131
	return 1
1132
}
1133
 
1134
# Description:
1135
#	Check to see if the patch has already been applied
1136
# Parameters:
1137
#	$1	- patch database directory
1138
#	$2	- patch number
1139
# Globals Set:
1140
#	isapplied will be set to "yes" if this is a re-application of a patch.
1141
#	This will not necessarily cause a bail out if there are packages that
1142
#	should be installed that were not installed the first time the patch
1143
#	was applied.
1144
#
1145
function check_if_applied
1146
{
1147
	if [[ "$PatchMethod" = "direct" ]]
1148
	then
1149
		if [[ "$ThisPatchFnd" = "yes" && $PATCH_UNCONDITIONAL != "true" ]]
1150
		then
1151
			isapplied="yes"
1152
		else
1153
			$RM -fr "$1/$2"
1154
		fi
1155
	else
1156
		if eval_inst_patches $PKGDB | $GREP -s "^Patch:[ 	]*$2" > /dev/null 2>&1
1157
		then
1158
			isapplied="yes"
1159
		else
1160
			$RM -fr "$1/$2"
1161
		fi
1162
	fi
1163
}
1164
 
1165
# Description:
1166
#   Print space error message
1167
#
1168
function space_error_msg
1169
{
1170
    /usr/bin/gettext "Not enough space in $1 to apply patch. $1 has $2 Kbytes available\n$1 needs $3 Kbytes free.\n"
1171
 
1172
}
1173
 
1174
# Description:
1175
#   Check space needed against space available
1176
#
1177
# Parameters:
1178
#	None
1179
#
1180
# Globals Used:
1181
#   ROOTDIR
1182
#	VarFS
1183
#	ClientFS
1184
#	OptFS
1185
#	UsrFS
1186
#	OpenwinFS
1187
#	Root_Kbytes_Needed
1188
#	Var_Kbytes_Needed
1189
#	Opt_Kbytes_Needed
1190
#	Usr_Kbytes_Needed
1191
#	Openwin_Kbytes_Needed
1192
#
1193
# Globals Set:
1194
#   None
1195
#
1196
function check_fs_space
1197
{
1198
	typeset -i Opt_Available=0
1199
	typeset -i Openwin_Available=0
1200
	typeset -i Root_Available=0
1201
	typeset -i Usr_Available=0
1202
	typeset -i Var_Available=0
1203
	typeset -i exit_status=0
1204
 
1205
	if [[ "$DRYRUN" = "no" ]]
1206
	then
1207
		/usr/bin/gettext "Verifying sufficient filesystem capacity (exhaustive method)...\n"
1208
	else
1209
		/usr/bin/gettext "Verifying sufficient filesystem capacity (dry run method)...\n"
1210
		return 1
1211
	fi
1212
 
1213
	#
1214
	# Bear in mind that df -b gives the total kbytes available to
1215
	# the super-user. That means we have to be conservative since
1216
	# there's no pad.
1217
	#
1218
	Tmp_Available=$($DF -b $ROOTDIR | $SED -e '1d')
1219
	Root_Available=${Tmp_Available:#* }
1220
 
1221
	#
1222
	# The root file system must have at least 1Mb of free
1223
	# space or there will be problems after rebooting
1224
	#
1225
	Root_Available=Root_Available-1000
1226
 
1227
	if (( Root_Kbytes_Needed > Root_Available ))
1228
	then
1229
		space_error_msg $ROOTDIR $Root_Available $Root_Kbytes_Needed
1230
		exit_status=18
1231
	fi
1232
 
1233
	if [[ -n "$UsrFS" ]]
1234
	then
1235
		Tmp_Available=$($DF -b $ROOTDIR/usr | $SED -e '1d')
1236
		Usr_Available=${Tmp_Available:#* }
1237
 
1238
		if (( Usr_Kbytes_Needed > Usr_Available ))
1239
		then
1240
			space_error_msg $ROOTDIR/usr $Usr_Available $Usr_Kbytes_Needed
1241
			exit_status=18
1242
		fi
1243
	fi
1244
 
1245
	if [[ -n "$OptFS" ]]
1246
	then
1247
		Tmp_Available=$($DF -b $ROOTDIR/opt | $SED -e '1d')
1248
		Opt_Available=${Tmp_Available:#* }
1249
		if (( Opt_Kbytes_Needed > Opt_Available ))
1250
		then
1251
			space_error_msg $ROOTDIR/opt $Opt_Available $Opt_Kbytes_Needed
1252
			exit_status=18
1253
		fi
1254
	fi
1255
 
1256
	if [[ -n "$VarFS" ]]
1257
	then
1258
		Tmp_Available=$($DF -b $ROOTDIR/var | $SED -e '1d')
1259
		Var_Available=${Tmp_Available:#* }
1260
		if (( Var_Kbytes_Needed > Var_Available ))
1261
		then
1262
			space_error_msg $ROOTDIR/var $Var_Available $Var_Kbytes_Needed
1263
			exit_status=18
1264
		fi
1265
	fi
1266
 
1267
	if [[ -n "$OpenwinFS" ]]
1268
	then
1269
		Tmp_Available=$($DF -b $ROOTDIR/usr/openwin | $SED -e '1d')
1270
		Openwin_Available=${Tmp_Available:#* }
1271
		if (( Openwin_Kbytes_Needed > Openwin_Available ))
1272
		then
1273
			space_error_msg $ROOTDIR/usr/openwin $Openwin_Available $Openwin_Kbytes_Needed
1274
			exit_status=18
1275
		fi
1276
	fi
1277
 
1278
	if (( exit_status != 0 ))
1279
	then
1280
		patch_quit $exit_status "no"
1281
		return 0
1282
	fi
1283
	return 1
1284
}
1285
 
1286
# Description:
1287
#	Compute the file system space requirements for /, /var, /opt,
1288
#   /usr, and /usr/openwin to determine if there is enough free space
1289
#   in which to place the patch.
1290
#
1291
# Parameters:
1292
#	None
1293
#
1294
# Globals Used:
1295
#
1296
# Globals Set:
1297
#
1298
function compute_fs_space_requirements
1299
{
1300
	typeset -i size=0
1301
 
1302
    if [[ "$DRYRUN" = "yes" ]]
1303
    then
1304
		return
1305
	fi 	
1306
 
1307
	if [[ "$ROOTDIR" != "/" ]]
1308
	then
1309
		VarFS=$($DF -a $ROOTDIR/var 2>/dev/null | $GREP var)
1310
		OptFS=$($DF -a $ROOTDIR/opt 2>/dev/null | $GREP opt)
1311
		UsrFS=$($DF -a $ROOTDIR/usr 2>/dev/null | $GREP usr)
1312
		OpenwinFS=$($DF -a $ROOTDIR/usr/openwin 2>/dev/null | $GREP openwin)
1313
	else
1314
		VarFS=$($DF -a /var 2>/dev/null | $GREP var)
1315
		OptFS=$($DF -a /opt 2>/dev/null | $GREP opt)
1316
		UsrFS=$($DF -a /usr 2>/dev/null | $GREP usr)
1317
		OpenwinFS=$($DF -a /usr/openwin 2>/dev/null | $GREP openwin)
1318
	fi
1319
 
1320
	# All sizes gathered to this point are in bytes. Need to
1321
	# divide by a K.
1322
 
1323
	if [[ -z "$OpenwinFS" ]]
1324
	then
1325
		Root_Kbytes_Needed=Usr_Kbytes_Needed+Openwin_Kbytes_Needed
1326
		Openwin_Kbytes_Needed=0
1327
	else
1328
		if (( Openwin_Kbytes_Needed > 0 ))
1329
		then
1330
			Openwin_Kbytes_Needed=Openwin_Kbytes_Needed/1024
1331
		fi
1332
	fi
1333
 
1334
	if [[ -z "$UsrFS" ]]
1335
	then
1336
		Root_Kbytes_Needed=Root_Kbytes_Needed+Usr_Kbytes_Needed
1337
		Usr_Kbytes_Needed=0
1338
	else
1339
		if (( Usr_Kbytes_Needed > 0 ))
1340
		then
1341
			Usr_Kbytes_Needed=Usr_Kbytes_Needed/1024
1342
		fi
1343
	fi
1344
 
1345
	if [[ -z "$OptFS" ]]
1346
	then
1347
		Root_Kbytes_Needed=Root_Kbytes_Needed+Opt_Kbytes_Needed
1348
		Opt_Kbytes_Needed=0
1349
	else
1350
		if (( Opt_Kbytes_Needed > 0 ))
1351
		then
1352
			Opt_Kbytes_Needed=Opt_Kbytes_Needed/1024
1353
		fi
1354
	fi
1355
 
1356
	#Var_Kbytes_Needed=Var_Kbytes_Needed+Kbytes_Required
1357
	if [[ -z "$VarFS" ]]
1358
	then
1359
		Root_Kbytes_Needed=Root_Kbytes_Needed+Var_Kbytes_Needed
1360
		Var_Kbytes_Needed=0
1361
	else
1362
		if (( Var_Kbytes_Needed > 0 ))
1363
		then
1364
			Var_Kbytes_Needed=Var_Kbytes_Needed/1024
1365
		fi
1366
	fi
1367
 
1368
	Root_Kbytes_Needed=Root_Kbytes_Needed/1024
1369
}
1370
 
1371
# Description:
1372
#	Generate a list of packages to be installed. Remove from the previously
1373
#	generated $pkglist any packages that have already been patched. This
1374
#	procedure is called only for a patch re-installation.
1375
# Parameters:
1376
#	$1	- package database directory
1377
#	$2	- patch database directory
1378
#	$3	- patch number
1379
# Globals Used:
1380
#	pkglist
1381
# Globals Set:
1382
#	pkglist
1383
function gen_uninstalled_pkgs
1384
{
1385
 
1386
	tmppkglist=""
1387
 
1388
	# Try to match up the arch with the instance.
1389
	for pk in $pkglist; do
1390
 
1391
		# Get the installed instance that matches. Only need to check
1392
		# the ARCH to determine if it is already installed.
1393
 
1394
		ptARCH=$(pkgparam -f $pk/pkginfo ARCH)
1395
		tmppk=${pk:%.*}
1396
 
1397
		# Since pkginfo directs its error messages to stdout we
1398
		# need to check for the existence of the pkg's directory
1399
		# to avoid an annoying error by pkginfo.
1400
 
1401
		if [[ -d $PKGDB/$tmppk ]]; then
1402
			pkgNames=$(pkginfo -R $ROOTDIR -x $tmppk.\* | \
1403
				$NAWK ' $1 ~ /[A-Z]/ {print $1}' 2>/dev/null)
1404
		else
1405
			tmppkglist="$tmppkglist $pk"
1406
		fi
1407
 
1408
		for pkn in $pkgNames; do
1409
			pkPTCHD=$(pkgparam -R $ROOTDIR $pkn PATCHLIST | \
1410
				$GREP -s $PatchNum 2>/dev/null)
1411
 
1412
			if [[ -n "$pkPTCHD" ]]; then
1413
				continue
1414
 
1415
			# We know the pkg exists but hasn't been patched.
1416
			else 
1417
				arch=$(pkgparam -R $ROOTDIR $pkn ARCH 2>/dev/null)
1418
				if [[ "$arch" = "$ptARCH" ]]; then
1419
					tmppkglist="$tmppkglist $pk"
1420
				fi
1421
			fi
1422
		done
1423
	done
1424
	pkglist="$tmppkglist"
1425
 
1426
	if [[ "$pkglist" = "" ]]
1427
	then
1428
		/usr/bin/gettext "Patch $3 has already been applied.\nSee patchadd(1M) for instructions.\n"
1429
		patch_quit 2 "no"
1430
		return 0
1431
	else
1432
		/usr/bin/gettext "Re-installing patch $3...\n"
1433
		/usr/bin/gettext "\nRe-installing Patch.\n" >> $2/$3/log
1434
 
1435
		# Re-build the PATCHDB since that's the way we update it
1436
		# when a patch pkg gets re-installed.
1437
		reapplied="yes"
1438
	fi
1439
	return 1
1440
}
1441
 
1442
# Description:
1443
#	Check to see if the patch is obsoleted by an earlier patch
1444
# Parameters:
1445
#	none
1446
# Globals used:
1447
#	PKGDB
1448
#	PatchBase
1449
#	PatchVers
1450
# Globals set:
1451
#	isapplied
1452
 
1453
function check_if_obsolete
1454
{
1455
	if [[ "$PatchMethod" = "direct" ]]
1456
	then
1457
		if [[ "$ObsoletedBy" = "none" ]]
1458
		then
1459
			return 1
1460
		else 
1461
			print_obsolete_msg "$ObsoletedBy"
1462
			patch_quit 6 "no"
1463
			return 0
1464
		fi
1465
	else
1466
		#
1467
		# Search for patches that specifically obsolete the current 
1468
		# patch.  Ignore if the PatchBase of the obsoletor is the same 
1469
		# as the obsoletee.
1470
		#
1471
		if eval_inst_patches $PKGDB | $GREP -v "Patch: $PatchBase" | \
1472
			$GREP -s "Obsoletes:.*$PatchBase.*Packages:" > /dev/null 2>&1
1473
		then
1474
			print_obsolete_msg "$ObsoletedBy"
1475
			eval_inst_patches $PKGDB | $GREP -v "Patch: $PatchBase" | \
1476
				$GREP "Obsoletes:.*$PatchBase.*Packages:"
1477
			patch_quit 6 "no"
1478
			return 0
1479
		fi
1480
	fi
1481
 
1482
	currentdir=$(pwd)
1483
	#
1484
	# Now search for patches with the same patch base, but a greater
1485
	# than rev. If an equal to rev, set the isapplied global to "yes"
1486
	#
1487
	oldRevs=
1488
	cd $PKGDB
1489
	oldRevs=$($GREP "SUNW_PATCHID=$PatchBase" ./*/pkginfo 2>/dev/null | \
1490
	         $SED 's/^.*-\([0-9][0-9]\).*$/\1/' | sort -u)
1491
	if [[ "$oldRevs" != "" ]]
1492
	then
1493
		oldRevs=$(echo $oldRevs | sort -u)
1494
		for ii in $oldRevs X
1495
		do
1496
			if [[ "$ii" = "X" ]]
1497
			then
1498
				break;
1499
			fi
1500
			if [[ "$ii" = "$PatchVers" ]]
1501
			then
1502
				isapplied="yes"
1503
				continue
1504
			elif [[ "$ii" -gt "$PatchVers" ]]
1505
			then
1506
				print_obsolete_msg "$PatchBase-$ii"
1507
				patch_quit 6 "no"
1508
				return 0
1509
			fi
1510
		done
1511
	fi
1512
 
1513
	cd $currentdir
1514
	return 1
1515
}
1516
 
1517
# Description:
1518
#	Determine if the patch contains any symbolic links. If so, die with
1519
#	an error and a message to the user. I assume the patch will be tested
1520
#	at least once in-house before getting to a non-sun user, so an
1521
#	external user should NEVER see a symbolic link message.
1522
# Parameters:
1523
#	None
1524
# Globals Set:
1525
#	None.
1526
# Globals Used:
1527
#	patchdir
1528
#
1529
function check_for_symbolic_link
1530
{
1531
	$RM -f /tmp/symlink.$$ > /dev/null 2>&1
1532
	olddir=$(pwd)
1533
	cd $patchdir
1534
	for ii in * X
1535
	do
1536
		if [[ "$ii" = X ]]
1537
		then
1538
			break
1539
		fi
1540
		if [[ ! -d "$ii" ]]
1541
		then
1542
			continue
1543
		fi
1544
		#
1545
		# Comment out ignoring symbolic links for packages with no current
1546
		# instance. New packages will not be added using patchadd.
1547
		#
1548
		# $GREP -s "VERSION=.*PATCH=" $1/$2/$ii/pkginfo
1549
		# if [[ $? != 0 ]]; then
1550
		# 	continue
1551
		# fi
1552
		symlinks=
1553
		symlinks=$($SED -n '/^[^ 	]*[ 	]*s[ 	]/p' $1/$2/$ii/pkgmap)
1554
		if [[ "$symlinks" != "" ]]; then
1555
			/usr/bin/gettext "Symbolic link in package $ii.\n" >> /tmp/symlink.$$
1556
		fi
1557
	done
1558
	if [[ -s /tmp/symlink.$$ ]]
1559
	then
1560
		cat /tmp/symlink.$$
1561
		/usr/bin/gettext "Symbolic links cannot be part of a patch.\n"
1562
		patch_quit 13 "no"
1563
		return 0
1564
	fi
1565
	cd $olddir
1566
	return 1
1567
}
1568
 
1569
# Description:
1570
#	Find package instance of originally-installed package. Extract the
1571
#	PKGID, ARCH, and VERSION by scanning the pkginfo files of each patch
1572
#	package. Check to see if the packages that are being patched were 
1573
#	actually installed on the system in the first place.
1574
# Parameters:
1575
#	$1	- package database directory
1576
#	$2	- patch directory
1577
# Globals Set:
1578
#	pkglist
1579
#	is_a_root_pkg
1580
# Globals Used:
1581
#	pkglist
1582
 
1583
function check_pkgs_installed
1584
{
1585
	i=
1586
	j=
1587
	pkginst=
1588
	finalpkglist=
1589
	minver=
1590
	Pkgpatchver=
1591
	Pkgarch=
1592
	Pkginst=
1593
	Pkgabbrev=
1594
	Pkgver=
1595
	Pkgtype=
1596
	OrigPkgver=
1597
 
1598
	$TOUCH $LOGFILE
1599
 
1600
	# Search the installed pkginfo files for matches with the list 
1601
	# of packages to be patched.  The package names are listed in 
1602
	# global pkglist.  These names correspond to the package database 
1603
	# subdirectory names.
1604
	#
1605
	for i in $pkglist	# for each package in the patch
1606
	do
1607
		#
1608
		# Get the package abbreviation, architecture, version
1609
		# and target filesystem.
1610
		#
1611
		Pkginst=$(basename $i)
1612
		Pkgabbrev=$(pkgparam -f $i/pkginfo PKG)
1613
		Pkgarch=$(pkgparam -f $i/pkginfo ARCH)
1614
		Pkgpatchver=$(pkgparam -f $i/pkginfo VERSION)
1615
		Pkgtype=$(pkgparam -f $i/pkginfo SUNW_PKGTYPE)
1616
                echo "$Pkginst $Pkgabbrev $Pkgarch $Pkgpatchver $Pkgtype"
1617
		if [[ "$Pkgtype" = "root" && "$service_specified" = "y" ]]
1618
		then
1619
			is_a_root_pkg="yes"
1620
			continue
1621
		elif [[ "$Pkgtype" = "" ]]
1622
		then
1623
			Pkgtype="opt"
1624
		fi
1625
 
1626
		#
1627
		# First the easy test, see if there's a package by
1628
		# that name installed.
1629
		#
1630
                echo "  check if this exists $1/$Pkgabbrev"
1631
		if [ ! -d "$1/$Pkgabbrev" ] && [ ! -d $1/$Pkgabbrev.* ]
1632
		then
1633
			/usr/bin/gettext "Package not patched:\n" >> $LOGFILE
1634
			/usr/bin/gettext "PKG=$Pkginst\n" >> $LOGFILE
1635
			/usr/bin/gettext "Original package not installed.\n" >> $LOGFILE
1636
 
1637
			continue
1638
		fi
1639
 
1640
		#
1641
		# At this point, there's a package of that name
1642
		# installed. So now we have to look for the right
1643
		# architecture and version. This is pretty easy for a
1644
		# direct instance patch. For the progressive instance
1645
		# patch, there's a lot of munging around with the various
1646
		# installed versions.
1647
 
1648
		if [[ "$netImage" = "product" ]]
1649
		then
1650
			arg="-d"
1651
		else
1652
			arg="-R"
1653
		fi
1654
		if [[ "$PatchMethod" = "direct" ]]
1655
		then
1656
			if [[ $ROOTDIR = "/" ]]
1657
			then
1658
				pkginst=$(pkginfo -a $Pkgarch -v $Pkgpatchver $Pkgabbrev.\* 2>/dev/null | $NAWK ' { print $2 } ')
1659
			else
1660
				pkginst=$(pkginfo $arg $ROOTDIR -a $Pkgarch -v $Pkgpatchver $Pkgabbrev.\* 2>/dev/null | $NAWK ' { print $2 } ')
1661
			fi
1662
 
1663
                        echo "Patch method direct $pkginst "
1664
			if [[ -n $pkginst ]] 
1665
			then
1666
				finalpkglist="$finalpkglist $i,$pkginst"
1667
			else
1668
				/usr/bin/gettext "Package not patched:\n" >> $LOGFILE
1669
				/usr/bin/gettext "PKG=$Pkginst\n" >> $LOGFILE
1670
				/usr/bin/gettext "Original package not installed.\n" >> $LOGFILE
1671
 
1672
				continue
1673
			fi
1674
 
1675
		else
1676
                        echo "Patch method not direct $pkginst "
1677
			#
1678
			# Get the package version number.
1679
			#
1680
			Pkgver=$($SED -n \
1681
			   -e 's/^[ 	]*VERSION[ 	]*=[ 	]*\([^ 	]*\)[ 	]*$/\1/p' \
1682
			   -e 's/^[ 	]*VERSION[ 	]*=[ 	]*\([^ 	]*\),PATCH=.*$/\1/p' $i/pkginfo )
1683
			minver=$(expr $Pkgver : '\(.*\)\.0$')
1684
			while [ "$minver" != "" ]
1685
			do
1686
			        Pkgver=$minver
1687
			        minver=$(expr $Pkgver : '\(.*\)\.0$')
1688
			done
1689
 
1690
			for j in $1/$Pkgabbrev $1/$Pkgabbrev.* X
1691
			do
1692
				if [[ "$j" = "X" ]]
1693
				then
1694
					break
1695
				fi
1696
				if [[ ! -d $j ]]
1697
				then
1698
					continue;
1699
				fi
1700
				OrigPkgver=$($SED -n 's/^VERSION=\(.*\)$/\1/p' $j/pkginfo)
1701
				minver=$(expr $OrigPkgver : '\(.*\)\.0$')
1702
 
1703
				while [[ "$minver" != "" ]]
1704
				do
1705
					OrigPkgver=$minver
1706
					minver=$(expr $OrigPkgver : '\(.*\)\.0$')
1707
				done
1708
			    if $GREP -s "^PKG=$Pkgabbrev$" $j/pkginfo >/dev/null 2>&1 \
1709
				  && $GREP -s "^ARCH=$Pkgarch$" $j/pkginfo >/dev/null 2>&1 \
1710
				  && [ "$OrigPkgver" = "$Pkgver" ] ;
1711
				then
1712
					pkginst=$(basename $j)
1713
					finalpkglist="$finalpkglist $i,$pkginst"
1714
					break;
1715
				else
1716
					/usr/bin/gettext "Package not patched:\n" >> $LOGFILE
1717
					/usr/bin/gettext "PKG=$Pkgabbrev\n" >> $LOGFILE
1718
					/usr/bin/gettext "ARCH=$Pkgarch\n" >> $LOGFILE
1719
					/usr/bin/gettext "VERSION=$OrigPkgver\n" >> $LOGFILE
1720
					tmp=""
1721
					tmp=$($GREP "^ARCH=$Pkgarch$" $j/pkginfo 2>/dev/null)
1722
					if [[ "$tmp" = "" ]]
1723
					then
1724
						/usr/bin/gettext "Architecture mismatch.\n" >> $LOGFILE
1725
					fi
1726
					if  [[ "$OrigPkgver" != "$Pkgver" ]]
1727
					then
1728
						/usr/bin/gettext "Version mismatch.\n" >> $LOGFILE
1729
					fi
1730
					echo "" >> $LOGFILE
1731
				fi
1732
 
1733
			done
1734
		fi
1735
	done
1736
 
1737
	pkglist=$finalpkglist
1738
}
1739
 
1740
# Description:
1741
#	If validation is being done, and pkgchk reported ERRORs, bail out.
1742
#	If no validation is being done, keep a list of files that failed
1743
#	validation. If this patch needs to be backed out, don't do an installf
1744
#	on these files. Any files that failed validation before the patch was
1745
#	applied should still fail validation after the patch is backed out.
1746
#	This will be the .validation.errors file in the patch directory.
1747
# Parameters:
1748
#	$1	- validation status [ "yes" or "no" ]
1749
# Globals Used:
1750
#	PKGCOFILE
1751
#	VALERRFILE
1752
 
1753
function check_validation
1754
{
1755
	if [[ "$1" = "yes" && -s $PKGCOFILE ]]
1756
	then
1757
		if $GREP -s ERROR $PKGCOFILE >/dev/null 2>&1
1758
		then
1759
			/usr/bin/gettext "The following validation error was found:\n"
1760
			cat $PKGCOFILE
1761
			/usr/bin/gettext "\nSee the Install.info file for instructions regarding patch validation errors.\n"
1762
			patch_quit 10 "no"
1763
			return 0
1764
		fi
1765
 
1766
	fi
1767
	if [[ -s $VALWARNFILE ]]
1768
	then
1769
		$CP $VALWARNFILE $VALERRFILE
1770
	fi
1771
	return 1
1772
}
1773
 
1774
# Description:
1775
#	Create the remote file associated with the backout data
1776
# Parameters:
1777
#       $1      - patch database directory
1778
#       $2      - patch number
1779
# Globals Used:
1780
#	PATCH_UNDO_ARCHIVE
1781
 
1782
function create_remote_file
1783
{
1784
	cat > $1/$2/save/remote << EOF
1785
# Backout data stored remotely
1786
TYPE=filesystem
1787
FIND_AT=$PATCH_UNDO_ARCHIVE/$2/archive.cpio
1788
STATE=N/A
1789
EOF
1790
}
1791
 
1792
# Description:
1793
# 	Create a spooling area in the sadm/patch/<patchID> tree for files
1794
# 	which are being replaced by the patch. Store the validation error
1795
# 	file with it.
1796
# Parameters:
1797
#	$1	- patch database directory
1798
#	$2	- patch number
1799
# Globals Used:
1800
#	VALERRFILE
1801
 
1802
function create_archive_area
1803
{
1804
	if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]; then
1805
		/usr/bin/gettext "Creating patch archive area...\n"
1806
		$MD -p -m 750 $PATCH_UNDO_ARCHIVE/$2
1807
		chown -h -f -R root $PATCH_UNDO_ARCHIVE/$2
1808
		chgrp -h -f -R sys $PATCH_UNDO_ARCHIVE/$2
1809
 
1810
		$MD -p -m 750 $1/$2/save
1811
		chown -h -f -R root $1/$2
1812
		chgrp -h -f -R sys $1/$2
1813
		create_remote_file $1 $2
1814
	elif [[ ! -d $1/$2/save ]]
1815
	then
1816
		/usr/bin/gettext "Creating patch archive area...\n"
1817
		$MD -p -m 750 $1/$2/save
1818
		chown -h -f -R root $1/$2
1819
		chgrp -h -f -R sys $1/$2
1820
	fi
1821
	if [ -s $VALERRFILE ]
1822
	then
1823
		$CP $VALERRFILE $1/$2/.validation.errors
1824
	fi
1825
}
1826
 
1827
# Description:
1828
#	Scan the patch package maps for a list of affected files.
1829
# Parameters:
1830
#	$1	- package database directory
1831
#	$2	- package relocation argument
1832
#
1833
# Locals Used
1834
#	arg
1835
#
1836
# Globals Used:
1837
#	PKGCOFILE
1838
#	PATCHFILES
1839
#	pkglist
1840
#
1841
function gen_install_filelist
1842
{
1843
	if [[ "$DRYRUN" = "yes" ]]
1844
	then
1845
		return
1846
	fi
1847
 
1848
	pkgfiles=/tmp/pkgfiles.$$
1849
	resfiles=/tmp/resolvedfiles.$$
1850
	macrofiles=/tmp/pkgmacros.$$
1851
	pkginst=
1852
	pkginfofile=
1853
	patchpkg=
1854
	basedir=
1855
	i=
1856
	$RM -f $PATCHFILES
1857
	/usr/bin/gettext "Generating list of files to be patched...\n"
1858
	for i in $pkglist
1859
	do
1860
		patchpkg=`expr $i : '\(.*\),.*'`
1861
		pkginst=`expr $i : '.*,\(.*\)'`
1862
		if [[ $pkginst = "" ]]
1863
		then
1864
			continue
1865
		fi
1866
 
1867
		pkginfofile="$1/$pkginst/pkginfo"
1868
		pkgmapfile="$1/$pkginst/pkgmap"
1869
 
1870
		# Get the BASEDIR
1871
		basedir=$(pkgparam -f $pkginfofile BASEDIR)
1872
 
1873
		#
1874
		# Parse out the pkgmap files to get the file names.
1875
		# First, get rid of all checksum info. Then get rid
1876
		# of all info file entries. Replace all BASEDIR values
1877
		# with emptiness (BASEDIR will be prepended).  Delete
1878
		# all entries that are the BASEDIR without a file
1879
		# (directory entries).  Get the file name. If it's a
1880
		# symbolic link, keep the link, don't follow it to the
1881
		# file.
1882
		#
1883
		$SED -e '/^:/d' \
1884
		    -e '/^[^ ][^ ]* i/d' \
1885
		    -e 's, \$BASEDIR/, ,' \
1886
		    -e '/ \$BASEDIR /d' \
1887
		    -e 's/^[^ ]* . \([^ ]*\) \([^ ]*\).*$/\2 \1/' \
1888
		    -e 's/=.*//' $patchpkg/pkgmap > $pkgfiles
1889
		#
1890
		# Resolve any macros in the list of files before determining if
1891
		# the file is relocatable.
1892
		#
1893
		if [[ -s $pkgfiles ]]
1894
		then
1895
			# resolve any macros in the list of files
1896
			(	# different shell
1897
			$RM -f $macrofiles $resfiles
1898
 
1899
			# Extract every macro that may be meaningful
1900
			# and throw quotes around all of the values
1901
			# assigned.
1902
			$NAWK -F= '
1903
				$1 ~ /PATCHLIST/	{ next; }
1904
				$1 ~ /OBSOLETES/	{ next; }
1905
				$1 ~ /ACTIVE_PATCH/	{ next; }
1906
				$1 ~ /PATCH_INFO/	{ next; }
1907
				$1 ~ /UPDATE/		{ next; }
1908
				$1 ~ /SCRIPTS_DIR/	{ next; }
1909
				$1 ~ /PATCH_NO_UNDO/	{ next; }
1910
				$1 ~ /INSTDATE/		{ next; }
1911
				$1 ~ /PKGINST/		{ next; }
1912
				$1 ~ /OAMBASE/		{ next; }
1913
				$1 ~ /PATH/		{ next; }
1914
				{
1915
					printf("%s=\"%s\"\n", $1, $2);
1916
				} ' $pkginfofile > $macrofiles
1917
 
1918
			. $macrofiles
1919
			cat $pkgfiles |
1920
			while read i
1921
			do
1922
				eval /usr/bin/echo $i >> $resfiles
1923
			done
1924
			)	# back to original shell
1925
 
1926
			#
1927
			# Prepend the basedir to the file name if the file is
1928
			# relocatable, then add it to the pkgfile list. 
1929
			#
1930
			$MV $resfiles $pkgfiles
1931
 
1932
			# The following line is being called in its own shell
1933
			# do to on an x86 system a pkgmap file with ~230 lines
1934
			# causes some internal jsh limit to get exhausted.
1935
 
1936
			(cat $pkgfiles | parse_sizes $patchpkg)
1937
 
1938
 			$SED -e "s,^\([^/]\),$basedir/&," \
1939
 			    -e 's,\/\/,\/,g' $pkgfiles > $resfiles
1940
 
1941
			#
1942
			# If there are some files to patch in the package, see if 
1943
			# they have validation errors. Ignore any validation errors 
1944
			# for files having class action scripts. The remaining 
1945
			# validation errors will be put in a validation error file.
1946
			#
1947
			if [[ -s $resfiles && "$PatchType" != "diPatch" ]]
1948
			then
1949
				cat $resfiles |
1950
				while read j
1951
				do
1952
					jfile=$(echo $j | $SED 's/^\([^ ]*\).*/\1/')
1953
					class=$(echo $j | $SED 's/^[^ ]* \(.*\)/\1/')
1954
					badfile=
1955
					badfile=$(pkgchk $2 -p $jfile\
1956
						$patchpkg 2>&1 | \
1957
						$GREP "^ERROR:" | \
1958
						$SED -n 's/^ERROR:[ 	]*//p')
1959
					if [ "$badfile" != "" ]
1960
					then
1961
						if [ "$class" != "" -a "$class" != "preserve" -a ! -f $patchdir/$patchpkg/install/i.$class ]
1962
						then
1963
							pkgchk $2 -p $jfile\
1964
							$patchpkg >> $PKGCOFILE 2>&1
1965
						fi
1966
						echo $jfile >> $VALWARNFILE
1967
					fi
1968
				done
1969
			fi
1970
		 	$SED 's/^\([^ ]*\).*/\1/' $resfiles >> $PATCHFILES
1971
		fi
1972
	done
1973
}
1974
 
1975
# Description: 
1976
# 	Set flag in case of power outage.
1977
# Parameters: 
1978
# 
1979
# Globals Used:
1980
#	RECOVERDIR
1981
#	INTERUPTION
1982
#	PatchNum
1983
# 
1984
function file_recovery
1985
{ 
1986
	if [[ "$PatchMethod" = "direct" ]]
1987
	then
1988
		if [[ -d "$RECOVERDIR" ]]
1989
		then
1990
			INTERRUPTION="yes"
1991
		else
1992
			if [[ ! -d "$RECOVERDIR" ]]; then
1993
				$MD $RECOVERDIR 
1994
			fi
1995
			$TOUCH $RECOVERDIR/.$PatchNum
1996
			sync
1997
		fi
1998
	fi
1999
} 
2000
 
2001
# Description:
2002
#   Used in the file system space calculation.  Determine where each
2003
#   identified file will be placed, and add its size to the correct
2004
#   running total.
2005
# Parameters:
2006
#	$1	- patch package name
2007
# Globals Used:
2008
#	Openwin_Kbytes_Needed
2009
#	Usr_Kbytes_Needed
2010
#	Opt_Kbytes_Needed
2011
#	Var_Kbytes_Needed
2012
#	Root_Kbytes_Needed
2013
#
2014
function parse_sizes
2015
{
2016
	typeset -i size=0
2017
	typeset -i installedSize=0
2018
 
2019
	while read Filename junk
2020
	do
2021
		($GREP " $Filename " $1/pkgmap  |
2022
		while read part ftype f3 f4 f5 f6 f7 f8 Junk
2023
		do
2024
			case $ftype in
2025
				f|e|v)
2026
					$($VALPATH -a $f4)
2027
					ret=$?
2028
					if [[ "$ret" != 0 ]]
2029
					then
2030
						# Prepend the basedir to
2031
						# the relocatable objects
2032
						if [[ "$basedir" = "/" ]]
2033
						then
2034
							pathname="$basedir$f4"
2035
						else
2036
							pathname="$basedir/$f4"
2037
						fi
2038
					else
2039
						pathname=$f4
2040
					fi
2041
 
2042
					# Calculate the difference from the
2043
					# installing object with the object
2044
					# that is already installed.
2045
					if [[ "$ROOTDIR" != "/" ]]
2046
					then
2047
						# Prepend the root path to the installed object
2048
						tmpPath="$ROOTDIR$pathname"
2049
					else
2050
						tmpPath="$pathname"
2051
					fi
2052
 
2053
					if [[ -f "$tmpPath" ]]
2054
					then
2055
						installedSize=$($WC -c $tmpPath | $NAWK ' \
2056
						  { print $1 } ')
2057
						size=$f8
2058
						size=size-installedSize
2059
						if (( size < 0 ))
2060
						then
2061
							size=0
2062
						fi
2063
					else
2064
						size=$f8
2065
					fi
2066
 
2067
					case $pathname in
2068
						usr\/openwin\/*|\/usr\/openwin\/*|openwin\/*|\/openwin\/*)
2069
							Openwin_Kbytes_Needed=Openwin_Kbytes_Needed+size ;;
2070
						usr\/*|\/usr\/*)
2071
							Usr_Kbytes_Needed=Usr_Kbytes_Needed+size ;;
2072
						var\/*|\/var\/*)
2073
							Var_Kbytes_Needed=Var_Kbytes_Needed+size ;;
2074
						opt\/*|\/opt\/*)
2075
							Opt_Kbytes_Needed=Opt_Kbytes_Needed+size ;;
2076
						*)
2077
							Root_Kbytes_Needed=Root_Kbytes_Needed+size ;;
2078
					esac
2079
					;;
2080
				i)
2081
					size=$f4
2082
					Var_Kbytes_Needed=Var_Kbytes_Needed+size
2083
					;;
2084
				d|l|s|p|b|c|x)
2085
					$($VALPATH -a $f4)
2086
					ret=$?
2087
					if [[ "$ret" != 0 ]]
2088
					then
2089
						# Prepend the basedir to
2090
						# the relocatable objects
2091
						if [[ "$basedir" = "/" ]]
2092
						then
2093
							pathname="$basedir$f4"
2094
						else
2095
							pathname="$basedir/$f4"
2096
						fi
2097
					else
2098
						pathname=$f4
2099
					fi
2100
 
2101
					case $pathname in
2102
						usr\/openwin\/*|\/usr\/openwin\/*|openwin\/*|\/openwin\/*)
2103
							Openwin_Kbytes_Needed=Openwin_Kbytes_Needed+512 ;;
2104
						usr\/*|\/usr\/*)
2105
							Usr_Kbytes_Needed=Usr_Kbytes_Needed+512 ;;
2106
						var\/*|\/var\/*)
2107
							Var_Kbytes_Needed=Var_Kbytes_Needed+512 ;;
2108
						opt\/*|\/opt\/*)
2109
							Opt_Kbytes_Needed=Opt_Kbytes_Needed+512 ;;
2110
						*)
2111
							Root_Kbytes_Needed=Root_Kbytes_Needed+512 ;;
2112
					esac
2113
					;;
2114
				*)
2115
					;;
2116
			esac
2117
		done)
2118
	done
2119
}
2120
 
2121
# Description:
2122
#	Generate a list of files which are "to be patched." Determine their
2123
#	total size in bytes to figure out the space requirements of backing
2124
#	them up.
2125
# Parameters:
2126
#	none
2127
# Globals Used:
2128
#	PATCHFILES
2129
#	EXISTFILES
2130
#
2131
function gen_patch_filelist
2132
{
2133
	typeset -i tmp_total=0
2134
	typeset -i kbytes_total=0
2135
	typeset -i kb=0
2136
	size=
2137
 
2138
	if [[ "$DRYRUN" = "yes"  || "$PATCH_NO_UNDO" = "true" ]]
2139
	then
2140
		return
2141
	fi
2142
 
2143
	if [[ -s $PATCHFILES ]]
2144
	then
2145
		cat $PATCHFILES |
2146
		while read j
2147
		do
2148
			if $LS -d $ROOTDIR$j >/dev/null 2>&1
2149
			then
2150
				echo "."$j >> $EXISTFILES
2151
				size=$($LS -Ldl $ROOTDIR$j)
2152
				size=$(echo $size | $NAWK ' { print $5 } ')
2153
#				size=$($WC -c $ROOTDIR$j)
2154
#				size=$(echo $size | $SED 's/\ .*//')
2155
				if [ "$size" != "" ]
2156
				then
2157
					tmp_total=tmp_total+$size
2158
				fi
2159
				if (( tmp_total >= 1024 ))
2160
				then
2161
					kb=tmp_total/1024
2162
					tmp_total=tmp_total-kb*1024
2163
					kbytes_total=kbytes_total+kb
2164
				fi
2165
#break
2166
			fi
2167
		done;
2168
		if (( tmp_total > 0 ))
2169
		then
2170
			kbytes_total=kbytes_total+1
2171
		fi
2172
		Kbytes_Required=kbytes_total
2173
	else
2174
		$RM -f $EXISTFILES
2175
	fi
2176
}
2177
 
2178
# Description:
2179
# 	Assemble a list of the patch package IDs contained in the patch
2180
#	(at least one directory with a pkginfo file must exist due to checks
2181
#	in activate_patch)
2182
# Parameters:
2183
#	none
2184
# Globals Set:
2185
#	pkglist
2186
#
2187
function gen_patchpkg_list
2188
{
2189
	pkg=
2190
	for i in */pkginfo X
2191
	do
2192
		if [ "$i" = "X" ]
2193
		then
2194
			break
2195
		fi
2196
 
2197
		pkg=`expr $i : '\(.*\)/pkginfo'`
2198
		pkglist="$pkglist $pkg"
2199
	done
2200
}
2201
 
2202
# Description:
2203
#	Get the product version <name>_<version> of local Solaris installation
2204
# Parameters:
2205
#	$1	target host softinfo directory path
2206
#	$2	managing host softinfo directory path
2207
#	$3	root of the target host
2208
# Globals Set:
2209
#	prodver
2210
#
2211
function get_OS_version 
2212
{
2213
	# If this a patch to a net install image we don't care about 
2214
	# the managing and target host we know it will be a 2.6 or 
2215
	# beyond OS.
2216
	if [[ "$netImage" = "boot" ]]
2217
	then
2218
        MgrProduct="Solaris"
2219
        MgrOSVers=$(uname -r | $SED -n -e 's/5\./2\./p' -e 's/4\./1\./p')
2220
		if [[ "$MgrOSVers" < "2.6" ]]
2221
		then
2222
			/usr/bin/gettext "This system must be running Solaris 2.6 or later\nin order to install a patch to a Net Install Image."
2223
			patch_quit 1 "yes"
2224
		fi
2225
        Mgrprodver=$MgrProduct"_"$MgrOSVers	
2226
        TrgOSVers=$MgrOSVers
2227
        Product=$MgrProduct
2228
        prodver=$Mgrprodver
2229
		return
2230
	fi
2231
 
2232
	if [[ "$2" != "none" ]]
2233
	then
2234
		MgrProduct=$($SED -n 's/^OS=\(.*\)/\1/p' $2)
2235
		MgrOSVers=$($SED -n 's/^VERSION=\(.*\)/\1/p' $2)
2236
		Mgrprodver=$MgrProduct"_"$MgrOSVers
2237
	else
2238
		MgrProduct="Solaris"
2239
		MgrOSVers=$(uname -r | $SED -n -e 's/5\./2\./p' -e 's/4\./1\./p')
2240
		Mgrprodver=$MgrProduct"_"$MgrOSVers
2241
	fi
2242
 
2243
	if [[ $3 = "/" ]]	# If there's not a client
2244
	then
2245
		Product=$MgrProduct
2246
		TrgOSVers=$MgrOSVers
2247
		prodver=$Mgrprodver
2248
 
2249
	# OK, there is a client
2250
	elif [[ "$1" = "none" ]]	# but no softinfo file
2251
	then
2252
		/usr/bin/gettext "patchadd is unable to find the INST_RELEASE file for the target filesystem.\nThis file must be present for patchadd to function correctly.\n"
2253
		patch_quit 11 "yes"
2254
	else
2255
		Product=$($SED -n 's/^OS=\(.*\)/\1/p' $1)
2256
		TrgOSVers=$($SED -n 's/^VERSION=\(.*\)/\1/p' $1)
2257
		prodver=$Product"_"$TrgOSVers
2258
	fi
2259
}
2260
 
2261
# Description:
2262
# 	Actually install patch packages which apply to the system
2263
# Parameters:
2264
#	$1	- patch database directory
2265
#	$2	- patch number
2266
#	$3	- patch directory
2267
#	$4	- package add relocation argument
2268
#	$5	- package database directory
2269
# Globals Used:
2270
#	ADMINTFILE
2271
#	ADMINFILE
2272
#	pkglist
2273
#
2274
function install_patch_pkgs
2275
{
2276
	typeset -i pkgadderr=0
2277
	typeset -i real_pkgadderr_2=0
2278
 
2279
	i=
2280
	ij=
2281
	pkginst=
2282
	pkginfofile=
2283
	patchpkg=
2284
	basedir=
2285
	pkgDispList=""
2286
	#
2287
	#	Write out the contents of the logfile if there were any
2288
	#	messages. Do this now, because the $1/$2 directory may not
2289
	#	exist before this point.
2290
	#
2291
	if [ -f $LOGFILE ]
2292
	then
2293
		cat $LOGFILE >> $1/$2/log
2294
		$RM -f $LOGFILE
2295
	fi
2296
 
2297
	move_libraries
2298
 
2299
	/usr/bin/gettext "Installing patch packages...\n"
2300
	for ij in $pkglist
2301
	do
2302
		i=`expr $ij : '\(.*\),.*'`
2303
		pkginst=`expr $ij : '.*,\(.*\)'`
2304
 
2305
		pkginfofile="$5/$pkginst/pkginfo"
2306
 
2307
		basedir=$($GREP '^BASEDIR' $pkginfofile | $SED -e 's@.*=\ *@@' -e 's@/a/@/@' -e 's@/a$@/@')
2308
		if [ ! -d $1/$2/$i ]
2309
		then
2310
			$MD -m 750 $1/$2/$i
2311
		fi
2312
		$CP $i/pkgmap $1/$2/$i/pkgmap
2313
		$CP $i/pkginfo $1/$2/$i/pkginfo
2314
 		$CP $ADMINTFILE $ADMINFILE
2315
		echo basedir=$basedir >>$ADMINFILE
2316
 
2317
		/usr/bin/gettext "\nDoing pkgadd of $i package:\n"
2318
 
2319
		if [[ $PatchType = "caPatch" ]]
2320
		then
2321
			$CP $RESPONSE_FILE $RESPONSE_FILE.1
2322
			pkgadd $4 -S -a $ADMINFILE -r $RESPONSE_FILE.1 -n -d $3 $i >>$LOGFILE </dev/null 2>&1
2323
		else
2324
			pkgadd $4 -S -a $ADMINFILE -n -d $3 $i >>$LOGFILE </dev/null 2>&1
2325
		fi
2326
		pkgadderr=$?
2327
		exit_code=$pkgadderr
2328
 
2329
		if [[ $PatchType = "caPatch" ]]
2330
		then
2331
			$RM -f $RESPONSE_FILE.1
2332
		fi
2333
 
2334
		real_pkgadderr_2=0
2335
		if (( pkgadderr == 2 ))
2336
		then
2337
			if $GREP '^ERROR' $LOGFILE >/dev/null 2>&1
2338
			then
2339
				real_pkgadderr_2=1
2340
			fi
2341
		fi
2342
 
2343
		# reboot after installation of all packages
2344
		if (( pkgadderr == 10  || pkgadderr == 20 ))
2345
		then
2346
			/usr/bin/gettext "Reboot after patchadd has installed the patch.\n"
2347
		fi
2348
 
2349
		cat $LOGFILE >> $1/$2/log
2350
		cat $LOGFILE | $GREP -v "^$"
2351
		$RM -f $LOGFILE
2352
		if (( pkgadderr != 0 && real_pkgadderr_2 != 0 && \
2353
		      pkgadderr != 10 && pkgadderr != 20 ))
2354
		then
2355
			/usr/bin/gettext "Pkgadd of $i package failed with error code $pkgadderr.\n" |tee -a $1/$2/log
2356
			if [ "$isapplied" = "no" ]
2357
			then
2358
				/usr/bin/gettext "See /tmp/log.$2 for reason for failure.\n"
2359
				$CP $1/$2/log /tmp/log.$2
2360
				/usr/bin/gettext "Backing out patch:\n"
2361
				cd $3
2362
				if [ "$ROOTDIR" != "/" ]
2363
				then
2364
					/usr/sbin/patchrm $PKGDBARG $2
2365
				else
2366
					/usr/sbin/patchrm $2
2367
				fi
2368
			else
2369
				/usr/bin/gettext "See $1/$2/log for reason for failure.\nWill not backout patch...patch re-installation.\nWarning: The system may be in an unstable state!\n"
2370
			fi
2371
			patch_quit 5 "no"
2372
			return 0
2373
		fi
2374
		pkgDispList="$pkgDispList $i"
2375
 
2376
	done
2377
	remove_libraries
2378
	return 1
2379
}
2380
 
2381
# Description:
2382
#	Make internal variables available to child processes
2383
#   of patchadd.  This is done by writing them to a
2384
#   file and by exporting them.
2385
# Parameters:
2386
#	none
2387
# Environment Variables Set:
2388
#	none
2389
#
2390
function make_params_available
2391
{
2392
	echo "saveold=$saveold" > $PARAMS_FILE
2393
	echo "validate=$validate" >> $PARAMS_FILE
2394
	echo "patchdir=$patchdir" >> $PARAMS_FILE
2395
	echo "patchnum=$PatchNum" >> $PARAMS_FILE
2396
	echo "patchbase=$PatchBase" >> $PARAMS_FILE
2397
	echo "patchrev=$PatchVers" >> $PARAMS_FILE
2398
	echo "ROOTDIR=$ROOTDIR" >> $PARAMS_FILE
2399
	echo "PATCHDB=$PATCHDB" >> $PARAMS_FILE
2400
	echo "PKGDB=$PKGDB" >> $PARAMS_FILE
2401
	echo "PKGDBARG=$PKGDBARG" >> $PARAMS_FILE
2402
	echo "PATCHMETHOD=PatchMethod" >> $PARAMS_FILE
2403
	echo "UNINST_REQS=\"$UninstReqs\"" >> $PARAMS_FILE
2404
	echo "PATCH_UNDO_ARCHIVE=$PATCH_UNDO_ARCHIVE" >> $PARAMS_FILE
2405
	echo "PATCH_BUILD_DIR=$PATCH_BUILD_DIR" >> $PARAMS_FILE
2406
	echo "INTERRUPTION=$INTERRUPTION" >> $PARAMS_FILE
2407
 
2408
	echo "INSTALL_PATCHDIR=$INSTALL_PATCHDIR" >> $PARAMS_FILE
2409
 
2410
	export saveold validate patchdir PatchNum PatchBase PatchVers
2411
	export PARAMS_FILE ROOTDIR PATCHDB PKGDB PKGDBARG
2412
}
2413
 
2414
# Description:
2415
#	Copy required libraries to TMP_LIB_DIR, set and
2416
#	export LD_PRELOAD.
2417
# Parameters:
2418
#	none
2419
# Environment Variables Set:
2420
#	LD_PRELOAD
2421
#
2422
function move_libraries
2423
{
2424
	typeset -i Rev=0
2425
 
2426
	Rev=$(echo $TrgOSVers | $SED -e 's/[0-9]\.//' -e 's/_.*$//')
2427
	if (( Rev >= 5 ))
2428
	then
2429
		if [ ! -d $TMP_LIB_DIR ]
2430
		then
2431
			$MD -p -m755 $TMP_LIB_DIR
2432
		fi
2433
 
2434
		LD_PRELOAD=
2435
		for Lib in libc libdl libelf libintl libw libgen libadm
2436
		do
2437
			if [[ ! -f /usr/lib/${Lib}.so.1 ]]; then
2438
				continue
2439
			fi
2440
 
2441
			$CP /usr/lib/${Lib}.so.1 ${TMP_LIB_DIR}/${Lib}.so.1
2442
 
2443
			chown bin ${TMP_LIB_DIR}/${Lib}.so.1
2444
			chgrp bin ${TMP_LIB_DIR}/${Lib}.so.1
2445
			chmod 755 ${TMP_LIB_DIR}/${Lib}.so.1
2446
 
2447
			LD_PRELOAD="${LD_PRELOAD} ${TMP_LIB_DIR}/${Lib}.so.1"
2448
		done
2449
		export LD_PRELOAD
2450
		libs_are_moved="yes"
2451
	fi
2452
}
2453
 
2454
 
2455
# Description:
2456
#	Find the appropriate softinfo files for the manager and the target.
2457
# Parameters:
2458
#	$1	ROOT of target filesystem
2459
# Globals set:
2460
#	TRGSOFTINFO
2461
#	MGRSOFTINFO
2462
# Globals used:
2463
#	OLD_SOFTINFO
2464
#	NEW_SOFTINFO
2465
function find_softinfos
2466
{
2467
	if [[ "$netImage" = "boot" || "$netImage" = "product" ]]
2468
	then
2469
		return
2470
	fi
2471
 
2472
	if [[ -f $NEW_SOFTINFO ]]
2473
	then
2474
		MGRSOFTINFO=$NEW_SOFTINFO
2475
	elif [[ -f $OLD_SOFTINFO ]]
2476
	then
2477
		MGRSOFTINFO=$OLD_SOFTINFO
2478
	fi
2479
 
2480
	if [[ "$1" = "/" || "$1" = "" ]]
2481
	then
2482
		TRGSOFTINFO=$MGRSOFTINFO
2483
	elif [[ -f $1$NEW_SOFTINFO ]]
2484
	then
2485
		TRGSOFTINFO=$1$NEW_SOFTINFO
2486
	elif [[ -f $1$OLD_SOFTINFO ]]
2487
	then
2488
		TRGSOFTINFO=$1$OLD_SOFTINFO
2489
	fi
2490
 
2491
}
2492
 
2493
# Description:
2494
#   Check the host system for 2.6 existence.
2495
#
2496
function check_for_2_6
2497
{
2498
	# Only the managing hosts OS is checked for now
2499
	# 9/21/96
2500
 
2501
	mgrOS=
2502
	mgrOS=$($UNAME -r)
2503
 
2504
	if [[ "$mgrOS" < "5.6" ]]
2505
	then
2506
		/usr/bin/gettext "WARNING: patchadd must be executed from a 2.6 or later system.\n\n"
2507
		exit 32
2508
	fi
2509
}
2510
 
2511
# Description:
2512
# 	Parse the arguments and set all affected global variables
2513
# Parameters:
2514
#	Argument list passed into patchadd 
2515
# Globals Set:
2516
#	validate
2517
#	saveold
2518
#	force
2519
#	printpatches
2520
#	patchdir
2521
#	ROOTDIR
2522
#	PATCHDB
2523
#	PKGDB
2524
#	PKGDBARG
2525
# Globals Used:
2526
#	Mgrprodver
2527
#	MGRSOFTINO
2528
#	TRGSOFTINFO
2529
#	PKGDB
2530
#	PATCHDB
2531
#
2532
function parse_args
2533
{
2534
	# Inserted for readability reasons
2535
	echo ""
2536
	service_specified="n"
2537
	rootdir_specified="n"
2538
	orig_dir=$(pwd)
2539
	while [ "$1" != "" ]
2540
	do
2541
		case $1 in
2542
		-i) interactive=1; shift ;;
2543
		-u) validate="no"; PATCH_UNCONDITIONAL="true"; shift;;
2544
		-d)	saveold="no"; PATCH_NO_UNDO="true";
2545
			if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
2546
			then
2547
				/usr/bin/gettext "The -d option and the -B option are mutually exclusive.\n"
2548
				patch_quit 1 "yes"
2549
			fi	
2550
			shift ;;
2551
		-B)	shift
2552
			if [[ "$PATCH_NO_UNDO" = "true" ]]
2553
			then
2554
				/usr/bin/gettext "The -d option and the -B option are mutually exclusive.\n"
2555
				patch_quit 1 "yes"
2556
			fi
2557
			if [[ -d $1 ]]
2558
			then
2559
				determine_directory $1
2560
				if [[ $ret = 0 ]]
2561
				then
2562
					PATCH_BUILD_DIR=$1
2563
					PATCH_UNDO_ARCHIVE=$1
2564
				else
2565
					PATCH_BUILD_DIR=$curdir
2566
					PATCH_UNDO_ARCHIVE=$curdir
2567
				fi
2568
			else
2569
				/usr/bin/gettext "Specified backout directory $1 cannot be found.\n"
2570
				patch_quit 26 "yes"
2571
			fi
2572
			shift;;
2573
		-p)	printpatches="yes"; shift;;
2574
		-S)	shift
2575
			if [ "$rootdir_specified" = "y" ]
2576
			then
2577
				/usr/bin/gettext "The -S and -R arguments are mutually exclusive.\n"
2578
				print_usage
2579
				patch_quit 1 "yes"
2580
			fi
2581
 
2582
			find_softinfos /export/$1
2583
 
2584
			get_OS_version "$TRGSOFTINFO" "$MGRSOFTINFO" "$1"
2585
 
2586
			if [ "$1" != "$Mgrprodver" ]
2587
			then
2588
				if [ -d "/export/$1$PKGDB" ]
2589
				then
2590
					ROOTDIR=/export/$1
2591
					PATCHDB=$ROOTDIR$PATCHDB
2592
					PKGDB=$ROOTDIR$PKGDB
2593
					PKGDBARG="-R $ROOTDIR"
2594
				else
2595
					/usr/bin/gettext "The $1 service cannot be found on this system.\n"
2596
					print_usage
2597
					patch_quit 1 "yes"
2598
				fi
2599
			fi
2600
                        service_specified="y"
2601
			shift;;
2602
		-V) echo "@(#) patchadd.ksh 2.5 99/04/06"
2603
			patch_quit 0 "yes";;
2604
		-R)	shift
2605
			if [ "$service_specified" = "y" ]
2606
			then
2607
				/usr/bin/gettext "The -S and -R arguments are mutually exclusive.\n"
2608
				print_usage
2609
				patch_quit 1 "yes"
2610
			fi
2611
			if [ ! -d "$1" ]
2612
			then
2613
				/usr/bin/gettext "The Package Install Root directory $1 cannot be found on this system.\n"
2614
				print_usage
2615
				patch_quit 1 "yes"
2616
			else
2617
				determine_directory $1
2618
				if [[ $ret = 0 ]]
2619
				then
2620
					ROOTDIR=$1
2621
				else
2622
					ROOTDIR=$curdir
2623
				fi
2624
				PATCHDB=$ROOTDIR$PATCHDB
2625
				PKGDB=$ROOTDIR$PKGDB
2626
				PKGDBARG="-R $ROOTDIR"
2627
				rootdir_specified="y"
2628
			fi
2629
			shift;;
2630
        -M) shift
2631
			if [ ! -d "$1" ]
2632
			then
2633
				/usr/bin/gettext "The patch directory $1 cannot be found on this system.\n"
2634
				print_usage
2635
				patch_quit 1 "yes"
2636
			else
2637
				determine_directory $1
2638
                if [[ $ret = 0 ]]
2639
                then
2640
                    multiPtchDir=$1
2641
                else
2642
                    multiPtchDir=$curdir
2643
                fi
2644
				multiPtchInstall="yes"
2645
			fi
2646
			shift;;
2647
        -C) shift
2648
            if [[ "$service_specified" = "y" || "$rootdir_specified" = "y" ]]
2649
            then
2650
                /usr/bin/gettext "The -S, -R and -C arguments are mutually exclusive.\n"
2651
                print_usage
2652
                patch_quit 1 "yes"
2653
            fi 
2654
            if [ ! -d "$1" ]
2655
            then
2656
                /usr/bin/gettext "The path to the net install image $1 cannot be found.\n" 
2657
                print_usage
2658
                patch_quit 1 "yes"
2659
            else
2660
				determine_Product_Boot $1
2661
                determine_directory $1
2662
                if [[ $ret = 0 ]]
2663
                then
2664
                    ROOTDIR=$1
2665
                else
2666
                    ROOTDIR=$curdir
2667
                fi
2668
                PATCHDB=$ROOTDIR$PATCHDB
2669
                PKGDB=$ROOTDIR$PKGDB
2670
                PKGDBARG="-C $ROOTDIR"
2671
				PatchMethod="direct"
2672
            fi
2673
            shift;;
2674
 
2675
		-*)	print_usage; patch_quit 1 "yes";;
2676
		 *)	if [[ "$multiPtchInstall" = "yes" ]]
2677
			then
2678
				if [[ -d "$multiPtchDir/$1" ]]
2679
				then
2680
					multiPtchList="$multiPtchList $1"
2681
					lastPtchInList=$1
2682
				elif [[ -f "$multiPtchDir/$1" ]]
2683
				then
2684
					process_multi_patch_file "$multiPtchDir/$1"
2685
					multiPtchList=$($NAWK ' { print $1 } ' $multiPtchDir/$1)
2686
					lastPtchInList=$($TAIL -1 $multiPtchDir/$1)
2687
				else
2688
					/usr/bin/gettext "The patch or patch_list $1 cannot be found in\n$multiPtchDir.\n"
2689
					patch_quit 33 "yes"
2690
				fi
2691
			else
2692
				break
2693
			fi
2694
			shift;;
2695
		esac
2696
	done
2697
 
2698
	PATCHDBFILE=$ROOTDIR/var/sadm/patch/.patchDB
2699
 
2700
	if [[ "$printpatches" = "yes" ]]
2701
	then
2702
		check_PatchDBs
2703
		eval_inst_patches $PKGDB
2704
		if [[ -f "$INSTPATCHES_FILE" ]]; then
2705
			$RM -f $INSTPATCHES_FILE
2706
		fi
2707
		exit 0
2708
	fi
2709
	if [[ "$1" = "" && "$multiPtchInstall" = "no" ]]
2710
	then
2711
		/usr/bin/gettext "No patch directory specified.\n"
2712
		print_usage
2713
		patch_quit 1 "yes"
2714
	fi
2715
	if [[ ! -d "$1" && "$multiPtchInstall" = "no" ]]
2716
	then
2717
		/usr/bin/gettext "Patch directory $1 does not exist.\n"
2718
		print_usage
2719
		patch_quit 1 "yes"
2720
	fi
2721
	if [[ "$multiPtchInstall" = "no" ]]
2722
	then
2723
		determine_directory $1
2724
		if [[ $ret = 0 ]]
2725
		then
2726
			patchdir=$1
2727
		else
2728
			patchdir=$curdir
2729
		fi
2730
		multiPtchList=$(basename $patchdir)
2731
	fi
2732
	RECOVERDIR=$ROOTDIR/var/sadm/.patchRec
2733
        INSTALL_PATCHDIR=$patchdir
2734
}
2735
 
2736
# Description:
2737
#   Determine if this patch is being applied to the net install
2738
#   images boot or product area.
2739
# Parameters:
2740
#   $1 - The file containing the patches to install.
2741
# Locals Used:
2742
#   file_errors
2743
 
2744
function process_multi_patch_file
2745
{
2746
	file_errors=
2747
 
2748
	file_errors=$($NAWK ' { print $2 } ' $1)
2749
	if [[ -n $file_errors ]]
2750
	then
2751
		/usr/bin/gettext "Only one patch per line is allowed in the file\n$1.\n"
2752
		patch_quit 33 "yes"
2753
	fi
2754
}
2755
 
2756
# Description:
2757
#	Determine if this patch is being applied to the net install
2758
#	images boot or product area. 
2759
# Parameters:
2760
#   $1 - command line argument
2761
# Locals Used:
2762
#	result	
2763
# Globals Used:
2764
#	netImage
2765
 
2766
function determine_Product_Boot
2767
{
2768
	result=$(basename $1)
2769
	if [[ "$result" = "Boot" ]]
2770
	then
2771
		if [[ -d $1/.tmp_proto ]]
2772
		then
2773
			netImage="boot"
2774
		else
2775
			/usr/bin/gettext "Although this appears to be a valid Net Install Image,\nit doesn't have the neccessary directories."
2776
			patch_quit 31 "yes"
2777
		fi
2778
	elif [[ "$result" = "Product" ]]
2779
	then
2780
		netImage="product"
2781
	else
2782
		/usr/bin/gettext "Argument to the -C command line option is not a valid net install image path."
2783
		patch_quit 31 "yes"
2784
	fi
2785
}
2786
 
2787
# Description:
2788
# 	Derive the full path name from a (possibly) relative path name.
2789
# Parameters:
2790
#	$1      - command line argument
2791
#
2792
# Globals Used:
2793
#	olddir
2794
#	patchdir  
2795
#	ret
2796
 
2797
function determine_directory
2798
{
2799
	$($VALPATH -a $1)
2800
	ret=$?
2801
	if [[ $ret != 0 ]]
2802
	then
2803
		cd $1 3>/dev/null
2804
		if [[ $? = 0 ]]
2805
		then
2806
			curdir=$(pwd)
2807
			cd $orig_dir
2808
		else
2809
			/usr/bin/gettext "Can not determine relative directory.\n"
2810
			patch_quit 27 "yes"
2811
		fi
2812
	else 
2813
		return
2814
	fi
2815
}
2816
 
2817
# Description:
2818
#	Print the patch obsolecensce message
2819
# Parameters:
2820
#	$1	- number of patch which obsoleted this patch
2821
#
2822
function print_obsolete_msg
2823
{
2824
	if [[ $1 = "none" ]]
2825
	then
2826
		/usr/bin/gettext "This patch is obsoleted by the following which has already\nbeen applied to this system.\n"
2827
	else
2828
		/usr/bin/gettext "This patch is obsoleted by patch $1 which has already\nbeen applied to this system.\n"
2829
	fi
2830
}
2831
 
2832
# Description:
2833
#	Print the list of patch packages which were applied, and those
2834
#	which were not.
2835
# Parameters:
2836
#	none
2837
# Globals Used:
2838
#	pkglist
2839
#
2840
function print_results
2841
{
2842
	i=
2843
	p=
2844
	/usr/bin/gettext "\nPatch packages installed:\n"
2845
	if [[ -n "$pkgDispList" ]]
2846
	then
2847
		if [[ "$exit_code" = 0 || "$exit_code" = 20 || \
2848
		  "$exit_code" = 10 ]]
2849
		then
2850
			for i in $pkgDispList
2851
			do
2852
				echo "  ${i%,*}"
2853
			done
2854
		fi
2855
	else
2856
		/usr/bin/gettext "      none\n\n"
2857
	fi
2858
	echo ""
2859
}
2860
 
2861
# Description:
2862
#	remove the TMP_LIB_DIR directory
2863
# Parameters:
2864
#	none
2865
# Environment Variables Set:
2866
#	LD_PRELOAD
2867
#
2868
function remove_libraries
2869
{
2870
	LD_PRELOAD=
2871
	export LD_PRELOAD
2872
	$RM -rf $TMP_LIB_DIR
2873
	libs_are_moved="no"
2874
}
2875
 
2876
# Description:
2877
#	Check space requirements for the backout
2878
#	data for both direct instance and progressive instance patches.
2879
# Parameters:
2880
#	$1      - database directory (PKGDB or PATCHDB)
2881
#	$2      - patch number
2882
#	$3      - patch directory
2883
#	$4      - save old files [ "yes" or "no" ]
2884
# Environment Variables Set:
2885
#
2886
function check_backout_space
2887
{
2888
	typeset -i kbytes_avail=0
2889
	typeset -i buffer=10
2890
 
2891
	if [[ "$DRYRUN" = "yes" || "$PATCH_NO_UNDO" = "true" ]]
2892
	then
2893
		return 1
2894
	elif [[ ! -s $EXISTFILES && $1 = "$PATCHDB" ]]
2895
	then
2896
		$TOUCH $1/$2/.nofilestosave
2897
	elif [[ $4 = "yes" ]]
2898
	then
2899
		if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
2900
		then
2901
			backout_dir=$PATCH_UNDO_ARCHIVE
2902
		elif [[ "$netImage" = "boot" ]]
2903
		then
2904
			backout_dir=$ROOTDIR
2905
		else
2906
			backout_dir=$1
2907
		fi	
2908
 
2909
		# Is there enough space? Use sed to extract the fourth field of
2910
		# df output (can't use awk because it may not be installed).
2911
 
2912
		kbytes_avail=$($DF -b $backout_dir | tail -1 | \
2913
		$SED 's/^[^   ]*[     ]*\([^  ]*\).*/\1/')
2914
 
2915
		# To build and compress the backout packages in the archive directory
2916
		# takes about 3x as much space then there really needs to be
2917
		# to save just the archive.
2918
		Kbytes_Required=Kbytes_Required*3+buffer
2919
		if (( Kbytes_Required > kbytes_avail ))
2920
		then
2921
			/usr/bin/gettext "Insufficient space in $backout_dir to save old files.\nSpace required in kilobytes:  $Kbytes_Required\nSpace available in kilobytes:  $kbytes_avail\n"
2922
			if [ "$isapplied" = no ]
2923
			then
2924
				cd $3
2925
				if [ "$ROOTDIR" != "/" ]
2926
				then
2927
					/usr/sbin/patchrm $PKGDBARG $2
2928
				else
2929
					/usr/sbin/patchrm $2
2930
				fi
2931
					$RM -fr $backout_dir/$2
2932
			fi
2933
			patch_quit 4 "no"
2934
			return 0
2935
		fi
2936
	fi
2937
	return 1
2938
}
2939
 
2940
# Description:
2941
# 	Archive files which will be overwritten by the patch application,
2942
#	if the patch actually affects any existing files.
2943
# Parameters:
2944
#	$1	- patch database directory
2945
#	$2	- patch number
2946
#	$3	- patch directory
2947
#	$4	- save old files [ "yes" or "no" ]
2948
# Globals Used:
2949
#	EXISTFILES
2950
#
2951
 
2952
function save_overwritten_files
2953
{
2954
	typeset -i exit_code=0
2955
	archive_path=
2956
 
2957
	if [[ -f $1/$2/.nofilestosave || "$PATCH_NO_UNDO" = "true" ]]
2958
	then
2959
		return 1
2960
	elif [ "$4" = "yes" ]
2961
	then
2962
		/usr/bin/gettext "Saving a copy of existing files to be patched...\n"
2963
 
2964
		cd $ROOTDIR
2965
 
2966
		if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
2967
		then
2968
			archive_path=$PATCH_UNDO_ARCHIVE/$2
2969
		else
2970
			archive_path=$1/$2/save
2971
		fi
2972
 
2973
        if [ "$isapplied" = "no" ]
2974
        then
2975
            cpio -oL -O $archive_path/archive.cpio < $EXISTFILES
2976
            exit_code=$?
2977
 
2978
		else
2979
			if [ ! -d $TMP_ARCHIVE ]
2980
			then
2981
				$MD $TMP_ARCHIVE
2982
			fi
2983
 
2984
			cd $TMP_ARCHIVE
2985
			if [ -f $archive_path/archive.cpio.Z ]
2986
			then
2987
				zcat $archive_path/archive.cpio.Z | cpio -idum
2988
			else
2989
				cpio -idum -I $archive_path/archive.cpio
2990
			fi
2991
			$FIND . -print > $TMP_FILELIST
2992
 
2993
			cd $ROOTDIR
2994
			cpio -oL -O /tmp/archive.cpio < $EXISTFILES >/dev/null 2>&1
2995
			exit_code=$?
2996
 
2997
			cd $TMP_ARCHIVE
2998
			cpio -oAL -O /tmp/archive.cpio < $TMP_FILELIST >/dev/null 2>&1
2999
			exit_code=exit_code+$?
3000
 
3001
			cd $ROOTDIR
3002
			$RM -rf $TMP_ARCHIVE/* $TMP_FILELIST
3003
			rmdir $TMP_ARCHIVE
3004
		fi
3005
		if (( exit_code != 0 ))
3006
		then
3007
			/usr/bin/gettext "Save of old files failed.\nSee Install.info file for instructions.\n"
3008
			if [ "$isapplied" = "no" ]
3009
			then
3010
				cd $3
3011
				if [ "$ROOTDIR" != "/" ]
3012
				then
3013
					/usr/sbin/patchrm $PKGDBARG $2
3014
				else
3015
					/usr/sbin/patchrm $2
3016
				fi
3017
				$RM -fr "$1/$2"
3018
			fi
3019
			patch_quit 4 "no"
3020
			return 0
3021
		fi
3022
		if [ -x /usr/bin/compress ]
3023
		then
3024
			if [ "$isapplied" = "no" ]
3025
			then
3026
				compress $archive_path/archive.cpio
3027
			else
3028
				compress /tmp/archive.cpio
3029
			fi
3030
			if [ $? = 0 ]
3031
			then
3032
				/usr/bin/gettext "	File compression used.\n"
3033
			else
3034
				/usr/bin/gettext "	No file compression used.\n"
3035
			fi
3036
		else
3037
			/usr/bin/gettext "	No file compression used.\n"
3038
		fi
3039
		if [ "$isapplied" = "yes" ]
3040
		then
3041
			$CP /tmp/archive.cpio* $1/$2/save
3042
		fi
3043
		chmod 600 $archive_path/archive.cpio*
3044
		$TOUCH $1/$2/.oldfilessaved
3045
		sync
3046
	fi
3047
	cd $3
3048
	return 1
3049
}
3050
 
3051
# Description:
3052
#	Finish up the patch
3053
# Parameters:
3054
#	$1	- patch database directory
3055
#	$2	- patch number
3056
#
3057
function set_patch_status
3058
{
3059
	if [[ ! -d $1/$2 ]]
3060
	then
3061
		$MD -m 750 -p $1/$2
3062
	fi
3063
	$MV -f /tmp/ACTION.$PatchNum $1/$2 >/dev/null 2>&1
3064
	$CP -p README.$2 $1/$2 >/dev/null 2>&1
3065
 
3066
	# Note the following line should be removed for 2.7.
3067
	# Since 2.6 is a transitional release we keep backoutpatch
3068
	# around.
3069
 
3070
	$CP -p backoutpatch $1/$2 >/dev/null 2>&1
3071
 
3072
	$CP -p prebackout postbackout $1/$2 > /dev/null 2>&1
3073
}
3074
 
3075
# Description:
3076
# Parameters:
3077
#	$1	- patch database directory
3078
#	$2	- patch number
3079
#	$3	- patch directory
3080
#
3081
function trap_backoutsaved
3082
{
3083
	/usr/bin/gettext "Interrupt signal detected.\n"
3084
	if [[ "$isapplied" = "no" ]]
3085
	then
3086
		/usr/bin/gettext "Backing out patch:\n"
3087
		cd $3
3088
		if [[ "$ROOTDIR" != "/" ]]
3089
		then
3090
			/usr/sbin/patchrm $PKGDBARG $2
3091
		else
3092
			/usr/sbin/patchrm $2
3093
		fi
3094
		$RM -fr "$1/$2"
3095
	else
3096
		if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
3097
		then
3098
			$CP /tmp/archive.cpio* $PATCH_UNDO_ARCHIVE/$2
3099
		else
3100
			$CP /tmp/archive.cpio* $1/$2/save
3101
		fi
3102
		$RM -f /tmp/archive.cpio*
3103
		/usr/bin/gettext "Patchadd Interrupted.\n" >> $1/$2/log
3104
	fi
3105
	patch_quit 12 "yes"
3106
}
3107
 
3108
# Description:
3109
# Parameters:
3110
#	$1	- patch directory
3111
#	$2	- patch number
3112
#
3113
function trap_backout
3114
{
3115
	/usr/bin/gettext "Interrupt signal detected.\nBacking out Patch:\n"
3116
	cd $1
3117
	if [[ "$ROOTDIR" != "/" ]]
3118
	then
3119
		/usr/sbin/patchrm $PKGDBARG $2
3120
	else
3121
		/usr/sbin/patchrm $2
3122
	fi
3123
	if [[ "$isapplied" = "yes" ]]
3124
	then
3125
		$RM -f /tmp/archive.cpio*
3126
	fi
3127
	patch_quit 12 "yes"
3128
}
3129
 
3130
# Description:
3131
# Parameters:
3132
# 	$1	- patch database directory
3133
#	$2	- patch number
3134
#
3135
function trap_notinstalled
3136
{
3137
	/usr/bin/gettext "Interrupt signal detected. Patch not installed.\n"
3138
	$RM -fr /tmp/*.$$
3139
	$RM -f $INSTPATCHES_FILE
3140
	if [[ "$isapplied" = "no" ]]
3141
	then
3142
		$RM -fr "$1/$2"
3143
	else
3144
		/usr/bin/gettext "Install Interrupted.\n" >> $1/$2/log
3145
	fi
3146
	patch_quit 12 "yes"
3147
}
3148
 
3149
# Description:
3150
#	 Make sure effective UID is '0'
3151
# Parameters:
3152
#	none
3153
#
3154
function validate_uid
3155
{
3156
	typeset -i uid
3157
	uid=$(id | $SED 's/uid=\([0-9]*\)(.*/\1/')
3158
	if (( uid != 0 ))
3159
	then
3160
		/usr/bin/gettext "You must be root to execute this script.\n"
3161
		patch_quit 3 "yes"
3162
	fi
3163
}
3164
 
3165
# Description:
3166
#	Assume that any system on which the SUNWcsu package is NOT
3167
#	installed is a client. It is a safe bet that this criterion
3168
#	will remain valid through Solaris 2.3. Later releases may require
3169
#	that this test be changed. Make sure pkgadd is executable too.
3170
# Parameters:
3171
#	none
3172
# Globals Set:
3173
#	client
3174
#
3175
function verify_client
3176
{
3177
	pkginfo -q SUNWcsu
3178
	if [[ $? != 0 ]]
3179
	then
3180
		client=yes
3181
		sum /usr/sbin/pkgadd > /dev/null 2>&1
3182
		if [[ $? != 0 ]]
3183
		then
3184
			/usr/bin/gettext "The /usr/sbin/pkgadd command is not executable.\nSee pkgadd(1M) for instructions\nfor making this command executable.\n"
3185
			patch_quit 9 "yes"
3186
		fi
3187
	fi
3188
}
3189
 
3190
# Description:
3191
#	Get key parameters relating to this patch
3192
# Parameters:
3193
#	none
3194
# Globals Set:
3195
#	Obsoletes	those patches that this one obsoletes
3196
#	Incompat	those patches with which this one is incompatible
3197
#	Requires	those patches that this one requires
3198
#	ReqArrElem[]	an ordered mapping of "yes" or "no" attributes
3199
#			associated with each entry in Requires. If it
3200
#			is "yes", that package has been found on the
3201
#			system. If "no", it has not been found.
3202
#	ReqArrCount	The count of elements in the above array
3203
#
3204
# Locals Used:
3205
#	list
3206
#	tmp
3207
#	tmpInstalled
3208
#
3209
function collect_data
3210
{
3211
	tmp=
3212
	list=
3213
	tmpInstalled=
3214
 
3215
	cd $patchdir
3216
	for pkg in *
3217
	do
3218
		if [[ -f $pkg/pkginfo ]]
3219
		then
3220
			# Collect the data from a pkginfo file
3221
			tmp=$($GREP OBSOLETES $pkg/pkginfo)
3222
			if [[ $tmp = "" ]]
3223
			then
3224
				Obsoletes=""
3225
			else
3226
				Obsoletes=$(pkgparam -f $pkg/pkginfo ${tmp:%=*})
3227
			fi
3228
 
3229
			tmp=$($GREP INCOMPAT $pkg/pkginfo)
3230
			if [[ $tmp = "" ]]
3231
			then
3232
				Incompat=""
3233
			else
3234
				Incompat=$(pkgparam -f $pkg/pkginfo ${tmp:%=*})
3235
			fi
3236
 
3237
			tmp=$($GREP REQUIRES $pkg/pkginfo)
3238
			if [[ $tmp = "" ]]
3239
			then
3240
				Requires=""
3241
			else
3242
				Requires=$(pkgparam -f $pkg/pkginfo ${tmp:%=*})
3243
			fi
3244
			for req in $Requires
3245
			do
3246
				ReqArrElem[$ReqArrCount]="no"
3247
				ReqArrCount=ReqArrCount+1;
3248
			done
3249
			break
3250
		fi
3251
	done
3252
}
3253
 
3254
# Description:
3255
#	Get the sum of the PATCHID and the PATCHLIST parameters.
3256
#
3257
 
3258
function pkginfoParamSum
3259
{
3260
    dbSum=$($NAWK '/PATCHID/ {print} /PATCHLIST/ {print}' \
3261
        $PKGDB/*/pkginfo 2>/dev/null | $SUM | $NAWK '{print $1}')
3262
}
3263
 
3264
# Description:
3265
#   Check to see if any pkginfo files have changed since the last
3266
#	patchadd or patchrm. If so, recreate the database.
3267
#	NOTE: There will be times when the database is considered out
3268
#	of sync due to a pkg command. 
3269
#
3270
function check_PatchDBs
3271
{
3272
	if [[ -f $PATCHDBFILE ]]; then
3273
		pkginfoParamSum
3274
		pdbSum=$($NAWK ' $1 ~ /Version/ { print $3} ' $PATCHDBFILE) 
3275
		if (( dbSum != pdbSum )); then
3276
			recreatePatchDB="yes"
3277
			$RM -f $PATCHDBFILE
3278
		fi 
3279
	else
3280
		pkginfoParamSum
3281
		recreatePatchDB="yes"
3282
	fi
3283
}
3284
 
3285
# Description:
3286
#	Load the patch compatibility arrays.
3287
#
3288
# Parameters:
3289
#	$1 - The line from the .patchDB.
3290
function LoadPtchArrays
3291
{
3292
	installedPtch[$insPs]=""
3293
	installedObs[$insPs]=""
3294
	installedReq[$insPs]=""
3295
	installedInc[$insPs]=""
3296
	installedPkgs[$insPs]=""
3297
 
3298
	while (( "$#" != "0" ))
3299
	do
3300
		case $1 in
3301
			"Patch:"|"Obsoletes:"|"Requires:"| \
3302
			"Incompatibles:"|"Packages:" )
3303
				mode=$1
3304
				shift;;
3305
			"Version" )
3306
				break;;
3307
			* ) 
3308
 
3309
			case $mode in
3310
				"Patch:" )
3311
					 installedPtch[$insPs]=$1
3312
					 shift;;
3313
		 		"Obsoletes:" )
3314
					 installedObs[$insPs]="${installedObs[$insPs]} $1" 
3315
					 shift;;  
3316
		 		"Requires:" )
3317
					 installedReq[$insPs]="${installedReq[$insPs]} $1"
3318
					 shift;;  
3319
		 		"Incompatibles:" )
3320
					 installedInc[$insPs]="${installedInc[$insPs]} $1"
3321
					 shift;;  
3322
		 		"Packages:" )
3323
					 installedPkgs[$insPs]="${installedPkgs[$insPs]} $1"
3324
					 shift;;  
3325
			esac
3326
		esac
3327
	done
3328
}
3329
 
3330
# Description:
3331
#   Find installing compatibility issues.
3332
#
3333
# Parameters
3334
# 	$1 - installed patch
3335
#	$2 - installed patch base code
3336
#	$3 - installed patch version
3337
#
3338
function CheckInstallingCompats
3339
{
3340
	# Check for incompatible patches
3341
	for incompat in $Incompat
3342
	do
3343
		get_base_code $incompat
3344
 
3345
		if [[ "$2" = "$cur_base_code" ]]
3346
		then
3347
			get_vers_no $incompat $cur_base_code
3348
			if [[ $3 -ge $cur_vers_no ]]
3349
			then
3350
				InstIncompat=$1
3351
			fi
3352
		fi
3353
	done
3354
 
3355
	# Check for required patches
3356
	if [[ $ReqArrCount -gt 0 && $validate = "yes" ]]
3357
	then
3358
		req_count=0;
3359
 
3360
		for required in $Requires; do
3361
			get_base_code $required
3362
 
3363
			if [[ "$2" = "$cur_base_code" ]]
3364
			then
3365
				get_vers_no $required $cur_base_code
3366
 
3367
				if [[ $3 -ge $cur_vers_no ]]
3368
				then
3369
					ReqArrElem[$req_count]="yes"
3370
				fi
3371
			fi
3372
			req_count=req_count+1
3373
		done
3374
	fi
3375
 
3376
	for obs_entry in $obsoletes
3377
	do
3378
		get_base_code $obs_entry
3379
 
3380
		if [[ "$cur_base_code" = "$PatchBase" ]]
3381
		then
3382
			get_vers_no $obs_entry $cur_base_code
3383
			if [[ $cur_vers_no -ge $PatchVers ]]
3384
			then
3385
				ObsoletedBy=$1
3386
			else
3387
				ObsoletePast=$PatchBase
3388
				ObsoletedBy=$1
3389
			fi
3390
		fi
3391
	done
3392
}
3393
 
3394
# Description:
3395
#   Find previously installed patches that the applying patch is
3396
#	incompatible with.
3397
# Parameters:
3398
#   none
3399
#
3400
# Locals Used:
3401
#	list
3402
#	obsPatch
3403
#	incPat
3404
#	obsVer
3405
#	obsBase
3406
#	incVer
3407
#	incBase
3408
#	tmpStr
3409
#
3410
function eval_compats
3411
{
3412
	typeset -i reqMet=0
3413
	typeset -i ctr=0
3414
	typeset -i insPs=0
3415
 
3416
	patchFile=""
3417
	patchFileStripped=/tmp/patchDBstripped.$$
3418
 
3419
	if [[ "$validate" = "no" ]]
3420
	then
3421
		ReqdPatchCnt=0
3422
		return
3423
	fi
3424
 
3425
	if [[ "$PatchMethod" = "progressive" ]]
3426
	then
3427
		return
3428
	fi
3429
 
3430
	if [[ -s "$PATCHDBFILE" ]]; then
3431
		patchFile=$PATCHDBFILE
3432
	elif [[ ! -s $INSTPATCHES_FILE ]]; then
3433
		return
3434
	else
3435
		patchFile=$INSTPATCHES_FILE
3436
	fi
3437
 
3438
	$SED 's/,//g' $patchFile > $patchFileStripped 
3439
 
3440
	while read line
3441
	do
3442
		LoadPtchArrays $line
3443
		insPs=insPs+1
3444
	done < $patchFileStripped
3445
 
3446
	obsPatch=""
3447
 
3448
	ctr=1
3449
 
3450
	while (( ctr < insPs ))
3451
	do
3452
		# If this is a reinstallation of an already installed
3453
		# patch get out. This stuff doesn't apply.
3454
 
3455
		if [[ ${installedPtch[$ctr]} = "$PatchNum" ]]
3456
		then
3457
			cd $patchdir
3458
			return
3459
		fi
3460
 
3461
		# If an earlier rev of a patch is already installed then 
3462
		# the stuff below doesn't apply.
3463
 
3464
		get_base_code ${installedPtch[$ctr]}
3465
		instBase=$cur_base_code
3466
 
3467
		get_vers_no ${installedPtch[$ctr]} $instBase
3468
		instVers=$cur_vers_no
3469
 
3470
		if [[ "$instBase" = "$PatchBase" ]]
3471
		then
3472
			if [[ "$instVers" -ge "$PatchVers" ]]
3473
			then
3474
				cd $patchdir
3475
				return
3476
			fi
3477
		fi
3478
 
3479
		obsoletes=${installedObs[$ctr]}
3480
 
3481
		if [[ "$compatsAlreadyChecked" == "no" ]]; then
3482
			CheckInstallingCompats ${installedPtch[$ctr]} $instBase $instVers
3483
		fi
3484
 
3485
		ctr=ctr+1
3486
	done
3487
 
3488
	if [[ "$unReqAlreadyChecked" == "no" ]]; then
3489
		CheckUninstalledReqs
3490
	fi
3491
	tmpUninstReqs="$UninstReqs"
3492
 
3493
	# At this point we know if all the installing patches requirements
3494
	# have been met. Now we need to check to see if any required or
3495
	# incompatible patches have been obsoleted. 
3496
 
3497
	ctr=1
3498
	tmpObsdUninstReqs=""
3499
 
3500
	while (( ctr < insPs ))
3501
	do
3502
		# Check all the installed patches for obsoletions.
3503
 
3504
		if [[ -n ${installedObs[$ctr]} ]]
3505
		then
3506
 
3507
			for ob in ${installedObs[$ctr]}
3508
			do
3509
				get_base_code $ob
3510
				obBase=$cur_base_code
3511
				get_vers_no $ob $obBase
3512
				obVers=$cur_vers_no
3513
 
3514
				# Check the obsoleted patches to see if they
3515
				# obsolete a patch that is required to be
3516
				# installed. If that is true then a
3517
				# requirement has been met.
3518
 
3519
				for obReq in $Requires
3520
				do
3521
					# A counter is needed to determine if 
3522
					# all req's have been met.
3523
 
3524
					get_base_code $obReq
3525
					obPatchBase=$cur_base_code
3526
 
3527
					if [[ "$obBase" = "$obPatchBase" ]]
3528
					then
3529
 
3530
						# At this point we know the 
3531
						# the installing patch requires
3532
						# a patch that has been obsoleted
3533
						# by an already installed patch.
3534
						# This may even be a patch that hasn't
3535
						# been installed. (sigh)
3536
						# We need to check to see if this
3537
						# is truely valid.
3538
 
3539
						for un in $UninstReqs
3540
						do
3541
							if [[ "$un" != "$obReq" ]]
3542
							then
3543
								# Reconstruct
3544
								# theuninstalled
3545
								# req's list.				
3546
								tmpObsdUninstReqs="$tmpObsUninstReqs $un"
3547
							fi
3548
						done
3549
						ReqdPatchCnt=ReqdPatchCnt-1
3550
					fi
3551
				done
3552
 
3553
				# Check the installing patch to see if
3554
				# it is incompatible with a patch that
3555
				# has been installed and has been obsoleted.
3556
 
3557
				for inc in $Incompat
3558
				do
3559
					get_base_code $inc
3560
					obPatchBase=$cur_base_code
3561
					if [[ "$obBase" = "$obPatchBase" ]]
3562
					then
3563
						InstIncompat=${installedPtch[$ctr]}
3564
						#InstIncompat=$patch
3565
						check_patch_compatibility
3566
					fi
3567
				done
3568
			done
3569
		fi
3570
 
3571
		# Handle previously installed patches with
3572
		# requirements.
3573
 
3574
		if [[ -n ${installedReq[$ctr]} ]]
3575
		then
3576
			for req in ${installedReq[$ctr]}
3577
			do
3578
				get_base_code $req
3579
				reqBase=$cur_base_code
3580
				get_vers_no $req $reqBase
3581
				reqVers=$cur_vers_no
3582
				incReqObFlag="req"
3583
				check_INC_REQ_OBS "$reqBase" "$reqVers" \
3584
				  ${installedPtch[$ctr]} "${installedPkgs[$ctr]}" \
3585
				  "$incReqObFlag"
3586
			done
3587
		fi
3588
 
3589
		# Handle previously installed patches with
3590
		# incompatibilities.
3591
 
3592
		if [[ -n ${installedInc[$ctr]} ]]
3593
		then
3594
			for inc in ${installedInc[$ctr]}
3595
			do
3596
				get_base_code $inc
3597
				incBase=$cur_base_code
3598
				get_vers_no $inc $incBase
3599
				incVers=$cur_vers_no
3600
				incReqObFlag="inc"
3601
				check_INC_REQ_OBS "$incBase" "$incVers" \
3602
				  ${installedPtch[$ctr]} "${installedPkgs[$ctr]}" \
3603
				  "$incReqObFlag"
3604
			done
3605
		fi
3606
		ctr=ctr+1
3607
	done
3608
 
3609
	if [[ -n "$tmpUninstReqs" || -n "$tmpObsdUninstReqs" ]]
3610
	then
3611
		UninstReqs="$tmpUninstReqs $tmpObsdUninstReqs"
3612
	fi
3613
 
3614
	cd $patchdir
3615
}
3616
 
3617
# Description:
3618
#   Check  the REQUIREd or INCOMPATs installed patch to determine
3619
# 	if it has been obsoleted.
3620
# Parameters:
3621
#   none
3622
# Locals Set:
3623
#   obsByPatch
3624
#   obsPatch
3625
# Globals Set:
3626
#   none
3627
# Parameters:
3628
#   $1  Base code of either INCOMPAT or REQUIRE patch.
3629
#   $2  Version of either INCOMPAT or REQUIRE patch.
3630
#   $3  The patch associated with the INCOMPAT or REQUIRE requirement.
3631
#	$4  The pkg associated with the patch.
3632
#   $5  A flag determining either INCOMPAT or REQ.
3633
#
3634
function check_INC_REQ_OBS
3635
{
3636
	obsByPatch=""
3637
	obsPatch=""
3638
 
3639
	# Check to see if the incompatible/required patch has 
3640
	# been explicitly obsoleted.
3641
 
3642
	for instPkg in $4
3643
	do
3644
		if [[ -f $instPkg/save/$3/obsoleted_by ]]
3645
		then 
3646
			obsByPatch=$(/usr/bin/cat \
3647
			  $instPkg/save/$3/obsoleted_by)
3648
			break
3649
		fi
3650
	done
3651
 
3652
	# Check to see if this is an implicit/requires patch 
3653
	# that obsoletes the installing patch.
3654
 
3655
	if [[ -z "$obsByPatch" ]]
3656
	then 
3657
		# We need to check to see if the obsoleted patch 
3658
		# is obsoleted by an already installed patch.
3659
 
3660
		for ob in $instPkg/save/$ObsArrEntry
3661
		do
3662
			if [[ -f $ob/obsoleted_by ]]
3663
			then
3664
				obsPatch=$($NAWK ' { print $1 } ' \
3665
				  $ob/obsoleted_by)
3666
			fi
3667
			if [[ -n "$obsPatch" ]]
3668
			then
3669
				break
3670
			fi
3671
		done
3672
	fi
3673
 
3674
	if [[ "$PatchBase" = "$1" ]]
3675
	then
3676
		if [[ "$5" = "inc" && "$PatchVers" -ge "$2" ]]
3677
		then
3678
			if [[ -n "$obsByPatch" ]]
3679
			then
3680
				InstIncompat=$obsByPatch
3681
			else
3682
				InstIncompat=$3
3683
			fi
3684
		elif [[ "$5" = "req" && "$PatchVers" -le "$2" ]]
3685
		then
3686
			if [[ -n "$obsByPatch" ]]
3687
			then
3688
				ReqdPatchCnt=1
3689
				UninstReqs=$obsByPatch
3690
			else
3691
				ReqdPatchCnt=1
3692
				UninstReqs=$3
3693
			fi
3694
		fi
3695
		check_patch_compatibility
3696
	fi
3697
 
3698
	# Check to see if this patch explicitly obsoletes 	
3699
	# a patch that is INCOMPAT.
3700
 
3701
	if [[ "$5" = "inc" ]]
3702
	then
3703
		for ob in $Obsoletes
3704
		do
3705
			get_base_code $ob
3706
			obsBase=$cur_base_code
3707
			get_vers_no $ob $cur_base_code
3708
			obsVers=$cur_vers_no
3709
 
3710
			#if [[ "$obsBase" = "$1" && "$obsVers" -ge "$2" ]]
3711
			if [[ "$obsBase" = "$1" ]]
3712
			then
3713
				if [[ -n "$obsByPatch" ]]
3714
				then
3715
					InstIncompat=$obsByPatch
3716
				else 
3717
					InstIncompat=$3
3718
				fi
3719
				check_patch_compatibility
3720
			fi
3721
		done
3722
	fi
3723
}
3724
 
3725
# Description:   
3726
#   Construct the files needed to backout the patch for dryrun mode.
3727
# Parameters:
3728
#   none    
3729
# Globals Set:   
3730
#   none    
3731
# Parameters:
3732
#	$1	Dryrun directory
3733
#
3734
function construct_backout_files {
3735
	$NAWK ' { print $2 } ' $1/dryrun.ipo.asc > $PATCHFILES
3736
}
3737
 
3738
# Description:
3739
#   Check to see if there will be enough space for the backout pkg(s).
3740
#	There is no 100% sure way to calculate the size of the FS needed
3741
#	to produce the backout pkg and to save the backout pkg.
3742
# Parameters:
3743
#   none
3744
# Globals Set:
3745
#   none
3746
# Locals Used:
3747
#	spaceRequired
3748
# Parameters:
3749
#	$1 Dryrun Directory
3750
#
3751
function check_dryrun_backoutSpace {
3752
	typeset -i totalDRBytesNeeded=0
3753
	typeset -i totalDRKBytesNeeded=0
3754
	typeset -i DRBytesNeeded=0
3755
	typeset -i DRBytesAvail=0
3756
	typeset -i DRKbytesAvail=0
3757
 
3758
	# NOTE: This function makes it best guess at how big the backout
3759
	# staging area needs to be to save the backout pkg(s). It does a
3760
	# good job except for hard links. If a hard link is being installed
3761
	# but already exists pkgadd -D will determine that it does not need
3762
	# to be installed which is correct. Although the preinstall script
3763
	# will still insert the target link in the staging area and since
3764
	# this function relies on the output of pkgadd -D, the target link
3765
	# isn't accounted for during the space calculations.
3766
 
3767
	cat $PATCHFILES | while read line
3768
	do
3769
		DRBytesNeeded=0
3770
		if [[ "$ROOTDIR" != "/"  ]]; then
3771
			line="$ROOTDIR$line"
3772
		fi
3773
 
3774
		DRBytesNeeded=$($WC -c $line 2>/dev/null | $NAWK ' { print $1 } ' )
3775
		if (( DRBytesNeeded == 0 )); then
3776
 
3777
			# Add 512 bytes for directories
3778
			DRBytesNeeded=DRBytesNeeded+512
3779
		fi
3780
		totalDRBytesNeeded=DRBytesNeeded+totalDRBytesNeeded
3781
	done
3782
 
3783
    # To build and compress the backout packages in the archive directory
3784
    # takes about 3x as much space then there really needs to be
3785
    # to save just the archive. This is due to the proto directory,
3786
	# the make of the pkg and the translation of the pkg.
3787
 
3788
	totalDRBytesNeeded=totalDRBytesNeeded*3+100
3789
 
3790
	if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]
3791
    then
3792
        backout_dir=$PATCH_UNDO_ARCHIVE
3793
    else
3794
		if [[ "$netImage" = "boot" ]]
3795
		then
3796
        	backout_dir=$ROOTDIR/tmp
3797
		else
3798
        	backout_dir=$PKGDB
3799
		fi
3800
    fi
3801
 
3802
    # Is there enough space? Use sed to extract the fourth field of df.
3803
    DRKbytesAvail=$($DF -b $backout_dir | tail -1 | \
3804
    $SED 's/^[^   ]*[     ]*\([^  ]*\).*/\1/')
3805
 
3806
	DRBytesAvail=DRKbytesAvail*1024
3807
 
3808
    if (( totalDRBytesNeeded > DRBytesAvail ))
3809
    then
3810
		totalDRKBytesNeeded=totalDRBytesNeeded/1024
3811
        /usr/bin/gettext "Insufficient space in $backout_dir to save old files.\nSpace required in kilobytes:  $totalKbytesNeeded\nSpace available in kilobytes:  $DRKbytesAvail\n"
3812
        $RM -fr $backout_dir/$2
3813
		patch_quit 4 "no"
3814
		return 0
3815
    fi
3816
	return 1
3817
}
3818
 
3819
# Description:
3820
#   Check the applicable files systems for writability.
3821
# Parameters:
3822
 
3823
function checkFS {
3824
	fileSys=""
3825
	fileSys=$($NAWK ' $3 ~ /FALSE/ { print $1 } ' $dryrunDir/dryrun.fs.asc)
3826
	if [[ -n "$fileSys" ]]; then
3827
		/usr/bin/gettext "\nThe $fileSys file system is not writable.\n" \
3828
			>> $LOGFILE
3829
		/usr/bin/gettext "Patch $PatchNum can not be installed until $fileSys\n" \
3830
			>> $LOGFILE
3831
		/usr/bin/gettext "is made writable.\n\n" >> $LOGFILE
3832
		return 0
3833
	fi
3834
	return 1
3835
}
3836
 
3837
# Description:
3838
#   Evaluate the dry run data
3839
# Parameters:
3840
#	$1 - exit code from pkgadd -D. 
3841
# Globals Set:
3842
#   none
3843
# Locals Used:
3844
#   dryrunExit
3845
#   dryrunDir
3846
#
3847
function eval_dryrun {
3848
	dryrunExit=
3849
	dryrunDir=
3850
 
3851
	dryrunDir="/tmp/$PatchNum.$$"
3852
 
3853
	if [[ ! -d "$dryrunDir"  || "$1" != "0" ]]; then
3854
		dryrunFailure="yes"
3855
		return
3856
	fi
3857
 
3858
	dryrunExit=$($NAWK -F= ' $1 ~ /^EXITCODE$/ { print $2 } ' $dryrunDir/dryrun.isum.asc )
3859
 
3860
	# Check the FS's for writability. bug 4155609
3861
 
3862
	if [[ "$dryrunExit" != "0" ]]
3863
	then   
3864
		eval_dryrun_failures "$dryrunDir"
3865
		dryrunFailure="yes"
3866
	fi
3867
 
3868
	if [[ "$saveold" = "yes" ]]
3869
	then
3870
		construct_backout_files "$dryrunDir"
3871
		if check_dryrun_backoutSpace "$dryrunDir"
3872
		then
3873
			dryrunFailure="yes"
3874
		fi
3875
	fi
3876
 
3877
	if checkFS; then
3878
		dryrunFailure="yes"
3879
	fi
3880
 
3881
}
3882
 
3883
# Description:
3884
#   Evaluate the dry run failures.
3885
# Parameters:
3886
#   $1  Dryrun directory
3887
# Globals Set:
3888
#   none
3889
# Locals Used:
3890
#   dryrunFailures
3891
#   failed
3892
#   exitCheck
3893
#
3894
function eval_dryrun_failures  {
3895
 
3896
	failed=
3897
	dryrunFailures=""
3898
	spaceNeeded=""
3899
 
3900
    /usr/bin/gettext "The following errors were reported by pkgadd dryrun...\n\n"
3901
 
3902
    exitCheck=$($NAWK -F= ' $2 ~ /!0/ { print $1 } ' $1/dryrun.isum.asc )
3903
    for code in $exitCheck
3904
    do
3905
        case $code in
3906
            CHECKINSTALLEXITCODE)   /usr/bin/gettext "  The checkinstall script failed.\n" ;;
3907
            REQUESTEXITCODE)        /usr/bin/gettext "  The request script failed.\n" ;;
3908
        esac
3909
    done
3910
 
3911
    dryrunFailures=$($NAWK -F= ' $2 ~ /NOT_OK/ { print $1 } ' \
3912
		$1/dryrun.isum.asc )
3913
 
3914
    failed="  Installation failed due to"
3915
    for param in $dryrunFailures
3916
    do
3917
        case $param in
3918
            SPACE)      /usr/bin/gettext "$failed lack of space reported by pkgadd dryrun\n\n" ;;
3919
            PARTIAL)    /usr/bin/gettext "$failed partial install reported by pkgadd dryrun\n\n" ;;
3920
            RUNLEVEL)   /usr/bin/gettext "$failed incorrect run level\n\n" ;;
3921
            PKGFILES)   /usr/bin/gettext "$failed bad pkg reported by pkgadd dryrun\n\n" ;;
3922
            DEPEND)     /usr/bin/gettext "$failed incorrect depend file\n\n" ;;
3923
            CONFLICT)   /usr/bin/gettext "$failed conflicts reported by pkgadd dryrun\n\n" ;;
3924
            SETUID)     /usr/bin/gettext "$failed incorrect uid\n\n" ;;
3925
            PKGDIRS)    /usr/bin/gettext "$failed package directories not found\n\n" ;;
3926
        esac
3927
    done
3928
 
3929
	doLogfile
3930
 
3931
	patch_quit 30 "no"
3932
}
3933
 
3934
# Description:
3935
#	Setup the net install boot image to look like an installed system.
3936
# Parameters:
3937
#	none
3938
# Globals Set:
3939
#	none
3940
#
3941
function setup_net_image {
3942
 
3943
	if [[ "$netImage" != "boot" ]]
3944
	then
3945
		return
3946
	fi
3947
 
3948
	# Check to see if there was an interruption that left the loop back
3949
	# mounts mounted for Net Install Patching.
3950
 
3951
	if [[ -d $ROOTDIR/mnt/root ]]
3952
	then
3953
		restore_net_image 
3954
	fi 
3955
 
3956
	# The .../Boot/.tmp_proto/root needs to be re-mapped to .../Boot/tmp in order
3957
	# for the boot image to be patched successfully.
3958
 
3959
	$MOUNT -F lofs -O $ROOTDIR/tmp $ROOTDIR/mnt
3960
	$MOUNT -F lofs -O $ROOTDIR/.tmp_proto $ROOTDIR/tmp
3961
	$MOUNT -F lofs -O $ROOTDIR/mnt/root/var $ROOTDIR/tmp/root/var
3962
 
3963
	# At this point patchadd thinks the net install image is just like
3964
	# an installed image.
3965
}
3966
 
3967
# Description:
3968
#	Restore the net image to the way it was before mucking 
3969
#	with it in the setup_net_image function.
3970
# Parameters:
3971
#	none
3972
# Globals Set:
3973
#	none
3974
#
3975
function restore_net_image {
3976
 
3977
	if [[ "$netImage" != "boot" ]]
3978
	then
3979
		return
3980
	fi
3981
 
3982
	$UMOUNT $ROOTDIR/tmp/root/var
3983
	$UMOUNT $ROOTDIR/tmp
3984
	$UMOUNT $ROOTDIR/mnt
3985
}
3986
 
3987
# Description:
3988
#	Patch the product Database on the netinstall image.
3989
# Parameters:
3990
#	none
3991
# Globals Set:
3992
#	none
3993
#
3994
function patch_product {
3995
 
3996
	# This routine was the beginning of the Fresh bits function.
3997
	# It is not functional and therefore is not called.
3998
 
3999
	if [[ "$netImage" != "product" ]]
4000
	then
4001
		return
4002
	fi
4003
 
4004
	eval_utilities
4005
	activate_patch "$patchdir"
4006
	cd $patchdir
4007
 
4008
	collect_data
4009
 
4010
	# If this is the first patch to the product area create the patch repository.
4011
	if [[ ! -d "$PATCHDB" ]]
4012
	then
4013
		$MD -p -m 750 $PATCHDB
4014
	fi
4015
 
4016
	# Check to see if the pkg to patch is in the product area
4017
	# and all VERSION and ARCH are the right instance.
4018
	eval_inst_patches $PKGDB 
4019
	check_patch_compatibility
4020
	check_if_applied "$PATCHDB" "$PatchNum"
4021
	check_if_obsolete "$PATCHDB"    # see if this package is already obsolete
4022
	if [[ "$isapplied" = "yes" ]]
4023
	then
4024
		eval_applied_patch $PATCHDB $PKGDB $PatchMethod $saveold $PatchNum
4025
	fi
4026
	gen_patchpkg_list
4027
	check_pkgs_installed "$PKGDB" "$patchdir"
4028
 
4029
	#### Make sure what PKGDBARG is !!!
4030
	gen_install_filelist "$PKGDB" "$PKGDBARG"
4031
	gen_patch_filelist
4032
 
4033
	check_reloc_dir
4034
	merge_pkgmaps
4035
 
4036
}
4037
 
4038
# Description:
4039
#	Merge the PATCHLIST with each pkgmap called out by the pkg.
4040
# Parameters:
4041
#	none
4042
# Globals Set:
4043
#	none
4044
#
4045
function merge_pkgmaps {
4046
 
4047
	for pkg in $pkglist
4048
	do
4049
		echo "test"	
4050
		cd $ROOTDIR/$pkg
4051
		$NAWK ' 
4052
			$1 ~ /[:]/ { 		# size line
4053
				if (NF == 3) {	# if uncompressed
4054
					uncompress="yes" }
4055
				} ' pkgmap
4056
		if [[ "$uncompress" != "yes" ]]
4057
		then
4058
			zcat reloc.cpio.Z | cpio -idum	
4059
		fi
4060
		$DIFF pkgmap $patchDir/$pkg/pkgmap | $NAWK ' $1 ~ /[>]/ {
4061
			if ($3 == "i") { next; }
4062
			if ($3 == "v" || $3 == "e") { next; }
4063
			{ print $2 $3 $4 $5 $6 $7 $8 } } ' > tmpPkgmap
4064
		cat tmpPkgmap |
4065
		while read line 
4066
		do
4067
			$GREP $line pkgmap
4068
			if [[ $? = 0 ]]
4069
			then
4070
				$SED 's/$line/'
4071
			fi
4072
		########
4073
		## Continue with merging the maps
4074
		########				
4075
 
4076
		done
4077
 
4078
	done
4079
}
4080
 
4081
# Description:
4082
#	Ceck to see if the reloc directory is compressed, if it is
4083
#	decompress it and poke in the objects being replaced by the patch.
4084
# Parameters:
4085
#	none
4086
# Globals Set:
4087
#	none
4088
#
4089
function check_reloc_dir {
4090
 
4091
	for pkg in $pkglist
4092
	do
4093
		cd $ROOTDIR/$pkg
4094
		if [[ -d reloc ]]
4095
		then
4096
			cd reloc
4097
		fi
4098
		if [[ -f reloc.cpio.Z ]]
4099
		then
4100
			zcat reloc.cpio.Z | cpio -idum 
4101
		else
4102
			cpio -idum -l reloc.cpio
4103
		fi
4104
 
4105
	done
4106
}
4107
 
4108
# Description:
4109
#   Check exit code from pkgadd
4110
# Parameters:
4111
#   $1  exitcode from pkgadd
4112
# Globals Set:
4113
#   none 
4114
#
4115
function check_pkgadd_exitcode {
4116
    pkgadd_code=$1
4117
 
4118
    # If it's a suspend (exit code 4), then the
4119
    # message type is the appropriate patchadd
4120
    # exit code and the appropriate message follows.
4121
    # A suspend means, nothing has been installed.
4122
    if [[ $pkgadd_code == 4 ]]  # suspend
4123
    then 
4124
        Message=$($EGREP PaTcH_MsG $LOGFILE | $SED s/PaTcH_MsG\ //)
4125
        if [[ $Message = "" ]]
4126
        then
4127
            pkgadd_code=5
4128
        else
4129
            Msg_Type=$(echo $Message | $NAWK ' { print $1 } ')
4130
            Message=$(echo $Message | $SED s/$Msg_Type\ //)
4131
 
4132
            /usr/bin/gettext "$Message/n" >> $LOGFILE
4133
            /usr/bin/gettext "$Message"
4134
			if [[ "$lastPtchInList" != "$PatchNum" ]]
4135
			then
4136
				# If there are more pkgs in the list skip them since this patch
4137
				# will not be installed.
4138
				/usr/bin/gettext "Skipping patch $PatchNum"
4139
        		/usr/sbin/patchrm -R $ROOTDIR $PatchNum
4140
        		Something_Installed=0
4141
				pkg=
4142
				return 1
4143
			else
4144
            	patch_quit $Msg_Type "no"
4145
				return 0
4146
			fi
4147
        fi
4148
    fi
4149
 
4150
    # reboot after installation of all packages
4151
    if [[ $pkgadd_code == 10  || $pkgadd_code == 20 ]]
4152
    then 
4153
        /usr/bin/gettext "Reboot after patchadd has installed the patch.\n"
4154
    fi
4155
 
4156
    if [[ $pkgadd_code == 5 ]]  # administration
4157
    then 
4158
        cat $LOGFILE
4159
		if [[ "$lastPtchInList" != "$PatchNum" ]]
4160
		then
4161
			# If there are more pkgs in the list skip them since this patch
4162
			# will not be installed.
4163
			/usr/bin/gettext "Skipping patch $PatchNum"
4164
        	/usr/sbin/patchrm -R $ROOTDIR $PatchNum
4165
        	Something_Installed=0
4166
			pkg=
4167
			return 1
4168
		else
4169
        	/usr/sbin/patchrm -R $ROOTDIR $PatchNum
4170
        	Something_Installed=0
4171
		fi
4172
    elif [[ $pkgadd_code != 0 ]]
4173
    then
4174
        $EGREP ERROR $LOGFILE
4175
		if [[ "$lastPtchInList" != "$PatchNum" ]]
4176
		then
4177
			# If there are more pkgs in the list skip them since this patch
4178
			# will not be installed.
4179
			/usr/bin/gettext "Skipping patch $PatchNum"
4180
        	/usr/sbin/patchrm -R $ROOTDIR $PatchNum
4181
        	Something_Installed=0
4182
			pkg=
4183
			return 1
4184
		else
4185
        	/usr/sbin/patchrm -R $ROOTDIR $PatchNum
4186
        	Something_Installed=0
4187
        	patch_quit 5 "no"
4188
			return 0
4189
		fi
4190
    else
4191
        Something_Installed=1
4192
    fi
4193
	return 1
4194
}
4195
 
4196
# Description:
4197
#	If installing a patch in the mini-root invoke pkgadd with the -M option.
4198
# Parameters:
4199
#	none
4200
# Globals Set:
4201
#	MOPTION
4202
#
4203
function check_pkgadd_M_option {
4204
 
4205
	[[ "$mgrOS" > "5.5.1" ]] &&  [[ "$ROOTDIR" != "/" ]] && MOPTION="-M"
4206
}
4207
 
4208
# Description:
4209
#	Apply a direct instance patch
4210
# Parameters:
4211
#	none
4212
# Globals Set:
4213
#	pkgDispList
4214
#
4215
function apply_diPatch {	
4216
	exit_code=0
4217
 
4218
	pkgInst=""
4219
	pkgDispList=""
4220
	dryrunFailure=""
4221
	ReqArrCount=0
4222
	firstTimeThru="yes"
4223
	cd $patchdir
4224
	curdir=$(pwd)
4225
 
4226
	# strip the installed instance out of the package list
4227
	# and the pkgabbrev.
4228
	for pkg in $pkglist
4229
	do
4230
		newpkglist="$newpkglist ${pkg:%,*}"
4231
		pkgInst="$pkgInst ${pkg:#*,}"
4232
	done
4233
 
4234
	pkglist=$newpkglist
4235
 
4236
	/usr/bin/gettext "Installing patch packages...\n"
4237
 
4238
	# actually install the packages
4239
	#
4240
	for pkg in $pkglist
4241
	do
4242
		if [[ -f $pkg/pkginfo ]]	# If this is a package
4243
		then
4244
			$CP $RESPONSE_FILE $RESPONSE_FILE.1
4245
			if [[ "$DRYRUN" = "no" ]]
4246
			then   
4247
				pkgadd $MOPTION -S -n -a $ADMINTFILE -r $RESPONSE_FILE.1 \
4248
			      -R $ROOTDIR -d . $pkg 1>>$LOGFILE </dev/null 2>&1
4249
				exit_code=$?
4250
			else
4251
				if [[ "$firstTimeThru" = "yes" ]]
4252
				then
4253
					pkgadd -D /tmp/$PatchNum.$$ -S -n -a $ADMINTFILE \
4254
					  $MOPTION -r $RESPONSE_FILE.1 \
4255
			    	  -R $ROOTDIR -d . $pkglist 1>>$LOGFILE </dev/null 2>&1
4256
					exit_code=$?
4257
					firstTimeThru="no"	
4258
					eval_dryrun "$exit_code"
4259
					if [[ "$dryrunFailure" = "yes" ]]
4260
					then
4261
						/usr/bin/gettext "\nPatch $PatchNum failed to install due to a failure produced by pkgadd.\n\n"
4262
						doLogfile
4263
						return 0
4264
					fi
4265
				fi
4266
                pkgadd -S -n -a $ADMINTFILE -r $RESPONSE_FILE.1 \
4267
                $MOPTION -R $ROOTDIR -d . $pkg 1>>$LOGFILE </dev/null 2>&1
4268
                exit_code=$?
4269
			fi
4270
           	if check_pkgadd_exitcode "$exit_code"
4271
			then
4272
				return 0
4273
			fi
4274
		fi
4275
		$RM -f $RESPONSE_FILE.1
4276
 
4277
		if [[ "$exit_code" = "0" || "$exit_code" = "10" \
4278
		  || "$exit_code" = "20" ]]
4279
		then
4280
			# We want to populate the PATCHDBFILE with the
4281
			# instance of the pkg if it exists,
4282
			# not just the pkgabbrev.
4283
 
4284
			if [[ -n "$pkgInst" ]]; then
4285
				tmppkgList=""
4286
				pkgCtr=0
4287
				for inst in $pkgInst; do
4288
					installed="${inst:%\.*}"
4289
					pkg="${pkg:%\.*}"
4290
					if [[ "$installed" == "$pkg" && \
4291
						"$pkgCtr" == 0 ]]; then
4292
						pkgDispList="$pkgDispList $inst"
4293
						pkgCtr=1
4294
					else
4295
 
4296
						# Reconstruct the pkgInst list.
4297
						# This needs to be done in case
4298
						# there are multiple ARCH's
4299
						# being installed and the pkgs
4300
						# in the patch may contain
4301
						# SUNWxx, SUNWxx.u SUNWxx.m
4302
 
4303
						tmppkgList="$tmppkgList $inst"
4304
					fi
4305
				done
4306
			else
4307
				pkgDispList="$pkgDispList $pkg"
4308
			fi
4309
			pkgInst="$tmppkgList"
4310
		fi
4311
 
4312
	done
4313
 
4314
	if (( Something_Installed == 1 ))
4315
	then
4316
		cd $ROOTDIR
4317
		cd var/sadm/pkg
4318
 
4319
		InstPkgs=$(pkginfo -R $ROOTDIR | $NAWK '
4320
		    { printf ("%s ", $2) }
4321
		END { printf("\n") } ')
4322
 
4323
		#
4324
		# With that done successfully, obsolete explicitly
4325
		# listed prior patches.
4326
		#
4327
		for patch in $Obsoletes
4328
		do
4329
			get_base_code $patch
4330
			patch_base=$cur_base_code
4331
 
4332
			get_vers_no $patch $patch_base
4333
			patch_vers=$cur_vers_no
4334
 
4335
			for pkg in $InstPkgs
4336
			do
4337
				#
4338
				# Locate all applicable obsoleted patches
4339
				# by searching for entries with identical
4340
				# base codes and versions greater than or
4341
				# equal to the one specified.
4342
				#
4343
				cd $pkg/save
4344
 
4345
				patch_list=$($LS -db $patch_base* 2>/dev/null)
4346
 
4347
				for cur_patch in $patch_list
4348
				do
4349
					get_vers_no $cur_patch $patch_base
4350
					if [[ $cur_vers_no -gt $patch_vers ]]
4351
					then
4352
						/usr/bin/gettext "WARNING: Later version of obsolete patch $patch was found.\nLeaving $cur_patch as is.\n"
4353
						continue;
4354
					fi
4355
 
4356
					if [[ -f $cur_patch/undo ]]
4357
					then
4358
						$MV $cur_patch/undo $cur_patch/obsolete
4359
						echo $PatchNum >> $cur_patch/obsoleted_by
4360
					elif [[ -f $cur_patch/undo.Z ]]
4361
					then
4362
						$MV $cur_patch/undo.Z $cur_patch/obsolete.Z
4363
						echo $PatchNum >> $cur_patch/obsoleted_by
4364
						elif [[ -f $cur_patch/remote ]]
4365
                        then
4366
                            set_remote_state $pkg $cur_patch
4367
                            check_remote_file $pkg $cur_patch
4368
                            echo $PatchNum >> $cur_patch/obsoleted_by
4369
					elif  [[ -f $cur_patch/obsolete || -f $cur_patch/obsolete.Z ]]
4370
					then
4371
						$GREP $PatchNum $cur_patch/obsoleted_by >/dev/null
4372
						if [[ $? -ne 0 ]]
4373
						then
4374
							echo $PatchNum >> $cur_patch/obsoleted_by
4375
						fi
4376
					fi
4377
				done
4378
 
4379
				cd $ROOTDIR
4380
				cd var/sadm/pkg
4381
			done
4382
		done
4383
		/usr/bin/gettext "\nPatch number $PatchNum has been successfully installed.\n"
4384
	else
4385
		/usr/bin/gettext "Installation of patch number $PatchNum has been suspended.\n"
4386
    fi
4387
 
4388
	doLogfile
4389
 
4390
	$RM -f $RESPONSE_FILE
4391
	cd $curdir
4392
	return 1
4393
}
4394
 
4395
# Description:
4396
#	Copy the temporary log file. 
4397
#
4398
 
4399
function doLogfile
4400
{
4401
	if [ -f $LOGFILE ]
4402
	then
4403
		if [[ ! -d $PATCHDB/$PatchNum ]]
4404
		then
4405
			$MD -p -m 750 $PATCHDB/$PatchNum
4406
		fi 
4407
 
4408
		/usr/bin/gettext "See $PATCHDB/$PatchNum/log for details\n"
4409
		$CP -p $LOGFILE $PATCHDB/$PatchNum/log
4410
		$RM -f $LOGFILE
4411
	fi
4412
}
4413
 
4414
# Description:
4415
#	Determine which patch is required for this OS release to work.
4416
# Parameters:
4417
#	$1	Solaris release of the managing host
4418
#	$2	The patch method to use
4419
# Globals Set:
4420
#	ReqdOSPatch	patch number that this OS requires
4421
#	ReqdOSPatchBase	base number of the above patch
4422
#	ReqdOSPatchVers	version number of the above patch
4423
#
4424
function ident_reqd_patch {
4425
 
4426
	if [[ ! -d $PATCHDB ]]
4427
	then
4428
		$MD -p -m 750 $PATCHDB
4429
	fi
4430
 
4431
	cd $PATCHDB
4432
 
4433
	if [[ "$PatchMethod" = "direct" ]]
4434
	then
4435
		case $1 in
4436
			"2.0")
4437
				/usr/bin/gettext "ERROR: Solaris 2.0 is not capable of installing patches\nto a 2.5 or later client.\n";
4438
				patch_quit 21 "yes";;
4439
			"2.1")
4440
				/usr/bin/gettext "ERROR: Solaris 2.1 is not capable of installing patches\nto a 2.5 or later client.\n";
4441
				patch_quit 21 "yes";;
4442
			"2.2")
4443
				ReqdOSPatch="101122-07";;
4444
			"2.3")
4445
				ReqdOSPatch="101331-06";;
4446
			"2.4")
4447
				MgrPlatform=$(uname -p);
4448
				case $MgrPlatform in
4449
					"sparc")
4450
						ReqdOSPatch="102039-04";;
4451
					"i386")
4452
						ReqdOSPatch="102041-04";;
4453
				esac;;
4454
		esac
4455
 
4456
		if [[ "$ReqdOSPatch" != "none" ]]
4457
		then
4458
			get_base_code $ReqdOSPatch
4459
			ReqdOSPatchBase=$cur_base_code;
4460
 
4461
			get_vers_no $ReqdOSPatch $cur_base_code
4462
			ReqdOSPatchVers=$cur_vers_no;
4463
 
4464
			for apatch in *
4465
			do
4466
				get_base_code $apatch
4467
				if [[ "$ReqdOSPatchBase" = "$cur_base_code" ]]
4468
				then
4469
					get_vers_no $apatch $cur_base_code
4470
					if [[ "$ReqdOSPatchVers" -le "$cur_vers_no" ]]
4471
					then
4472
						ReqdOSPatchFnd="true"
4473
					fi
4474
				fi
4475
			done
4476
		fi
4477
	fi
4478
 
4479
	cd $patchdir
4480
}
4481
 
4482
# Description:
4483
#	Evaluate the patch provided and return the patch type.
4484
# Parameters:
4485
#	$1 - patch directory
4486
# Globals Set:
4487
#	PatchType	one of:
4488
#				diPatch		direct instance patch
4489
#				caPatch		cross architecture patch
4490
#				piPatch		progressive instance patch
4491
#
4492
function eval_patch {
4493
	if [[ -f ${1}/.diPatch ]]
4494
	then
4495
		if [[ -d ${1}/old_style_patch ]]
4496
		then
4497
			PatchType="caPatch"
4498
		else
4499
			PatchType="diPatch"
4500
		fi
4501
	else
4502
		PatchType="piPatch"
4503
	fi
4504
}
4505
 
4506
# Description:
4507
#   Evaluate the patch methodology to be used based upon the
4508
#	Solaris version of the manager and target hosts.
4509
# Parameters:
4510
#	$1	Managing host OS version
4511
#	$2	Target host OS version
4512
#	$3	patch type
4513
# Globals Set:
4514
#	PatchMethod	one of:
4515
#				direct		direct instance method
4516
#				progressive	progressive instance method
4517
#	PATCH_PROGRESSIVE
4518
#
4519
function eval_OS_version {
4520
    if [[ "$1" > "2.5" ]]
4521
    then
4522
        if [[ "$2" < "2.5" ]]
4523
        then
4524
            PatchMethod="progressive"
4525
            PATCH_PROGRESSIVE="true"
4526
        else
4527
            if [[ $3 = "diPatch" || $3 = "caPatch" ]]
4528
            then
4529
                PatchMethod="direct"
4530
                PATCH_PROGRESSIVE="false"
4531
				if [[ "$1" > "2.5.1" ]]
4532
				then
4533
					DRYRUN="yes"
4534
				fi
4535
			else
4536
				PatchMethod="progressive"
4537
				PATCH_PROGRESSIVE="true"
4538
            fi
4539
        fi
4540
 
4541
	elif [[ "$1" < "2.5" ]]
4542
	then
4543
		if [[ "$2" < "2.5" ]]
4544
		then
4545
			PatchMethod="progressive"
4546
			PATCH_PROGRESSIVE="true"
4547
		else
4548
			if [[ $3 = "diPatch" || $3 = "caPatch" ]]
4549
			then
4550
				PatchMethod="direct"
4551
				PATCH_PROGRESSIVE="false"
4552
			else
4553
				PatchMethod="progressive"
4554
				PATCH_PROGRESSIVE="true"
4555
			fi
4556
		fi
4557
	else
4558
		if [[ "$2" < "2.5" ]]
4559
		then
4560
			if [[ $PatchType = "diPatch" ]]
4561
			then
4562
				/usr/bin/gettext "ERROR: This direct instance patch cannot be installed\nonto a Solaris $TrgOSVers host.\n"
4563
				patch_quit 21 "yes"
4564
			else
4565
				PatchMethod="progressive"
4566
				PATCH_PROGRESSIVE="true"
4567
			fi
4568
		else
4569
			if [[ $3 = "diPatch" || $3 = "caPatch" ]]
4570
			then
4571
				PatchMethod="direct"
4572
				PATCH_PROGRESSIVE="false"
4573
				if [[ "$2" > "2.5.1" ]]
4574
				then
4575
					DRYRUN="yes"
4576
				fi
4577
			else
4578
				PatchMethod="progressive"
4579
				PATCH_PROGRESSIVE="true"
4580
			fi
4581
		fi
4582
	fi
4583
}
4584
 
4585
# Description:
4586
#       Evaluate the applied patch to be sure we aren't going to hose up 
4587
#	any existing backout data.
4588
#
4589
#	If this is a progressive instance patch, here's how it is evaluated:
4590
# prev  | curr | .nofilestosave |   OK to   |  How to verify previous
4591
# save  | save |    exist?      | continue? |    save/no_save state
4592
#-------+------+----------------+-----------+--------------------------
4593
#       |      |      yes       |           | a. empty save directory
4594
# 1 yes | yes  |----------------| continue  +--------------------------
4595
#       |      |       no       |           | b. ! empty save directory
4596
#-------+------+----------------+-----------+--------------------------
4597
#       |      |      yes       | continue  | a. empty save directory
4598
# 2 yes |  no  |----------------+-----------+--------------------------
4599
#       |      |       no       | terminate | b. ! empty save directory
4600
#-------+------+----------------+-----------+--------------------------
4601
# 3  no |  no  |       no       | continue  |    empty save directory
4602
#-------+------+----------------+-----------+--------------------------
4603
# 4  no | yes  |       no       | terminate |    empty save directory
4604
#-------+------+----------------+-----------+--------------------------
4605
#
4606
#	And the direct instance patch is evaluated as follows:
4607
#  prev  | curr |   OK to   |  How to verify previous
4608
#  save  | save | continue? |    save/no_save state
4609
# -------+------+-----------+------------------------------------------
4610
# A.  no | yes  | terminate | ! -d /var/sadm/pkg/<pkg>/save/<patch_id>
4611
# -------+------+-----------+------------------------------------------
4612
# B.  no |  no  | continue  | ! -f /var/sadm/pkg/<pkg>/save/<patch_id>
4613
# -------+------+-----------+------------------------------------------
4614
# C. yes |  --  | continue  |   -f /var/sadm/pkg/<pkg>/save/<patch_id>
4615
# -------+------+-----------+------------------------------------------
4616
#
4617
# Parameters:
4618
#	$1	patch database directory
4619
#	$2	package database directory
4620
#	$3	the patch method
4621
#	$4	the saveold parameter value
4622
#	$5	the patch number
4623
# Globals Set:
4624
#
4625
function eval_applied_patch { 
4626
	if [[ "$3" = "progressive" ]]
4627
	then
4628
		if [[ "${4}" = "no" ]]
4629
		then
4630
			if [ ! -f "${1}/${5}/.nofilestosave" -a \
4631
			    \( -f "${1}/${5}/save/archive.cpio" -o \
4632
			    -f "${1}/${5}/save/archive.cpio.Z" \) ]
4633
	       		then
4634
				# condition #2b - terminate
4635
				/usr/bin/gettext "A previous installation of patch ${5} was invoked which saved\nfiles that were to be patched.\nSince files have already been saved, you must apply this patch\nWITHOUT the -d option.\n"
4636
				patch_quit 17 "no"
4637
				return 0
4638
			elif [ -f "${1}/${5}/.nofilestosave" -a \
4639
			    ! -f "${1}/${5}/save/archive.cpio" -a \
4640
			    ! -f "${1}/${5}/save/archive.cpio.Z" -a \
4641
			    ! -f "${1}/${5}/save/remote" ]
4642
			then
4643
				# condition #2a - $RM .nofilestosave
4644
				$RM ${1}/${5}/.nofilestosave
4645
			fi
4646
		else	# ${4} = "yes"
4647
			if [ ! -f "${1}/${5}/.nofilestosave"    -a \
4648
			    ! -f "${1}/${5}/save/archive.cpio" -a \
4649
			    ! -f "${1}/${5}/save/archive.cpio.Z" -a \
4650
			    ! -f "${1}/${5}/save/remote" ]
4651
			then
4652
				# condition #4 - terminate
4653
				/usr/bin/gettext "A previous installation of patch ${5} was invoked with the -d option.\ni.e. Do not save files that would be patched\nTherefore, this invocation of patchadd\nmust also be run with the -d option.\n"
4654
				patch_quit 17 "no"
4655
				return 0
4656
			fi
4657
		fi
4658
	else	# $3 != "progressive"
4659
		$FIND ${2}/. -name "${5}" -print >/dev/null 2>&1
4660
		prev_save=$?
4661
		if [[ $prev_save != 0 && "${4}" = "yes" ]]
4662
		then
4663
			# condition A.
4664
			/usr/bin/gettext "A previous installation of patch ${5} was invoked\nwith the -d option. i.e. Do not save files that would be patched\nTherefore, this invocation of patchadd\nmust also be run with the -d option.\n"
4665
			patch_quit 17 "no"
4666
			return 0
4667
		fi
4668
	fi
4669
	return 1
4670
}
4671
 
4672
function eval_utilities {
4673
	for command in $REQD_CMDS; do
4674
		if [[ ! -f $command ]]
4675
		then
4676
			/usr/bin/gettext "ERROR: Cannot find $command which is required for proper execution of patchadd.\n"
4677
			patch_quit 1 "yes"
4678
		fi
4679
	done		
4680
}
4681
 
4682
# Description:
4683
#       Check the remote file to see if the remotely stored backout data
4684
#	location needs to be changed.
4685
# Parameters:
4686
#       $1      - package associated with the patch
4687
#       $2      - the patch number
4688
#
4689
# Environment Variable Set:
4690
#
4691
function check_remote_file
4692
{
4693
	if [[ "$PatchMethod" = "direct" ]]
4694
	then
4695
		if [[ -f $PKGDB/$1/save/$2/remote && -s $PKGDB/$1/save/$2/remote ]]
4696
		then
4697
			PATCH_UNDO_ARCHIVE=$($GREP "FIND_AT" $PKGDB/$1/save/$2/remote \
4698
			  | $AWK -F= '{print $2}')
4699
			PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)
4700
		fi
4701
	else
4702
		# Add logic for pi patches
4703
		echo $PATCH_UNDO_ARCHIVE > /dev/null
4704
	fi
4705
}
4706
 
4707
# Description:
4708
#       Change the STATE parameter to an obsolete state
4709
# Parameters:
4710
#       $1      - package associated with the patch
4711
#       $2      - the patch number
4712
#
4713
# Environment Variable Set:
4714
#	none
4715
 
4716
function set_remote_state
4717
{
4718
        $($GREP . $PKGDB/$1/save/$2/remote | $SED 's/STATE=.*/STATE=obsolete/' > $TEMP_REMOTE)
4719
        $RM -f $PKGDB/$1/save/$2/remote
4720
        $MV $TEMP_REMOTE $PKGDB/$1/save/$2/remote
4721
        $RM -f $TEMP_REMOTE
4722
 
4723
}
4724
 
4725
# Description:
4726
#       Determine if the patch is a progressive instance patch
4727
# Parameters:
4728
#	none
4729
#
4730
# Environment Variable Set:
4731
#	none 
4732
 
4733
function is_progressive
4734
{
4735
	if [[ "$PatchMethod" = "progressive" ]]
4736
	then
4737
		echo $PatchNum | $GREP $PatchIdFormat >/dev/null
4738
		if [[ $? -ne 0 ]]
4739
		then
4740
			/usr/bin/gettext "Invalid patch id format: $PatchNum.\n"
4741
			patch_quit 29 "no"
4742
			return 0
4743
		fi
4744
		if [[ "$PatchType" = "diPatch" ]]
4745
		then
4746
			/usr/bin/gettext "ERROR:  A progressive instance patch is required\nbut patch number $PatchNum is direct instance only\nand can only be installed onto a host running Solaris 2.5 or later.\n"
4747
			patch_quit 22 "no"
4748
			return 0
4749
		elif [[ "$PatchType" = "caPatch" ]]
4750
		then
4751
			cd old_style_patch
4752
			patchdir=$(pwd)
4753
		fi
4754
	fi
4755
	return 1
4756
}
4757
 
4758
# Description:
4759
#       Display error messages if the patch being applied conflicts with incompatible,
4760
#	required or obsolete patches.
4761
# Parameters:
4762
#	none
4763
#
4764
# Environment Variable Set:
4765
#       none
4766
 
4767
function check_patch_compatibility
4768
{
4769
	if [[ "$InstIncompat" != "" ]]
4770
	then
4771
     	/usr/bin/gettext "ERROR: This patch is incompatible with patch $InstIncompat\nwhich has already been applied to the system.\n"
4772
       	patch_quit 24 "no"
4773
		return 0
4774
	fi
4775
 
4776
	if (( ReqdPatchCnt == 1 ))
4777
	then
4778
       	/usr/bin/gettext "ERROR: This patch requires patch $UninstReqs\nwhich has not been applied to the system.\n"
4779
       	patch_quit 25 "no"
4780
		return 0
4781
	elif (( ReqdPatchCnt > 1 ))
4782
	then
4783
       	/usr/bin/gettext "ERROR: This patch requires the following patches\nwhich have not been applied to the system:\n"
4784
       	echo "    $UninstReqs"
4785
       	patch_quit 25 "no"
4786
		return 0
4787
	fi
4788
 
4789
	if [[ "$ObsoletePast" != "" ]]
4790
	then
4791
       	/usr/bin/gettext "WARNING: This patch appears to have been produced after the\nbase code $ObsoletePast was obsoleted. This patch will be treated\nas though it were also obsoleted.\n"
4792
	fi
4793
 
4794
	if [[ "$ReqdOSPatch" != "none" && "$ReqdOSPatchFnd" != "true" ]]
4795
	then
4796
       	/usr/bin/gettext "ERROR: This Solaris $MgrOSVers server requires the following patch before it\ncan apply a patch to a Solaris $TrgOSVers client.\n    patch base number : $ReqdOSPatchBase\n    patch version number : $ReqdOSPatchVers or higher.\n"
4797
       	patch_quit 21 "yes"
4798
	fi
4799
	return 1
4800
} 
4801
 
4802
############################################
4803
#		Main Routine		   #
4804
############################################
4805
 
4806
#
4807
# -	Get the product version <name>_<version> of local Solaris
4808
#	installation (sets the prodver global variable)
4809
# -	Parse the argument list and set globals accordingly
4810
# -	Make sure the user is running as 'root'
4811
#
4812
 
4813
CmdArgs=$*
4814
 
4815
set_globals
4816
 
4817
validate_uid	# the caller must be "root"
4818
 
4819
parse_args $CmdArgs
4820
 
4821
check_for_2_6	# Needed in case usr/sbin is nfs mounted
4822
 
4823
setup_net_image
4824
 
4825
check_PatchDBs
4826
 
4827
# determine the OS versions involved
4828
find_softinfos $ROOTDIR
4829
get_OS_version $TRGSOFTINFO $MGRSOFTINFO $ROOTDIR
4830
 
4831
eval_utilities		# make sure the required utilities are available
4832
 
4833
# If we're in the mini-root, invoke pkgadd with -M
4834
# or if the managing host is 2.6 or later.
4835
check_pkgadd_M_option
4836
 
4837
for ptch in $multiPtchList
4838
do
4839
	set_globals
4840
	if [[ "$multiPtchInstall" = "yes" ]]
4841
	then
4842
		patchdir="$multiPtchDir/$ptch"
4843
	fi
4844
 
4845
	eval_patch $patchdir	# determine what type of patch it is
4846
 
4847
	# Establish the patching options based on the versions involved
4848
	eval_OS_version $MgrOSVers $TrgOSVers $PatchType
4849
 
4850
	# Clear the list of installed patches, if it's there
4851
	$RM -f $INSTPATCHES_FILE
4852
 
4853
	if activate_patch "$patchdir"
4854
	then
4855
		continue
4856
	fi
4857
 
4858
	# Hopefully there won't be many patches that contain this script.
4859
	# This could have dier consequences.
4860
	if execute_prePatch "$patchdir" "$ROOTDIR"	# do it
4861
	then
4862
		continue
4863
	fi
4864
 
4865
	#
4866
	# Change to the patch directory and set globals according to the patchID
4867
	# found in the pkginfo files of the patch packages.
4868
	#
4869
	collect_data
4870
 
4871
	# Check to see if there are any remains from a previous installation.
4872
	check_file_recovery_dir
4873
 
4874
	if is_progressive
4875
	then
4876
		continue
4877
	fi
4878
 
4879
	ident_reqd_patch $MgrOSVers	# determine if this host needs a patch
4880
 
4881
	# Check the output from the pkginfo command.
4882
	# See if there are any corrupt pkginfo files...
4883
	#chk_pkginfo_cmd
4884
 
4885
	if [[ "$PatchMethod" = "direct" ]]
4886
	then
4887
		/usr/bin/gettext "Checking installed patches...\n"
4888
	fi
4889
 
4890
	eval_inst_patches $PKGDB > /dev/null 2>&1	# Scan installed patches & analyze.
4891
 
4892
	check_if_applied "$PATCHDB" "$PatchNum"
4893
 
4894
	if [[ "$isapplied" = "yes" ]]
4895
	then
4896
		if eval_applied_patch $PATCHDB $PKGDB $PatchMethod $saveold $PatchNum 
4897
		then
4898
			continue
4899
		fi
4900
	fi
4901
 
4902
	# Evaluate the compatibility of REQUIRES INCOMPATS and
4903
	# OBSOLETES.
4904
	eval_compats
4905
 
4906
	if check_if_obsolete "$PATCHDB"	# see if this package is already obsolete
4907
	then
4908
		continue
4909
	fi
4910
 
4911
	# For the old-style patch, there were sometimes problems running on a
4912
	# client and also symbolic links were not allowed. We check for those next.
4913
	if [[ "$PatchMethod" = "progressive" ]]
4914
	then
4915
		verify_client
4916
		if check_for_symbolic_link "$patchdir"
4917
		then
4918
			continue
4919
		fi
4920
	fi
4921
 
4922
	trap 'trap_notinstalled "$PATCHDB" "$PatchNum"' 1 2 3 15	# set the trap
4923
 
4924
	build_admin_file
4925
 
4926
	gen_patchpkg_list
4927
 
4928
	# If this is a re-installation of the patch, remove the already
4929
	# installed packages from the package list. If all packages in 
4930
	# the patch have already been applied, then exit.
4931
	#
4932
	if [[ "$isapplied" = "yes" ]]; then
4933
		if gen_uninstalled_pkgs $PKGDB $PATCHDB $PatchNum
4934
		then
4935
			continue
4936
		fi
4937
	fi
4938
 
4939
	check_pkgs_installed "$PKGDB" "$patchdir"
4940
 
4941
	if check_for_action "$client" "$is_a_root_pkg" 
4942
	then
4943
		continue
4944
	fi
4945
 
4946
	if check_patch_compatibility
4947
	then
4948
		continue
4949
	fi
4950
 
4951
	# Set flag in case of power outage
4952
	file_recovery 		
4953
 
4954
	# Construct the required response file
4955
	build_response_file $PatchType $PatchMethod
4956
 
4957
	make_params_available   # export parameters for use by patch scripts
4958
 
4959
	# If there is a prepatch file in the $patchdir directory,
4960
	# execute it. If the return code is not 0, exit patchadd
4961
	# with an error. Lord knows what this does. We just have to hope
4962
	# it's benign.
4963
	#
4964
	if [[ "$isapplied" = "no" ]]	# if this isn't a reinstallation
4965
	then
4966
		if execute_prepatch "$patchdir"	# do it
4967
		then
4968
			continue
4969
		fi
4970
	fi
4971
 
4972
	gen_install_filelist "$PKGDB" "$PKGDBARG"
4973
 
4974
	#
4975
	# OK, which patch method are we using?
4976
	#
4977
	if [[ "$PatchMethod" = "direct" ]]
4978
	then
4979
		#
4980
		# This is how we install a direct instance patch
4981
		#
4982
		gen_patch_filelist
4983
 
4984
		compute_fs_space_requirements 
4985
 
4986
		if check_fs_space
4987
		then
4988
			continue
4989
		fi
4990
 
4991
		if check_backout_space "$PKGDB" "$PatchNum" "$patchdir" "$saveold"
4992
		then
4993
			continue
4994
		fi
4995
 
4996
		if apply_diPatch
4997
		then
4998
			continue
4999
		fi
5000
 
5001
	else	
5002
		if check_validation "$validate"
5003
		then
5004
			continue
5005
		fi
5006
 
5007
		gen_patch_filelist
5008
 
5009
		compute_fs_space_requirements 
5010
 
5011
		if check_fs_space
5012
		then
5013
			continue
5014
		fi
5015
 
5016
		create_archive_area "$PATCHDB" "$PatchNum"
5017
 
5018
		if check_backout_space "$PATCHDB" "$PatchNum" "$patchdir" "$saveold"
5019
		then
5020
			continue
5021
		fi
5022
 
5023
		trap 'trap_backoutsaved "$PATCHDB" "$PatchNum" "$patchdir"' 1 2 3 15
5024
 
5025
		# -	Save current versions of files to be patched
5026
		# -	On servers, spool the patch into /export/root/templates for
5027
		#	future clients (CURRENTLY DISABLED)
5028
		# -	Build admin file for later use by pkgadd
5029
		if save_overwritten_files "$PATCHDB" "$PatchNum" "$patchdir" "$saveold"
5030
		then
5031
			continue
5032
		fi
5033
 
5034
		trap 'trap_backout "$patchdir" "$PatchNum"' 1 2 3 15
5035
 
5036
		# -	Install the patch packages
5037
		# -	Print results of install
5038
		# -	Save ACTION file if exists and README file.
5039
		if install_patch_pkgs "$PATCHDB" "$PatchNum" "$patchdir" \
5040
		  "$PKGDBARG" "$PKGDB"
5041
		then
5042
			continue
5043
		fi
5044
	fi
5045
 
5046
	if execute_postpatch "$PATCHDB" "$PatchNum" "$patchdir"
5047
	then
5048
		continue
5049
	fi
5050
 
5051
	update_patchDB "$PatchNum"
5052
 
5053
	print_results
5054
 
5055
	if [[ "$PatchMethod" = "progressive" ]]
5056
	then
5057
		/usr/bin/gettext "\nPatch installation completed.\n"
5058
		/usr/bin/gettext "See $PATCHDB/$PatchNum/log for more details.\n\n"
5059
	fi
5060
 
5061
	set_patch_status "$PATCHDB" "$PatchNum"
5062
 
5063
	remove_files
5064
done
5065
patch_quit 0 "yes"