aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Bersenev <bay@hackerdom.ru>2011-07-06 23:44:26 +0000
committerAlexander Bersenev <bay@hackerdom.ru>2011-07-06 23:44:26 +0000
commiteb64287c7e19a3b5671dc3b45c092722739b3b65 (patch)
tree5f764a51d4969943d630d0280bcecdb82d417183
parentwork with usersandbox feature, futher work for outout (diff)
downloadautodep-eb64287c7e19a3b5671dc3b45c092722739b3b65.tar.gz
autodep-eb64287c7e19a3b5671dc3b45c092722739b3b65.tar.bz2
autodep-eb64287c7e19a3b5671dc3b45c092722739b3b65.zip
many new calls hooked, internal structures format was vhanged
-rw-r--r--NOTES22
-rwxr-xr-xlogger/src/autodep/showfsevents.py140
-rw-r--r--logger/src/hook_lib/file_hook.c337
3 files changed, 324 insertions, 175 deletions
diff --git a/NOTES b/NOTES
index 54b2aee..fd20dab 100644
--- a/NOTES
+++ b/NOTES
@@ -13,17 +13,17 @@ This is few notes mainly for myself.
3. Format of events structure:
[
{
- <stage of building>:{<filename>:[<was readed>,<was writed>]}
+ <stage of building>:{<filename>:(<was readed>,<was writed>)}
},
{
- <stage of building>:{<filename>:[<was not found>,<was blocked>]}
+ <stage of building>:{<filename>:(<was not found>,<was blocked>)}
}
]
4. Format of converted events structure:
{
- packagesinfo: {
- <package>: {
+# packagesinfo: {
+ <package|unknown>: {
stage: {
<filename>:
{found:[<was readed>,<was writed>],
@@ -32,12 +32,12 @@ This is few notes mainly for myself.
}
}
- otherfilesinfo: {
- stage:{
- <filename>:
- {found:[<was readed>,<was writed>],
- notfound:[<was not found>,<was blocked>]}
- }
- }
+ #otherfilesinfo: {
+ # stage:{
+ # <filename>:
+ # {found:[<was readed>,<was writed>],
+ # notfound:[<was not found>,<was blocked>]}
+ #}
+ #}
}
diff --git a/logger/src/autodep/showfsevents.py b/logger/src/autodep/showfsevents.py
index b738a76..68f8425 100755
--- a/logger/src/autodep/showfsevents.py
+++ b/logger/src/autodep/showfsevents.py
@@ -11,10 +11,13 @@ import logfs.portage_utils
args_parser=optparse.OptionParser("%prog [options] <command>")
args_parser.add_option("-b", "--block",action="store", type="string",
dest="packages", default="", help="block an access to files from this packages")
+args_parser.add_option("-u", "--unknown", action="store_true", dest="show_unknown",
+ default=False, help="show unknown stage and files from unknown package")
args_parser.add_option("-v", action="store_true", dest="verbose",
default=False, help="show accessed files")
-args_parser.add_option("-u", "--unknown", action="store_true", dest="show_unknown_stage",
- default=False, help="show unknown stage")
+args_parser.add_option("-n","--notfound", action="store_true", dest="show_notfound",
+ default=False, help="show not founded files")
+
args_parser.add_option("--hooklib",action="store_const", dest="approach",
const="hooklib", help="use ld_preload logging approach(default)")
@@ -73,12 +76,13 @@ file_to_package=logfs.portage_utils.getpackagesbyfiles(filenames)
# this part is completly unreadable. It converting one complex struct(returned by getfsevents) to
# another complex struct which good for generating output
+# old struct is also used during output
-events_converted_for_output={}
+#events_converted_for_output={}
packagesinfo={}
-events_converted_for_output["packagesinfo"]=packagesinfo
-otherfilesinfo={}
-events_converted_for_output["otherfilesinfo"]=otherfilesinfo
+#events_converted_for_output=packagesinfo
+#otherfilesinfo={}
+#events_converted_for_output["otherfilesinfo"]=otherfilesinfo
for stage in sorted(events):
succ_events=events[stage][0]
@@ -87,15 +91,18 @@ for stage in sorted(events):
for filename in succ_events:
if filename in file_to_package:
package=file_to_package[filename]
- if not package in packagesinfo:
- packagesinfo[package]={}
- stageinfo=packagesinfo[package]
- if not stage in stageinfo:
- stageinfo[stage]={}
else:
- stageinfo=otherfilesinfo
- if not stage in stageinfo:
- stageinfo[stage]={}
+ package="unknown"
+
+ if not package in packagesinfo:
+ packagesinfo[package]={}
+ stageinfo=packagesinfo[package]
+ if not stage in stageinfo:
+ stageinfo[stage]={}
+# else:
+# stageinfo=otherfilesinfo
+# if not stage in stageinfo:
+# stageinfo[stage]={}
filesinfo=stageinfo[stage]
if not filename in filesinfo:
@@ -105,15 +112,17 @@ for stage in sorted(events):
for filename in fail_events:
if filename in file_to_package:
package=file_to_package[filename]
- if not package in packagesinfo:
- packagesinfo[package]={}
- stageinfo=packagesinfo[package]
- if not stage in stageinfo:
- stageinfo[stage]={}
else:
- stageinfo=otherfilesinfo
- if not stage in stageinfo:
- stageinfo[stage]={}
+ package="unknown"
+ if not package in packagesinfo:
+ packagesinfo[package]={}
+ stageinfo=packagesinfo[package]
+ if not stage in stageinfo:
+ stageinfo[stage]={}
+ #else:
+ # stageinfo=otherfilesinfo
+ # if not stage in stageinfo:
+ # stageinfo[stage]={}
filesinfo=stageinfo[stage]
if not filename in filesinfo:
@@ -133,15 +142,18 @@ for package in packagesinfo:
stagesorder={"clean":1,"setup":2,"unpack":3,"prepare":4,"configure":5,"compile":6,"test":7,
"install":8,"preinst":9,"postinst":10,"prerm":11,"postrm":12,"unknown":13}
-
+# print information grouped by package
for package in sorted(packagesinfo):
# not showing special directory package
if package=="directory":
continue
+ if package=="unknown" and not options.show_unknown:
+ continue
+
stages=[]
for stage in sorted(packagesinfo[package].keys(), key=stagesorder.get):
- if stage!="unknown" or options.show_unknown_stage or not was_emerge_process:
+ if stage!="unknown" or options.show_unknown or not was_emerge_process:
stages.append(stage)
if len(stages)!=0:
@@ -158,56 +170,36 @@ for package in sorted(packagesinfo):
else:
old_was_readed, old_was_writed=filenames[filename]
filenames[filename]=[old_was_readed | was_readed, old_was_writed | was_writed ]
-
+
+ # this is here for readability
+ action={
+ (False,False):"accessed",
+ (True,False):"readed",
+ (False,True):"writed",
+ (True,True):"readed and writed"
+ }
+
for filename in filenames:
- if filenames[filename]==[False,False]:
- action="accessed"
- elif filenames[filename]==[True,False]:
- action="readed"
- elif filenames[filename]==[False,True]:
- action="writed"
- elif filenames[filename]==[True,True]:
- action="readed and writed"
- print " %-56s %-21s" % (filename,action)
-
+ event_info=tuple(filenames[filename])
+ print " %-56s %-21s" % (filename,action[event_info])
+
+# print not founded files with stages
+if options.show_notfound:
+ filenames={}
+ print "\nNot founded files:"
+ for stage in sorted(events, key=stagesorder.get):
+ print "%s:" % stage
-
-"""
-for stage in sorted(events, key=stagesorder.get):
- succ_events=events[stage][0]
- fail_events=events[stage][1]
- print "On stage %s:" % stage
- for filename in sorted(succ_events, key=file_to_package.get):
- print " %-40s" % filename,
- action=""
- if succ_events[filename]==[False,False]:
- action="accessed",
- elif succ_events[filename]==[True,False]:
- action="readed",
- elif succ_events[filename]==[False,True]:
- action="writed",
- elif succ_events[filename]==[True,True]:
- action="readed and writed",
-
- print " %-21s " % action,
- if filename in file_to_package:
- print file_to_package[filename],
- print
+ action={
+ (True,False):"file not found",
+ (True,True):"blocked and not found",
+ (False,True):"blocked",
+ (False,False):"other error"
+ }
+
+ fail_events=events[stage][1]
- for filename in sorted(fail_events, key=file_to_package.get):
- print " %-40s" % filename,
- action=""
- if fail_events[filename]==[True,False]:
- action="file not found"
- elif fail_events[filename]==[True,True]:
- action="blocked and not found"
- elif fail_events[filename]==[False,True]:
- action="blocked"
- elif fail_events[filename]==[False,False]:
- action="other error"
- print " %-21s " % action,
- if filename in file_to_package:
- print file_to_package[filename],
- print
- """
-##logfs.fstracer.getfsevents("emerge", ["emerge","--info"])
+ for filename in sorted(fail_events, key=file_to_package.get):
+ reason=tuple(fail_events[filename])
+ print " %-56s %-21s" % (filename,action[reason])
+
diff --git a/logger/src/hook_lib/file_hook.c b/logger/src/hook_lib/file_hook.c
index 9012b20..efe3c9c 100644
--- a/logger/src/hook_lib/file_hook.c
+++ b/logger/src/hook_lib/file_hook.c
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
@@ -25,6 +26,7 @@
#define MAXENVSIZE 65536
#define MAXENVITEMSIZE 256
+#define MAXARGS 256
//extern int errorno;
pthread_mutex_t socketblock = PTHREAD_MUTEX_INITIALIZER;
@@ -41,8 +43,13 @@ size_t (*_fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream);
int (*_execve)(const char *filename, char *const argv[],char *const envp[]);
int (*_execv)(const char *path, char *const argv[]);
int (*_execvp)(const char *file, char *const argv[]);
+int (*_execvpe)(const char *file, char *const argv[], char *const envp[]);
+
+//int (*_execl)(const char *path, const char *arg, ...);
int (*_fexecve)(int fd, char *const argv[], char *const envp[]);
+
+
int (*_system)(const char *command);
pid_t (*_fork)();
@@ -52,8 +59,11 @@ int (*_close)(int fd); // we hooking this, because some programs closes our sock
int log_socket=-1;
-char log_socket_name[MAXSOCKETPATHLEN];
char ld_preload_orig[MAXPATHLEN];
+char log_socket_name[MAXSOCKETPATHLEN];
+
+char ld_preload_env[MAXENVITEMSIZE]; // value: LD_PRELOAD=ld_preload_orig
+char log_socket_env[MAXENVITEMSIZE]; // value: LOG_SOCKET=log_socket_name
void __doconnect(){
if(strlen(log_socket_name)>=MAXSOCKETPATHLEN) {
@@ -126,9 +136,13 @@ void _init() {
_write= (ssize_t (*)(int fd, const void *buf, size_t count)) dlsym(RTLD_NEXT, "write");
_fork = (pid_t (*)()) dlsym(RTLD_NEXT, "fork");
+
_execve = (int (*)(const char *filename, char *const argv[],char *const envp[])) dlsym(RTLD_NEXT, "execve");
_execv = (int (*)(const char *path, char *const argv[])) dlsym(RTLD_NEXT, "execv");
_execvp = (int (*)(const char *file, char *const argv[])) dlsym(RTLD_NEXT, "execvp");
+ _execvpe = (int (*)(const char *file, char *const argv[], char *const envp[])) dlsym(RTLD_NEXT, "execvpe");
+
+ //_execl =(int (*)(const char *path, const char *arg, ...)) dlsym(RTLD_NEXT, "execl");
_fexecve = (int (*)(int fd, char *const argv[], char *const envp[])) dlsym(RTLD_NEXT, "fexecve");
@@ -142,12 +156,17 @@ void _init() {
if(_open==NULL || _open64==NULL ||
_fopen==NULL || _fopen64==NULL ||
_read==NULL || _write==NULL ||
- _fork==NULL || _execve==NULL || _execv==NULL || _fexecve==NULL || _execvp==NULL ||
- _system==NULL || _setenv==NULL || _close==NULL) {
+ _fork==NULL ||
+ _execve==NULL || _execv==NULL || _execvp==NULL || _execvpe==NULL ||
+ _fexecve==NULL || _system==NULL || _setenv==NULL || _close==NULL) {
fprintf(stderr,"Failed to load original functions of hook\n");
exit(1);
}
+ snprintf(ld_preload_env,MAXENVITEMSIZE,"LD_PRELOAD=%s",ld_preload_orig);
+ snprintf(log_socket_env,MAXENVITEMSIZE,"LOG_SOCKET=%s",log_socket_name);
+
+
__doconnect();
}
@@ -250,6 +269,59 @@ static int __is_event_allowed(const char *event_type,const char *filename, char*
}
+
+void __fixenv() {
+ _setenv("LOG_SOCKET",log_socket_name,1);
+ _setenv("LD_PRELOAD",ld_preload_orig,1);
+ snprintf(ld_preload_env,MAXENVITEMSIZE,"LD_PRELOAD=%s",ld_preload_orig);
+ snprintf(log_socket_env,MAXENVITEMSIZE,"LOG_SOCKET=%s",log_socket_name);
+}
+
+/*
+ * Fixes LD_PRELOAD and LOG_SOCKET in envp and puts modified value in envp_new
+*/
+void __fixenvp(char *const envp[], char *envp_new[]) {
+ int ld_preload_valid=0;
+ int log_socket_valid=0;
+ int i;
+ for(i=0;envp[i];i++){
+ if(strncmp(envp[i],"LD_PRELOAD=",11)==0)
+ if(strcmp(envp[i]+11,ld_preload_orig)==0)
+ ld_preload_valid=1;
+ if(strncmp(envp[i],"LOG_SOCKET=",11)==0)
+ if(strcmp(envp[i]+11,log_socket_name)==0)
+ log_socket_valid=1;
+ }
+ if(!ld_preload_valid || !log_socket_valid) {
+ for(i=0; envp[i] && i<MAXENVSIZE-3; i++) {
+ if(strncmp(envp[i],"LD_PRELOAD=",11)==0) {
+ envp_new[i]=ld_preload_env;
+ ld_preload_valid=1;
+ } else if(strncmp(envp[i],"LOG_SOCKET=",11)==0) {
+ envp_new[i]=log_socket_env;
+ log_socket_valid=1;
+ } else {
+ envp_new[i]=envp[i];
+ }
+ }
+
+ if(!ld_preload_valid) {
+ envp_new[i]=ld_preload_env;
+ i++;
+ }
+ if(!log_socket_valid) {
+ envp_new[i]=log_socket_env;
+ i++;
+ }
+ envp_new[i]=NULL;
+ }
+}
+
+/*
+ * Below are functions we hooking
+ * The common strategy is:
+ * 1) ask python part for allowness 2) do call 3) tell a result
+*/
int open(const char * path, int flags, mode_t mode) {
int ret;
char fullpath[MAXPATHLEN];
@@ -356,8 +428,6 @@ ssize_t read(int fd, void *buf, size_t count){
__log_event("read",fullpath,"OK",0,stage);
}
- //__log_event("debug",fullpath,"ERR",getpid(),stage);
-
errno=saved_errno;
return ret;
}
@@ -380,13 +450,8 @@ ssize_t write(int fd,const void *buf, size_t count){
}
pid_t fork(void) {
- //fprintf(stderr,"prefork %s %s\n",getenv("LOG_SOCKET"),log_socket_orig);
- //int succ=
- _setenv("LOG_SOCKET",log_socket_name,1);
- _setenv("LD_PRELOAD",ld_preload_orig,1);
- //ld_preload_orig
- //fprintf(stderr,"prefork %s%p%p%d %s\n",getenv("LOG_SOCKET"),_setenv,setenv,succ,log_socket_orig);
+ __fixenv();
int ret=_fork();
int saved_errno=errno;
@@ -405,77 +470,196 @@ pid_t fork(void) {
int execve(const char *filename, char *const argv[],
char *const envp[]) {
+ char *stage=__get_stage();
+ if(! __is_event_allowed("open",filename,stage)) {
+ __log_event("open",filename,"DENIED",errno,stage);
+ errno=2; // not found
+ return -1;
+ }
+
if(access(filename, F_OK)!=-1)
- __log_event("read",filename,"OK",0,__get_stage());
+ __log_event("read",filename,"OK",0,stage);
else
- __log_event("open",filename,"ERR",2,__get_stage());
+ __log_event("open",filename,"ERR",2,stage);
- //fprintf(stderr,"executing %s pid=%d", filename,getpid());
- char *new_envp[MAXENVSIZE];
- char new_ld_preload[MAXENVITEMSIZE];
- char new_log_socket[MAXENVITEMSIZE];
+ char *envp_new[MAXENVSIZE];
+ __fixenvp(envp,envp_new);
+
+ int ret=_execve(filename, argv, envp_new);
- int ld_preload_valid=0;
- int log_socket_valid=0;
- int i;
- for(i=0;envp[i];i++){
- if(strncmp(envp[i],"LD_PRELOAD=",11)==0)
- if(strcmp(envp[i]+11,ld_preload_orig)==0)
- ld_preload_valid=1;
- if(strncmp(envp[i],"LOG_SOCKET=",11)==0)
- if(strcmp(envp[i]+11,log_socket_name)==0)
- log_socket_valid=1;
+ return ret;
+}
+
+int execv(const char *path, char *const argv[]){
+ char *stage=__get_stage();
+ if(! __is_event_allowed("open",path,stage)) {
+ __log_event("open",path,"DENIED",errno,stage);
+ errno=2; // not found
+ return -1;
}
- if(!ld_preload_valid || !log_socket_valid) {
- snprintf(new_ld_preload,MAXENVITEMSIZE,"LD_PRELOAD=%s",ld_preload_orig);
- snprintf(new_log_socket,MAXENVITEMSIZE,"LOG_SOCKET=%s",log_socket_name);
- for(i=0; envp[i] && i<MAXENVSIZE-3; i++) {
- if(strncmp(envp[i],"LD_PRELOAD=",11)==0) {
- new_envp[i]=new_ld_preload;
- ld_preload_valid=1;
- } else if(strncmp(envp[i],"LOG_SOCKET=",11)==0) {
- new_envp[i]=new_log_socket;
- log_socket_valid=1;
- } else {
- new_envp[i]=envp[i];
- }
+
+ __fixenv();
+
+ if(access(path, F_OK)!=-1)
+ __log_event("read",path,"OK",0,stage);
+ else
+ __log_event("open",path,"ERR",2,stage);
+
+ return _execv(path,argv);
+}
+
+int execvp(const char *file, char *const argv[]){
+ char *stage=__get_stage();
+ if(strchr(file,'/')!=NULL) {
+ if(! __is_event_allowed("open",file,stage)) {
+ __log_event("open",file,"DENIED",errno,stage);
+ errno=2; // not found
+ return -1;
}
+
+ if(access(file, F_OK)!=-1)
+ __log_event("read",file,"OK",0,stage);
+ else
+ __log_event("open",file,"ERR",2,stage);
+
+ } else {
+ // TODO: may me repeat bash's PATH parsing logic here
+ }
- if(!ld_preload_valid) {
- new_envp[i]=new_ld_preload;
- i++;
+ __fixenv();
+
+
+ return _execvp(file,argv);
+}
+
+int execvpe(const char *file, char *const argv[],
+ char *const envp[]){
+ char *stage=__get_stage();
+
+ if(strchr(file,'/')!=NULL) {
+ if(! __is_event_allowed("open",file,stage)) {
+ __log_event("open",file,"DENIED",errno,stage);
+ errno=2; // not found
+ return -1;
}
- if(!log_socket_valid) {
- new_envp[i]=new_log_socket;
- i++;
-}
- new_envp[i]=NULL;
- envp=new_envp;
-// for(i=0;envp[i];i++){
-// printf("BAY: %s\n",envp[i]);
-// }
+
+ if(access(file, F_OK)!=-1)
+ __log_event("read",file,"OK",0,stage);
+ else
+ __log_event("open",file,"ERR",2,stage);
+
+ } else {
+ // TODO: may me repeat bash's PATH parsing logic here
+ }
+
+ char *envp_new[MAXENVSIZE];
+ __fixenvp(envp,envp_new);
+
+ return _execvpe(file,argv,envp_new);
+}
+int execl(const char *path, const char *arg, ...){
+ char *stage=__get_stage();
+ if(! __is_event_allowed("open",path,stage)) {
+ __log_event("open",path,"DENIED",errno,stage);
+ errno=2; // not found
+ return -1;
}
+
+ __fixenv();
+
+ if(access(path, F_OK)!=-1)
+ __log_event("read",path,"OK",0,stage);
+ else
+ __log_event("open",path,"ERR",2,stage);
- fflush(stderr);
- int ret=_execve(filename, argv, envp);
+ va_list ap;
+ char * argv[MAXARGS+1];
+ int i=0;
- return ret;
+ va_start(ap,arg);
+ while(arg!=0 && i<MAXARGS) {
+ argv[i++]=arg;
+ arg=va_arg(ap,const char *);
+ }
+ argv[i]=NULL;
+ va_end(ap);
+ return _execv(path,argv);
}
-//int clone(int (*fn)(void *), void *child_stack,
-// int flags, void *arg, ...) {
-// fprintf(stderr,"clone pid=%d",getpid());
-// fflush(stderr);
+int execlp(const char *file, const char *arg, ...) {
+ char *stage=__get_stage();
+ if(strchr(file,'/')!=NULL) {
+ if(! __is_event_allowed("open",file,stage)) {
+ __log_event("open",file,"DENIED",errno,stage);
+ errno=2; // not found
+ return -1;
+ }
+ if(access(file, F_OK)!=-1)
+ __log_event("read",file,"OK",0,stage);
+ else
+ __log_event("open",file,"ERR",2,stage);
+ } else {
+ // TODO: may me repeat bash's PATH parsing logic here
+ }
-// return -1;//_clone(fn,child_stack,flags,arg);
-//}
+ __fixenv();
+
+ va_list ap;
+ char * argv[MAXARGS+1];
+ int i=0;
+
+ va_start(ap,arg);
+ while(arg!=0 && i<MAXARGS) {
+ argv[i++]=arg;
+ arg=va_arg(ap,const char *);
+ }
+ argv[i]=NULL;
+ va_end(ap);
+ return _execvp(file,argv);
+}
-/*int fexecve(int fd, char *const argv[], char *const envp[]) {
+int execle(const char *path, const char *arg, ... ){
+ char *stage=__get_stage();
+ if(! __is_event_allowed("open",path,stage)) {
+ __log_event("open",path,"DENIED",errno,stage);
+ errno=2; // not found
+ return -1;
+ }
+
+ if(access(path, F_OK)!=-1)
+ __log_event("read",path,"OK",0,stage);
+ else
+ __log_event("open",path,"ERR",2,stage);
+
+ va_list ap;
+ char * argv[MAXARGS+1];
+ argv[0]=arg;
+
+ va_start(ap,arg);
+ int i=0;
+ while(argv[i++]!=NULL && i<MAXARGS) {
+ argv[i]=va_arg(ap,const char *);
+ }
+ char *const *envp=va_arg(ap, const char *const *);
+
+ char *envp_new[MAXENVSIZE];
+ __fixenvp(envp,envp_new);
+
+ va_end(ap);
+ return _execve(path,argv,envp_new);
+}
+
+
+
+/*
+int fexecve(int fd, char *const argv[], char *const envp[]) {
fprintf(stderr,"fexecuting pid=%d",getpid());
fflush(stderr);
- return _fexecve(fd,argv,envp);
+
+ int ret=_fexecve(fd, argv, envp);
+ return ret;
}
int execle(const char *path, const char *arg, ...) {
@@ -485,38 +669,11 @@ int execle(const char *path, const char *arg, ...) {
return 0;
}
-int execl(const char *path, const char *arg, ...){
- fprintf(stderr,"execluting 1 pid=%d",getpid());
- fflush(stderr);
-//
- return 0;
-}
-int execv(const char *path, char *const argv[]){
- fprintf(stderr,"execvuting 1 pid=%d",getpid());
- fflush(stderr);
- _execv(path,argv);
- return 0;
-}
-int execvp(const char *file, char *const argv[]){
- fprintf(stderr,"execvpting 1 pid=%d",getpid());
- fflush(stderr);
- return _execvp(file,argv);
-
- return 0;
-}
-int execvpe(const char *file, char *const argv[],
- char *const envp[]){
- fprintf(stderr,"execvpeting 1 pid=%d",getpid());
- fflush(stderr);
-//
- return 0;
-}
-
int execlp(const char *file, const char *arg, ...){
fprintf(stderr,"execlpeting 1 pid=%d",getpid());
fflush(stderr);