blob: f2c8e2ac4b69a1b436340101aa5d72d6c5bb8fba [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001#!/sbin/sh
2#
3# Warning: if you want to run this script in cm-recovery change the above to #!/sbin/sh
4#
5# fix_permissions - fixes permissions on Android data directories after upgrade
6# shade@chemlab.org
7#
8# original concept: http://blog.elsdoerfer.name/2009/05/25/android-fix-package-uid-mismatches/
9# implementation by: Cyanogen
10# improved by: ankn, smeat, thenefield, farmatito, rikupw, Kastro
11#
12# v1.1-v1.31r3 - many improvements and concepts from XDA developers.
13# v1.34 through v2.00 - A lot of frustration [by Kastro]
14# v2.01 - Completely rewrote the script for SPEED, thanks for the input farmatito
15# /data/data depth recursion is tweaked;
16# fixed single mode;
17# functions created for modularity;
18# logging can be disabled via CLI for more speed;
19# runtime computation added to end (Runtime: mins secs);
20# progress (current # of total) added to screen;
21# fixed CLI argument parsing, now you can have more than one option!;
22# debug cli option;
23# verbosity can be disabled via CLI option for less noise;;
24# [by Kastro, (XDA: k4str0), twitter;mattcarver]
25# v2.02 - ignore com.htc.resources.apk if it exists and minor code cleanups,
26# fix help text, implement simulated run (-s) [farmatito]
27# v2.03 - fixed chown group ownership output [Kastro]
28
29VERSION="2.03"
30
31# Defaults
32DEBUG=0 # Debug off by default
33LOGGING=0 # Logging on by default
34VERBOSE=0 # Verbose on by default
35
36# Messages
37UID_MSG="Changing user ownership for:"
38GID_MSG="Changing group ownership for:"
39PERM_MSG="Changing permissions for:"
40
41# Programs needed
42ECHO="busybox echo"
43GREP="busybox grep"
44EGREP="busybox egrep"
45CAT="busybox cat"
46CHOWN="busybox chown"
47CHMOD="busybox chmod"
48MOUNT="busybox mount"
49UMOUNT="busybox umount"
50CUT="busybox cut"
51FIND="busybox find"
52LS="busybox ls"
53TR="busybox tr"
54TEE="busybox tee"
55TEST="busybox test"
56SED="busybox sed"
57RM="busybox rm"
58WC="busybox wc"
59EXPR="busybox expr"
60DATE="busybox date"
61
62# Initialise vars
63CODEPATH=""
64UID=""
65GID=""
66PACKAGE=""
67REMOVE=0
68NOSYSTEM=0
69ONLY_ONE=""
70SIMULATE=0
71SYSREMOUNT=0
72SYSMOUNT=0
73DATAMOUNT=0
74SYSSDMOUNT=0
75FP_STARTTIME=$( $DATE +"%m-%d-%Y %H:%M:%S" )
76FP_STARTEPOCH=$( $DATE +%s )
77
78fp_usage()
79{
80 $ECHO "Usage $0 [OPTIONS] [APK_PATH]"
81 $ECHO " -d turn on debug"
82 $ECHO " -f fix only package APK_PATH"
83 $ECHO " -l disable logging for this run (faster)"
84 $ECHO " -r remove stale data directories"
85 $ECHO " of uninstalled packages while fixing permissions"
86 $ECHO " -s simulate only"
87 $ECHO " -u check only non-system directories"
88 $ECHO " -v disable verbosity for this run (less output)"
89 $ECHO " -V print version"
90 $ECHO " -h this help"
91}
92
93fp_parseargs()
94{
95 # Parse options
96 while $TEST $# -ne 0; do
97 case "$1" in
98 -d)
99 DEBUG=1
100 ;;
101 -f)
102 if $TEST $# -lt 2; then
103 $ECHO "$0: missing argument for option $1"
104 exit 1
105 else
106 if $TEST $( $ECHO $2 | $CUT -c1 ) != "-"; then
107 ONLY_ONE=$2
108 shift;
109 else
110 $ECHO "$0: missing argument for option $1"
111 exit 1
112 fi
113 fi
114 ;;
115 -r)
116 REMOVE=1
117 ;;
118 -s)
119 SIMULATE=1
120 ;;
121 -l)
122 if $TEST $LOGGING -eq 0; then
123 LOGGING=1
124 else
125 LOGGING=0
126 fi
127 ;;
128 -v)
129 if $TEST $VERBOSE -eq 0; then
130 VERBOSE=1
131 else
132 VERBOSE=0
133 fi
134 ;;
135 -u)
136 NOSYSTEM=1
137 ;;
138 -V)
139 $ECHO "$0 $VERSION"
140 exit 0
141 ;;
142 -h)
143 fp_usage
144 exit 0
145 ;;
146 -*)
147 $ECHO "$0: unknown option $1"
148 $ECHO
149 fp_usage
150 exit 1
151 ;;
152 esac
153 shift;
154 done
155}
156
157fp_print()
158{
159 MSG=$@
160 if $TEST $LOGGING -eq 1; then
161 $ECHO $MSG | $TEE -a $LOG_FILE
162 else
163 $ECHO $MSG
164 fi
165}
166
167fp_start()
168{
169 if $TEST $SIMULATE -eq 0 ; then
170 if $TEST $( $GREP -c " /system " "/proc/mounts" ) -ne 0; then
171 DEVICE=$( $GREP " /system " "/proc/mounts" | $CUT -d ' ' -f1 )
172 if $TEST $DEBUG -eq 1; then
173 fp_print "/system mounted on $DEVICE"
174 fi
175 if $TEST $( $GREP " /system " "/proc/mounts" | $GREP -c " ro " ) -ne 0; then
176 $MOUNT -o remount,rw $DEVICE /system
177 SYSREMOUNT=1
178 fi
179 else
180 $MOUNT /system > /dev/null 2>&1
181 SYSMOUNT=1
182 fi
183
184 if $TEST $( $GREP -c " /data " "/proc/mounts" ) -eq 0; then
185 $MOUNT /data > /dev/null 2>&1
186 DATAMOUNT=1
187 fi
188
189 if $TEST -e /dev/block/mmcblk0p2 && $TEST $( $GREP -c " /sd-ext " "/proc/mounts" ) -eq 0; then
190 $MOUNT /sd-ext > /dev/null 2>&1
191 SYSSDMOUNT=1
192 fi
193 fi
194 if $TEST $( $MOUNT | $GREP -c /sdcard ) -eq 0; then
195 LOG_FILE="/data/fix_permissions.log"
196 else
197 LOG_FILE="/sdcard/fix_permissions.log"
198 fi
199 if $TEST ! -e "$LOG_FILE"; then
200 > $LOG_FILE
201 fi
202
203 fp_print "$0 $VERSION started at $FP_STARTTIME"
204}
205
206fp_chown_uid()
207{
208 FP_OLDUID=$1
209 FP_UID=$2
210 FP_FILE=$3
211
212 #if user ownership doesn't equal then change them
213 if $TEST "$FP_OLDUID" != "$FP_UID"; then
214 if $TEST $VERBOSE -ne 0; then
215 fp_print "$UID_MSG $FP_FILE from '$FP_OLDUID' to '$FP_UID'"
216 fi
217 if $TEST $SIMULATE -eq 0; then
218 $CHOWN $FP_UID "$FP_FILE"
219 fi
220 fi
221}
222
223fp_chown_gid()
224{
225 FP_OLDGID=$1
226 FP_GID=$2
227 FP_FILE=$3
228
229 #if group ownership doesn't equal then change them
230 if $TEST "$FP_OLDGID" != "$FP_GID"; then
231 if $TEST $VERBOSE -ne 0; then
232 fp_print "$GID_MSG $FP_FILE from '$FP_OLDGID' to '$FP_GID'"
233 fi
234 if $TEST $SIMULATE -eq 0; then
235 $CHOWN :$FP_GID "$FP_FILE"
236 fi
237 fi
238}
239
240fp_chmod()
241{
242 FP_OLDPER=$1
243 FP_OLDPER=$( $ECHO $FP_OLDPER | cut -c2-10 )
244 FP_PERSTR=$2
245 FP_PERNUM=$3
246 FP_FILE=$4
247
248 #if the permissions are not equal
249 if $TEST "$FP_OLDPER" != "$FP_PERSTR"; then
250 if $TEST $VERBOSE -ne 0; then
251 fp_print "$PERM_MSG $FP_FILE from '$FP_OLDPER' to '$FP_PERSTR' ($FP_PERNUM)"
252 fi
253 #change the permissions
254 if $TEST $SIMULATE -eq 0; then
255 $CHMOD $FP_PERNUM "$FP_FILE"
256 fi
257 fi
258}
259
260fp_all()
261{
262 FP_NUMS=$( $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | $WC -l )
263 I=0
264 $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | while read all_line; do
265 I=$( $EXPR $I + 1 )
266 fp_package "$all_line" $I $FP_NUMS
267 done
268}
269
270fp_single()
271{
272 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 )
273 if $TEST $FP_SFOUND -gt 1; then
274 fp_print "Cannot perform single operation on $FP_SFOUND matched package(s)."
275 elif $TEST $FP_SFOUND = "" -o $FP_SFOUND -eq 0; then
276 fp_print "Could not find the package you specified in the packages.xml file."
277 else
278 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 )
279 fp_package "${FP_SPKG}" 1 1
280 fi
281}
282
283fp_package()
284{
285 pkgline=$1
286 curnum=$2
287 endnum=$3
288 CODEPATH=$( $ECHO $pkgline | $SED 's%.* codePath="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
289 PACKAGE=$( $ECHO $pkgline | $SED 's%.* name="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
290 UID=$( $ECHO $pkgline | $SED 's%.*serId="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
291 GID=$UID
292 APPDIR=$( $ECHO $CODEPATH | $SED 's%^\(.*\)/.*%\1%' )
293 APK=$( $ECHO $CODEPATH | $SED 's%^.*/\(.*\..*\)$%\1%' )
294
295 #debug
296 if $TEST $DEBUG -eq 1; then
297 fp_print "CODEPATH: $CODEPATH APPDIR: $APPDIR APK:$APK UID/GID:$UID:$GID"
298 fi
299
300 #check for existence of apk
301 if $TEST -e $CODEPATH; then
302 fp_print "Processing ($curnum of $endnum): $PACKAGE..."
303
304 #lets get existing permissions of CODEPATH
305 OLD_UGD=$( $LS -ln "$CODEPATH" )
306 OLD_PER=$( $ECHO $OLD_UGD | $CUT -d ' ' -f1 )
307 OLD_UID=$( $ECHO $OLD_UGD | $CUT -d ' ' -f3 )
308 OLD_GID=$( $ECHO $OLD_UGD | $CUT -d ' ' -f4 )
309
310 #apk source dirs
311 if $TEST "$APPDIR" = "/system/app"; then
312 #skip system apps if set
313 if $TEST "$NOSYSTEM" = "1"; then
314 fp_print "***SKIPPING SYSTEM APP ($PACKAGE)!"
315 return
316 fi
317 fp_chown_uid $OLD_UID 0 "$CODEPATH"
318 fp_chown_gid $OLD_GID 0 "$CODEPATH"
319 fp_chmod $OLD_PER "rw-r--r--" 644 "$CODEPATH"
320 elif $TEST "$APPDIR" = "/data/app"; then
321 fp_chown_uid $OLD_UID 1000 "$CODEPATH"
322 fp_chown_gid $OLD_GID 1000 "$CODEPATH"
323 fp_chmod $OLD_PER "rw-r--r--" 644 "$CODEPATH"
324 elif $TEST "$APPDIR" = "/data/app-private"; then
325 fp_chown_uid $OLD_UID 1000 "$CODEPATH"
326 fp_chown_gid $OLD_GID $GID "$CODEPATH"
327 fp_chmod $OLD_PER "rw-r-----" 640 "$CODEPATH"
328 fi
329 else
330 fp_print "$CODEPATH does not exist ($curnum of $endnum). Reinstall..."
331 if $TEST $REMOVE -eq 1; then
332 if $TEST -d /data/data/$PACKAGE ; then
333 fp_print "Removing stale dir /data/data/$PACKAGE"
334 if $TEST $SIMULATE -eq 0 ; then
335 $RM -R /data/data/$PACKAGE
336 fi
337 fi
338 fi
339 fi
340
341 #the data/data for the package
342 if $TEST -d "/data/data/$PACKAGE"; then
343 #find all directories in /data/data/$PACKAGE
344 $FIND /data/data/$PACKAGE -type d -exec $LS -ldn {} \; | while read dataline; do
345 #get existing permissions of that directory
346 OLD_PER=$( $ECHO $dataline | $CUT -d ' ' -f1 )
347 OLD_UID=$( $ECHO $dataline | $CUT -d ' ' -f3 )
348 OLD_GID=$( $ECHO $dataline | $CUT -d ' ' -f4 )
349 FILEDIR=$( $ECHO $dataline | $CUT -d ' ' -f9 )
350 FOURDIR=$( $ECHO $FILEDIR | $CUT -d '/' -f5 )
351
352 #set defaults for iteration
353 ISLIB=0
354 REVPERM=755
355 REVPSTR="rwxr-xr-x"
356 REVUID=$UID
357 REVGID=$GID
358
359 if $TEST "$FOURDIR" = ""; then
360 #package directory, perms:755 owner:$UID:$GID
361 fp_chmod $OLD_PER "rwxr-xr-x" 755 "$FILEDIR"
362 elif $TEST "$FOURDIR" = "lib"; then
363 #lib directory, perms:755 owner:1000:1000
364 #lib files, perms:755 owner:1000:1000
365 ISLIB=1
366 REVPERM=755
367 REVPSTR="rwxr-xr-x"
368 REVUID=1000
369 REVGID=1000
370 fp_chmod $OLD_PER "rwxr-xr-x" 755 "$FILEDIR"
371 elif $TEST "$FOURDIR" = "shared_prefs"; then
372 #shared_prefs directories, perms:771 owner:$UID:$GID
373 #shared_prefs files, perms:660 owner:$UID:$GID
374 REVPERM=660
375 REVPSTR="rw-rw----"
376 fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
377 elif $TEST "$FOURDIR" = "databases"; then
378 #databases directories, perms:771 owner:$UID:$GID
379 #databases files, perms:660 owner:$UID:$GID
380 REVPERM=660
381 REVPSTR="rw-rw----"
382 fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
383 elif $TEST "$FOURDIR" = "cache"; then
384 #cache directories, perms:771 owner:$UID:$GID
385 #cache files, perms:600 owner:$UID:GID
386 REVPERM=600
387 REVPSTR="rw-------"
388 fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
389 else
390 #other directories, perms:771 owner:$UID:$GID
391 REVPERM=771
392 REVPSTR="rwxrwx--x"
393 fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
394 fi
395
396 #change ownership of directories matched
397 if $TEST "$ISLIB" = "1"; then
398 fp_chown_uid $OLD_UID 1000 "$FILEDIR"
399 fp_chown_gid $OLD_GID 1000 "$FILEDIR"
400 else
401 fp_chown_uid $OLD_UID $UID "$FILEDIR"
402 fp_chown_gid $OLD_GID $GID "$FILEDIR"
403 fi
404
405 #if any files exist in directory with improper permissions reset them
406 $FIND $FILEDIR -type f -maxdepth 1 ! -perm $REVPERM -exec $LS -ln {} \; | while read subline; do
407 OLD_PER=$( $ECHO $subline | $CUT -d ' ' -f1 )
408 SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
409 fp_chmod $OLD_PER $REVPSTR $REVPERM "$SUBFILE"
410 done
411
412 #if any files exist in directory with improper user reset them
413 $FIND $FILEDIR -type f -maxdepth 1 ! -user $REVUID -exec $LS -ln {} \; | while read subline; do
414 OLD_UID=$( $ECHO $subline | $CUT -d ' ' -f3 )
415 SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
416 fp_chown_uid $OLD_UID $REVUID "$SUBFILE"
417 done
418
419 #if any files exist in directory with improper group reset them
420 $FIND $FILEDIR -type f -maxdepth 1 ! -group $REVGID -exec $LS -ln {} \; | while read subline; do
421 OLD_GID=$( $ECHO $subline | $CUT -d ' ' -f4 )
422 SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
423 fp_chown_gid $OLD_GID $REVGID "$SUBFILE"
424 done
425 done
426 fi
427}
428
429date_diff()
430{
431 if $TEST $# -ne 2; then
432 FP_DDM="E"
433 FP_DDS="E"
434 return
435 fi
436 FP_DDD=$( $EXPR $2 - $1 )
437 FP_DDM=$( $EXPR $FP_DDD / 60 )
438 FP_DDS=$( $EXPR $FP_DDD % 60 )
439}
440
441fp_end()
442{
443 if $TEST $SYSREMOUNT -eq 1; then
444 $MOUNT -o remount,ro $DEVICE /system > /dev/null 2>&1
445 fi
446
447 if $TEST $SYSSDMOUNT -eq 1; then
448 $UMOUNT /sd-ext > /dev/null 2>&1
449 fi
450
451 if $TEST $SYSMOUNT -eq 1; then
452 $UMOUNT /system > /dev/null 2>&1
453 fi
454
455 if $TEST $DATAMOUNT -eq 1; then
456 $UMOUNT /data > /dev/null 2>&1
457 fi
458
459 FP_ENDTIME=$( $DATE +"%m-%d-%Y %H:%M:%S" )
460 FP_ENDEPOCH=$( $DATE +%s )
461
462 date_diff $FP_STARTEPOCH $FP_ENDEPOCH
463
464 fp_print "$0 $VERSION ended at $FP_ENDTIME (Runtime:${FP_DDM}m${FP_DDS}s)"
465}
466
467#MAIN SCRIPT
468
469fp_parseargs $@
470fp_start
471if $TEST "$ONLY_ONE" != "" -a "$ONLY_ONE" != "0" ; then
472 fp_single "$ONLY_ONE"
473else
474 fp_all
475fi
476fp_end