Shell Notes

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
# Print absolute path of the script.
function abs_path() {
python -c "import os.path; print(os.path.realpath('$0'))";
}

# get absolute path of the current script
ABS_PATH=`abs_path`

# get path of directory
$(dirname $ABS_PATH)

# get filename
$(basename $ABS_PATH)

# Download the tar file specified by arg1, extract to arg2 (the
# top-level folder will be stripped) and remove the downloaded
# file.
# e.g. download_and_extract_to \
# http://releases.llvm.org/3.6.0/cfe-3.6.0.src.tar.xz \
# llvm/tools/clang
# @arg1 download_url
# @arg2 extract_to_folder
function download_and_extract_to() {
URL=$1
FOLDER=$2

FILENAME=$(basename $URL)

wget $URL
mkdir -p $FOLDER
tar --strip 1 -xf $FILENAME -C $FOLDER
rm $FILENAME
}

# empty a file
: > file.txt
truncate -s0 file.txt

# build file index for current directory
find $(pwd) -type f > filelist.txt

# copy a part of a file
dd count=<copy_N_ibs_sized_blocks> skip==<copy_N_ibs_sized_blocks> \
if=<input_file> of=<output_file>
# add iflag=count_bytes,skip_bytes to copy and skip in bytes
# instead of blocks
dd iflag=count_bytes,skip_bytes count=<copy_bytes> skip=<skip_bytes> \
if=<input_file> of=<output_file>

# search for keyword in some specific types of files
find . -type f -name "*.java" -print0 |xargs -0 grep -li "keyword"

# -n1 is used to execute the command once for each result
find . -type f -name "*.java" -print0 |xargs -0 -n1 echo

# The -I option to xargs takes a string that will be
# replaced with the supplied input before the command
# is executed. A common choice is %.
find /path -type f -name '*~' -print0 | xargs -0 -I % cp -a % ~/backups

# The word bash at the end of the line is interpreted by bash
# -c as special parameter $0.
# The single quote ' is critical, otherwise $filename will be
# replaced before the script is executed.
find /path -type f -name '*~' -print0 | xargs -0 bash -c \
'for filename; do cp -a "$filename" ~/backups; done' bash

Outlook Search Criteria

Type this To find this
bobby moore Items containing both bobby and moore, but not necessarily in that order.
"bobby moore" Items containing the exact phrase bobby moore. Note the use of double quotes so that the search results match the exact phrase within the quotes.
hasattachment:yes Items that have attachments. You can also use hasattachment:true to get the same results.
subject:"bobby moore" Items whose subject contains the phrase bobby moore.
subject:bobby moore Items with bobby in the subject line and with moore anywhere else in the document.
hasflag:true Items that are flagged for follow up.
subject:status received:May Items received from anyone during the month of May (any year) where the subject contains status.
bobby AND moore Items containing both bobby and moore, but not necessarily in that order. Note that logical operators such as AND, NOT, and OR must be in uppercase letters.
bobby NOT moore Items containing bobby, but not moore.
bobby OR moore Items containing bobby, moore, or both.

Reference

Learn to narrow your search criteria for better searches in Outlook

How to Remove u200b

Remove

Search regular expression \x{200b}.
\u200b cannot match it in SublimeText.

u200b (ZERO WIDTH SPACE)

UTF-8 (hex) 0xE2 0x80 0x8B (e2808b)
UTF-16 (hex) 0x200B (200b)

SublimeText Plugin

Preferences -> Browse Packages. Put the following two files under User.

x_u200b_killer.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sublime, sublime_plugin

class ShowU200b(sublime_plugin.EventListener):
def on_modified_async(self, view):
u200b_regions = view.find_all('\u200b')
if len(u200b_regions) > 0:
view.add_regions("u200b_regions", u200b_regions, "string", "circle")
view.show_popup('U200B Detected!!!')
else:
view.erase_regions("u200b_regions")


class RemoveU200b(sublime_plugin.TextCommand):
def run(self, edit):
print('Removing U200B')

regions = self.view.find_all('\u200b')
for r in reversed(regions):
self.view.erase(edit, r)

x_u200b_killer.sublime-commands

1
2
3
[
{ "caption": "Remove U200b", "command": "remove_u200b" },
]

Reference

Unicode Character ‘ZERO WIDTH SPACE’ (U+200B)
delete U+200B zero-width space characters using sublime text 3

Android Root Note

How Apps Use Root Privilege

Apps use the following code to gain root privilege. Basically, a new root shell process is created with Runtime.getRuntime().exec("su"). Then commands are sent to the new process through stdin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
OutputStream stdin = null;
DataOutputStream os = null;
Process process = Runtime.getRuntime().exec("su");

stdin = process.getOutputStream();
try {
os = new DataOutputStream(stdin);
os.writeBytes("ls /data\n");
os.writeBytes("exit\n");
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
close(os);
}

How Root is Achieved

Since Apps use su to gain root privilege, we need a su binary with the following requirements:

  • existing. su may not necessarily exist.
  • chmod 4755. Apps should be able to execute su. The suid bit should have been set.
  • selinux is off. root can turn off selinux with the cmd setenforce 0.
  • Disable the uid check for the su from AOSP. The su source code in AOSP contains the following check. Apps cannot pass this check.
    1
    if (current_uid != AID_ROOT && current_uid != AID_SHELL) error(1, 0, "not allowed");

Even if the su meets the above requirements, it’s still possible that su doen’t work for Apps. For example, /system maybe mounted as nosuid for Apps. To bypass SELinux and other limitations, some su solutions start a root sudaemon at boot up time. When Apps execute /system/xbin/su, /system/xbin/su accepts the commands and forwards them to the sudaemon.

How to Root an Emulator/Device with eng Build (works on Nougat)

  • Download SuperSu ZIP format
  • Start up the emulator with a writable system partition.
    emulator -avd [emulator_name] -writable-system
  • Unzip SuperSU. Get the SU related binaries for the correct architecture and put it in the right directory
    1
    2
    3
    4
    5
    6
    adb root
    adb remount
    adb push {supsersu_path}/{architecture}/su /system/xbin/su # may need su.pie, adb push {supsersu_path}/{architecture}/su.pie /system/xbin/su
    adb push {supsersu_path}/{architecture}/supolicy /system/xbin
    adb push {supsersu_path}/{architecture}/libsupol.so /system/lib
    adb shell chmod 06755 /system/xbin/su
  • Start the su daemon
    1
    2
    3
    # in adb root shell
    adb shell /system/xbin/su --init
    adb shell /system/xbin/su --daemon
  • Turn off SELinux
    1
    2
    # in adb root shell
    adb shell setenforce 0
  • Install SuperSu App
    1
    adb install {supsersu_path}/common/Superuser.apk
  • Open SuperSu App
    • If it complains about that the device is not rooted, you may have missed some previous steps. Check and do it again.
    • If it complains about outdated su binary, you can ignore it. If you accept to update the su binary, it is possible that your device can NOT boot up. If you decline to update the su binary, you need to turn off selinux every time you reboot the device.

Reference

Rooting the Android Emulator – on Android Studio 2.3 (Android 4.4+)
Android系统Root原理初探
Android高级Root技术原理解析

Automatically Turn on NumLock for Ubuntu

First install numlockx

$ sudo apt-get install numlockx

Method 1
$ sudo vim /etc/rc.local
Add the following content before exit 0

1
2
3
if [-x /usr/bin/numlockx ]; then
numlockx on
fi

Method 2
$ sudo vim /usr/share/lightdm/lightdm.conf.d/50-unity-greeter.conf
Add greeter-setup-script=/usr/bin/numlockx on at the end.