summaryrefslogblamecommitdiffstats
path: root/prebuilt/fix_permissions.sh
blob: f2c8e2ac4b69a1b436340101aa5d72d6c5bb8fba (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476



























































































































































































































































































































































































































































































                                                                                                                                                                            
#!/sbin/sh
#
# Warning: if you want to run this script in cm-recovery change the above to #!/sbin/sh
#
# fix_permissions - fixes permissions on Android data directories after upgrade
# shade@chemlab.org
#
# original concept: http://blog.elsdoerfer.name/2009/05/25/android-fix-package-uid-mismatches/
# implementation by: Cyanogen
# improved by: ankn, smeat, thenefield, farmatito, rikupw, Kastro
#
# v1.1-v1.31r3 - many improvements and concepts from XDA developers.
# v1.34 through v2.00 -  A lot of frustration [by Kastro]
# v2.01	- Completely rewrote the script for SPEED, thanks for the input farmatito
#         /data/data depth recursion is tweaked;
#         fixed single mode;
#         functions created for modularity;
#         logging can be disabled via CLI for more speed; 
#         runtime computation added to end (Runtime: mins secs); 
#         progress (current # of total) added to screen;
#         fixed CLI argument parsing, now you can have more than one option!;
#         debug cli option;
#         verbosity can be disabled via CLI option for less noise;;
#         [by Kastro, (XDA: k4str0), twitter;mattcarver]
# v2.02 - ignore com.htc.resources.apk if it exists and minor code cleanups,
#         fix help text, implement simulated run (-s) [farmatito]
# v2.03 - fixed chown group ownership output [Kastro]

VERSION="2.03"

# Defaults
DEBUG=0 # Debug off by default
LOGGING=0 # Logging on by default
VERBOSE=0 # Verbose on by default

# Messages
UID_MSG="Changing user ownership for:"
GID_MSG="Changing group ownership for:"
PERM_MSG="Changing permissions for:"

# Programs needed
ECHO="busybox echo"
GREP="busybox grep"
EGREP="busybox egrep"
CAT="busybox cat"
CHOWN="busybox chown"
CHMOD="busybox chmod"
MOUNT="busybox mount"
UMOUNT="busybox umount"
CUT="busybox cut"
FIND="busybox find"
LS="busybox ls"
TR="busybox tr"
TEE="busybox tee"
TEST="busybox test"
SED="busybox sed"
RM="busybox rm"
WC="busybox wc"
EXPR="busybox expr"
DATE="busybox date"

# Initialise vars
CODEPATH=""
UID=""
GID=""
PACKAGE=""
REMOVE=0
NOSYSTEM=0
ONLY_ONE=""
SIMULATE=0
SYSREMOUNT=0
SYSMOUNT=0
DATAMOUNT=0
SYSSDMOUNT=0
FP_STARTTIME=$( $DATE +"%m-%d-%Y %H:%M:%S" )
FP_STARTEPOCH=$( $DATE +%s )

fp_usage()
{
	$ECHO "Usage $0 [OPTIONS] [APK_PATH]"
	$ECHO "      -d         turn on debug"
	$ECHO "      -f         fix only package APK_PATH"	
	$ECHO "      -l         disable logging for this run (faster)"
	$ECHO "      -r         remove stale data directories"
	$ECHO "                 of uninstalled packages while fixing permissions"
	$ECHO "      -s         simulate only"
	$ECHO "      -u         check only non-system directories"
	$ECHO "      -v         disable verbosity for this run (less output)"
	$ECHO "      -V         print version"
	$ECHO "      -h         this help"
}

fp_parseargs()
{
	# Parse options
	while $TEST $# -ne 0; do
		case "$1" in
			-d)
				DEBUG=1
			;;
			-f)
				if $TEST $# -lt 2; then
					$ECHO "$0: missing argument for option $1"
					exit 1
				else
					if $TEST $( $ECHO $2 | $CUT -c1 ) != "-"; then
						ONLY_ONE=$2
						shift;
					else
						$ECHO "$0: missing argument for option $1"
						exit 1
					fi
				fi
			;;
			-r)
				REMOVE=1
			;;
			-s)
				SIMULATE=1
			;;
			-l)
				if $TEST $LOGGING -eq 0; then
					LOGGING=1
				else
					LOGGING=0
				fi
			;;
			-v)
				if $TEST $VERBOSE -eq 0; then
					VERBOSE=1
				else
					VERBOSE=0
				fi
			;;
			-u)
				NOSYSTEM=1
			;;
			-V)
				$ECHO "$0 $VERSION"
				exit 0
			;;
			-h)
				fp_usage
				exit 0
			;;
			-*)
				$ECHO "$0: unknown option $1"
				$ECHO
				fp_usage
				exit 1
			;;
		esac
		shift;
	done
}

fp_print()
{
	MSG=$@
	if $TEST $LOGGING -eq 1; then
		$ECHO $MSG | $TEE -a $LOG_FILE
	else
		$ECHO $MSG
	fi
}

fp_start()
{
	if $TEST $SIMULATE -eq 0 ; then
		if $TEST $( $GREP -c " /system " "/proc/mounts" ) -ne 0; then
			DEVICE=$( $GREP " /system " "/proc/mounts" | $CUT -d ' ' -f1 )
			if $TEST $DEBUG -eq 1; then
				fp_print "/system mounted on $DEVICE"
			fi
			if $TEST $( $GREP " /system " "/proc/mounts" | $GREP -c " ro " ) -ne 0; then
				$MOUNT -o remount,rw $DEVICE /system
				SYSREMOUNT=1
			fi
		else
			$MOUNT /system > /dev/null 2>&1
			SYSMOUNT=1
		fi
	
		if $TEST $( $GREP -c " /data " "/proc/mounts" ) -eq 0; then
			$MOUNT /data > /dev/null 2>&1
			DATAMOUNT=1
		fi
	
		if $TEST -e /dev/block/mmcblk0p2 && $TEST $( $GREP -c " /sd-ext " "/proc/mounts" ) -eq 0; then
				$MOUNT /sd-ext > /dev/null 2>&1
			SYSSDMOUNT=1
		fi
	fi	
	if $TEST $( $MOUNT | $GREP -c /sdcard ) -eq 0; then
		LOG_FILE="/data/fix_permissions.log"
	else
		LOG_FILE="/sdcard/fix_permissions.log"
	fi
	if $TEST ! -e "$LOG_FILE"; then
		> $LOG_FILE
	fi

	fp_print "$0 $VERSION started at $FP_STARTTIME"
}

fp_chown_uid()
{
	FP_OLDUID=$1
	FP_UID=$2
	FP_FILE=$3
	
	#if user ownership doesn't equal then change them
	if $TEST "$FP_OLDUID" != "$FP_UID"; then
		if $TEST $VERBOSE -ne 0; then
			fp_print "$UID_MSG $FP_FILE from '$FP_OLDUID' to '$FP_UID'"
		fi
		if $TEST $SIMULATE -eq 0; then
			$CHOWN $FP_UID "$FP_FILE"
		fi
	fi
}

fp_chown_gid()
{
	FP_OLDGID=$1
	FP_GID=$2
	FP_FILE=$3
	
	#if group ownership doesn't equal then change them
	if $TEST "$FP_OLDGID" != "$FP_GID"; then
		if $TEST $VERBOSE -ne 0; then
			fp_print "$GID_MSG $FP_FILE from '$FP_OLDGID' to '$FP_GID'"
		fi
		if $TEST $SIMULATE -eq 0; then
			$CHOWN :$FP_GID "$FP_FILE"
		fi
	fi
}

fp_chmod()
{
	FP_OLDPER=$1
	FP_OLDPER=$( $ECHO $FP_OLDPER | cut -c2-10 )
	FP_PERSTR=$2
	FP_PERNUM=$3
	FP_FILE=$4
	
	#if the permissions are not equal
	if $TEST "$FP_OLDPER" != "$FP_PERSTR"; then
		if $TEST $VERBOSE -ne 0; then
			fp_print "$PERM_MSG $FP_FILE from '$FP_OLDPER' to '$FP_PERSTR' ($FP_PERNUM)"
		fi
		#change the permissions
		if $TEST $SIMULATE -eq 0; then	
			$CHMOD $FP_PERNUM "$FP_FILE"
		fi
	fi
}
  
fp_all()
{
	FP_NUMS=$( $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | $WC -l )
	I=0
	$CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | while read all_line; do
		I=$( $EXPR $I + 1 )
		fp_package "$all_line" $I $FP_NUMS
	done
}

fp_single()
{
	FP_SFOUND=$( $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | $GREP -i $ONLY_ONE | wc -l )
	if $TEST $FP_SFOUND -gt 1; then
		fp_print "Cannot perform single operation on $FP_SFOUND matched package(s)."
	elif $TEST $FP_SFOUND = "" -o $FP_SFOUND -eq 0; then
		fp_print "Could not find the package you specified in the packages.xml file."
	else
		FP_SPKG=$( $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | $GREP -i $ONLY_ONE )
		fp_package "${FP_SPKG}" 1 1
	fi
}

fp_package()
{
	pkgline=$1
	curnum=$2
	endnum=$3
	CODEPATH=$( $ECHO $pkgline | $SED 's%.* codePath="\(.*\)".*%\1%' |  $CUT -d '"' -f1 )
	PACKAGE=$( $ECHO $pkgline | $SED 's%.* name="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
	UID=$( $ECHO $pkgline | $SED 's%.*serId="\(.*\)".*%\1%' |  $CUT -d '"' -f1 )
	GID=$UID
	APPDIR=$( $ECHO $CODEPATH | $SED 's%^\(.*\)/.*%\1%' )
	APK=$( $ECHO $CODEPATH | $SED 's%^.*/\(.*\..*\)$%\1%' )
	
	#debug
	if $TEST $DEBUG -eq 1; then
		fp_print "CODEPATH: $CODEPATH APPDIR: $APPDIR APK:$APK UID/GID:$UID:$GID"
	fi
	
	#check for existence of apk
	if $TEST -e $CODEPATH;  then
		fp_print "Processing ($curnum of $endnum): $PACKAGE..."
		
		#lets get existing permissions of CODEPATH
		OLD_UGD=$( $LS -ln "$CODEPATH" )
		OLD_PER=$( $ECHO $OLD_UGD | $CUT -d ' ' -f1 )
		OLD_UID=$( $ECHO $OLD_UGD | $CUT -d ' ' -f3 )
		OLD_GID=$( $ECHO $OLD_UGD | $CUT -d ' ' -f4 )
		
		#apk source dirs
		if $TEST "$APPDIR" = "/system/app"; then
			#skip system apps if set
			if $TEST "$NOSYSTEM" = "1"; then
				fp_print "***SKIPPING SYSTEM APP ($PACKAGE)!"
				return
			fi
			fp_chown_uid $OLD_UID 0 "$CODEPATH"
			fp_chown_gid $OLD_GID 0 "$CODEPATH"
			fp_chmod $OLD_PER "rw-r--r--" 644 "$CODEPATH"
		elif $TEST "$APPDIR" = "/data/app"; then
			fp_chown_uid $OLD_UID 1000 "$CODEPATH"
			fp_chown_gid $OLD_GID 1000 "$CODEPATH"
			fp_chmod $OLD_PER "rw-r--r--" 644 "$CODEPATH"
		elif $TEST "$APPDIR" = "/data/app-private"; then
			fp_chown_uid $OLD_UID 1000 "$CODEPATH"
			fp_chown_gid $OLD_GID $GID "$CODEPATH"
			fp_chmod $OLD_PER "rw-r-----" 640 "$CODEPATH"
		fi
	else
		fp_print "$CODEPATH does not exist ($curnum of $endnum). Reinstall..."
		if $TEST $REMOVE -eq 1; then
			if $TEST -d /data/data/$PACKAGE ; then
				fp_print "Removing stale dir /data/data/$PACKAGE"
				if $TEST $SIMULATE -eq 0 ; then
					$RM -R /data/data/$PACKAGE
				fi
			fi
		fi
	fi
		
	#the data/data for the package
	if $TEST -d "/data/data/$PACKAGE"; then   
		#find all directories in /data/data/$PACKAGE
		$FIND /data/data/$PACKAGE -type d -exec $LS -ldn {} \; | while read dataline; do
			#get existing permissions of that directory
			OLD_PER=$( $ECHO $dataline | $CUT -d ' ' -f1 )
			OLD_UID=$( $ECHO $dataline | $CUT -d ' ' -f3 )
			OLD_GID=$( $ECHO $dataline | $CUT -d ' ' -f4 )
			FILEDIR=$( $ECHO $dataline | $CUT -d ' ' -f9 )
			FOURDIR=$( $ECHO $FILEDIR | $CUT -d '/' -f5 )
			
			#set defaults for iteration
			ISLIB=0
			REVPERM=755
			REVPSTR="rwxr-xr-x"
			REVUID=$UID
			REVGID=$GID
				
			if $TEST "$FOURDIR" = ""; then
				#package directory, perms:755 owner:$UID:$GID
				fp_chmod $OLD_PER "rwxr-xr-x" 755 "$FILEDIR"
			elif $TEST "$FOURDIR" = "lib"; then
				#lib directory, perms:755 owner:1000:1000
				#lib files, perms:755 owner:1000:1000
				ISLIB=1
				REVPERM=755
				REVPSTR="rwxr-xr-x"
				REVUID=1000
				REVGID=1000
				fp_chmod $OLD_PER "rwxr-xr-x" 755 "$FILEDIR"
			elif $TEST "$FOURDIR" = "shared_prefs"; then
				#shared_prefs directories, perms:771 owner:$UID:$GID
				#shared_prefs files, perms:660 owner:$UID:$GID
				REVPERM=660
				REVPSTR="rw-rw----"
				fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
			elif $TEST "$FOURDIR" = "databases"; then
				#databases directories, perms:771 owner:$UID:$GID
				#databases files, perms:660 owner:$UID:$GID
				REVPERM=660
				REVPSTR="rw-rw----"
				fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
			elif $TEST "$FOURDIR" = "cache"; then
				#cache directories, perms:771 owner:$UID:$GID
				#cache files, perms:600 owner:$UID:GID
				REVPERM=600
				REVPSTR="rw-------"
				fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
			else
				#other directories, perms:771 owner:$UID:$GID     
				REVPERM=771
				REVPSTR="rwxrwx--x"
				fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
			fi
			
			#change ownership of directories matched
			if $TEST "$ISLIB" = "1"; then
				fp_chown_uid $OLD_UID 1000 "$FILEDIR"
				fp_chown_gid $OLD_GID 1000 "$FILEDIR"
			else
				fp_chown_uid $OLD_UID $UID "$FILEDIR"
				fp_chown_gid $OLD_GID $GID "$FILEDIR"
			fi
			
			#if any files exist in directory with improper permissions reset them
			$FIND $FILEDIR -type f -maxdepth 1 ! -perm $REVPERM -exec $LS -ln {} \; | while read subline; do
				OLD_PER=$( $ECHO $subline | $CUT -d ' ' -f1 )
				SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
				fp_chmod $OLD_PER $REVPSTR $REVPERM "$SUBFILE"
			done
			
			#if any files exist in directory with improper user reset them
			$FIND $FILEDIR -type f -maxdepth 1 ! -user $REVUID -exec $LS -ln {} \; | while read subline; do
				OLD_UID=$( $ECHO $subline | $CUT -d ' ' -f3 )
				SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
				fp_chown_uid $OLD_UID $REVUID "$SUBFILE"
			done
			
			#if any files exist in directory with improper group reset them
			$FIND $FILEDIR -type f -maxdepth 1 ! -group $REVGID -exec $LS -ln {} \; | while read subline; do
				OLD_GID=$( $ECHO $subline | $CUT -d ' ' -f4 )
				SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
				fp_chown_gid $OLD_GID $REVGID "$SUBFILE"
			done
		done
	fi
}

date_diff()
{
	if $TEST $# -ne 2; then
		FP_DDM="E"
		FP_DDS="E"
		return
	fi
	FP_DDD=$( $EXPR $2 - $1 )
	FP_DDM=$( $EXPR $FP_DDD / 60 )
	FP_DDS=$( $EXPR $FP_DDD % 60 )
}

fp_end()
{
	if $TEST $SYSREMOUNT -eq 1; then
		$MOUNT -o remount,ro $DEVICE /system > /dev/null 2>&1
	fi
	
	if $TEST $SYSSDMOUNT -eq 1; then
		$UMOUNT /sd-ext > /dev/null 2>&1
	fi
	
	if $TEST $SYSMOUNT -eq 1; then
		$UMOUNT /system > /dev/null 2>&1
	fi
	
	if $TEST $DATAMOUNT -eq 1; then
		$UMOUNT /data > /dev/null 2>&1
	fi
	
	FP_ENDTIME=$( $DATE +"%m-%d-%Y %H:%M:%S" )
	FP_ENDEPOCH=$( $DATE +%s )
	
	date_diff $FP_STARTEPOCH $FP_ENDEPOCH
	
	fp_print "$0 $VERSION ended at $FP_ENDTIME (Runtime:${FP_DDM}m${FP_DDS}s)"
}

#MAIN SCRIPT

fp_parseargs $@
fp_start
if $TEST "$ONLY_ONE" != "" -a "$ONLY_ONE" != "0" ; then
	fp_single "$ONLY_ONE"
else 
	fp_all
fi
fp_end