blob: 6d063f9531a8a110a852956929e3d83194cbf1ec [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;
Dees_Troy4be841b2012-09-26 14:07:15 -040018# logging can be disabled via CLI for more speed;
19# runtime computation added to end (Runtime: mins secs);
Dees_Troy51a0e822012-09-05 15:24:24 -040020# 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]
Dees_Troy4be841b2012-09-26 14:07:15 -040028# v2.04 - replaced /system/sd with $SD_EXT_DIRECTORY [Firerat]
29VERSION="2.04"
Dees_Troy51a0e822012-09-05 15:24:24 -040030
31# Defaults
32DEBUG=0 # Debug off by default
Dees_Troy4be841b2012-09-26 14:07:15 -040033LOGGING=1 # Logging on by default
34VERBOSE=1 # Verbose on by default
Dees_Troy51a0e822012-09-05 15:24:24 -040035
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 )
Dees_Troy4be841b2012-09-26 14:07:15 -040077if $TEST "$SD_EXT_DIRECTORY" = ""; then
78 #check for mount point, /system/sd included in tests for backward compatibility
79 for MP in /sd-ext /system/sd;do
80 if $TEST -d $MP; then
81 SD_EXT_DIRECTORY=$MP
82 break
83 fi
84 done
85fi
Dees_Troy51a0e822012-09-05 15:24:24 -040086fp_usage()
87{
Dees_Troy4be841b2012-09-26 14:07:15 -040088 $ECHO "Usage $0 [OPTIONS] [APK_PATH]"
89 $ECHO " -d turn on debug"
90 $ECHO " -f fix only package APK_PATH"
91 $ECHO " -l disable logging for this run (faster)"
92 $ECHO " -r remove stale data directories"
93 $ECHO " of uninstalled packages while fixing permissions"
94 $ECHO " -s simulate only"
95 $ECHO " -u check only non-system directories"
96 $ECHO " -v disable verbosity for this run (less output)"
97 $ECHO " -V print version"
98 $ECHO " -h this help"
Dees_Troy51a0e822012-09-05 15:24:24 -040099}
100
101fp_parseargs()
102{
Dees_Troy4be841b2012-09-26 14:07:15 -0400103 # Parse options
104 while $TEST $# -ne 0; do
105 case "$1" in
106 -d)
107 DEBUG=1
108 ;;
109 -f)
110 if $TEST $# -lt 2; then
111 $ECHO "$0: missing argument for option $1"
112 exit 1
113 else
114 if $TEST $( $ECHO $2 | $CUT -c1 ) != "-"; then
115 ONLY_ONE=$2
116 shift;
117 else
118 $ECHO "$0: missing argument for option $1"
119 exit 1
120 fi
121 fi
122 ;;
123 -r)
124 REMOVE=1
125 ;;
126 -s)
127 SIMULATE=1
128 ;;
129 -l)
130 if $TEST $LOGGING -eq 0; then
131 LOGGING=1
132 else
133 LOGGING=0
134 fi
135 ;;
136 -v)
137 if $TEST $VERBOSE -eq 0; then
138 VERBOSE=1
139 else
140 VERBOSE=0
141 fi
142 ;;
143 -u)
144 NOSYSTEM=1
145 ;;
146 -V)
147 $ECHO "$0 $VERSION"
148 exit 0
149 ;;
150 -h)
151 fp_usage
152 exit 0
153 ;;
154 -*)
155 $ECHO "$0: unknown option $1"
156 $ECHO
157 fp_usage
158 exit 1
159 ;;
160 esac
161 shift;
162 done
Dees_Troy51a0e822012-09-05 15:24:24 -0400163}
164
165fp_print()
166{
Dees_Troy4be841b2012-09-26 14:07:15 -0400167 MSG=$@
168 if $TEST $LOGGING -eq 1; then
169 $ECHO $MSG | $TEE -a $LOG_FILE
170 else
171 $ECHO $MSG
172 fi
Dees_Troy51a0e822012-09-05 15:24:24 -0400173}
174
175fp_start()
176{
Dees_Troy4be841b2012-09-26 14:07:15 -0400177 if $TEST $SIMULATE -eq 0 ; then
178 if $TEST $( $GREP -c " /system " "/proc/mounts" ) -ne 0; then
179 DEVICE=$( $GREP " /system " "/proc/mounts" | $CUT -d ' ' -f1 )
180 if $TEST $DEBUG -eq 1; then
181 fp_print "/system mounted on $DEVICE"
182 fi
183 if $TEST $( $GREP " /system " "/proc/mounts" | $GREP -c " ro " ) -ne 0; then
184 $MOUNT -o remount,rw $DEVICE /system
185 SYSREMOUNT=1
186 fi
187 else
188 $MOUNT /system > /dev/null 2>&1
189 SYSMOUNT=1
190 fi
191
192 if $TEST $( $GREP -c " /data " "/proc/mounts" ) -eq 0; then
193 $MOUNT /data > /dev/null 2>&1
194 DATAMOUNT=1
195 fi
196
197 if $TEST -e /dev/block/mmcblk0p2 && $TEST $( $GREP -c " $SD_EXT_DIRECTORY " "/proc/mounts" ) -eq 0; then
198 $MOUNT $SD_EXT_DIRECTORY > /dev/null 2>&1
199 SYSSDMOUNT=1
200 fi
201 fi
202 if $TEST $( $MOUNT | $GREP -c /sdcard ) -eq 0; then
203 LOG_FILE="/data/fix_permissions.log"
204 else
205 LOG_FILE="/sdcard/fix_permissions.log"
206 fi
207 if $TEST ! -e "$LOG_FILE"; then
208 > $LOG_FILE
209 fi
210
211 fp_print "$0 $VERSION started at $FP_STARTTIME"
Dees_Troy51a0e822012-09-05 15:24:24 -0400212}
213
214fp_chown_uid()
215{
Dees_Troy4be841b2012-09-26 14:07:15 -0400216 FP_OLDUID=$1
217 FP_UID=$2
218 FP_FILE=$3
219
220 #if user ownership doesn't equal then change them
221 if $TEST "$FP_OLDUID" != "$FP_UID"; then
222 if $TEST $VERBOSE -ne 0; then
223 fp_print "$UID_MSG $FP_FILE from '$FP_OLDUID' to '$FP_UID'"
224 fi
225 if $TEST $SIMULATE -eq 0; then
226 $CHOWN $FP_UID "$FP_FILE"
227 fi
228 fi
Dees_Troy51a0e822012-09-05 15:24:24 -0400229}
230
231fp_chown_gid()
232{
Dees_Troy4be841b2012-09-26 14:07:15 -0400233 FP_OLDGID=$1
234 FP_GID=$2
235 FP_FILE=$3
236
237 #if group ownership doesn't equal then change them
238 if $TEST "$FP_OLDGID" != "$FP_GID"; then
239 if $TEST $VERBOSE -ne 0; then
240 fp_print "$GID_MSG $FP_FILE from '$FP_OLDGID' to '$FP_GID'"
241 fi
242 if $TEST $SIMULATE -eq 0; then
243 $CHOWN :$FP_GID "$FP_FILE"
244 fi
245 fi
Dees_Troy51a0e822012-09-05 15:24:24 -0400246}
247
248fp_chmod()
249{
Dees_Troy4be841b2012-09-26 14:07:15 -0400250 FP_OLDPER=$1
251 FP_OLDPER=$( $ECHO $FP_OLDPER | cut -c2-10 )
252 FP_PERSTR=$2
253 FP_PERNUM=$3
254 FP_FILE=$4
255
256 #if the permissions are not equal
257 if $TEST "$FP_OLDPER" != "$FP_PERSTR"; then
258 if $TEST $VERBOSE -ne 0; then
259 fp_print "$PERM_MSG $FP_FILE from '$FP_OLDPER' to '$FP_PERSTR' ($FP_PERNUM)"
260 fi
261 #change the permissions
262 if $TEST $SIMULATE -eq 0; then
263 $CHMOD $FP_PERNUM "$FP_FILE"
264 fi
265 fi
Dees_Troy51a0e822012-09-05 15:24:24 -0400266}
Dees_Troy4be841b2012-09-26 14:07:15 -0400267
Dees_Troy51a0e822012-09-05 15:24:24 -0400268fp_all()
269{
Dees_Troy4be841b2012-09-26 14:07:15 -0400270 FP_NUMS=$( $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | $WC -l )
271 I=0
272 $CAT /data/system/packages.xml | $EGREP "^<package.*serId" | $GREP -v framework-res.apk | $GREP -v com.htc.resources.apk | while read all_line; do
273 I=$( $EXPR $I + 1 )
274 fp_package "$all_line" $I $FP_NUMS
275 done
Dees_Troy51a0e822012-09-05 15:24:24 -0400276}
277
278fp_single()
279{
Dees_Troy4be841b2012-09-26 14:07:15 -0400280 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 )
281 if $TEST $FP_SFOUND -gt 1; then
282 fp_print "Cannot perform single operation on $FP_SFOUND matched package(s)."
283 elif $TEST $FP_SFOUND = "" -o $FP_SFOUND -eq 0; then
284 fp_print "Could not find the package you specified in the packages.xml file."
285 else
286 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 )
287 fp_package "${FP_SPKG}" 1 1
288 fi
Dees_Troy51a0e822012-09-05 15:24:24 -0400289}
290
291fp_package()
292{
Dees_Troy4be841b2012-09-26 14:07:15 -0400293 pkgline=$1
294 curnum=$2
295 endnum=$3
296 CODEPATH=$( $ECHO $pkgline | $SED 's%.* codePath="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
297 PACKAGE=$( $ECHO $pkgline | $SED 's%.* name="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
298 UID=$( $ECHO $pkgline | $SED 's%.*serId="\(.*\)".*%\1%' | $CUT -d '"' -f1 )
299 GID=$UID
300 APPDIR=$( $ECHO $CODEPATH | $SED 's%^\(.*\)/.*%\1%' )
301 APK=$( $ECHO $CODEPATH | $SED 's%^.*/\(.*\..*\)$%\1%' )
302
303 #debug
304 if $TEST $DEBUG -eq 1; then
305 fp_print "CODEPATH: $CODEPATH APPDIR: $APPDIR APK:$APK UID/GID:$UID:$GID"
306 fi
307
308 #check for existence of apk
309 if $TEST -e $CODEPATH; then
310 fp_print "Processing ($curnum of $endnum): $PACKAGE..."
311
312 #lets get existing permissions of CODEPATH
313 OLD_UGD=$( $LS -ln "$CODEPATH" )
314 OLD_PER=$( $ECHO $OLD_UGD | $CUT -d ' ' -f1 )
315 OLD_UID=$( $ECHO $OLD_UGD | $CUT -d ' ' -f3 )
316 OLD_GID=$( $ECHO $OLD_UGD | $CUT -d ' ' -f4 )
317
318 #apk source dirs
319 if $TEST "$APPDIR" = "/system/app"; then
320 #skip system apps if set
321 if $TEST "$NOSYSTEM" = "1"; then
322 fp_print "***SKIPPING SYSTEM APP ($PACKAGE)!"
323 return
324 fi
325 fp_chown_uid $OLD_UID 0 "$CODEPATH"
326 fp_chown_gid $OLD_GID 0 "$CODEPATH"
327 fp_chmod $OLD_PER "rw-r--r--" 644 "$CODEPATH"
328 elif $TEST "$APPDIR" = "/data/app" || $TEST "$APPDIR" = "/sd-ext/app"; then
329 fp_chown_uid $OLD_UID 1000 "$CODEPATH"
330 fp_chown_gid $OLD_GID 1000 "$CODEPATH"
331 fp_chmod $OLD_PER "rw-r--r--" 644 "$CODEPATH"
332 elif $TEST "$APPDIR" = "/data/app-private" || $TEST "$APPDIR" = "/sd-ext/app-private"; then
333 fp_chown_uid $OLD_UID 1000 "$CODEPATH"
334 fp_chown_gid $OLD_GID $GID "$CODEPATH"
335 fp_chmod $OLD_PER "rw-r-----" 640 "$CODEPATH"
336 fi
337 else
338 fp_print "$CODEPATH does not exist ($curnum of $endnum). Reinstall..."
339 if $TEST $REMOVE -eq 1; then
340 if $TEST -d /data/data/$PACKAGE ; then
341 fp_print "Removing stale dir /data/data/$PACKAGE"
342 if $TEST $SIMULATE -eq 0 ; then
343 $RM -R /data/data/$PACKAGE
344 fi
345 fi
346 fi
347 fi
348
349 #the data/data for the package
350 if $TEST -d "/data/data/$PACKAGE"; then
351 #find all directories in /data/data/$PACKAGE
352 $FIND /data/data/$PACKAGE -type d -exec $LS -ldn {} \; | while read dataline; do
353 #get existing permissions of that directory
354 OLD_PER=$( $ECHO $dataline | $CUT -d ' ' -f1 )
355 OLD_UID=$( $ECHO $dataline | $CUT -d ' ' -f3 )
356 OLD_GID=$( $ECHO $dataline | $CUT -d ' ' -f4 )
357 FILEDIR=$( $ECHO $dataline | $CUT -d ' ' -f9 )
358 FOURDIR=$( $ECHO $FILEDIR | $CUT -d '/' -f5 )
359
360 #set defaults for iteration
361 ISLIB=0
362 REVPERM=755
363 REVPSTR="rwxr-xr-x"
364 REVUID=$UID
365 REVGID=$GID
366
367 if $TEST "$FOURDIR" = ""; then
368 #package directory, perms:755 owner:$UID:$GID
369 fp_chmod $OLD_PER "rwxr-xr-x" 755 "$FILEDIR"
370 elif $TEST "$FOURDIR" = "lib"; then
371 #lib directory, perms:755 owner:1000:1000
372 #lib files, perms:755 owner:1000:1000
373 ISLIB=1
374 REVPERM=755
375 REVPSTR="rwxr-xr-x"
376 REVUID=1000
377 REVGID=1000
378 fp_chmod $OLD_PER "rwxr-xr-x" 755 "$FILEDIR"
379 elif $TEST "$FOURDIR" = "shared_prefs"; then
380 #shared_prefs directories, perms:771 owner:$UID:$GID
381 #shared_prefs files, perms:660 owner:$UID:$GID
382 REVPERM=660
383 REVPSTR="rw-rw----"
384 fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
385 elif $TEST "$FOURDIR" = "databases"; then
386 #databases directories, perms:771 owner:$UID:$GID
387 #databases files, perms:660 owner:$UID:$GID
388 REVPERM=660
389 REVPSTR="rw-rw----"
390 fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
391 elif $TEST "$FOURDIR" = "cache"; then
392 #cache directories, perms:771 owner:$UID:$GID
393 #cache files, perms:600 owner:$UID:GID
394 REVPERM=600
395 REVPSTR="rw-------"
396 fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
397 else
398 #other directories, perms:771 owner:$UID:$GID
399 REVPERM=771
400 REVPSTR="rwxrwx--x"
401 fp_chmod $OLD_PER "rwxrwx--x" 771 "$FILEDIR"
402 fi
403
404 #change ownership of directories matched
405 if $TEST "$ISLIB" = "1"; then
406 fp_chown_uid $OLD_UID 1000 "$FILEDIR"
407 fp_chown_gid $OLD_GID 1000 "$FILEDIR"
408 else
409 fp_chown_uid $OLD_UID $UID "$FILEDIR"
410 fp_chown_gid $OLD_GID $GID "$FILEDIR"
411 fi
412
413 #if any files exist in directory with improper permissions reset them
414 $FIND $FILEDIR -type f -maxdepth 1 ! -perm $REVPERM -exec $LS -ln {} \; | while read subline; do
415 OLD_PER=$( $ECHO $subline | $CUT -d ' ' -f1 )
416 SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
417 fp_chmod $OLD_PER $REVPSTR $REVPERM "$SUBFILE"
418 done
419
420 #if any files exist in directory with improper user reset them
421 $FIND $FILEDIR -type f -maxdepth 1 ! -user $REVUID -exec $LS -ln {} \; | while read subline; do
422 OLD_UID=$( $ECHO $subline | $CUT -d ' ' -f3 )
423 SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
424 fp_chown_uid $OLD_UID $REVUID "$SUBFILE"
425 done
426
427 #if any files exist in directory with improper group reset them
428 $FIND $FILEDIR -type f -maxdepth 1 ! -group $REVGID -exec $LS -ln {} \; | while read subline; do
429 OLD_GID=$( $ECHO $subline | $CUT -d ' ' -f4 )
430 SUBFILE=$( $ECHO $subline | $CUT -d ' ' -f9 )
431 fp_chown_gid $OLD_GID $REVGID "$SUBFILE"
432 done
433 done
434 fi
Dees_Troy51a0e822012-09-05 15:24:24 -0400435}
436
437date_diff()
438{
Dees_Troy4be841b2012-09-26 14:07:15 -0400439 if $TEST $# -ne 2; then
440 FP_DDM="E"
441 FP_DDS="E"
442 return
443 fi
444 FP_DDD=$( $EXPR $2 - $1 )
445 FP_DDM=$( $EXPR $FP_DDD / 60 )
446 FP_DDS=$( $EXPR $FP_DDD % 60 )
Dees_Troy51a0e822012-09-05 15:24:24 -0400447}
448
449fp_end()
450{
Dees_Troy4be841b2012-09-26 14:07:15 -0400451 if $TEST $SYSREMOUNT -eq 1; then
452 $MOUNT -o remount,ro $DEVICE /system > /dev/null 2>&1
453 fi
454
455 if $TEST $SYSSDMOUNT -eq 1; then
456 $UMOUNT $SD_EXT_DIRECTORY > /dev/null 2>&1
457 fi
458
459 if $TEST $SYSMOUNT -eq 1; then
460 $UMOUNT /system > /dev/null 2>&1
461 fi
462
463 if $TEST $DATAMOUNT -eq 1; then
464 $UMOUNT /data > /dev/null 2>&1
465 fi
466
467 FP_ENDTIME=$( $DATE +"%m-%d-%Y %H:%M:%S" )
468 FP_ENDEPOCH=$( $DATE +%s )
469
470 date_diff $FP_STARTEPOCH $FP_ENDEPOCH
471
472 fp_print "$0 $VERSION ended at $FP_ENDTIME (Runtime:${FP_DDM}m${FP_DDS}s)"
Dees_Troy51a0e822012-09-05 15:24:24 -0400473}
474
475#MAIN SCRIPT
476
477fp_parseargs $@
478fp_start
479if $TEST "$ONLY_ONE" != "" -a "$ONLY_ONE" != "0" ; then
Dees_Troy4be841b2012-09-26 14:07:15 -0400480 fp_single "$ONLY_ONE"
481else
482 fp_all
Dees_Troy51a0e822012-09-05 15:24:24 -0400483fi
484fp_end