int main() { int fd; int wd; #define EV_BUFF 1024 char buffer[EV_BUFF]; fd = inotify_init(); if(fd < 0) xdie("inotify_init failed!"); /* create dir and try to watch it */ umask(0); mkdir(WATCHDIR, S_IRWXU | S_IRWXG); chown(WATCHDIR, AID_SYSTEM, AID_AUDIO); wd = inotify_add_watch(fd, WATCHDIR, IN_CREATE|IN_DELETE); if(wd < 0) xdie("inotify_add_watch failed!"); init_freq(); for(;;) { ALOGI("inotify event\n"); update_freq(); read(fd, buffer, EV_BUFF); } close(fd); return 0; }
void load_programs() { char* home = getenv("USERNAME"); char* path = malloc(50 + strlen(home)); DIR* dir; struct dirent * entry; sprintf(path,"/home/%s/.hgame/bin/",home); if(!(dir = opendir(path))) xdie("opendir"); while((entry = readdir(dir))) { if(!strcmp(entry->d_name + (strlen(entry->d_name)) - 3,".so")) { sprintf(path,"/home/%s/.hgame/bin/%s",home,entry->d_name); hgame_main.programs = realloc(hgame_main.programs,sizeof(struct hgame_program) * ++hgame_main.program_c); hgame_main.programs[hgame_main.program_c-1] = *(load_program(path)); memset(path,0,strlen(path)); } } }
void* xmalloc(int size) { void* p = malloc(size); if(!p) xdie("malloc"); return p; }
/* ** Try to figure out the GID android gave to the java polly helper ** Dies on error */ gid_t get_jpolly_gid() { struct stat xstat; int r; r = stat(JPOLLY_PATH, &xstat); if(r == -1 || xstat.st_gid < 10000) /* fixme: 10000: grab first possible app-gid from android includes */ xdie("failed to get gid of jpolly"); return xstat.st_gid; }
/* ** Creates the socket used by libcallvolume */ int get_audio_socket() { struct sockaddr_un saddr; int afd; if( (afd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) xdie("Could not create new socket"); saddr.sun_family = AF_UNIX; strcpy(saddr.sun_path, SOCKET_PATH); unlink(SOCKET_PATH); // may fail if( bind(afd, (struct sockaddr*)&saddr, sizeof(struct sockaddr_un) ) != 0 ) xdie("bind failed"); if(listen(afd, 64)) xdie("listen failed!"); return afd; }
char *xvasprintf(const char *fmt, va_list ap) { int r; char *retp; r = vasprintf(&retp, fmt, ap); if(r < 0) xdie("vasprintf\n"); return retp; }
void init_signal(void) { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sa.sa_sigaction = handle; if(sigaction(SIGSEGV,&sa,NULL) == -1) xdie("sigaction"); }
/* out is assumed to be of size PATH_MAX */ void make_path(char *out, const char *a, const char *b) { int alen, blen; alen = strlen(a); blen = strlen(b); if(alen + blen + 2 > PATH_MAX) xdie("attempted buffer overflow!?"); memmove(out, a, alen); out[alen] = '/'; memmove(out + alen + 1, b, blen); out[alen + blen + 1] = '\0'; }
/* Die with an error message if we can't malloc() enough space and do an * sprintf() into that space. */ char *xasprintf(const char *format, ...) { va_list p; int r; char *retp; va_start(p, format); r = vasprintf(&retp, format, p); va_end(p); if(r < 0) xdie("vasprintf\n"); return retp; }
/************************************************************ * Called if inotify registered a change * *************************************************************/ static void update_freq() { DIR *dfd; struct dirent *dentry; int i; int on; int minfreq; int maxfreq; dfd = opendir(WATCHDIR); if(dfd == NULL) xdie("opendir() failed"); on = 0; minfreq = MINFREQ_BASE; while( (dentry = readdir(dfd)) != NULL ) { ALOGI("+ item %d %s %d\n", dentry->d_type, dentry->d_name, strcmp(T_SCREEN_ON, dentry->d_name)); if(!strcmp(T_SCREEN_ON, dentry->d_name)) on = 1; if(!strcmp(T_AUDIO_ON, dentry->d_name)) minfreq = bval(minfreq, MINFREQ_AUDIO); if(!strcmp(T_A2DP_ON, dentry->d_name)) minfreq = bval(minfreq, MINFREQ_A2DP); if(!strcmp(T_MTP_ON, dentry->d_name)) minfreq = bval(minfreq, MINFREQ_MTP); } closedir(dfd); maxfreq = (on ? pp[0] : pp[1]); if(minfreq > maxfreq) maxfreq = minfreq; /* write twice to avoid state-change erros in the tegra cpufreq driver (new_min > old_freq) */ for(i=0;i<=1;i++) { sysfs_write("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", minfreq); sysfs_write("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", maxfreq); sysfs_write("/sys/module/cpu_tegra/parameters/cpu_user_cap", maxfreq); /* same as max_freq */ } sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/boost_factor", on ? pp[2] : pp[3]); sysfs_write("/sys/kernel/tegra_cap/core_cap_level", on ? pp[4] : pp[5]); sysfs_write("/sys/kernel/tegra_cap/core_cap_state", on ? pp[6] : pp[7]); /* always enabled (?) */ sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/max_boost", on ? pp[8] : pp[9]); sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/go_maxspeed_load", on ? pp[10]: pp[11]); }
/* ** Send an AT command to the modem ** Returns != 0 if the reply contained OK */ void send_xdrv_command(const char *cmd, int fd) { char atbuff[GBUFFSIZE]; size_t bread; struct timespec tx; /* the modem needs some time -fixme: this is hacky */ tx.tv_sec = 0; tx.tv_nsec = 75000000; DMSG(">>> %s", cmd); if( write(fd, cmd, strlen(cmd)) == -1 ) xdie("mux error: write failed"); nanosleep(&tx, NULL); bread = read(fd, &atbuff, GBUFFSIZE); DMSG("<<< %d bytes", bread); /* fixme: this should probably search for \r\nOK\r\n */ }
/* ** Try to grab a new pty ** Returns an opened FD, dies on error */ int get_pts_socket() { int i; int pts_fd = -1; char pts_path[GBUFFSIZE]; char fuser_cmd[GBUFFSIZE]; for(i=MUX_PTS_LAST;i>=MUX_PTS_FIRST;i--) { snprintf(pts_path, GBUFFSIZE,"/dev/pts/%d", i); snprintf(fuser_cmd, GBUFFSIZE, "/system/xbin/fuser %s", pts_path); DMSG("Searching for %s, executing %s", pts_path, fuser_cmd); if( (system(fuser_cmd) != 0) && (pts_fd = open(pts_path, O_RDWR)) != -1 ) { DMSG("Free pty is at %s, opened as fd %d", pts_path, pts_fd); break; } } if(pts_fd < 0) xdie("no free pts found"); return pts_fd; }
int main() { int afd, pfd, cfd; char rbuff[GBUFFSIZE]; size_t buff_len; int atlen = strlen(AT_PREFIX); gid_t jgid; /* make socket unreadable */ umask( 0777 ); /* get unix domain socket and pts */ afd = get_audio_socket(); pfd = get_pts_socket(); jgid= get_jpolly_gid(); /* only allow write access to the media user */ chown(SOCKET_PATH, USER_MEDIA, jgid); chmod(SOCKET_PATH, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP ); /* drop root */ setgid(jgid); setuid(USER_MEDIA); if(setuid(0) != -1) xdie("failed to drop root!"); /* terminates process if modem is stuck */ signal(SIGALRM, suicide); DMSG("socket setup finished. afd=%d, pfd=%d", afd, pfd); while( (cfd = accept(afd, NULL, NULL)) ) { /* read incomding data: we expect something like this: path,40,5,3,0,0,1,3,0,1,0,1,2,13 ..but we need.. AT+XDRV=40,5,3,0,0,1,3,0,1,0,1,2,13 the AT command string is 3 bytes longer, so we read to rbuff[3] and overwrite the rest afterwards */ memset(&rbuff, 0, GBUFFSIZE); buff_len = 3+read(cfd, &rbuff[3], GBUFFSIZE-3-2); /* -3 = offset, -2 = \r\0 */ memcpy(&rbuff, AT_PREFIX, atlen); /* add AT+XDRV= */ memcpy(&rbuff[buff_len], "\r\0", 2); /* terminate string */ /* send command to modem if it looks ok */ if(buff_len == TERM_LEN && memcmp(&rbuff, TERM_MAGIC, TERM_LEN) == 0) { DMSG("Poison cracker received, commiting suicide in %d seconds", TERM_DELAY); sleep(TERM_DELAY); xdie("terminating"); } else if(buff_len >= CALLVOLUME_CMDLEN && at_args_sane(&rbuff[atlen], buff_len-atlen) == 1) { alarm(AT_TIMEOUT); send_xdrv_command(rbuff, pfd); alarm(0); } else { DMSG("silently dropping invalid command with %d bytes len", buff_len); } close(cfd); } DMSG("exiting, accept returned false on fd %d", afd); close(afd); close(pfd); xdie("terminating"); return 0; }
/* ** Called by signal handler ** -> fired if the modem is stuck */ void suicide(int sig) { xdie("AT command timed out - terminating"); }
int main(int argc,char **argv) { int i; char* file = NULL; char* line = NULL; int execute = 0; init_signal(); o_stream = stdout; while((i = getopt_long(argc, argv, "svhxo:", long_options, NULL)) > 0) { switch(i) { case 's': suppress_error = 1; break; case 'v': die(VPRINT); case 'o': file = strdup(optarg); break; case 'x': execute = 1; break; case '?': case 'h': default: die(USAGE,argv[0]); break; } } banner(); if(optind >= argc) die(USAGE,argv[0]); if(!(i_stream = fopen(argv[optind],"r"))) xdie("fopen"); i_file = argv[optind]; if(file && !(o_stream = fopen(file,"w"))) xdie("fopen"); if(o_stream != stdout) { printf("Output redirected to %s...\n",file); close(1); if(dup(fileno(o_stream)) < 0) xdie("dup"); } hexmne.symbols = malloc(sizeof(struct hexmne_sym)); hexmne.syms_len = 1; hexmne.symbols[0].name = strdup("$$"); hexmne.symbols[0].offset = 0; line = xmalloc(256); hexmne.instr = xmalloc(sizeof(struct hexmne_instr)); hexmne.instr_len = i = 0; while(fgets(line,256,i_stream)) { line[strlen(line)-1] = '\0'; #ifdef _DEBUG printf("[DEBUG] %d:%s\n",nline,line); #endif if(line[0] == '#' || line[0] == '\0') continue; if(stroff(line,'#') != -1) line[stroff(line,'#')] = '\0'; if(line[0] == '@') { hexmne_preprocess( line ); continue; } hexmne_parse_all( line ); } #ifdef _DEBUG dump_symbols(); #endif relocateAllSymbols(); putchar('\n'); printInstr(); if(execute) lxs_execute(); free(hexmne.symbols); free(hexmne.instr); free(line); if(file) free(file); if(o_stream != stdout) fclose(o_stream); return 0; }