summaryrefslogtreecommitdiffstats
path: root/prebuilt/fix_permissions.sh
blob: 3723a126c69282420d4131d267a41cb341b14eea (plain) (blame)
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
477
478
479
480
481
482
483
484
#!/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]
# v2.04 - replaced /system/sd with $SD_EXT_DIRECTORY [Firerat]
VERSION="2.04"

# Defaults
DEBUG=0 # Debug off by default
LOGGING=1 # Logging on by default
VERBOSE=1 # 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 )
if $TEST "$SD_EXT_DIRECTORY" = ""; then
    #check for mount point, /system/sd included in tests for backward compatibility
    for MP in /sd-ext /system/sd;do
        if $TEST -d $MP; then
            SD_EXT_DIRECTORY=$MP
            break
        fi
    done
fi
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_DIRECTORY " "/proc/mounts" ) -eq 0; then
         $MOUNT $SD_EXT_DIRECTORY > /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" || $TEST "$APPDIR" = "/sd-ext/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" || $TEST "$APPDIR" = "/sd-ext/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_DIRECTORY > /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