Esempio n. 1
0
static int purge_one_with_subjobs(edg_wll_Context ctx, purge_ctx_t *prg, edg_wll_JobStat *stat, const edg_wll_PurgeRequest *request, edg_wll_PurgeResult *result) {
	char *job_s;
	int i;

	if (purge_one(ctx,stat,prg->dumpfile,request->flags&EDG_WLL_PURGE_REALLY_PURGE,ctx->isProxy)) return edg_wll_Error(ctx, NULL, NULL);
	purge_throttle(prg);

/* XXX: change with the streaming interface */
	if (request->flags & EDG_WLL_PURGE_LIST_JOBS) {
		job_s = glite_jobid_unparse(stat->jobId);
		if (prg->naffected_jobs % GRAN == 0 || !result->jobs)
			result->jobs = realloc(result->jobs,(prg->naffected_jobs+GRAN+1) * sizeof(*(result->jobs)));
		result->jobs[prg->naffected_jobs] = job_s;
		result->jobs[prg->naffected_jobs+1] = NULL;
	}
	prg->naffected_jobs++;

	/* purge the subjobs */
	if (stat->children_num && stat->children) {
		for (i = 0; i < stat->children_num && stat->children[i]; i++) {
			if (purge_one(ctx, stat->children_states + i, prg->dumpfile, request->flags&EDG_WLL_PURGE_REALLY_PURGE,ctx->isProxy)) {
				return edg_wll_Error(ctx, NULL, NULL);
			}
			purge_throttle(prg);

			if (request->flags & EDG_WLL_PURGE_LIST_JOBS) {
				if (prg->naffected_jobs % GRAN == 0 || !result->jobs)
					result->jobs = realloc(result->jobs,(prg->naffected_jobs+GRAN+1) * sizeof(*(result->jobs)));
				result->jobs[prg->naffected_jobs] = strdup(stat->children[i]);
				result->jobs[prg->naffected_jobs+1] = NULL;
			}
			prg->naffected_jobs++;
		}
	}

	return edg_wll_Error(ctx, NULL, NULL);
}
Esempio n. 2
0
int main(int argc,char **argv) {

        /* VARIABLES DECLARATION */ 
	edg_wll_Context	ctx;
	struct tm	tm;
	time_t	from,to;
	int	i, err = 0;

        /* VARIABLES INITIALIZATION */ 
	edg_wll_QueryRec	cond[4];	/* [3] is terminator */
	edg_wll_Event	*events = NULL;

	edg_wll_InitContext(&ctx);

	if (argc != 3) usage(argv[0]);

	
	memset(&tm,0,sizeof tm);

	if (sscanf(argv[1],"%d-%d-%d:%d:%d:%d",
		&tm.tm_year,
		&tm.tm_mon,
		&tm.tm_mday,
		&tm.tm_hour,
		&tm.tm_min,
                &tm.tm_sec)!= 6) usage(argv[0]);

	tm.tm_mon--;
	tm.tm_year -= 1900;

	from = timegm(&tm);
        memset(&tm,0,sizeof tm);
	
	if (sscanf(argv[2],"%d-%d-%d:%d:%d:%d",
		&tm.tm_year,
		&tm.tm_mon,
		&tm.tm_mday,
		&tm.tm_hour,
		&tm.tm_min,
                &tm.tm_sec) != 6) usage(argv[0]);

	tm.tm_mon--;
	tm.tm_year -= 1900;

	to = timegm(&tm);

	memset(cond,0,sizeof cond);

        /* QUERY CONDITIONS INITIALIZATION: ALL JOBS DONE WITHIN TIME INTERVAL */
	cond[0].attr = EDG_WLL_QUERY_ATTR_TIME;
	cond[0].op = EDG_WLL_QUERY_OP_WITHIN;
	cond[0].value.t.tv_sec = from;
	cond[0].value2.t.tv_sec = to;

	cond[1].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE;
	cond[1].value.i = EDG_WLL_EVENT_TRANSFER;

        cond[2].attr =  EDG_WLL_QUERY_ATTR_SOURCE;
        cond[2].value.i = EDG_WLL_SOURCE_JOB_SUBMISSION;
	
	if (edg_wll_QueryEventsProxy(ctx,NULL,cond,&events)) {
		char	*et,*ed;
        	et = ed = NULL;

		edg_wll_Error(ctx,&et,&ed);
		fprintf(stderr,"edg_wll_QueryEventsProxy: %s, %s\n",
			et,ed ? ed : "");

		free(et); free(ed);
		err = 1;
		goto cleanup;
	}
//   printf("JOBS TRANSFERED TO CONDOR\n");
//   printf("OWNER\tJOBID\tSOURCE\tQUEUE\tTIMESTAMP\tRESULT\n");
	for (i=0; events[i].type; i++) {
		edg_wll_Event	*e = events+i;

		if (e->transfer.result == 2) {
			char	*job = glite_jobid_unparse(e->any.jobId);
                        printf("%s\t%s\t%s",
                                e->any.user,
                                job,
                                ctime(&e->transfer.timestamp.tv_sec)
                                );

			free(job);
		}
	}
				
cleanup:
	if (events) {
		for (i=0; events[i].type; i++) edg_wll_FreeEvent(events+i);
		free(events); events = NULL;
	}

	edg_wll_FreeContext(ctx);

	return err;
}
Esempio n. 3
0
int main(int argc,char **argv) {

        /* VARIABLES DECLARATION */ 
	edg_wll_Context	ctx;
	struct tm	tm;
	time_t	from,to;
	int	i, err = 0;

        /* VARIABLES INITIALIZATION */ 
	edg_wll_QueryRec	cond[3];	/* [2] is terminator */
	edg_wll_Event	*events = NULL;

	edg_wll_InitContext(&ctx);

	if (argc != 3) usage(argv[0]);
	memset(&tm,0,sizeof tm);
	if (sscanf(argv[1],"%d-%d-%d:%d:%d:%d",
		&tm.tm_year,
		&tm.tm_mon,
		&tm.tm_mday,
		&tm.tm_hour,
		&tm.tm_min,
                &tm.tm_sec)!= 6) usage(argv[0]);

	tm.tm_mon--;
	tm.tm_year -= 1900;
	from = timegm(&tm);

	memset(&tm,0,sizeof tm);
	if (sscanf(argv[2],"%d-%d-%d:%d:%d:%d",
		&tm.tm_year,
		&tm.tm_mon,
		&tm.tm_mday,
		&tm.tm_hour,
		&tm.tm_min,
                &tm.tm_sec) != 6) usage(argv[0]);

	tm.tm_mon--;
	tm.tm_year -= 1900;
	to = timegm(&tm);
	memset(cond,0,sizeof cond);

        /* QUERY CONDITIONS INITIALIZATION: ALL JOBS DONE WITHIN TIME INTERVAL */
	cond[0].attr = EDG_WLL_QUERY_ATTR_TIME;
	cond[0].op = EDG_WLL_QUERY_OP_WITHIN;
	cond[0].value.t.tv_sec = from;
	cond[0].value2.t.tv_sec = to;

	cond[1].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE;
	cond[1].value.i = EDG_WLL_EVENT_DONE;
	
	if (edg_wll_QueryEventsProxy(ctx,NULL,cond,&events)) {
		char	*et,*ed;
        	et = ed = NULL;

		edg_wll_Error(ctx,&et,&ed);
		fprintf(stderr,"edg_wll_QueryEventsProxy: %s, %s\n",
			et,ed ? ed : "");

		free(et); free(ed);
		err = 1;
		goto cleanup;
	}

        /* SELECTION OF DONE FAILED-OR-OK JOBS */
//   printf("SELECTION OF DONE JOBS\n");
//   printf("OWNER\tJOBID\tEXITCODE\tTIMESTAMP\tFAILUREREASON\n");     
	for (i=0; events[i].type; i++) {
		edg_wll_Event	*e = events+i;
                if(e->done.status_code == EDG_WLL_DONE_OK) {
                        char    *job = glite_jobid_unparse(e->any.jobId);

                        printf("%s\t%s\t%s",
                                e->any.user,
                                job,
                                ctime(&e->done.timestamp.tv_sec)
                                //asctime(gmtime(&e->done.timestamp.tv_sec))
                                );
                        free(job);
                }

/*		if (e->done.status_code == EDG_WLL_DONE_FAILED) {
			char	*job = glite_jobid_unparse(e->any.jobId);                        
                        printf("%s\t%s\t%d\t%s\t%s\n",
                                e->any.user,
                                job,
                                e->done.status_code,
                                ctime(&e->done.timestamp.tv_sec),
                                e->done.reason
                                );
			free(job);
		} else if(e->done.status_code == EDG_WLL_DONE_OK) {
			char	*job = glite_jobid_unparse(e->any.jobId);

                        printf("%s\t%s\t%d\t%s\tNULL\n",
                                e->any.user,
                                job,
                                e->done.status_code,
                                ctime(&e->done.timestamp.tv_sec)                               
                                );
			free(job);}*/
	}
				
cleanup:
	if (events) {
		for (i=0; events[i].type; i++) edg_wll_FreeEvent(events+i);
		free(events); events = NULL;
	}

	edg_wll_FreeContext(ctx);

	return err;
}
Esempio n. 4
0
cms::Message *
OutputPlugin::createMessage(edg_wll_JobStat &state_out)
{
	cms::TextMessage *cms_msg = session->createTextMessage();
	char *s;
	unsigned int i;
	std::ostringstream body;
	bool first = true;

	body << "{";
	/* jobid */
	s = glite_jobid_unparse(state_out.jobId);
	if(s) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"jobid\" : \"" << s << "\"";
		free(s);
	}
	/* ownerDn */
	if(state_out.owner) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"ownerDn\" : \"" << state_out.owner << "\"";
		// cms_msg->setStringProperty("ownerDn", val);
	}
	/* voname */
	s = edg_wll_JDLField(&state_out,"VirtualOrganisation");
	if(s) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"VirtualOrganisation\" : \"" << s << "\"";
		free(s);
	}
	/* bkHost */
	glite_jobid_getServerParts(state_out.jobId, &s, &i);
	if(s) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"bkHost\" : \"" << s << "\"";
		free(s);
	}
	/* networkServer */
	/* TODO: XXX cut out hostname */
	if(state_out.network_server) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"networkHost\" : \"" << state_out.network_server << "\"";
	}
	timeval2str(&state_out.lastUpdateTime, &s);
	if(s) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"lastUpdateTime\" : \"" << s << "\"";
		free(s);
	}
	/* stateName */
	s = edg_wll_StatToString(state_out.state);
	if(s) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"stateName\" : \"" << s << "\"";
		free(s);
	}
	timeval2str(&state_out.stateEnterTime, &s);
	if(s) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"stateStartTime\" : \"" << s << "\"";
		free(s);
	}
	/* condorId */
	if(state_out.condorId) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"condorId\" : \"" << state_out.condorId << "\"";
	}
	/* destSite */
	if(state_out.destination) {
		if (first) { first = false; } else { body << ", "; }
		if (trio_asprintf(&s, "%|Js", state_out.destination) == -1) s = NULL;
		body << "\"destSite\" : \"" << s << "\"";
		free(s);
	}
	/* exitCode */
	if (first) { first = false; } else { body << ", "; }
	body << "\"exitCode\" : " << state_out.exit_code;
	/* doneCode */
	if (first) { first = false; } else { body << ", "; }
	body << "\"doneCode\" : " << state_out.done_code;
	/* statusReason */
	if(state_out.reason) {
		if (first) { first = false; } else { body << ", "; }
		if (trio_asprintf(&s, "%|Js", state_out.reason) == -1) s = NULL;
		body << "\"statusReason\" : \"" << s << "\"";
		free(s);
	}
	/* summaries */
	if(state_out.history) {
		if (first) { first = false; } else { body << ", "; }
		body << "\"history\" : " << state_out.history;
	}
	body << "}";

	cms_msg->setText(body.str().c_str());
	cms_msg->setStringProperty("Content-type", "text/javascript");

	return cms_msg;
}
Esempio n. 5
0
int purge_one(edg_wll_Context ctx,edg_wll_JobStat *stat,int dump, int purge, int purge_from_proxy_only)
{
	char	*dbjob = NULL;
	char	*stmt = NULL;
	glite_lbu_Statement	q = NULL;
	int		ret,dumped = 0;
	char	*res[10];
	char	*prefix = NULL, *suffix = NULL, *root = NULL;
	char	*prefix_id = NULL, *suffix_id = NULL;
	int	sql_retval;
	glite_jobid_const_t job = stat->jobId;
	edg_wll_JobStat new_stat;

	edg_wll_ResetError(ctx);
	if ( !purge && dump < 0 ) return 0;

	do {

        	if (edg_wll_Transaction(ctx)) goto err;

		switch (edg_wll_jobMembership(ctx, job)) {
			case DB_PROXY_JOB:
				if (!ctx->isProxy) {
					/* should not happen */
					goto commit;
				}
				/* continue */
				break;
			case DB_SERVER_JOB:
				if (purge_from_proxy_only) {
					/* no action needed */
					goto commit;
				}
				if (ctx->isProxy) {
					/* should not happen */
					goto commit;
				}
				/* continue */
				break;
			case DB_PROXY_JOB+DB_SERVER_JOB:
				if (ctx->isProxy) {
					purge = 0;
					if (unset_proxy_flag(ctx, job) < 0) {
						goto rollback;
					}
				}
				else {
					purge = 0;
					/* if server&proxy DB is shared ... */
					if (is_job_local(ctx,job) && purge_from_proxy_only) {
						if (unset_proxy_flag(ctx, job) < 0) {
							goto rollback;
						}
					}
					else {
						if (unset_server_flag(ctx, job) < 0) {
							goto rollback;
						}
					}
				}
				break;
			case 0:
				// Zombie job (server=0, proxy=0)? should not happen;
				// clear it to keep DB healthy
				break;
			default:
				goto rollback;
				break;
		}

		dbjob = glite_jobid_getUnique(job);	/* XXX: strict jobid already checked */


		if ( purge )
		{
			enum edg_wll_StatJobtype jobtype = get_job_type(ctx, job);

			// get job prefix/suffix before its state is deleted
			if ( jobtype == EDG_WLL_NUMBER_OF_JOBTYPES) goto rollback;
			if (get_jobid_suffix(ctx, job, jobtype, &root, &suffix)
			 || get_jobid_prefix(ctx, job, jobtype, &prefix)) {
				glite_common_log(LOG_CATEGORY_CONTROL, 
					LOG_PRIORITY_WARN, 
					"[%d] unknown job type %d of job %s", 
					getpid(), jobtype, dbjob);
				edg_wll_ResetError(ctx);
			}

			// notifications
			memcpy(&new_stat, stat, sizeof new_stat);
			new_stat.state = EDG_WLL_JOB_PURGED;
			edg_wll_NotifMatch(ctx, stat, &new_stat);
		}

		if ( purge )
		{
			edg_wll_jobsconnection_purgeall(ctx, job);
		}

		if ( purge )
		{
			trio_asprintf(&stmt,"delete from jobs where jobid = '%|Ss'",dbjob);
			glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);
			if (edg_wll_ExecSQL(ctx,stmt,NULL) < 0) goto rollback;
			free(stmt); stmt = NULL;

			trio_asprintf(&stmt,"delete from states where jobid = '%|Ss'",dbjob);
			glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);
			if (edg_wll_ExecSQL(ctx,stmt,NULL) < 0) goto rollback; 
			free(stmt); stmt = NULL;

			trio_asprintf(&stmt,"delete from status_tags where jobid = '%|Ss'",dbjob);
			glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);
			if (edg_wll_ExecSQL(ctx,stmt,NULL) < 0) goto rollback;
			free(stmt); stmt = NULL;
		}

		if ( purge && prefix && suffix )
		{
			/* Store zombie prefix */
		
			// See if that prefix is already stored in the database	
			trio_asprintf(&stmt,"select prefix_id from zombie_prefixes where prefix = '%|Ss'", prefix);
			glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);

			sql_retval = edg_wll_ExecSQL(ctx,stmt,&q);
			free(stmt); stmt = NULL;

			if (sql_retval < 0) goto rollback;

			if (sql_retval == 0) { //prefix does not exist yet
				glite_lbu_FreeStmt(&q);

				trio_asprintf(&stmt,"insert into zombie_prefixes (prefix) VALUES ('%|Ss')", prefix);
				glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);

				if (edg_wll_ExecSQL(ctx,stmt,&q) <= 0) goto rollback;

				free(stmt); stmt = NULL;
				glite_lbu_FreeStmt(&q);

				// The record should exist now, however we need to look up the prefix_id 
				trio_asprintf(&stmt,"select prefix_id from zombie_prefixes where prefix = '%|Ss'", prefix);
				glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);

				if (edg_wll_ExecSQL(ctx,stmt,&q) <= 0) goto rollback;
				free(stmt); stmt = NULL;
			}
			ret = edg_wll_FetchRow(ctx,q, 1, NULL, &prefix_id);
			glite_lbu_FreeStmt(&q);


			/* Store zombie suffix */

			// See if that suffix is already stored in the database	
			trio_asprintf(&stmt,"select suffix_id from zombie_suffixes where suffix = '%|Ss'", suffix);
			glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);

			sql_retval = edg_wll_ExecSQL(ctx,stmt,&q);
			free(stmt); stmt = NULL;

			if (sql_retval < 0) goto rollback;

			if (sql_retval == 0) { //suffix does not exist yet
				glite_lbu_FreeStmt(&q);

				trio_asprintf(&stmt,"insert into zombie_suffixes (suffix) VALUES ('%|Ss')", suffix);
				glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);

				if (edg_wll_ExecSQL(ctx,stmt,&q) <= 0) goto rollback;

				free(stmt); stmt = NULL;
				glite_lbu_FreeStmt(&q);

				// The record should exist now, however we need to look up the suffix_id 
				trio_asprintf(&stmt,"select suffix_id from zombie_suffixes where suffix = '%|Ss'", suffix);
				glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);

				if (edg_wll_ExecSQL(ctx,stmt,&q) <= 0) goto rollback;
				free(stmt); stmt = NULL;
			}
			ret = edg_wll_FetchRow(ctx,q, 1, NULL, &suffix_id);
			glite_lbu_FreeStmt(&q);


			/* Store zombie job */

			trio_asprintf(&stmt,"insert into zombie_jobs (jobid, prefix_id, suffix_id)"
					" VALUES ('%|Ss', '%|Ss', '%|Ss')", root, prefix_id, suffix_id);
			glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);

			if (edg_wll_ExecSQL(ctx,stmt,&q) < 0) {
				if (edg_wll_Error(ctx, NULL, NULL) == EEXIST) {
					/* job already among zombies */
					/* print warning but continue */
					/* erasing other jobs */
					char *et, *ed, *msg, *job_s;

					edg_wll_Error(ctx, &et, &ed);
					job_s = glite_jobid_unparse(job);
					
					asprintf(&msg,"Warning: erasing job %s that already existed in this LB "
						"(reused jobid or corruped DB) (%s: %s)",job_s,et,ed);
					glite_common_log(LOG_CATEGORY_CONTROL, LOG_PRIORITY_WARN, "[%d] %s", getpid(), msg);
					free(et); free(ed); free(msg); free(job_s);
					edg_wll_ResetError(ctx);
				}
				else goto rollback;
			}
			glite_lbu_FreeStmt(&q);
			free(stmt); stmt = NULL;
		}

		if (dump >= 0) 
			trio_asprintf(&stmt,
				"select event,code,prog,host,u.cert_subj,time_stamp,usec,level,arrived,seqcode "
				"from events e,users u "
				"where e.jobid='%|Ss' "
				"and u.userid=e.userid "
				"order by event", dbjob);
		else
			trio_asprintf(&stmt,"select event from events "
				"where jobid='%|Ss' "
				"order by event", dbjob);

		glite_common_log_msg(LOG_CATEGORY_LB_SERVER_DB, LOG_PRIORITY_DEBUG, stmt);

		if (edg_wll_ExecSQL(ctx,stmt,&q) < 0) goto rollback;
		free(stmt); stmt = NULL;

		dumped = 1;
		while ((ret = edg_wll_FetchRow(ctx,q,sizofa(res),NULL,res)) > 0) {
			int	event, ret_dump = 0, i;

			event = atoi(res[0]);

			if (dump >= 0) {
				assert(ret == 10);
				ret_dump = dump_events( ctx, job, dump, (char **) &res);
			}

			for (i=0; i<sizofa(res); i++) free(res[i]);

			if (dump >= 0 && ret_dump) goto rollback;

			if ( purge ) 
				if (edg_wll_delete_event(ctx,dbjob,event)) goto rollback;
		}
		glite_lbu_FreeStmt(&q);
		if (ret < 0) goto rollback;

commit:
rollback:;
	} while (edg_wll_TransNeedRetry(ctx));


err:
	free(root);
	free(suffix);
	free(prefix);
	free(prefix_id);
	free(suffix_id);
	free(dbjob);
	free(stmt);
	glite_lbu_FreeStmt(&q);

	return edg_wll_Error(ctx,NULL,NULL);
}
Esempio n. 6
0
int main(int argc,char **argv) {
	edg_wll_Context	ctx;
	struct tm	tm;
	time_t	from,to;
	int	i, err = 0;

	edg_wll_QueryRec	cond[3],jcond[2];	/* [2] is terminator */
	edg_wll_Event	*events = NULL;

	if (edg_wll_InitContext(&ctx) != 0) {
		fprintf(stderr, "Couldn't create L&B context.\n");
		return 1;
	}

	if (argc != 3) usage(argv[0]);

	
	memset(&tm,0,sizeof tm);

	if (sscanf(argv[1],"%d-%d-%d:%d:%d",
		&tm.tm_year,
		&tm.tm_mon,
		&tm.tm_mday,
		&tm.tm_hour,
		&tm.tm_min) != 5) usage(argv[0]);

	tm.tm_mon--;
	tm.tm_year -= 1900;

	from = mktime(&tm);
	
	if (sscanf(argv[2],"%d-%d-%d:%d:%d",
		&tm.tm_year,
		&tm.tm_mon,
		&tm.tm_mday,
		&tm.tm_hour,
		&tm.tm_min) != 5) usage(argv[0]);

	tm.tm_mon--;
	tm.tm_year -= 1900;

	to = mktime(&tm);

	memset(jcond,0,sizeof jcond);

	jcond[0].attr = EDG_WLL_QUERY_ATTR_OWNER;
	jcond[0].op = EDG_WLL_QUERY_OP_UNEQUAL;
	jcond[0].value.c = "nonexistent";

	memset(cond,0,sizeof cond);
	cond[0].attr = EDG_WLL_QUERY_ATTR_TIME;
	cond[0].op = EDG_WLL_QUERY_OP_WITHIN;
	cond[0].value.t.tv_sec = from;
	cond[0].value2.t.tv_sec = to;

	cond[1].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE;
	cond[1].value.i = EDG_WLL_EVENT_DONE;
	
	if (edg_wll_QueryEvents(ctx,jcond,cond,&events)) {
		char	*et,*ed;
		et = ed = NULL;

		edg_wll_Error(ctx,&et,&ed);
		fprintf(stderr,"edg_wll_QueryEventsProxy: %s, %s\n",
			et,ed ? ed : "");

		free(et); free(ed);
		err = 1;
		goto cleanup;
	}

	for (i=0; events[i].type; i++) {
		edg_wll_Event	*e = events+i;

		if (e->done.status_code == EDG_WLL_DONE_FAILED) {
			char	*job = glite_jobid_unparse(e->any.jobId);

			printf("%s\t%s\t%s\t%s\n",
				job,
				ctime(&e->done.timestamp.tv_sec),
				e->done.host,
				e->done.reason
				);

			free(job);
		}
	}
				
cleanup:
	if (events) {
		for (i=0; events[i].type; i++) edg_wll_FreeEvent(events+i);
		free(events); events = NULL;
	}

	edg_wll_FreeContext(ctx);

	return err;
}