Pages

Friday, November 8, 2013

Custom System Service using XposedBridge

For those of you who don't know XposedBridge, you should really have a look at it. By enabling you to hook any Class and Method within Android, system classes as well as normal application classes, this is just as powerful a tool as a root shell session. This however operates within the Java VM instead of hacking your way in from a shell.

After working with XposedBridge for awhile, I started stumbling across a few limitations. The Xposed Framework might be able to hook any method in any class, but it can of cause only add a hook before and after execution of the original method. This means that you cannot change anything within a method, but instead either replace it, change the arguments being parsed to it or change the result from it. In most cases this will be enough, however since Android parses a lot of things between multiple processes in JVM and Native code (which you cannot hook), there are circumstances where this will not be enough. For an example, if you decide to add a hook to PhoneWindowManager's interceptKeyBeforeQueueing or interceptKeyBeforeDispatching methods to change the incoming key code or some policy flags, that hook will not be enough. The two original methods will be executed with these new values, but after they have executed, the Native Event Handler will parse the original values to the application dispatchers, and your hook changes will not affect that part. This means that you would also have to add a hook to the KeyEvent's dispatch method. But, since that one will run in different processes than your first hook(s), you cannot share data between them, not even if you add all hooks to one single class instance or use a static class.

In some cases, you can use Broadcasts to send data from one process to another. But the problem with Broadcasts is that you cannot be sure about when the receiver will be invoked or when it is done processing your data. Also, sending a Broadcast or adding a Receiver requires access to a Context, and when working with Xposed you will not always have one of those. The best option in these cases is adding a custom System Service that you can use to share data between processes. The positive thing about System Services, unlike normal Application Services, is that they are available always, from the beginning of System Boot and until the System is shut down. Also they are much easier to connect to. Normally you would not be able to create such a service, but since we are working with XposedBridge, you can actually add whatever you'd like since you can operate as being part of Android.

The first thing that we will need, is an AIDL interface file. You cannot have a System Service without this. In your project, create a new package named android.os and in that package create a new file named ICustomService.aidl that looks like the below example.

android.os.ICustomService.aidl:
package android.os;
/** {@hide} */
interface IXAService {

}

We will also need a class in our regular project package that will be used to hook the service into Android. Create a class named CustomServiceHook.java somewhere in your project package.

CustomServiceHook.java:
public final class CustomServiceHook implements IXposedHookZygoteInit {
 @Override
 public void initZygote(IXposedHookZygoteInit.StartupParam startupParam) throws Throwable {
  CustomService.inject();
 }
}

Since you should already be familiar with XposedBridge, you should already know how to add this hook to be invoked by Xposed during boot.

The CustomService class that we call in our hook above is our System Service Class. The inject() method is a static method from where we will inject the Service into Android so that it can be used by our module. Create a new package named com.android.server and create a new class in that package named CustomService.java.

com.android.server.CustomService.java:
public class CustomService extends ICustomService.Stub {
 public static void inject() {

 }
}

This is our basic classes. Now it's time to extend CustomService.java to actually make it work. All of Android's original services are created and registered from com.android.server.SystemServer.java. However, all of the creation and registration is done from within a Thread. The problem here is that this Thread keeps the System Context as a normal variable, so we have no way to access it outside the Run() method. And since we cannot hook our way into the method but only add a hook before or after, this method and class is of no use to us.

However, the first thing that this method does, is invoke the main() method of com.android.server.am.ActivityManagerService in order to get the System Context. So if we add a hook after that method, the hook will be invoked in the beginning of the SystemServer thread, and we will also have access to the System Context which will be in the result from the main() method that we added our hook to. Let's change our CustomService.java file and add this hook to it.

com.android.server.CustomService.java:
public class CustomService extends ICustomService.Stub {

 private Context mContext;

 private static CustomService oInstance;

 public static void inject() {
  final Class ActivityManagerServiceClazz = XposedHelpers.findClass("com.android.server.am.ActivityManagerService", null);
  
  XposedBridge.hookAllMethods(
   ActivityManagerServiceClazz, 
   "main", 
   new XC_MethodHook() {
    @Override
    protected final void afterHookedMethod(final MethodHookParam param) {
     Context context = (Context) param.getResult();
     
     oInstance = new CustomService(context);
     
     XposedHelpers.callMethod(
       XposedTools.findClass("android.os.ServiceManager"), 
       "addService", 
       new Class[]{String.class, IBinder.class}, 
       "custom.service", 
       oInstance
     );
    }
   }
  );
 }

 public XAService(Context context) {
  mContext = context;
 }
}

The service will now be created and registered with Android during boot, but we are not quite done yet. At the time this service is created, no other services are available. So if you want to do some initializing, the constructor is not the place to do it. What we need is yet another hook that will be invoked once the system is ready. The ActivityManagerService class also has a good place for this. It has a systemReady() method that is invoked once all of the services has been created and is up and running. Let's add this to our CustomService class.

com.android.server.CustomService.java:
public class CustomService extends ICustomService.Stub {

 private Context mContext;

 private static CustomService oInstance;

 public static void inject() {
  final Class ActivityManagerServiceClazz = XposedHelpers.findClass("com.android.server.am.ActivityManagerService", null);
  
  XposedBridge.hookAllMethods(
   ActivityManagerServiceClazz, 
   "main", 
   new XC_MethodHook() {
    @Override
    protected final void afterHookedMethod(final MethodHookParam param) {
     Context context = (Context) param.getResult();
     
     oInstance = new CustomService(context);
     
     XposedHelpers.callMethod(
       XposedTools.findClass("android.os.ServiceManager"), 
       "addService", 
       new Class[]{String.class, IBinder.class}, 
       "custom.service", 
       oInstance
     );
    }
   }
  );

  XposedBridge.hookAllMethods(
   ActivityManagerServiceClazz, 
   "systemReady", 
   new XC_MethodHook() {
    @Override
    protected final void afterHookedMethod(final MethodHookParam param) {
     oInstance.systemReady();
    }
   }
  );
 }

 public XAService(Context context) {
  mContext = context;
 }

 private void systemReady() {
  // Make your initialization here
 }
}

Now you are done. Your new service will now be loaded into Android's ServiceManager during boot via our first hook to the ActivityServiceManager.main() method and it will be initialized once all services is ready via our second hook to ActivityServiceManager.systemReady().

After the initialization, you can access the binder using ServiceManager.getService( name ) just like with any other System Service provided by Android.

All that is left is to implement whatever options you would like this service to provide and start using it in your module.

Example of usage:
public class SomeClass {
 ICustomService mService;
 
 public void someMethod() {
  if (mService == null) {
   mService = ICustomService.Stub.asInterface(
     ServiceManager.getService("custom.service")
   );
  }
  
  mService.someServiceMethod();
 }
}

Friday, August 23, 2013

Controlled Environment

You are building a library of some sort, and you want to have a primary class with additional "extender" classes which all should be accessed through your primary one. Why? Don't know, hopefully you do since your the one making it. However, what is to stop anyone from accessing your "extender" classes directly? You could add your "extender" classes as sub-classes to the primary and make your constructors private or protected. But if your planing on expanding this library a great deal, you will end up with a pretty large file at the end. And splitting your "extender" classes into single files with private and protected constructors will just ensure that not even your primary class will be able to create instances of them. So what's left? I know that some languages actually has a feature which allows you to lock a class and define whom has access to create an instance. I have not worked with Java for long, so I don't know whether or not this feature exists in Java. But there are other ways of doing this, which will actually work in other OOP capable languages as well.

The trick here is Data Types. This is something that Java is very strict about, which makes this so much easier. What you need to do, is have a small class that only your primary can create an instance from. The easiest way is to place this as a sub-class to the primary class. This small class will be used to parse along as an argument to a static method in each "extender" class, who’s job is to return an instance of themselves. Meanwhile we will keep each "extender" constructor private, so that no other can access it. And we will make each class final, so that they cannot be extended in order to bypass this protection.

This is our primary class:
public final class MyPrimary {
    public MyExtender extender(String param) {
        MyTransport transport = new MyTransport();
        transport.arguments = new Object[] { (Object) param };

        return (MyExtender) MyExtender.getInstance( transport ).instance;
    }

    public final static interface MyDataType {}

    public final static class MyTransport {
        private MyTransport() {}

        Object[] arguments;
        MyDataType instance;
    }
}

This is one of our extenders:
public final class MyExtender implements MyDataType {
    public static MyTransport getInstance(MyTransport transport) {
        transport.instance = (MyDataType) new MyExtender( (String) transport.arguments[0] );

        return transport;
    }

    private MyExtender(String param) {
        ...
    }
}

In order to get an instance from MyExtender, you will need to parse through it's getInstance method. However, this method requires a MyTransport argument, which only the primary class can create. From the getInstance method, it will attach an instance of itself and then return the MyTransport object to the primary class. And by implementing MyDataType, you can use the same MyTransport class for any extender classes as they will all be able to be casted to the same data type.

That is all that there is to it. And like mentioned above, this can be used in any OOP language. In some however, you will need some manual checking of data types. PHP for an example does not really care about data types, so you will need to do a manual instanceOf check in the extender getInstance methods to make sure that the argument really is a MyTransport object. But that is not all that difficult to implement.

Saturday, July 13, 2013

Add missing Android Activity tools

One major issue with Android, is that Google have never implemented a proper way of detecting which Activity is currently in the foreground and which are behind. If you open multiple Activities in an application, and then flip the screen, all the callbacks (onCreate(), onResume() etc) will be invoked in all your Activities. The problem is that you might have some code in some of these Activities that you do not wish to have executed, unless the Activity holding that code, is currently placed in the foreground. Problem is that you can't check this state of an Activity. At least not in a proper way.

public Boolean isForeground() {
    ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
}

There is the possibility to use something like the above. There is just two issues regarding this. For one, google states that getSystemService(Context.ACTIVITY_SERVICE) is only intended for debugging and presenting task management user interfaces, and that it should never be used for core logic in an application. Second, you need to have android.permission.GET_TASKS added to the application in order to use this, which is not ideal for a simple task like this.

So what we can do instead, is extending the Activity class with a custom one which includes this missing feature and then extend our application Activities with our custom one instead.

public class ExtendedActivity extends Activity {
 
 private final static ArrayList mActivities = new ArrayList();
 
 private final static Object oLock = new Object();
 
 private Boolean mReCreate = false;
 
 @Override
 public void onSaveInstanceState(Bundle savedInstanceState) {
  savedInstanceState.putBoolean("mReCreate", true);

  super.onSaveInstanceState(savedInstanceState);
 }
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  if (savedInstanceState != null) {
   mReCreate = savedInstanceState.getBoolean("mReCreate");
  }
  
  synchronized (oLock) {
   mActivities.add( (mReCreate ? mActivities.size() : 0), this.getClass().getName());
  }
 }
 
 @Override
 protected void onDestroy() {
  super.onDestroy();
  
  synchronized (oLock) {
   mActivities.remove(this.getClass().getName());
  }
 }
 
 public final Boolean isForeground() {
  synchronized (oLock) {
   return mActivities.size() == 0 || mActivities.get(0).equals(this.getClass().getName());
  }
 }
}

What this does, it keep track of all active Activities and in which order they where opened. We only need to extend all of our Activities using this one, and then we can use isForeground() to check the state of an Activity Object.

public class MyActivity extends ExtendedActivity {

 @Override
 protected void onResume() {
  super.onResume();
  
  if ( isForeground() ) {
            // Do something
        }
 }
}

Sunday, June 30, 2013

Android Activity in Dialog Style

I was working on an Application where I had created a custom settings Activity (Not using the Android built-in settings tools), in order to adopt the same layout style as in the rest of the Application. It worked fine, and now I wanted to add some additional tablet styles as well. When using the Application on a tablet, I wanted a more dialog like view, something without a panel and did not take up the whole screen, but instead placed itself on top of the main activity. When searching the web for a solution to this, the only thing that I could find over and over again, was to add the Dialog Theme to the Activity via AndroidManifest.xml. I had two issues with this. For one, I did not want a Dialog like Activity for all devices, but only for tablets. And second, I have my own custom themes that I apply to all Activities. So I went another way which I was sure would work.

public class ActivityAppSettings extends Activity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  if (getApplication() != null && ((ApplicationBase) getApplication()).mTheme > 0) {
   setTheme( ((ApplicationBase) getApplication()).mTheme );
  }
  
  super.onCreate(savedInstanceState);
  
  if (getResources().getString(R.string.config_screen_type).equals("xlarge")) {
   requestWindowFeature(Window.FEATURE_NO_TITLE);
  
   Rect display = new Rect();
   getWindow().getDecorView().getWindowVisibleDisplayFrame(display);
   getWindow().setBackgroundDrawable(new ColorDrawable(0));

   getWindow().setLayout(
     (int) ((display.width() > display.height() ? display.height() : display.width()) * 0.7), 
     (int) (display.height() * 0.7)
   );
  }
  
  setContentView(R.layout.activity_app_settings);
 }
}

Sure enough it worked, but with one little issue. The space around the Activity was not transparent. It seamed that you could not change the window background from within the Activity. The panel however was removed, the size was set at 70% of the screen size and my custom theme had been applied to the content within, but with a black background surrounding it all.

I needed another work-around. I went to AndroidManifest.xml and applied Androids's Translucent theme to the Activity.

<activity android:theme="@android:style/Theme.Translucent"

The Activity theme would still be replaced by my Custom theme from within the Activity, but since you cannot change the window background from within there, the transparency would still stick. And then on Phones, you just apply a background to the main View, which you then configure as match_parent for both height and width, which will overlay the transparent window background, making it seam like a regular full-screen Activity.

Friday, June 28, 2013

Check Android Uptime

So you are programming an application for Android. You have made a custom caching system which should clear the cache after each boot. One way to do this, could be to create an onBoot Receiver and have that clear out your cache. However, why have your application run on each boot if the user might not even use it all that much? And what if the user installed some Privacy Guard Application and disabled your app's receiver?

The best way to handle this, is to have the cache cleared on the first launch of the application. But in order to do this, you will have to know whether or not this actually is the first launch or not. To help you with this, Android has two useful methods. One to provide the total amount of milliseconds that have past since 1970 (or something like that) and one to provide the total amount of milliseconds that have pasted since the device was booted. Extract the boot time from the total time, and you will have the exact timestamp from when the device was started. Now just save this to your shared preferences and compare it with a fresh timestamp on each application launch.

public class myclass extends something {

    /*
     * We can use this to avoid to much checking.
     * As long as this static property exists, we know that device has not been rebooted and there is no reason to do a check.
     */
    private static Boolean oCacheCheck = false;
    
    public SharedPreferences getCache() {
        SharedPreferences preferences = .getSharedPreferences("cache", 0x00000000);

        if (!oCacheCheck) {
            Long freshTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
            Long cachedTime = preferences.getLong("timestamp", 0);

            if (freshTime == cachedTime) {
                Editor edit = preferences.edit();
    
                edit.clear();
                edit.putLong("timestamp", freshTime);
                edit.commit();
            }

            oCacheCheck = true;
        }

        return preferences;
    }
}

if (freshTime == cachedTime) {

There is however one tiny issue with this way of checking last boot time, and that is that both methods might take a few milliseconds to execute (depending on the speed of the device) and you can only execute one at a time. This means that your calculation could differ each time you run it, making the comparison with the cached timestamp useless.

The solution to this problem is to check the difference between the two timestamps instead of comparing them to see if they are equal. The methods might take a few milliseconds to execute and any type of device will take several seconds, some even minutes, to boot. So we will just check to see if the two timestamps has a difference less than 3 seconds.

public class myclass extends something {

    /*
     * We can use this to avoid to much checking.
     * As long as this static property exists, we know that device has not been rebooted and there is no reason to do a check.
     */
    private static Boolean oCacheCheck = false;
    
    public SharedPreferences getCache() {
        SharedPreferences preferences = .getSharedPreferences("cache", 0x00000000);

        if (!oCacheCheck) {
            Long freshTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
            Long cachedTime = preferences.getLong("timestamp", 0);

            /*
             * If this is grater than 3 second, then we will most likely have a fresh application launch. 
             * No device, no mater how slow, takes 3 seconds or more to execute the time methods.
             * And no device, no mater how fast, can boot and launch the application in less than 3 seconds. 
             */
            if ((freshTime - cachedTime) > 3000) {
                Editor edit = preferences.edit();
    
                edit.clear();
                edit.putLong("timestamp", freshTime);
                edit.commit();
            }

            oCacheCheck = true;
        }

        return preferences;
    }
}

if ((freshTime - cachedTime) > 3000) {

If, when you extract the cached timestamp from the fresh one, get a difference on more than +3000 milliseconds, you can be sure that the device has been rebooted since your last application launch.

Wednesday, May 8, 2013

Multiple Encrypted Disks with Linux

This is a fallow up to the parent guide, Full Disk Encryption with Linux. If you have not yet read it, then you are advised to do so before continuing with this one.

Encrypting you entire hard drive is great. But what if you like me, have more than one hard drive in your computer? One thing that is not great, is having to enter multiple passwords on each boot. Well, you don't have to.

The magic word here is Key File. It is a small file containing some random bytes which can be used as a key to unlock an encryption without using a password. An if you are a person that sucks at coming up with great passwords, it will in most cases be more secure than any password you would assign an encryption. The insecure part is how you store it.

In this guide, we will store this key on our primary encrypted hard drive. It will not be accessible until the first drive has been unlocked. We can then use it to unlock any additional drives that you may have attached to your computer, and get away with only having to type in one single password to unlock multiple drives.


Preparing the hard drive


You can skip this step if you already have an additional and fully encrypted hard drive, and just want to know how to assign a key to it.

Otherwise, let' wipe your drive.

shred -v /dev/sd<Y>

Remember to change Y to the letter matching your additional drive.

Now let's partitioning this drive. We will just create one single partition which will hold the encryption. Also, we will not be using LVM in this guide as we do not need things like SWAP or an OS on it. We have this on the primary disk.

cryptsetup -y --cipher aes-xts-plain --key-size 512 luksFormat /dev/sd<Y>

We will also need it unlocked in order to use it.

cryptsetup luksOpen /dev/sd<Y> <Enc_Name_Add>

And last, creating a new file system inside the encryption.

mkfs.ext4 -L Additional <Enc_Name_Add>

You can use whatever file system or label that you wish.


Creating the key


dd if=/dev/urandom of=/root/encryption.key bs=4096 count=1
chmod 0440 /root/encryption.key

Now we have an 4096bit key and it is only accessible by root, which means that it is quite secure even on a booted system.


Assigning the key


In order to use this key, we need to assign it to the encryption.

cryptsetup luksAddKey /dev/sd<Y> /root/encryption.key

Now the encryption can be unlocked by both the assigned password and this key.


Adding the encryption to crypttab


We will also need to add the encryption and key to crypttab to let the boot loader know how to handle this. Open /etc/crypttab with a file editor and add the line below.

<Enc_Name_Add> /dev/sd<Y> /root/encryption.key luks


Adding the unlocked partition to fstab


If you would like the partition to be mounted during boot, you will need to add it to fstab. Open the file /etc/fstab and add the line below.

/dev/mapper/<Enc_Name_Add> /media/additional ext4 defaults 0 2


Update grub and boot loader


Now we just need to rebuilt the kernel image, reboot and we are done.

update-grub
update-initramfs -u

You can redo this guide for as many disks as you like.

Full Disk Encryption with Linux

A great thing about Linux, is the built-in subsystem DMCrypt, which, with some help from the brilliant Initrd, allows you to make a full disk encryption, including the root partition (Boot excluded of cause) and have it unlocked by a key file or password during boot, all without any third party software. This guide will show you how to encrypt your entire hard drive and set up your computer to unlock it on each boot using a password.

What is even better, is Logical Volume Manager.  This will allow us to create partitions inside a partition, which means that we only need to encrypt one partition on the hard drive, and then create whatever volumes we need, inside that single encrypted partition.

Because Ubuntu is the most used distro of all the available once, this guide will use this for the examples. But it should be easy enough to incorporate this guide into other distro's as well, especially since this guide will be using a terminal to do all of the work, and the shell is mostly the same across all distro's.

Before we can continue, you need to download Ubuntu (Or any distro  of your choice), and create a live CD or USB Pen. Then boot up the live system, and once in the UI, press Ctrl+Alt+F1 to enter a terminal.

This guide will assume that you know your way around Linux. So we will not cover anything about creating live disks or how the shell works. You can google it if you don't already know. This is all about the encryption part.


Erasing the hard drive


The first thing to do, is erasing any existing data on the hard drive and replacing it with random bytes. Even though the hard drive will be encrypted, attachers will still be able to see which part of the drive contains any data. This allows them to focus on that specific part of the drive, and making it much easier cracking it. By placing random bytes across the whole drive, we hide the real data which makes it much harder to determinant which parts of the drive contains anything worth cracking.

shred -v /dev/sd<X>

Remember to replace X with the letter matching your drive. 


Preparing the hard drive


Next we need to create a new partitioning table. By wiping the drive, the existing table was erased along with the rest of the content. Use fdisk, or another partition manager, to create the table below.

Device  Type  Size
/dev/sd<X>1  Primary  1GB
/dev/sd<X>2  Extended  Everything
/dev/sd<X>5  Logical  Everything


Creating the encryption


Now we create the encryption on /dev/sd<X>5. This is the partition that will store our logical volumes.

cryptsetup -y --cipher aes-xts-plain --key-size 512 luksFormat /dev/sd<X>

After you have typed in the password that you wish to use, we need to unlock the encryption in order to use it.

cryptsetup luksOpen /dev/sd<X> <Enc_Name>

The Enc_Name is the name that will be used for the device map. It will create /dev/mapper/<Enc_Name> which is the entry point (door if you will) to the device behind the encryption. Just replace Enc_Name with the name that you wish to use.


Creating the LVM volumes


In this guide, we will be creating 3 volumes. 1 for SWAP, one for root and one for home. You can of cause create whatever you need or want.

Before we can create the volumes, we need to initiate our encrypted volume for LVM and create the volume group that will store the volumes.

pvcreate /dev/mapper/<Enc_Name>
vgcreate <Vg_Name> /dev/mapper/<Enc_Name>

Replace Vg_Name with the name that you wish for your volume group.

Now we are ready to create the actual volumes.

lvcreate -n swap -L 6G <Vg_Name>
lvcreate -n system -L 25G <Vg_Name>
lvcreate -n home -l 100%FREE <Vg_Name>

We now have 3 new devices
  1. /dev/mapper/<Vg_Name>-swap
  2. /dev/mapper/<Vg_Name>-system
  3. /dev/mapper/<Vg_Name>-home 
You can change the names to something else if you'd like, and/or change the sizes. The last volume we created are assigned 100%FREE, which means whatever is left after creating the first two. 


Installing the OS


It is now time to get the OS installed. Press Ctrl+Alt+F7 to get back into the live system UI and select install. Once you get to the partitioning part, select manual. Now assign appropriate mount points to the 3 logical volumes that we created before and use /dev/sd<X>1 as boot. Continue the installation. Once done, do NOT reboot, instead press Ctrl+Alt+F1 again to get back into the terminal.


Set up chroot


Now that we have the OS installed, we need to make some changes to it, but before we can do that, we need for it to act as the main OS. In other words, we need some help from chroot.

mkdir /mnt/system
mount /dev/mapper/<Enc_Name>-system /mnt/system
mount /dev/sd<X>1 /mnt/system/boot
mount --rbind /dev /mnt/system/dev
mount --rbind /sys /mnt/system/sys
mount --rbind /proc /mnt/system/proc
chroot /mnt/system

You should now have entered a new apparent root directory and we are ready to make changes to the OS that you have just installed.


Set up crypttab


The first thing that we need to do here, is edit/create /etc/crypttab. This is a file which will tell the boot loader how to handle the encrypted partition, or more accurate, it will tell the system how initrd should be structured once we rebuild it.

Open  /etc/crypttab with a file editor like nano, and append the content below.

<Enc_Name> /dev/sd<X>5 none luks,retry=1

This will tell the boot loader that /dev/sd<X>5 contains a luks encrypted partition, which should be decrypted to the device map <Enc_Name>. The none part is where we could have assigned a key file, without it, a password prompt will be used instead.


Loading modules


The second thing to do, is have some specific modules loaded on boot, which are needed to unlock the partition.

Open the file /etc/initramfs-tools/modules

dm-crypt
aes-x86_64 (aes-i586 is you are using 32bit)
xts
sha256_generic
sha512_generic
ahci


Recompiling kernel image


And last, we regenerate initrd

update-initramfs -u

Reboot your computer. During boot, you will be prompted to enter a password. Enter the password and your hard drive will decrypted and the computer will continue it's regular boot.

Next time you need to upgrade or for other reasons reinstall your OS, all you have to do, is decrypt/unlock the encrypted partition and then fallow this guide from the parts after the installation of the OS. Everything above that is a one time thing.

Tuesday, May 7, 2013

Redirecting stderr to a function

So, I was writing a shell script where I have made a custom log function to be used for custom messages, errors and warning. However, I also wanted to store everything from stderr in this log file, which I thought would be no big deal. I just added the below code.

exec 2> >(Log)

And then I added my Log function to the script

Log() {
    if [ -z "$1" ]; then
        read Message
    else
        Message="$1"
    fi

    ....
}

And it was working great, until I tested it in Born Shell. Here I got an redirect error. So I needed to look around for another way to do this and I stumbled across an article from Chris Siebenmann.  This is a great example, but I needed to append this to the whole script and not just one single command. This however was easy enough, I just needed to append a sub-process to all of my script content.

Log() {
    if [ -z "$1" ]; then
        read Message
    else
        Message="$1"
    fi

    if [ -n "$Message" ]; then
        ....
    fi
}

exec 3>&1

(
    .... Execute everything from here


) 2>&1 >&3 3>&- | Log

Now everything from stderr will be parsed to the function, and it will work with both Bash and Sh.