Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
tw_cli/tw_cli.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
221 lines (181 sloc)
5.42 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE /* See feature_test_macros(7) */ | |
#include <unistd.h> | |
#include <sys/syscall.h> /* For SYS_xxx definitions */ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <sys/ptrace.h> | |
#include <errno.h> | |
#include <signal.h> | |
#include <sys/user.h> | |
#include <syscall.h> | |
#include <fcntl.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <stdarg.h> | |
#include <regex.h> | |
typedef uint64_t u64; | |
typedef int64_t s64; | |
/* from include/linux/dirent.h : */ | |
struct linux_dirent64 { | |
u64 d_ino; | |
s64 d_off; | |
unsigned short d_reclen; | |
unsigned char d_type; | |
char d_name[0]; | |
}; | |
void die(char *fmt,...) { | |
va_list ap; | |
va_start(ap,fmt); | |
vfprintf(stderr,fmt,ap); | |
exit(1); | |
} | |
void die_regerror(int status,regex_t *re) { | |
char msg[80]; | |
int s; | |
s=regerror(status,re,msg,sizeof(msg)); | |
die("regex: %s\n",msg); | |
} | |
int hostnum(char *hostname) { | |
static regex_t *re=NULL; | |
int status; | |
regmatch_t match[2]; | |
if (!re) { | |
re=malloc(sizeof(*re)); | |
if (!re) die(""); | |
status=regcomp(re,"^host([0-9]+)$",REG_EXTENDED); | |
if (status) die_regerror(status,re); | |
} | |
status=regexec(re,hostname,sizeof(match)/sizeof(*match),match,0); | |
if (status==0) { | |
char c=hostname[match[1].rm_eo]; | |
match[1].rm_eo='\0'; | |
int num=atoi(&hostname[match[1].rm_so]); | |
match[1].rm_eo=c; | |
return(num); | |
} else if (status==REG_NOMATCH) { | |
return(-1); | |
} else { | |
die_regerror(status,re); | |
} | |
} | |
struct sortentry { | |
struct linux_dirent64 *dirent; | |
int hostnum; | |
}; | |
int compare_sortentry(const void *vp1,const void *vp2) { | |
struct sortentry *p1=(struct sortentry *)vp1; | |
struct sortentry *p2=(struct sortentry *)vp2; | |
if (p1->hostnum!=-1 && p2->hostnum!=-1) { | |
return p1->hostnum<p2->hostnum ? -1 : p1->hostnum>p2->hostnum ? 1 : 0; | |
} | |
return strcmp(p1->dirent->d_name,p2->dirent->d_name); | |
} | |
void fix_memory(pid_t pid,size_t count,void *dirp) { | |
char *memfilename; | |
int fd; | |
char *dirents_unsorted,*dirents_sorted; | |
struct sortentry *sort_array; | |
struct sortentry *sort_entry; | |
size_t s; | |
int entry_count; | |
int bpos; | |
int i; | |
struct linux_dirent64 *d; | |
if (count==0) return; | |
if (asprintf(&memfilename,"/proc/%d/mem",pid)==-1) die("%m\n"); | |
fd=open(memfilename,O_RDWR); | |
if (fd==-1) die (memfilename); | |
dirents_unsorted=malloc(count); | |
if(!dirents_unsorted) die (""); | |
if (lseek(fd,(off_t)dirp,SEEK_SET)==-1) die("%s: %m\n",memfilename); | |
s=read(fd,dirents_unsorted,count); | |
if (s == -1) die("%s: %m\n",memfilename); | |
if (s != count) die("short reads on childs memory not implemented"); | |
entry_count=0; | |
for (bpos=0;bpos<count;) { | |
d = (struct linux_dirent64 *) (dirents_unsorted + bpos); | |
entry_count++; | |
bpos+=d->d_reclen; | |
} | |
sort_array=malloc(entry_count*sizeof (*sort_array)); | |
if (!sort_array) die (""); | |
sort_entry=sort_array; | |
for (bpos=0;bpos<count;) { | |
d = (struct linux_dirent64 *) (dirents_unsorted + bpos); | |
sort_entry->dirent=d; | |
sort_entry->hostnum=hostnum(d->d_name); | |
sort_entry++; | |
bpos+=d->d_reclen; | |
} | |
// for (i=0;i<entry_count;i++) { printf("ary[%d] : %p : %s : %d\n",i,sort_array[i].dirent,sort_array[i].dirent->d_name,sort_array[i].hostnum); } | |
qsort(sort_array,entry_count,sizeof(*sort_array),compare_sortentry); | |
// for (i=0;i<entry_count;i++) { printf("ary[%d] : %p : %s : %d\n",i,sort_array[i].dirent,sort_array[i].dirent->d_name,sort_array[i].hostnum); } | |
dirents_sorted=malloc(count); | |
if(!dirents_sorted) die ("%m\n"); | |
bpos=0; | |
for (i=0;i<entry_count;i++) { | |
d = (struct linux_dirent64 *) (dirents_sorted + bpos); | |
memcpy(d,sort_array[i].dirent,sort_array[i].dirent->d_reclen); | |
bpos+=sort_array[i].dirent->d_reclen; | |
} | |
// for (bpos=0;bpos<count;) { d = (struct linux_dirent64 *) (dirents_sorted + bpos); printf(" --> %s\n",d->d_name); bpos+=d->d_reclen; } | |
if (lseek(fd,(off_t)dirp,SEEK_SET)==-1) die("%s: %m\n",memfilename); | |
s=write(fd,dirents_sorted,count); | |
if (s == -1) die(memfilename); | |
if (s != count) die("internal error: short write"); | |
close(fd); | |
free(memfilename); | |
free(dirents_unsorted); | |
free(dirents_sorted); | |
free(sort_array); | |
} | |
int main(int argc, char **argv) { | |
pid_t pid; | |
int status; | |
int syscall_state=0; | |
struct user user; | |
static const char *TW_CLI_ORIG="/root/bin/tw_cli.exe"; | |
pid=fork(); | |
if (pid==0) { | |
if (ptrace(PTRACE_TRACEME,NULL,NULL)==-1) die("ptrace: %m\n"); | |
execv(TW_CLI_ORIG,argv); | |
die("%s: %m\n",TW_CLI_ORIG); | |
} else if (pid==-1) { | |
die("fork: %m\n"); | |
} | |
while(1) { | |
pid=wait(&status); | |
if (pid==-1) die("wait: %m\n"); | |
if (WIFSIGNALED(status)) { | |
int signal=WTERMSIG(status); | |
die("child got signal %d - exiting\n",signal); | |
} else if (WIFSTOPPED(status)) { | |
int signal=WSTOPSIG(status); | |
if (signal==SIGTRAP) { | |
if(ptrace(PTRACE_SETOPTIONS,pid,NULL,PTRACE_O_TRACESYSGOOD)==-1) die("ptrace: %m\n"); | |
if(ptrace(PTRACE_SYSCALL,pid,NULL,NULL)==-1) die ("ptrace: %m\n"); | |
} else if (signal==SIGTRAP|0x80) { | |
if (syscall_state==1) { | |
if(ptrace(PTRACE_GETREGS,pid,NULL,&user)==-1) die("ptrace: %m\n");; | |
if (user.regs.orig_rax == SYS_getdents64) { | |
fix_memory(pid,(int)user.regs.rax,(void *)user.regs.rsi); | |
} | |
} | |
syscall_state=1-syscall_state; | |
if(ptrace(PTRACE_SYSCALL,pid,NULL,NULL)==-1) die("ptrace: %m\n");; | |
} else { | |
die("child stopped by signal %d - exiting\n",signal); | |
} | |
} else if (WIFEXITED(status)) { | |
if (WEXITSTATUS(status)) { | |
exit(1); | |
} else { | |
exit(0); | |
} | |
} else { | |
die("unexpected return from wait. status=%08x - exiting\n",status); | |
} | |
} | |
} | |