2
Copyright (C) 2003-2004 Douglas Thain and the University of Wisconsin
3
Copyright (C) 2005- The University of Notre Dame
4
This software is distributed under the GNU General Public License.
5
See the file COPYING for details.
8
#include "pfs_channel.h"
9
#include "pfs_process.h"
10
#include "pfs_dispatch.h"
12
#include "pfs_service.h"
13
#include "pfs_critical.h"
17
#include "stringtools.h"
20
#include "create_dir.h"
21
#include "file_cache.h"
24
#include "password_cache.h"
27
#include "pfs_resolve.h"
28
#include "chirp_filesystem.h"
29
#include "chirp_local.h"
30
#include "chirp_acl.h"
31
#include "chirp_global.h"
45
#include <sys/utsname.h>
49
pid_t trace_this_pid = -1;
51
int pfs_master_timeout = 300;
52
struct file_cache *pfs_file_cache = 0;
53
struct password_cache *pfs_password_cache = 0;
54
int pfs_trap_after_fork = 0;
55
int pfs_force_stream = 0;
56
int pfs_force_cache = 0;
57
int pfs_force_sync = 0;
58
int pfs_follow_symlinks = 1;
59
int pfs_session_cache = 0;
60
int pfs_use_helper = 1;
61
int pfs_checksum_files = 1;
62
int pfs_auto_gzip = 0;
63
int pfs_write_rval = 0;
64
const char *pfs_write_rval_file = "parrot.rval";
65
int pfs_enable_small_file_optimizations = 1;
66
char pfs_temp_dir[PFS_PATH_MAX];
68
int *pfs_syscall_totals32 = 0;
69
int *pfs_syscall_totals64 = 0;
71
const char *pfs_root_checksum=0;
72
const char *pfs_initial_working_directory=0;
74
char *pfs_false_uname = 0;
76
char *pfs_ldso_path = 0;
79
const char * pfs_username = 0;
81
INT64_T pfs_syscall_count = 0;
82
INT64_T pfs_read_count = 0;
83
INT64_T pfs_write_count = 0;
86
This process at the very top of the traced tree
87
and its final exit status, which we use to determine
91
static pid_t root_pid = -1;
92
static int root_exitstatus = 0;
93
static int channel_size = 10;
95
struct chirp_filesystem *cfs = &chirp_local_fs;
96
const char *chirp_transient_path = "./";
98
static void show_version( const char *cmd )
100
printf("%s version %d.%d.%d built by %s@%s on %s at %s\n",cmd,CCTOOLS_VERSION_MAJOR,CCTOOLS_VERSION_MINOR,CCTOOLS_VERSION_MICRO,BUILD_USER,BUILD_HOST,__DATE__,__TIME__);
104
static void get_linux_version()
107
int major,minor,micro,fields;
109
debug(D_DEBUG,"%s version %d.%d.%d built by %s@%s on %s at %s\n","parrot",CCTOOLS_VERSION_MAJOR,CCTOOLS_VERSION_MINOR,CCTOOLS_VERSION_MICRO,BUILD_USER,BUILD_HOST,__DATE__,__TIME__);
113
#ifdef CCTOOLS_CPU_I386
114
if(!strcmp(name.machine,"x86_64")) {
115
fatal("Sorry, you need to download a Parrot built specifically for an x86_64 CPU");
119
if(!strcmp(name.sysname,"Linux")) {
120
debug(D_DEBUG,"kernel is %s %s",name.sysname,name.release);
121
fields = sscanf(name.release,"%d.%d.%d",&major,&minor,µ);
125
pfs_trap_after_fork = 1;
127
} else if(minor==6) {
128
pfs_trap_after_fork = 0;
135
debug(D_NOTICE,"parrot_run %d.%d.%d has not been tested on %s %s yet, this may not work",CCTOOLS_VERSION_MAJOR,CCTOOLS_VERSION_MINOR,CCTOOLS_VERSION_MICRO,name.sysname,name.release);
138
static void pfs_helper_init( const char *argv0 )
140
char helper_path[PFS_PATH_MAX];
142
debug(D_DEBUG,"locating helper library...");
144
sprintf(helper_path,"%s/lib/libparrot_helper.so",INSTALL_PATH);
146
char * s = getenv("PARROT_HELPER");
148
debug(D_DEBUG,"PARROT_HELPER=%s",s);
149
strcpy(helper_path,s);
151
debug(D_DEBUG,"PARROT_HELPER is not set");
154
if(access(helper_path,R_OK)==0) {
155
debug(D_DEBUG,"found helper in %s",helper_path);
156
setenv("LD_PRELOAD",helper_path,1);
158
debug(D_DEBUG,"couldn't find helper library %s but continuing anyway.",helper_path);
162
static void show_use( const char *cmd )
164
/* 80-column text marker */
165
/******************************************************************************/
166
printf("Use: %s [options] <command> ...\n",cmd);
167
printf("Where options and environment variables are:\n");
168
printf(" -a <list> Use these Chirp authentication methods. (PARROT_CHIRP_AUTH)\n");
169
printf(" -A <file> Use this file as a default ACL. (PARROT_DEFAULT_ACL)\n");
170
printf(" -b <bytes> Set the I/O block size hint. (PARROT_BLOCK_SIZE)\n");
171
printf(" -c <file> Print exit status information to <file>.\n");
172
printf(" -C Enable data channel authentication in GridFTP.\n");
173
printf(" -d <name> Enable debugging for this sub-system. (PARROT_DEBUG_FLAGS)\n");
174
printf(" -D Disable small file optimizations.\n");
175
printf(" -F Enable file snapshot caching for all protocols.\n");
176
printf(" -f Disable following symlinks.\n");
177
printf(" -E <url> Endpoint for gLite combined catalog ifc. (PARROT_GLITE_CCURL)\n");
178
printf(" -G <num> Fake this gid; Real gid stays the same. (PARROT_GID)\n");
179
printf(" -H Disable use of helper library.\n");
180
printf(" -h Show this screen.\n");
181
printf(" -i <files> Comma-delimited list of tickets to use for authentication.\n");
182
printf(" -K Checksum files where available.\n");
183
printf(" -k Do not checksum files.\n");
184
printf(" -l <path> Path to ld.so to use. (PARROT_LDSO_PATH)\n");
185
printf(" -m <file> Use this file as a mountlist. (PARROT_MOUNT_FILE)\n");
186
printf(" -M/foo=/bar Mount (redirect) /foo to /bar. (PARROT_MOUNT_STRING)\n");
187
printf(" -N <name> Pretend that this is my hostname. (PARROT_HOST_NAME)\n");
188
printf(" -o <file> Send debugging messages to this file. (PARROT_DEBUG_FILE)\n");
189
printf(" -O <bytes> Rotate debug files of this size. (PARROT_DEBUG_FILE_SIZE)\n");
190
printf(" -p <hst:p> Use this proxy server for HTTP requests. (HTTP_PROXY)\n");
191
printf(" -Q Inhibit catalog queries to list /chirp.\n");
192
printf(" -R <cksum> Enforce this root filesystem checksum, where available.\n");
193
printf(" -s Use streaming protocols without caching.(PARROT_FORCE_STREAM)\n");
194
printf(" -S Enable whole session caching for all protocols.\n");
195
printf(" -t <dir> Where to store temporary files. (PARROT_TEMP_DIR)\n");
196
printf(" -T <time> Maximum amount of time to retry failures. (PARROT_TIMEOUT)\n");
197
printf(" -U <num> Fake this unix uid; Real uid stays the same. (PARROT_UID)\n");
198
printf(" -u <name> Use this extended username. (PARROT_USERNAME)\n");
199
printf(" -v Display version number.\n");
200
printf(" -w Initial working directory.\n");
201
printf(" -W Display table of system calls trapped.\n");
202
printf(" -Y Force sYnchronous disk writes. (PARROT_FORCE_SYNC)\n");
203
printf(" -Z Enable automatic decompression on .gz files.\n");
205
printf("Known debugging sub-systems are: ");
206
debug_flags_print(stdout);
208
printf("Enabled filesystems are:");
209
if(pfs_service_lookup("http")) printf(" http");
210
if(pfs_service_lookup("grow")) printf(" grow");
211
if(pfs_service_lookup("ftp")) printf(" ftp");
212
if(pfs_service_lookup("anonftp")) printf(" anonftp");
213
if(pfs_service_lookup("gsiftp")) printf(" gsiftp");
214
if(pfs_service_lookup("nest")) printf(" nest");
215
if(pfs_service_lookup("chirp")) printf(" chirp");
216
if(pfs_service_lookup("gfal")) printf(" gfal lfn guid srm");
217
if(pfs_service_lookup("rfio")) printf(" rfio");
218
if(pfs_service_lookup("dcap")) printf(" dcap");
219
if(pfs_service_lookup("glite")) printf(" glite");
220
if(pfs_service_lookup("lfc")) printf(" lfc");
221
if(pfs_service_lookup("irods")) printf(" irods");
222
if(pfs_service_lookup("hdfs")) printf(" hdfs");
223
if(pfs_service_lookup("bxgrid")) printf(" bxgrid");
224
if(pfs_service_lookup("s3")) printf(" s3");
225
if(pfs_service_lookup("root")) printf(" root");
226
if(pfs_service_lookup("xrootd")) printf(" xrootd");
232
For all of the signals that we handle, we want to
233
run the handler without interruption from other signals.
236
void install_handler( int sig, void (*handler)(int sig))
240
s.sa_handler = handler;
241
sigfillset(&s.sa_mask);
247
static void ignore_signal( int sig )
252
It would be nice if we could clean up everyone quietly and then
253
some time later, kill hard. However, on Linux, if someone kills
254
us before we have a chance to clean up, then due to a "feature"
255
of ptrace, all our children will be left stuck in a debug-wait
256
state. So, rather than chance ourselves getting killed, we
257
will be very agressive about cleaning up. Upon receiving any
258
shutdown signal, we immediately blow away everyone involved,
259
and then kill ourselves.
262
static void kill_everyone( int sig )
264
debug(D_NOTICE,"received signal %d (%s), killing all my children...",sig,string_signal(sig));
265
pfs_process_killall();
266
debug(D_NOTICE,"sending myself %d (%s), goodbye!",sig,string_signal(sig));
269
sigsetmask(~sigmask(sig));
271
kill(getpid(),SIGKILL);
277
kill(getpid(),SIGTERM);
282
Other less deadly signals we simply pass through to the root
283
of our children for its consideration.
286
static void pass_through( int sig )
288
pfs_process_raise(root_pid,sig,1);
292
We will be fighting with our child processes for control of
293
the terminal. Whenever a we want to write to the terminal,
294
we will get a SIGTTOU or SIGTTIN instructing us that its
295
not our turn. But, we are in charge! So, upon receipt
296
of these signals, grab control of the terminal.
299
static void control_terminal( int sig )
302
tcsetpgrp(1,getpid());
303
tcsetpgrp(2,getpid());
305
tcsetpgrp(0,getpid());
310
Here is the meat and potatoes. We have discovered that
311
something interesting has happened to this pid. Decode
312
the event and take the appropriate action.
315
static void handle_event( pid_t pid, int status, struct rusage usage )
317
struct pfs_process *p;
320
p = pfs_process_lookup(pid);
322
debug(D_PROCESS,"killing unexpected pid %d",pid);
327
if(WIFEXITED(status)) {
328
debug(D_PROCESS,"pid %d exited normally with code %d",pid,WEXITSTATUS(status));
329
pfs_process_stop(p,status,usage);
330
if(pid==root_pid) root_exitstatus = status;
331
} else if(WIFSIGNALED(status)) {
332
signum = WTERMSIG(status);
333
debug(D_PROCESS,"pid %d exited abnormally with signal %d (%s)",pid,signum,string_signal(signum));
334
pfs_process_stop(p,status,usage);
335
if(pid==root_pid) root_exitstatus = status;
336
} else if(WIFSTOPPED(status)) {
337
signum = WSTOPSIG(status);
338
if(signum==SIGTRAP) {
342
debug(D_PROCESS,"pid %d received signal %d (%s) (state %d)",pid,signum,string_signal(signum),p->state);
343
if(signum==SIGTTIN) {
345
tracer_continue(p->tracer,SIGCONT);
346
} else if(signum==SIGTTOU) {
349
tracer_continue(p->tracer,SIGCONT);
351
tracer_continue(p->tracer,signum);
352
if(signum==SIGSTOP && p->nsyscalls==0) {
353
kill(p->pid,SIGCONT);
358
fatal("pid %d stopped with strange status %d",pid,status);
362
struct timeval clock_to_timeval( clock_t c )
364
struct timeval result;
365
result.tv_sec = c/CLOCKS_PER_SEC;
366
result.tv_usec = (c - result.tv_sec)*1000000/CLOCKS_PER_SEC;
370
void handle_sigchld( int sig )
375
static void handle_sigio( int sig )
380
void write_rval(const char* message, int status) {
381
FILE *file = fopen(pfs_write_rval_file, "w+");
383
fprintf(file, "%s\n%d\n", message, status);
389
int main( int argc, char *argv[] )
394
struct pfs_process *p;
402
srand(time(0)*(getpid()+getuid()));
404
debug_config(argv[0]);
405
debug_config_file_size(0);
407
if(getenv("PARROT_ENABLED")) {
408
fprintf(stderr,"sorry, parrot_run cannot be run inside of itself.\n");
412
debug_config_fatal(pfs_process_killall);
413
debug_config_getpid(pfs_process_getpid);
415
install_handler(SIGQUIT,kill_everyone);
416
install_handler(SIGILL,kill_everyone);
417
install_handler(SIGABRT,kill_everyone);
418
install_handler(SIGIOT,kill_everyone);
419
install_handler(SIGBUS,kill_everyone);
420
install_handler(SIGFPE,kill_everyone);
421
install_handler(SIGSEGV,kill_everyone);
422
install_handler(SIGTERM,kill_everyone);
423
install_handler(SIGHUP,pass_through);
424
install_handler(SIGINT,pass_through);
425
install_handler(SIGTTIN,control_terminal);
426
install_handler(SIGTTOU,control_terminal);
427
install_handler(SIGCHLD,handle_sigchld);
428
install_handler(SIGIO,handle_sigio);
429
install_handler(SIGXFSZ,ignore_signal);
432
pfs_master_timeout = 300;
434
pfs_master_timeout = 3600;
440
putenv((char *)"PARROT_ENABLED=TRUE");
442
s = getenv("PARROT_BLOCK_SIZE");
443
if(s) pfs_service_set_block_size(string_metric_parse(s));
445
s = getenv("PARROT_MOUNT_FILE");
446
if(s) pfs_resolve_file_config(s);
448
s = getenv("PARROT_MOUNT_STRING");
449
if(s) pfs_resolve_manual_config(s);
451
s = getenv("PARROT_FORCE_STREAM");
452
if(s) pfs_force_stream = 1;
454
s = getenv("PARROT_FORCE_CACHE");
455
if(s) pfs_force_cache = 1;
457
s = getenv("PARROT_FOLLOW_SYMLINKS");
458
if(s) pfs_follow_symlinks = atoi(s);
460
s = getenv("PARROT_SESSION_CACHE");
461
if(s) pfs_session_cache = 1;
463
s = getenv("PARROT_HOST_NAME");
464
if(s) pfs_false_uname = s;
466
s = getenv("PARROT_UID");
467
if(s) pfs_uid = atoi(s);
469
s = getenv("PARROT_GID");
470
if(s) pfs_gid = atoi(s);
472
s = getenv("PARROT_TIMEOUT");
473
if(s) pfs_master_timeout = string_time_parse(s);
475
s = getenv("PARROT_GLITE_CCURL");
478
s = getenv("PARROT_FORCE_SYNC");
479
if(s) pfs_force_sync = 1;
481
s = getenv("PARROT_LDSO_PATH");
482
if(s) pfs_ldso_path = s;
484
s = getenv("PARROT_DEBUG_FLAGS");
486
char *x = xstrdup(s);
489
if(string_split(x,&nargs,&args)) {
490
for(int i=0;i<nargs;i++) {
491
debug_flags_set(args[i]);
497
s = getenv("PARROT_CHIRP_AUTH");
499
char *x = xstrdup(s);
502
if(string_split(x,&nargs,&args)) {
503
for(int i=0;i<nargs;i++) {
504
auth_register_byname(args[i]);
511
s = getenv("PARROT_USER_PASS");
513
char *x = xstrdup(s);
516
if(string_split(x,&nargs,&args)) {
517
pfs_password_cache = password_cache_init(args[0], args[1]);
521
sprintf(pfs_temp_dir,"/tmp/parrot.%d",getuid());
523
while((c=getopt(argc,argv,"+hA:a:b:B:c:Cd:DE:FfG:Hi:kKl:m:M:N:o:O:p:QR:sSt:T:U:u:vw:WYZ"))!=(char)-1) {
526
if(!auth_register_byname(optarg)) {
527
fprintf(stderr,"unknown auth type: %s\n",optarg);
533
chirp_acl_default(optarg);
536
pfs_service_set_block_size(string_metric_parse(optarg));
539
pfs_service_set_block_size(string_metric_parse(optarg));
543
pfs_write_rval_file = optarg;
546
ftp_lite_data_channel_authentication = 1;
549
if(!debug_flags_set(optarg)) show_use(argv[0]);
552
pfs_enable_small_file_optimizations = 0;
561
pfs_follow_symlinks = 0;
564
pfs_gid = atoi(optarg);
570
setenv(CHIRP_CLIENT_TICKETS, optarg, 1);
574
pfs_checksum_files = 0;
577
pfs_checksum_files = 1;
580
pfs_ldso_path = optarg;
583
pfs_resolve_file_config(optarg);
586
pfs_resolve_manual_config(optarg);
589
pfs_false_uname = optarg;
592
debug_config_file(optarg);
595
debug_config_file_size(string_metric_parse(optarg));
598
setenv("HTTP_PROXY",optarg,1);
601
chirp_global_inhibit_catalog(1);
604
pfs_root_checksum = optarg;
605
pfs_checksum_files = 1;
608
pfs_force_stream = 1;
612
pfs_session_cache = 1;
615
strcpy(pfs_temp_dir,optarg);
618
pfs_master_timeout = string_time_parse(optarg);
621
pfs_uid = atoi(optarg);
624
pfs_username = optarg;
630
show_version(argv[0]);
633
pfs_initial_working_directory = optarg;
636
pfs_syscall_totals32 = (int*) calloc(SYSCALL32_MAX,sizeof(int));
637
pfs_syscall_totals64 = (int*) calloc(SYSCALL64_MAX,sizeof(int));
647
cfs = &chirp_local_fs;
649
if(optind>=argc) show_use(argv[0]);
653
pfs_file_cache = file_cache_init(pfs_temp_dir);
654
if(!pfs_file_cache) fatal("couldn't setup cache in %s: %s\n",pfs_temp_dir,strerror(errno));
655
file_cache_cleanup(pfs_file_cache);
657
if(!did_ticket && getenv(CHIRP_CLIENT_TICKETS) == NULL) {
658
/* populate a list with tickets in the current directory */
661
char *tickets = xstrdup("");
662
sort_dir(".", &list, strcmp);
663
for (i = 0; list[i]; i++) {
664
if (strncmp(list[i], "ticket.", strlen("ticket.")) == 0 && (strlen(list[i]) == (strlen("ticket.")+(MD5_DIGEST_LENGTH<<1)))) {
665
debug(D_CHIRP, "adding ticket %s", list[i]);
666
tickets = (char *) xxrealloc(tickets, strlen(tickets)+1+strlen(list[i])+1);
667
if (*tickets != '\0') /* non-empty? */
668
strcat(tickets, ",");
669
strcat(tickets, list[i]);
672
setenv(CHIRP_CLIENT_TICKETS, tickets, 1);
677
if(!chose_auth) auth_register_all();
679
if(!pfs_channel_init(channel_size*1024*1024)) fatal("couldn't establish I/O channel");
681
if(pfs_use_helper) pfs_helper_init(argv[0]);
686
For reasons I don't understand yet, parrot gets very confused when
687
it is the session leader. This happens when it is run as the first
688
process in a pty, for example in an xterm or when run from a server.
689
So, when we are the session leader, disconnect from the terminal .
690
This disables features such as line editing and job control, but
691
prevents triggering some ugly bugs.
694
if(getsid(0)==getpid()) {
695
::ioctl(0,TIOCNOTTY,0);
701
debug(D_PROCESS,"pid %d started",pid);
703
for(i=0;i<sysconf(_SC_OPEN_MAX);i++) {
704
if(i!=pfs_channel_fd()) close(i);
708
kill(getpid(),SIGSTOP);
710
// This call is necessary to force the kernel to report the current heap
711
// size, so that Parrot can observe it in order to rewrite the following exec.
713
execvp(argv[optind],&argv[optind]);
714
debug(D_NOTICE,"unable to execute %s: %s",argv[optind],strerror(errno));
716
write_rval("noexec", 0);
720
debug(D_NOTICE,"unable to fork %s: %s",argv[optind],strerror(errno));
722
write_rval("nofork", 0);
731
debug(D_PROCESS,"attaching to pid %d",pid);
732
p = pfs_process_create(pid,getpid(),getpid(),0,SIGCHLD);
735
write_rval("noattach", 0);
738
fatal("unable to attach to pid %d: %s",pid,strerror(errno));
741
p->state = PFS_PROCESS_STATE_USER;
742
strcpy(p->name,argv[optind]);
744
while(pfs_process_count()>0) {
747
if(trace_this_pid!=-1) {
748
flags = WUNTRACED|__WALL;
750
flags = WUNTRACED|__WALL|WNOHANG;
752
pid = wait4(trace_this_pid,&status,flags,&usage);
754
handle_event(pid,status,usage);
759
if(pid==-1 && errno==ECHILD) break;
760
if(pfs_process_count()>0) pfs_poll_sleep();
763
if(pfs_syscall_totals32) {
764
printf("\nParrot System Call Summary:\n");
765
printf("%lld syscalls\n",pfs_syscall_count);
766
printf("%lld bytes read\n",pfs_read_count);
767
printf("%lld bytes written\n",pfs_write_count);
769
printf("\n32-bit System Calls:\n");
770
for(i=0;i<SYSCALL32_MAX;i++) {
771
if(pfs_syscall_totals32[i]) {
772
printf("%-20s %d\n",tracer_syscall32_name(i),pfs_syscall_totals32[i]);
776
#ifdef CCTOOLS_CPU_X86_64
778
printf("\n64-bit System Calls:\n");
779
for(i=0;i<SYSCALL64_MAX;i++) {
780
if(pfs_syscall_totals64[i]) {
781
printf("%-20s %d\n",tracer_syscall64_name(i),pfs_syscall_totals64[i]);
788
if(WIFEXITED(root_exitstatus)) {
789
status = WEXITSTATUS(root_exitstatus);
790
debug(D_PROCESS,"%s exited normally with status %d",argv[optind],status);
792
write_rval("normal", status);
796
signum = WTERMSIG(root_exitstatus);
797
debug(D_PROCESS,"%s exited abnormally with signal %d (%s)",argv[optind],signum,string_signal(signum));
799
write_rval("abnormal", signum);