#include "afni.h"
#include <sys/utsname.h>
#define FAIL_MESSAGE(reason) \
do{ fprintf(stderr,"\n" \
"\n** Version check disabled: %s", \
reason ) ; \
disabled = 1 ; } while(0)
static int disabled = 0 ;
#define VERSION_URL "http://afni.nimh.nih.gov/afni/AFNI.version"
#define STR_CHILD "tcp:localhost:20279"
#define AFNI_HOST "http://afni.nimh.nih.gov/afni/"
#define VSIZE 1024
static pid_t vc_child_pid = (pid_t)(-1) ;
static IOCHAN *vc_ioc = NULL ;
static char *motd_old = NULL ; /* 29 Nov 2005 */
static char *motd_new = NULL ;
#undef VERBOSE /* print messages on failure? */
/*------------------------------------------------------------------------*/
/*! This is only called from within the child process. */
static void vexit( int sig )
{
#ifdef VERBOSE
static volatile int fff=0 ;
if( fff ) _exit(1) ; else fff = 1 ;
fprintf(stderr,"** Version Check: child fails to complete: %d **\n",sig);
#endif
_exit(1);
}
/*------------------------------------------------------------------------*/
/*! This is called at main AFNI process exit,
to destroy vc_ioc if it is still open.
--------------------------------------------------------------------------*/
static void vc_exit(void){ iochan_close(vc_ioc) ; } /* 12 Dec 2002 */
/*------------------------------------------------------------------------*/
/*! Start the Web fetch to check the AFNI version in a child process.
To complete things, call AFNI_version_check() somewhat later.
--------------------------------------------------------------------------*/
void AFNI_start_version_check(void)
{
pid_t child_pid ;
#ifdef CYGWIN /* 18 Dec 2002 */
FAIL_MESSAGE("not possible under Cygwin") ;
return ;
#else
/*-- decide if we are to do anything --*/
if( AFNI_noenv("AFNI_VERSION_CHECK") ){ /* never check */
FAIL_MESSAGE("AFNI_VERSION_CHECK forbids") ;
return ;
}
#undef VDELAY
#define VDELAY 429999 /* 429999 s = 5 days */
/* check if we did this in the last VDELAY seconds */
{ char *home=getenv("HOME") , mname[VSIZE]="file:" ;
NI_stream ns ;
if( home != NULL ) strcat(mname,home) ;
strcat(mname,"/.afni.vctime") ;
ns = NI_stream_open( mname , "r" ) ;
if( ns != NULL ){
NI_element *nel = NI_read_element(ns,22) ;
NI_stream_close(ns) ;
if( nel != NULL ){
char *rhs ;
rhs = NI_get_attribute( nel , "version_check_time" ) ;
if( rhs != NULL ){
int last_time = strtol(rhs,NULL,10) ;
int dtime = ((int)time(NULL)) - last_time ;
if( dtime >= 0 && dtime < VDELAY ){ /* don't check */
NI_free_element(nel) ; disabled = 1 ; return ;
}
}
rhs = NI_get_attribute(nel,"version_string") ; /* 27 Jan 2003 */
if( rhs != NULL && strcmp(rhs,VERSION) != 0 ){
fprintf(stderr,
"\n** Your AFNI version changed from %s to %s since last check\n",
rhs , VERSION ) ;
}
rhs = NI_get_attribute(nel,"motd") ; /* 29 Nov 2005 */
if( rhs != NULL ) motd_old = strdup(rhs) ;
NI_free_element(nel) ;
}
}
}
/*-- OK, start the child process --*/
child_pid = fork() ;
if( child_pid == (pid_t)(-1) ){ /* bad */
FAIL_MESSAGE("can't fork") ;
return ;
}
/*---------------------------------------------------------*/
if( child_pid > 0 ){ /* I'm the parent */
/*-- save PID of child for later use --*/
vc_child_pid = child_pid ;
/*-- open an IOCHAN to talk to child --*/
vc_ioc = iochan_init( STR_CHILD , "accept" ) ;
if( vc_ioc == NULL ){
kill(child_pid,SIGTERM) ; /* cf. Abraham and Isaac */
vc_child_pid = (pid_t)(-1) ;
FAIL_MESSAGE("can't open connection to child") ;
} else {
fprintf(stderr,"\n** Version check: " VERSION_URL "\n" ); /* 13 Jan 2003 */
atexit( vc_exit ) ; /* 12 Dec 2002 */
}
return ;
/*---------------------------------------------------------*/
} else { /* I'm the child */
/* (never returns) */
int nbuf=0 , jj ;
char *vbuf=NULL ;
IOCHAN *ioc ;
struct utsname ubuf ;
char ua[512] ;
iochan_enable_perror(0) ; /* don't print TCP/IP error messages */
signal( SIGTERM , vexit ) ; /* if parent kills us, call vexit() */
/*-- get information from the AFNI server --*/
#define USE_HTTP_10
#ifdef USE_HTTP_10
# undef PCLAB
# ifdef SHOWOFF
# undef SHSH
# undef SHSHSH
# define SHSH(x) #x
# define SHSHSH(x) SHSH(x)
# define PCLAB SHSHSH(SHOWOFF)
# else
# define PCLAB "Unknown"
# endif
#endif
/** 25 Mar 2005: send more info in the request header **/
#ifdef USE_HTTP_10
ubuf.nodename[0] = ubuf.sysname[0] = ubuf.machine[0] = '\0' ;
jj = uname( &ubuf ) ;
if( jj >= 0 && ubuf.nodename[0] != '\0' )
sprintf( ua ,
"afni (avers='%s'; prec='%s' node='%s'; sys='%s'; mach='%s')" ,
VERSION, PCLAB, ubuf.nodename, ubuf.sysname, ubuf.machine ) ;
else
sprintf( ua , "afni (avers='%s'; prec='%s')" , VERSION , PCLAB ) ;
set_HTTP_10( 1 ) ;
set_HTTP_user_agent( ua ) ;
#else
set_HTTP_10( 0 ) ;
#endif
/* send the request */
nbuf = read_URL( VERSION_URL , &vbuf ) ; /* may take a while */
set_HTTP_10( 0 ) ;
/*-- if this failed, quit --*/
if( nbuf <= 0 || vbuf == NULL || vbuf[0] == '\0' ) vexit(1);
/*-- talk to parent process thru IOCHAN --*/
ioc = iochan_init( STR_CHILD , "create" ) ;
if( ioc == NULL ) vexit(2);
/*-- wait until ioc is ready for writing --*/
jj = iochan_writecheck(ioc,-1) ;
if( jj < 0 ) vexit(3);
/*-- send the info in vbuf --*/
iochan_sendall( ioc , vbuf , nbuf ) ;
while( ! iochan_clearcheck(ioc,10) ) /* loop until cleared */
iochan_sleep(10) ; /* by parent process */
iochan_sleep(10); /* a little extra napping */ _exit(0);
}
#endif /* not CYGWIN */
}
/******************************************/
#ifdef VERBOSE
# define KAPUT(ss) \
do{ fprintf(stderr,"** Version Check fails: %s **\n",ss); \
return 0; } while(0)
#else
# define KAPUT(ss) return
#endif
/*----------------------------------------------------------------------------*/
/*! Complete the version check by seeing if the child process
has any data to report from the AFNI web site.
- Returns 1 if the version at the AFNI site doesn't match the compiled-in
version of this program;
- Returns 0 if they match, or it can't tell.
- Also prints stuff out.
- 29 Nov 2005: also sets GLOBAL_motd string, maybe.
------------------------------------------------------------------------------*/
int AFNI_version_check(void)
{
int jj , nbuf=0 ;
char *vbuf=NULL ;
char vv[128]="none" ;
char *sname , *vvbuf ;
#ifdef CYGWIN /* 30 Jun 2005 [rickr] */
return 0;
#else
/* if something is rotten, then toss it out */
if( GLOBAL_argopt.allow_rt || disabled ) return 0 ; /* 27 Jan 2003 */
if( vc_ioc == NULL || vc_child_pid == (pid_t)(-1) ) KAPUT("bad child state");
jj = kill(vc_child_pid,0) ; /* is child alive? */
if( jj < 0 ){
IOCHAN_CLOSE(vc_ioc); vc_child_pid=(pid_t)(-1);
KAPUT("child not alive");
}
jj = iochan_readcheck( vc_ioc , 333 ) ; /* is iochan open yet? */
if( jj <= 0 ){
IOCHAN_CLOSE(vc_ioc); kill(vc_child_pid,SIGTERM); vc_child_pid=(pid_t)(-1);
KAPUT("connection to child gone bad");
}
/* if here, have data ready to read from child! */
nbuf = 0 ;
vbuf = AFMALL(char, VSIZE) ;
while(1){
jj = iochan_recv( vc_ioc , vbuf+nbuf , VSIZE-nbuf ) ;
if( jj < 1 ) break ;
nbuf += jj ;
if( nbuf >= VSIZE-1 ) break ;
jj = iochan_readcheck( vc_ioc , 5 ) ;
if( jj < 1 ) break ;
}
/* now wait for child to kill itself */
waitpid(vc_child_pid,NULL,WNOHANG); vc_child_pid = (pid_t)(-1);
IOCHAN_CLOSE(vc_ioc);
/* no data? */
if( nbuf <= 0 ){ free(vbuf); vbuf = NULL; KAPUT("bad version data"); } /* unlikely */
/* extract version and data/time strings from data */
vvbuf = strstr(vbuf,"AFNI_") ; /* 29 Nov 2005: scan for version string */
if( vvbuf == NULL ) vvbuf = vbuf ;
sscanf( vvbuf , "%127s" , vv ); /* get version string out of data */
vvbuf = strstr(vbuf,"motd=") ; /* 29 Nov 2005: motd string */
if( vvbuf != NULL ){
motd_new = (char *)calloc(sizeof(char),VSIZE) ;
sscanf( vvbuf+5 , "%988s" , motd_new ) ;
if( motd_new[0] == '\0' ){ free(motd_new); motd_new=NULL; }
}
free(vbuf) ; /* done with the input data from the child */
/* record the current time, so we don't check too often */
{ char *home=getenv("HOME") , mname[VSIZE]="file:" ;
NI_stream ns ;
if( home != NULL ) strcat(mname,home) ;
strcat(mname,"/.afni.vctime") ;
ns = NI_stream_open( mname , "w" ) ;
if( ns != NULL ){
NI_element *nel=NI_new_data_element("AFNI_vctime",0); char rhs[32];
sprintf(rhs,"%d",(int)time(NULL)) ;
NI_set_attribute( nel , "version_check_time" , rhs ) ;
if( strcmp(vv,"none") != 0 ) /* 27 Jan 2003 */
NI_set_attribute( nel , "version_string" , VERSION ) ;
if( motd_new != NULL )
NI_set_attribute( nel , "motd" , motd_new ) ; /* 29 Nov 2005 */
NI_write_element( ns , nel , NI_TEXT_MODE ) ;
NI_stream_close(ns) ;
}
}
/* 29 Nov 2005:
compare motd strings (old and new)
if different, save new one in GLOBAL_motd for display later */
if( motd_new != NULL ){
if( motd_old == NULL || strcmp(motd_new,motd_old) != 0 ){
GLOBAL_motd = motd_new ;
} else {
free(motd_new) ; motd_new = NULL ;
}
}
if( motd_old != NULL ){ free(motd_old); motd_old=NULL; }
/* compare version strings */
if( strcmp(vv,VERSION) == 0 ){ /* versions match */
fprintf(stderr,"\n** Version check: you are up-to-date!\n"
"** To disable future version checks:\n"
"** set environment variable AFNI_VERSION_CHECK to NO.\n"
"** Version checks are done about every %.1f days.\n",
rint(VDELAY/86400.0) ) ;
return 0 ;
}
/* print a message about version mismatch */
fprintf(stderr, "\n"
"****************************************************\n"
" This AFNI was compiled with the following settings:\n"
" Version ID = %s\n"
" Latest version at %s\n"
" Version ID = %s\n"
"****************************************************\n"
" To disable future version checks:\n"
" set environment variable AFNI_VERSION_CHECK to NO\n"
"****************************************************\n"
, VERSION, AFNI_HOST , vv ) ;
return 1 ;
#endif /* CYGWIN */
}
/*----------------------------------------------------------------------*/
/***---------------- 20 Nov 2003: auto-download stuff ----------------***/
#ifdef SHOWOFF
# undef SHSH
# undef SHSHSH
# define SHSH(x) #x
# define SHSHSH(x) SHSH(x)
# define SNAME "AFNI_UPDATER" /* script file name */
char * AFNI_make_update_script(void)
{
char *pg_ftp , *pg_afni , *pg_gzip , *pg_tar ;
char hbuf[4096], fname[128], adir[4096], *cpt, cwd[4096] ;
FILE *fp ;
static char sname[4096] ;
pg_ftp = THD_find_executable("ftp" ); if( pg_ftp == NULL ) return NULL;
pg_afni = THD_find_executable("afni"); if( pg_afni == NULL ) return NULL;
pg_gzip = THD_find_executable("gzip"); if( pg_gzip == NULL ) return NULL;
pg_tar = THD_find_executable("tar" ); if( pg_tar == NULL ) return NULL;
strcpy(adir,pg_afni) ; /* extract name of AFNI directory */
cpt = THD_trailname(adir,0) ;
*cpt = '\0' ;
if( strlen(adir) <= 0 ) return NULL ; /* no AFNI directory? */
strcpy( cwd , adir ) ; /* try to write a test file there */
strcat( cwd , "afni_qadgop" ) ;
fp = fopen( cwd , "a" ) ;
if( fp == NULL ) return NULL ; /* can't write to AFNI directory? */
fclose(fp) ; remove(cwd) ;
getcwd( cwd , 4096 ) ; /* get current directory for later use */
chdir( adir ) ; /* switch to AFNI directory for this work */
/* write a script to get and install the binary archive via FTP */
gethostname( hbuf , 4096 ) ;
strcpy( fname , SHSHSH(SHOWOFF) ) ; strcat( fname , ".tgz" ) ;
fp = fopen( SNAME , "w" ) ; if( fp == NULL ){ chdir(cwd); return NULL; }
fprintf( fp ,
"#!/bin/sh\n"
"echo '++ FTP-ing %s from afni.nimh.nih.gov'\n"
"%s -n afni.nimh.nih.gov << EEEEE\n" /* FTP to get file */
"user anonymous AFNI_UPDATER@%s\n"
"binary\n"
"passive\n"
"cd tgz\n"
"get %s\n"
"bye\n"
"EEEEE\n"
"echo '++ Unpacking %s'\n"
"%s -dc %s | %s xf -\n" /* uncompress and untar .tgz file */
"/bin/rm -f %s\n" /* delete .tgz file */
"echo '++ Moving files'\n"
"/bin/mv -f %s/* .\n" /* move untar-ed files up to here */
"/bin/rm -rf %s\n" /* remove any directory leftovers */
"echo '++ Finished'\n" ,
fname , /* filename to get (for 'FTP-ing' echo) */
pg_ftp , /* FTP program */
hbuf , /* hostname, for FTP password */
fname , /* filename to get (for FTP) */
fname , /* ditto (for 'Unpacking' echo) */
pg_gzip, fname, pg_tar, /* GZIP program, filename, TAR program */
fname , /* filename to delete */
SHSHSH(SHOWOFF) , /* directory to copy up */
SHSHSH(SHOWOFF) /* directory to delete */
) ;
fclose( fp ) ;
chmod( SNAME , S_IRUSR | S_IWUSR | S_IXUSR ) ; /* mark as executable */
/* get back to current working directory, then leave */
chdir(cwd) ;
sprintf(sname,"%s%s",adir,SNAME) ; return sname ;
}
#else /* undefined SHOWOFF */
char * AFNI_make_update_script(void){ return NULL; }
#endif /* SHOWOFF */
/*----------------------------------------------------------------------*/
#define MOTD_fails ERROR_message("Can't connect to AFNI server!\a\n")
/*----------------------------------------------------------------------*/
/*! Display the AFNI message of the day. [29 Nov 2005]
------------------------------------------------------------------------*/
void AFNI_display_motd( Widget w )
{
int nbuf ;
char *buf=NULL , url[VSIZE] ;
ENTRY("AFNI_display_motd") ;
set_HTTP_10( 0 ) ;
if( GLOBAL_motd == NULL || *GLOBAL_motd == '\0' ){ /* fetch motd name */
char *vbuf=NULL , *vvbuf ; /* from AFNI server */
nbuf = read_URL( VERSION_URL , &vbuf ) ;
if( nbuf <= 0 || vbuf == NULL ){ MOTD_fails; EXRETURN; }
vvbuf = strstr(vbuf,"motd=") ;
if( vvbuf == NULL ){ free(vbuf); MOTD_fails; EXRETURN; }
GLOBAL_motd = (char *)calloc(sizeof(char),VSIZE) ;
sscanf( vvbuf+5 , "%988s" , GLOBAL_motd ) ; free(vbuf) ;
if( GLOBAL_motd[0] == '\0' ){
free(GLOBAL_motd); GLOBAL_motd=NULL; MOTD_fails; EXRETURN;
}
}
sprintf(url,"%s%.988s",AFNI_HOST,GLOBAL_motd) ;
nbuf = read_URL( url , &buf ) ;
if( nbuf > 0 && buf != NULL ){
char *msg = malloc(sizeof(char)*(nbuf+2048)) ;
sprintf(msg,
"\n"
" *********** Current AFNI Message of the Day **********\n\n"
" [cf. %s ]\n\n"
" [cf. menu item Define Datamode -> Misc -> Message of the Day ]\n\n"
" ====================================================================\n\n"
"%s\n"
, url , buf );
if( w != NULL )
(void) new_MCW_textwin( w , msg , TEXT_READONLY );
else
fputs(msg,stderr) ;
free(msg) ; free(buf) ;
} else {
MOTD_fails ;
}
EXRETURN ;
}
syntax highlighted by Code2HTML, v. 0.9.1