Merge "First checkin of cpustats"
diff --git a/ext4_utils/Android.mk b/ext4_utils/Android.mk
index ceb3bdb..d12a6be 100644
--- a/ext4_utils/Android.mk
+++ b/ext4_utils/Android.mk
@@ -25,6 +25,12 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_C_INCLUDES += external/zlib
 
+ifeq ($(HAVE_SELINUX), true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -50,6 +56,12 @@
 LOCAL_C_INCLUDES += external/zlib
 LOCAL_SHARED_LIBRARIES := libz
 
+ifeq ($(HAVE_SELINUX), true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -59,6 +71,12 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_C_INCLUDES += external/zlib
 
+ifeq ($(HAVE_SELINUX), true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_STATIC_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -68,6 +86,12 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES += libext4_utils libz
 
+ifeq ($(HAVE_SELINUX), true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
@@ -77,6 +101,12 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES += libext4_utils libz
 
+ifeq ($(HAVE_SELINUX), true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
@@ -86,6 +116,12 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_STATIC_LIBRARIES += libext4_utils libz
 
+ifeq ($(HAVE_SELINUX), true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_STATIC_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 include $(BUILD_HOST_EXECUTABLE)
 
 include $(CLEAR_VARS)
diff --git a/ext4_utils/contents.c b/ext4_utils/contents.c
index d64f7e0..de38bb0 100644
--- a/ext4_utils/contents.c
+++ b/ext4_utils/contents.c
@@ -25,6 +25,7 @@
 #include "contents.h"
 #include "extent.h"
 #include "indirect.h"
+#include "xattr.h"
 
 #ifdef USE_MINGW
 #define S_IFLNK 0  /* used by make_link, not needed under mingw */
@@ -248,3 +249,51 @@
 
 	return 0;
 }
+
+#ifdef HAVE_SELINUX
+#define XATTR_SELINUX_SUFFIX "selinux"
+
+/* XXX */
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+
+int inode_set_selinux(u32 inode_num, const char *secon)
+{
+	struct ext4_inode *inode = get_inode(inode_num);
+	u32 *hdr;
+	struct ext4_xattr_entry *entry;
+	size_t name_len = strlen(XATTR_SELINUX_SUFFIX);
+	size_t value_len = strlen(secon)+1;
+	size_t size, min_offs;
+	char *val;
+
+	if (!secon)
+		return 0;
+
+	if (!inode)
+		return -1;
+
+	hdr = (u32 *) (inode + 1);
+	*hdr = cpu_to_le32(EXT4_XATTR_MAGIC);
+	entry = (struct ext4_xattr_entry *) (hdr+1);
+	memset(entry, 0, EXT4_XATTR_LEN(name_len));
+	entry->e_name_index = EXT4_XATTR_INDEX_SECURITY;
+	entry->e_name_len = name_len;
+	memcpy(entry->e_name, XATTR_SELINUX_SUFFIX, name_len);
+	entry->e_value_size = cpu_to_le32(value_len);
+	min_offs = (char *)inode + info.inode_size - (char*) entry;
+	size = EXT4_XATTR_SIZE(value_len);
+	val = (char *)entry + min_offs - size;
+	entry->e_value_offs = cpu_to_le16(min_offs - size);
+	memset(val + size - EXT4_XATTR_PAD, 0, EXT4_XATTR_PAD);
+	memcpy(val, secon, value_len);
+	inode->i_extra_isize = cpu_to_le16(sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE);
+
+	return 0;
+}
+#else
+int inode_set_selinux(u32 inode_num, const char *secon)
+{
+	return 0;
+}
+#endif
diff --git a/ext4_utils/contents.h b/ext4_utils/contents.h
index 3aafb1e..35867fd 100644
--- a/ext4_utils/contents.h
+++ b/ext4_utils/contents.h
@@ -29,6 +29,7 @@
 	u16 gid;
 	u32 *inode;
 	u32 mtime;
+	char *secon;
 };
 
 u32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries,
@@ -36,4 +37,5 @@
 u32 make_file(const char *filename, u64 len);
 u32 make_link(const char *filename, const char *link);
 int inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime);
+int inode_set_selinux(u32 inode_num, const char *secon);
 #endif
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index ccba132..6cd5ade 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -98,7 +98,8 @@
 /* Read a local directory and create the same tree in the generated filesystem.
    Calls itself recursively with each directory in the given directory */
 static u32 build_directory_structure(const char *full_path, const char *dir_path,
-		u32 dir_inode, fs_config_func_t fs_config_func)
+		u32 dir_inode, fs_config_func_t fs_config_func,
+		struct selabel_handle *sehnd)
 {
 	int entries = 0;
 	struct dentry *dentries;
@@ -155,6 +156,18 @@
 			error("can't set android permissions - built without android support");
 #endif
 		}
+#ifdef HAVE_SELINUX
+		if (sehnd) {
+			char *sepath = NULL;
+			asprintf(&sepath, "/%s", dentries[i].path);
+			if (selabel_lookup(sehnd, &dentries[i].secon, sepath, stat.st_mode) < 0) {
+				error("cannot lookup security context for %s", sepath);
+			}
+			if (dentries[i].secon)
+				printf("Labeling %s as %s\n", sepath, dentries[i].secon);
+			free(sepath);
+		}
+#endif
 
 		if (S_ISREG(stat.st_mode)) {
 			dentries[i].file_type = EXT4_FT_REG_FILE;
@@ -188,7 +201,7 @@
 			entry_inode = make_file(dentries[i].full_path, dentries[i].size);
 		} else if (dentries[i].file_type == EXT4_FT_DIR) {
 			entry_inode = build_directory_structure(dentries[i].full_path,
-					dentries[i].path, inode, fs_config_func);
+					dentries[i].path, inode, fs_config_func, sehnd);
 		} else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
 			entry_inode = make_link(dentries[i].full_path, dentries[i].link);
 		} else {
@@ -202,11 +215,15 @@
 			dentries[i].mtime);
 		if (ret)
 			error("failed to set permissions on %s\n", dentries[i].path);
+		ret = inode_set_selinux(entry_inode, dentries[i].secon);
+		if (ret)
+			error("failed to set SELinux context on %s\n", dentries[i].path);
 
 		free(dentries[i].path);
 		free(dentries[i].full_path);
 		free(dentries[i].link);
 		free((void *)dentries[i].filename);
+		free(dentries[i].secon);
 	}
 
 	free(dentries);
@@ -279,7 +296,8 @@
     free_data_blocks();
 }
 
-int make_ext4fs(const char *filename, s64 len)
+int make_ext4fs(const char *filename, s64 len,
+                const char *mountpoint, struct selabel_handle *sehnd)
 {
 	int fd;
 	int status;
@@ -293,7 +311,7 @@
 		return EXIT_FAILURE;
 	}
 
-	status = make_ext4fs_internal(fd, NULL, NULL, NULL, 0, 0, 0, 1, 0);
+	status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, 0, sehnd);
 	close(fd);
 
 	return status;
@@ -301,7 +319,7 @@
 
 int make_ext4fs_internal(int fd, const char *directory,
                          char *mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse,
-                         int crc, int wipe, int init_itabs)
+                         int crc, int wipe, int init_itabs, struct selabel_handle *sehnd)
 {
 	u32 root_inode_num;
 	u16 root_mode;
@@ -393,7 +411,8 @@
 	root_inode_num = build_default_directory_structure();
 #else
 	if (directory)
-		root_inode_num = build_directory_structure(directory, mountpoint, 0, fs_config_func);
+		root_inode_num = build_directory_structure(directory, mountpoint, 0,
+                        fs_config_func, sehnd);
 	else
 		root_inode_num = build_default_directory_structure();
 #endif
@@ -401,6 +420,29 @@
 	root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
 	inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
 
+#ifdef HAVE_SELINUX
+	if (sehnd) {
+		char *sepath = NULL;
+		char *secontext = NULL;
+
+		if (mountpoint[0] == '/')
+			sepath = strdup(mountpoint);
+		else
+			asprintf(&sepath, "/%s", mountpoint);
+		if (!sepath)
+			critical_error_errno("malloc");
+		if (selabel_lookup(sehnd, &secontext, sepath, S_IFDIR) < 0) {
+			error("cannot lookup security context for %s", sepath);
+		}
+		if (secontext) {
+			printf("Labeling %s as %s\n", sepath, secontext);
+			inode_set_selinux(root_inode_num, secontext);
+		}
+		free(sepath);
+		freecon(secontext);
+	}
+#endif
+
 	ext4_update_free();
 
 	if (init_itabs)
diff --git a/ext4_utils/make_ext4fs.h b/ext4_utils/make_ext4fs.h
index 4e2c307..c217c3d 100644
--- a/ext4_utils/make_ext4fs.h
+++ b/ext4_utils/make_ext4fs.h
@@ -24,14 +24,22 @@
 extern "C" {
 #endif
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#else
+struct selabel_handle;
+#endif
+
 typedef void (*fs_config_func_t)(const char *path, int dir, unsigned *uid, unsigned *gid,
         unsigned *mode);
 
 void reset_ext4fs_info();
-int make_ext4fs(const char *filename, s64 len);
+int make_ext4fs(const char *filename, s64 len,
+                const char *mountpoint, struct selabel_handle *sehnd);
 int make_ext4fs_internal(int fd, const char *directory,
                          char *mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse,
-                         int crc, int wipe, int init_itabs);
+                         int crc, int wipe, int init_itabs, struct selabel_handle *sehnd);
 
 #ifdef __cplusplus
 }
diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c
index 3aab795..d545423 100644
--- a/ext4_utils/make_ext4fs_main.c
+++ b/ext4_utils/make_ext4fs_main.c
@@ -42,6 +42,7 @@
 	fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path));
 	fprintf(stderr, "    [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n");
 	fprintf(stderr, "    [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n");
+	fprintf(stderr, "    [ -S file_contexts ]\n");
 	fprintf(stderr, "    [ -z | -s ] [ -t ] [ -w ] [ -c ] [ -J ]\n");
 	fprintf(stderr, "    <filename> [<directory>]\n");
 }
@@ -60,8 +61,12 @@
 	int init_itabs = 0;
 	int fd;
 	int exitcode;
+	struct selabel_handle *sehnd = NULL;
+#ifdef HAVE_SELINUX
+	struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
+#endif
 
-	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsct")) != -1) {
+	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsctS:")) != -1) {
 		switch (opt) {
 		case 'l':
 			info.len = parse_num(optarg);
@@ -115,6 +120,16 @@
 		case 't':
 			init_itabs = 1;
 			break;
+		case 'S':
+#ifdef HAVE_SELINUX
+			seopts[0].value = optarg;
+			sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+			if (!sehnd) {
+				perror(optarg);
+				exit(EXIT_FAILURE);
+			}
+#endif
+			   break;
 		default: /* '?' */
 			usage(argv[0]);
 			exit(EXIT_FAILURE);
@@ -167,7 +182,7 @@
 	}
 
 	exitcode = make_ext4fs_internal(fd, directory, mountpoint, fs_config_func, gzip,
-			sparse, crc, wipe, init_itabs);
+			sparse, crc, wipe, init_itabs, sehnd);
 	close(fd);
 
 	return exitcode;
diff --git a/ext4_utils/mkuserimg.sh b/ext4_utils/mkuserimg.sh
index 3f2d2d4..1136a9e 100755
--- a/ext4_utils/mkuserimg.sh
+++ b/ext4_utils/mkuserimg.sh
@@ -1,11 +1,11 @@
-#!/bin/bash
+#!/bin/bash -x
 #
 # To call this script, make sure make_ext4fs is somewhere in PATH
 
 function usage() {
 cat<<EOT
 Usage:
-mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE
+mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [FILE_CONTEXTS]
 EOT
 }
 
@@ -17,7 +17,7 @@
   shift
 fi
 
-if [ $# -ne 4 -a $# -ne 5 ]; then
+if [ $# -ne 4 -a $# -ne 5 -a $# -ne 6 ]; then
   usage
   exit 1
 fi
@@ -32,6 +32,7 @@
 EXT_VARIANT=$3
 MOUNT_POINT=$4
 SIZE=$5
+FC=$6
 
 case $EXT_VARIANT in
   ext4) ;;
@@ -47,7 +48,11 @@
     SIZE=128M
 fi
 
-MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE -l $SIZE -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR"
+if [ -n "$FC" ]; then
+    FCOPT="-S $FC"
+fi
+
+MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE $FCOPT -l $SIZE -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR"
 echo $MAKE_EXT4FS_CMD
 $MAKE_EXT4FS_CMD
 if [ $? -ne 0 ]; then
diff --git a/ext4_utils/xattr.h b/ext4_utils/xattr.h
new file mode 100644
index 0000000..2c6d9cc
--- /dev/null
+++ b/ext4_utils/xattr.h
@@ -0,0 +1,23 @@
+#include <sys/types.h>
+
+#define EXT4_XATTR_MAGIC 0xEA020000
+#define EXT4_XATTR_INDEX_SECURITY 6
+
+struct ext4_xattr_entry {
+    __u8 e_name_len;
+    __u8 e_name_index;
+    __le16 e_value_offs;
+    __le32 e_value_block;
+    __le32 e_value_size;
+    __le32 e_hash;
+    char e_name[0];
+};
+
+#define EXT4_XATTR_PAD_BITS 2
+#define EXT4_XATTR_PAD (1<<EXT4_XATTR_PAD_BITS)
+#define EXT4_XATTR_ROUND (EXT4_XATTR_PAD-1)
+#define EXT4_XATTR_LEN(name_len) \
+    (((name_len) + EXT4_XATTR_ROUND + \
+    sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
+#define EXT4_XATTR_SIZE(size) \
+    (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
diff --git a/su/su.c b/su/su.c
index b87cece..f87f073 100644
--- a/su/su.c
+++ b/su/su.c
@@ -44,6 +44,13 @@
     struct passwd *pw;
     int uid, gid, myuid;
 
+    /* Until we have something better, only root and the shell can use su. */
+    myuid = getuid();
+    if (myuid != AID_ROOT && myuid != AID_SHELL) {
+        fprintf(stderr,"su: uid %d not allowed to su\n", myuid);
+        return 1;
+    }
+
     if(argc < 2) {
         uid = gid = 0;
     } else {
@@ -57,13 +64,6 @@
         }
     }
 
-    /* Until we have something better, only root and the shell can use su. */
-    myuid = getuid();
-    if (myuid != AID_ROOT && myuid != AID_SHELL) {
-        fprintf(stderr,"su: uid %d not allowed to su\n", myuid);
-        return 1;
-    }
-    
     if(setgid(gid) || setuid(uid)) {
         fprintf(stderr,"su: permission denied\n");
         return 1;