--- /dev/null
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <signal.h>
+#include <pthread.h>
+#include <termios.h>
+#include <aul/aul.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+
+struct app_info {
+ char *appid;
+ int pid;
+};
+
+static int verbose = 0;
+static int doinfo = 0;
+static int timeout = 1;
+static int pid = -1;
+static struct termios sterm;
+
+static char *appid = NULL;
+static char *pname = NULL;
+static char *ename = NULL;
+static const char *oname = NULL;
+
+static struct option long_options[] = {
+ {"appid", required_argument, 0, 'a'},
+ {"pipe", required_argument, 0, 'p'},
+ {"exec", required_argument, 0, 'e'},
+ {"error", required_argument, 0, 'o'},
+ {"timeout", required_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"list", no_argument, 0, 'l'},
+ {"info", no_argument, 0, 'i'},
+ {0, 0, 0, 0}
+};
+
+static FILE *tf;
+
+static void *output_thread(void *arg)
+{
+ size_t lsize = 0;
+ char *buffer = NULL;
+
+ while (getline(&buffer, &lsize, tf) != -1) {
+ puts(buffer);
+ }
+ free(buffer);
+
+ exit(0);
+}
+
+static void *wait_thread(void *arg)
+{
+ while (aul_app_get_status_bypid(pid) >= 0)
+ sleep(1);
+ exit(0);
+}
+
+static void finish()
+{
+ tcsetattr(0,TCSANOW, &sterm);
+ if (tf != NULL) {
+ fclose(tf);
+ unlink(pname);
+ }
+ kill(getpid(), SIGKILL);
+}
+
+static void split(char *line, char **array, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ while(line[0] == ' ') *line++ = 0;
+ array[i] = line;
+ line = index(line, ' ');
+ if (line == NULL)
+ break;
+ *line++ = 0;
+ }
+ i++;
+ if (i < n) {
+ int k;
+
+ for (k = 0; k <= i; k++) {
+ printf("%d == %s\n", k, array[k]);
+ }
+ }
+ for (; i < n; i++) {
+ array[i] = NULL;
+ }
+}
+
+static void *outstat(void *arg)
+{
+
+ char *sline = NULL;
+ char *pline = NULL;
+ char *mtline = NULL;
+ char *mfline = NULL;
+ size_t slen = 0;
+ size_t plen = 0;
+ size_t mtlen = 0;
+ size_t mflen = 0;
+ FILE *sstat = fopen("/proc/stat","r");
+ FILE *pstat;
+ FILE *pmstat;
+ FILE *tf = fopen("/sys/devices/system/cpu/present","r");
+ int tmp, ncpu;
+ char *pidname;
+ long psize = sysconf(_SC_PAGESIZE);
+ struct statvfs fstat;
+
+ printf("psize %ld\n", psize);
+
+ if (sstat == NULL ) {
+ perror("open /proc/stat");
+ exit(1);
+ }
+
+ if (tf == NULL ) {
+ perror("open /sys/devices/system/cpu/present");
+ exit(1);
+ }
+
+ fscanf(tf, "%d-%d\n", &tmp, &ncpu);
+ fclose(tf);
+ ncpu = ncpu - tmp + 1;
+
+ tf = fopen("/proc/meminfo", "r");
+ if (tf == NULL ) {
+ perror("open /proc/meminfo");
+ exit(1);
+ }
+
+
+ if (asprintf(&pidname, "/proc/%d/statm", pid) == -1) {
+ perror("asprintf");
+ exit(1);
+ }
+
+ pmstat = fopen(pidname, "r");
+ if (pmstat == NULL) {
+ perror("open /proc/$pid/statm");
+ exit(1);
+ }
+
+ pidname[strlen(pidname) - 1] = 0;
+ pstat = fopen(pidname, "r");
+ if (pstat == NULL) {
+ perror("open /proc/$pid/stat");
+ exit(1);
+ }
+ free(pidname);
+
+ while(1) {
+ time_t t = time(NULL);
+ char *stats[5];
+ char *pstats[18];
+ char *mt[3];
+ char *mf[3];
+ long pages;
+ long available;
+
+ fseek(sstat, 0, SEEK_SET);
+ fflush(sstat);
+ slen = getline(&sline, &slen, sstat);
+ if (slen == -1)
+ exit(1);
+
+ split(sline, stats, 5);
+
+ fseek(pstat, 0, SEEK_SET);
+ fflush(pstat);
+ plen = getline(&pline, &plen, pstat);
+ if (plen == -1)
+ exit(1);
+
+ split(pline, pstats, sizeof(pstats) / sizeof(pstats[0]));
+
+ fseek(pmstat, 0, SEEK_SET);
+ fflush(pmstat);
+ fscanf(pmstat, "%ld", &pages);
+
+ fseek(tf, 0, SEEK_SET);
+ fflush(tf);
+ mtlen = getline(&mtline, &mtlen, tf);
+ mflen = getline(&mfline, &mflen, tf);
+ if (mtlen == -1 || mflen == -1)
+ exit(1);
+
+ split(mtline, mt, 3);
+ split(mfline, mf, 3);
+
+ if (statvfs(".", &fstat) < 0) {
+ perror("statfs");
+ exit(1);
+ }
+
+ available = (fstat.f_bsize >= 1024)
+ ? (fstat.f_bsize / 1024) * fstat.f_bavail
+ : fstat.f_bavail / (1024 / fstat.f_bsize);
+
+ printf("%ld %d" " %s %s %s" " %s %s" " %s %s %ld %ld\n",
+ t, ncpu,
+ stats[1], stats[3], stats[4], /* user system idle */
+ pstats[14 - 1], pstats[15 - 1], /* puser psystem */
+ mt[1], mf[1], available, pages * psize);
+
+ sleep(timeout);
+ }
+ return NULL;
+}
+
+
+static void CheckValue(char **value, const char *info)
+{
+ if (value[0] != NULL) {
+ fprintf(stderr, "%s is already defined to %s\n", info, *value);
+ exit(1);
+ }
+ value[0] = optarg;
+}
+
+static int output_app_info(const aul_app_info *info, void *data)
+{
+ if (info == NULL || info->appid == NULL)
+ return -1;
+ fprintf(stderr, "pid %d status %d appid %s\n",
+ info->pid, info->status, info->appid);
+ return 0;
+}
+
+static int ListApps(int n)
+{
+ aul_app_get_all_running_app_info(output_app_info, NULL);
+ exit(0);
+}
+
+static int process_option(int argc, char **argv)
+{
+ int option_index;
+
+ switch(getopt_long(argc, argv, "-a:p:vle:o:it:",
+ long_options, &option_index)) {
+ case 1:
+ if (appid == NULL) {
+ appid = optarg;
+ } else if (pname == NULL) {
+ pname = optarg;
+ } else {
+ fprintf(stderr, "Extra argument %s\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'a': CheckValue(&appid, "Appid"); break;
+ case 'p': CheckValue(&pname, "pipe name"); break;
+ case 'e': CheckValue(&ename, "exe name"); break;
+ case 'o': CheckValue(&oname, "error name"); break;
+ case 'v': verbose++; break;
+ case 'l': ListApps(0); exit(0);
+ case 'i': doinfo = 1; break;
+ case 't': timeout = atoi(optarg); break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static void SimpleThread(void* (*func)(void *))
+{
+ pthread_attr_t attr;
+ pthread_t thread;
+
+ if (pthread_attr_init(&attr)) {
+ perror("pthread_attr_init");
+ exit(1);
+ }
+
+ if (pthread_create(&thread, &attr, func, NULL)) {
+ perror("pthread_create");
+ exit(1);
+ }
+}
+
+
+static int find_pid(const aul_app_info *info, void *data)
+{
+ if (!strcmp(appid, info->appid)) {
+ *(int*)data = info->pid;
+ return -1;
+ }
+ return 0;
+}
+
+static void waitappid(int n)
+{
+ if (appid == NULL)
+ exit(1);
+
+ for (; n > 0; n--) {
+ if (aul_app_is_running(appid)) {
+ int npid = 0;
+ aul_app_get_all_running_app_info(find_pid, &npid);
+ if (npid) {
+ SimpleThread(&wait_thread);
+ pid = npid;
+ return;
+ }
+ }
+ sleep(1);
+ }
+ exit(1);
+}
+
+#if 1
+static int app_launch_handler(int npid, const char *app_id, void *data)
+{
+ if (verbose) {
+ fprintf(stderr, "app_launch_handler %d - %s\n", npid, app_id);
+ }
+
+ if (pid > 0 || strcmp(app_id, appid))
+ return 0;
+
+ pid = npid;
+ return 1;
+}
+
+static int app_dead_handler(int npid, void *data)
+{
+ if (verbose) {
+ fprintf(stderr, "app_dead_handler %d\n", npid);
+ }
+
+ if (npid != pid)
+ return 0;
+
+ sleep(1);
+ exit(0);
+ return 1;
+}
+#endif
+
+static void openFileProcess()
+{
+ int pipefd[2];
+ int pid;
+ int id;
+
+ if (ename == NULL) {
+ tf = fopen(pname, "r");
+ if (tf == NULL) {
+ perror("fopen");
+ exit(1);
+ }
+ return;
+ }
+
+ if (access(ename, X_OK)) {
+ perror("access");
+ exit(1);
+ }
+
+ /* We must start interpreter process */
+ if (pipe(pipefd)) {
+ perror("pipe");
+ exit(1);
+ }
+
+ id = open(pname, O_RDONLY);
+ if (id < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ exit(1);
+ }
+
+ if (pid == 0) { /* Child */
+ close(pipefd[0]);
+ dup2(pipefd[1], 1); /* stdout */
+ dup2(id, 0); /* stdin */
+ execl(ename, ename, NULL);
+ perror("execl");
+ exit(1);
+ }
+
+ /* Parent */
+ close(pipefd[1]);
+ close(id);
+
+ tf = fdopen(pipefd[0], "r");
+ if (tf == NULL) {
+ perror("fopen");
+ exit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ struct termios term;
+ char *line = NULL;
+ size_t len = 0;
+
+ while(!process_option(argc, argv));
+
+ if (appid == NULL) {
+ fprintf(stderr, "Unknown app id\n");
+ exit(1);
+ }
+
+ if (oname == NULL) {
+ oname = "/tmp/profctl.log";
+ }
+
+ freopen(oname, "w", stderr);
+ setbuf(stderr, NULL);
+
+ if (pname) {
+ unlink(pname);
+ if (mkfifo(pname, 0666)) {
+ perror("mkfifo");
+ exit(1);
+ }
+ /* This may be useful for "root on" start */
+ if (setxattr(pname, "security.SMACK64", "User::App::Shared",
+ strlen("User::App::Shared"),0)) {
+ perror("setattr");
+ }
+ }
+
+ /* stty */
+ tcgetattr(0, &term);
+ sterm = term;
+
+ term.c_lflag &= ~(ECHO|ECHONL); /* no echo and so on */
+ term.c_oflag &= ~OPOST; /* no additional CR and so on */
+
+ tcsetattr(0,TCSANOW, &term);
+
+ atexit(finish);
+
+ if (pname) {
+ openFileProcess();
+ SimpleThread(&output_thread);
+ }
+
+#if 1
+ aul_listen_app_launch_signal_v2(app_launch_handler, NULL);
+ aul_listen_app_dead_signal(app_dead_handler, NULL);
+#endif
+
+ /* Read command loop */
+ while((len = getline(&line, &len, stdin)) != -1) {
+ if (verbose) {
+ fprintf(stderr, "line :%s#\n", line);
+ }
+ if ((pid != -1) && !strncmp(line, "exit", 4)) {
+ kill(pid, SIGHUP);
+ break;
+ } else if ((pid != -1) && !strncmp(line, "kill", 4)) {
+ if (kill(pid, SIGINT))
+ perror("kill");
+ } else if ((pid != -1) && !strncmp(line, "start", 5)) {
+ if (kill(pid, SIGRTMIN+8))
+ perror("kill");
+ } else if ((pid != -1) && !strncmp(line, "stop", 4)) {
+ if (kill(pid, SIGRTMIN+7))
+ perror("kill");
+ } else if (!strncmp(line, "test", 4) && (pid == -1)) {
+ waitappid(10); /* try 10 seconds */
+ if (verbose) {
+ fprintf(stderr, "pid = %d\n", pid);
+ }
+ if (doinfo) {
+ SimpleThread(&outstat);
+ }
+ }
+ }
+
+ return 0;
+}
+