/** Parse the arguments line of an existing .condor.sub file, extracing the arguments we want to preserve when updating the .condor.sub file. @param subLine: the arguments line from the .condor.sub file @param shallowOpts: the condor_submit_dag shallow options @return 0 if successful, 1 if failed */ int parseArgumentsLine( const MyString &subLine, SubmitDagShallowOptions &shallowOpts ) { const char *line = subLine.Value(); const char *start = strchr( line, '"' ); const char *end = strrchr( line, '"' ); MyString arguments; if ( start && end ) { arguments = subLine.Substr( start - line, end - line ); } else { fprintf( stderr, "Missing quotes in arguments line: <%s>\n", subLine.Value() ); return 1; } ArgList arglist; MyString error; if ( !arglist.AppendArgsV2Quoted( arguments.Value(), &error ) ) { fprintf( stderr, "Error parsing arguments: %s\n", error.Value() ); return 1; } for ( int argNum = 0; argNum < arglist.Count(); argNum++ ) { MyString strArg = arglist.GetArg( argNum ); strArg.lower_case(); (void)parsePreservedArgs( strArg, argNum, arglist.Count(), arglist.GetStringArray(), shallowOpts); } return 0; }
void CBCI2000Controller::startup_modules( ArgList& ioArgs ) { std::vector<com::DualString> modules_ = ioArgs.GetStringArray( 1 ); std::vector<std::string> modules( modules_.begin(), modules_.end() ); CALL( StartupModules( modules ) ); }
static FILE * my_popenv_impl( const char *const args[], const char * mode, int want_stderr, uid_t privsep_uid, Env *env_ptr = 0, bool drop_privs = true ) { int pipe_d[2], pipe_d2[2]; int parent_reads; uid_t euid; gid_t egid; pid_t pid; FILE* retp; /* Figure out who reads and who writes on the pipe */ parent_reads = (mode[0] == 'r'); /* Create the pipe */ if( pipe(pipe_d) < 0 ) { dprintf(D_ALWAYS, "my_popenv: Failed to create the pipe, " "errno=%d (%s)\n", errno, strerror(errno)); return NULL; } /* Prepare for PrivSep if needed */ PrivSepForkExec psforkexec; if ( privsep_uid != (uid_t)-1 ) { if (!psforkexec.init()) { dprintf(D_ALWAYS, "my_popenv failure on %s\n", args[0]); close(pipe_d[0]); close(pipe_d[1]); return NULL; } } /* Create a pipe to detect execv failures */ if ( pipe(pipe_d2) < 0) { dprintf(D_ALWAYS, "my_popenv: Failed to create the pre-exec pipe, " "errno=%d (%s)\n", errno, strerror(errno)); close(pipe_d[0]); close(pipe_d[1]); return NULL; } int fd_flags; if ((fd_flags = fcntl(pipe_d2[1], F_GETFD, NULL)) == -1) { dprintf(D_ALWAYS, "my_popenv: Failed to get fd flags: errno=%d (%s)\n", errno, strerror(errno)); close( pipe_d[0] ); close( pipe_d[1] ); close( pipe_d2[0] ); close( pipe_d2[1] ); return NULL; } if (fcntl(pipe_d2[1], F_SETFD, fd_flags | FD_CLOEXEC) == -1) { dprintf(D_ALWAYS, "my_popenv: Failed to set new fd flags: errno=%d (%s)\n", errno, strerror(errno)); close( pipe_d[0] ); close( pipe_d[1] ); close( pipe_d2[0] ); close( pipe_d2[1] ); return NULL; } /* Create a new process */ if( (pid=fork()) < 0 ) { dprintf(D_ALWAYS, "my_popenv: Failed to fork child, errno=%d (%s)\n", errno, strerror(errno)); /* Clean up file descriptors */ close( pipe_d[0] ); close( pipe_d[1] ); close( pipe_d2[0] ); close( pipe_d2[1] ); return NULL; } /* The child */ if( pid == 0 ) { /* Don't leak out fds from the parent to our child. * Wish there was a more efficient way to do this, but * this is how we do it in daemoncore CreateProcess... * Of course, do not close stdin/out/err or the fds to * the pipes we just created above. */ for (int jj=3; jj < getdtablesize(); jj++) { if (jj != pipe_d[0] && jj != pipe_d[1] && jj != pipe_d2[0] && jj != pipe_d2[1]) { close(jj); } } close(pipe_d2[0]); if( parent_reads ) { /* Close stdin, dup pipe to stdout */ close( pipe_d[READ_END] ); bool close_pipe_end = false; if( pipe_d[WRITE_END] != 1 ) { dup2( pipe_d[WRITE_END], 1 ); close_pipe_end = true; } if (want_stderr) { if ( pipe_d[WRITE_END] != 2 ) { dup2( pipe_d[WRITE_END], 2 ); } else { close_pipe_end = false; } } if (close_pipe_end) { close(pipe_d[WRITE_END]); } } else { /* Close stdout, dup pipe to stdin */ close( pipe_d[WRITE_END] ); if( pipe_d[READ_END] != 0 ) { dup2( pipe_d[READ_END], 0 ); close( pipe_d[READ_END] ); } } /* to be safe, we want to switch our real uid/gid to our effective uid/gid (shedding any privledges we've got). we also want to drop any supplimental groups we're in. we want to run this popen()'ed thing as our effective uid/gid, dropping the real uid/gid. all of these calls will fail if we don't have a ruid of 0 (root), but that's harmless. also, note that we have to stash our effective uid, then switch our euid to 0 to be able to set our real uid/gid. We wrap some of the calls in if-statements to quiet some compilers that object to us not checking the return values. */ if (drop_privs) { euid = geteuid(); egid = getegid(); if( seteuid( 0 ) ) { } setgroups( 1, &egid ); if( setgid( egid ) ) { } if( setuid( euid ) ) _exit(ENOEXEC); // Unsafe? } /* before we exec(), clear the signal mask and reset SIGPIPE to SIG_DFL */ install_sig_handler(SIGPIPE, SIG_DFL); sigset_t sigs; sigfillset(&sigs); sigprocmask(SIG_UNBLOCK, &sigs, NULL); /* handle PrivSep if needed */ MyString cmd = args[0]; if ( privsep_uid != (uid_t)-1 ) { ArgList al; psforkexec.in_child(cmd, al); args = al.GetStringArray(); } /* set environment if defined */ if (env_ptr) { char **m_unix_env = NULL; m_unix_env = env_ptr->getStringArray(); execve(cmd.Value(), const_cast<char *const*>(args), m_unix_env ); // delete the memory even though we're on our way out // if exec failed. if (m_unix_env) { int i = 0; while (m_unix_env[i]) { delete m_unix_env[i]; i++; } delete [] m_unix_env; } } else { execvp(cmd.Value(), const_cast<char *const*>(args) ); } /* If we get here, inform the parent of our errno */ char result_buf[10]; int e = errno; // capture real errno int len = snprintf(result_buf, 10, "%d", errno); int ret = write(pipe_d2[1], result_buf, len); // Jump through some hoops just to use ret. if (ret < 1) { _exit( e ); } else { _exit( e ); } } /* The parent */ /* First, wait until the exec is called - determine status */ close(pipe_d2[1]); int exit_code; FILE *fh; if ((fh = fdopen(pipe_d2[0], "r")) == NULL) { dprintf(D_ALWAYS, "my_popenv: Failed to reopen file descriptor as file handle: errno=%d (%s)", errno, strerror(errno)); close(pipe_d2[0]); close(pipe_d[0]); close(pipe_d[1]); /* Ensure child process is dead, then wait for it to exit */ kill(pid, SIGKILL); while( waitpid(pid,NULL,0) < 0 && errno == EINTR ) { /* NOOP */ } return NULL; } /* Handle case where exec fails */ if (fscanf(fh, "%d", &exit_code) == 1) { fclose(fh); close(pipe_d[0]); close(pipe_d[1]); /* Ensure child process is dead, then wait for it to exit */ kill(pid, SIGKILL); while( waitpid(pid,NULL,0) < 0 && errno == EINTR ) { /* NOOP */ } errno = exit_code; return NULL; } fclose(fh); if( parent_reads ) { close( pipe_d[WRITE_END] ); retp = fdopen(pipe_d[READ_END],mode); } else { close( pipe_d[READ_END] ); retp = fdopen(pipe_d[WRITE_END],mode); } add_child(retp, pid); /* handle PrivSep if needed */ if ( privsep_uid != (uid_t)-1 ) { FILE* fp = psforkexec.parent_begin(); privsep_exec_set_uid(fp, privsep_uid); privsep_exec_set_path(fp, args[0]); ArgList al; for (const char* const* arg = args; *arg != NULL; arg++) { al.AppendArg(*arg); } privsep_exec_set_args(fp, al); Env env; env.Import(); privsep_exec_set_env(fp, env); privsep_exec_set_iwd(fp, "."); if (parent_reads) { privsep_exec_set_inherit_fd(fp, 1); if (want_stderr) { privsep_exec_set_inherit_fd(fp, 2); } } else { privsep_exec_set_inherit_fd(fp, 0); } if (!psforkexec.parent_end()) { dprintf(D_ALWAYS, "my_popenv failure on %s\n", args[0]); fclose(retp); return NULL; } } return retp; }
/** * merge_stderr_with_stdout is intended for clients of this function * that wish to have the old behavior, where stderr and stdout were * both added to the same StringList. */ int systemCommand( ArgList &args, priv_state priv, StringList *cmd_out, StringList * cmd_in, StringList *cmd_err, bool merge_stderr_with_stdout) { int result = 0; FILE *fp = NULL; FILE * fp_for_stdin = NULL; FILE * childerr = NULL; MyString line; char buff[1024]; StringList *my_cmd_out = cmd_out; priv_state prev = PRIV_UNKNOWN; int stdout_pipes[2]; int stdin_pipes[2]; int pid; bool use_privsep = false; switch ( priv ) { case PRIV_ROOT: prev = set_root_priv(); break; case PRIV_USER: case PRIV_USER_FINAL: prev = set_user_priv(); #if !defined(WIN32) if ( privsep_enabled() && (job_user_uid != get_condor_uid()) ) { use_privsep = true; } #endif break; default: // Stay as Condor user ; } #if defined(WIN32) if((cmd_in != NULL) || (cmd_err != NULL)) { vmprintf(D_ALWAYS, "Invalid use of systemCommand() in Windows.\n"); return -1; } //if ( use_privsep ) { // fp = privsep_popen(args, "r", want_stderr, job_user_uid); //} //else { fp = my_popen( args, "r", merge_stderr_with_stdout ); //} #else // The old way of doing things (and the Win32 way of doing // things) // fp = my_popen( args, "r", want_stderr ); if((cmd_err != NULL) && merge_stderr_with_stdout) { vmprintf(D_ALWAYS, "Invalid use of systemCommand().\n"); return -1; } PrivSepForkExec psforkexec; char ** args_array = args.GetStringArray(); int error_pipe[2]; // AIX 5.2, Solaris 5.9, HPUX 11 don't have AF_LOCAL if(pipe(stdin_pipes) < 0) { vmprintf(D_ALWAYS, "Error creating pipe: %s\n", strerror(errno)); deleteStringArray( args_array ); return -1; } if(pipe(stdout_pipes) < 0) { vmprintf(D_ALWAYS, "Error creating pipe: %s\n", strerror(errno)); close(stdin_pipes[0]); close(stdin_pipes[1]); deleteStringArray( args_array ); return -1; } if ( use_privsep ) { if(!psforkexec.init()) { vmprintf(D_ALWAYS, "my_popenv failure on %s\n", args_array[0]); close(stdin_pipes[0]); close(stdin_pipes[1]); close(stdout_pipes[0]); close(stdout_pipes[1]); deleteStringArray( args_array ); return -1; } } if(cmd_err != NULL) { if(pipe(error_pipe) < 0) { vmprintf(D_ALWAYS, "Could not open pipe for error output: %s\n", strerror(errno)); close(stdin_pipes[0]); close(stdin_pipes[1]); close(stdout_pipes[0]); close(stdout_pipes[1]); deleteStringArray( args_array ); return -1; } } // Now fork and do what my_popen used to do pid = fork(); if(pid < 0) { vmprintf(D_ALWAYS, "Error forking: %s\n", strerror(errno)); close(stdin_pipes[0]); close(stdin_pipes[1]); close(stdout_pipes[0]); close(stdout_pipes[1]); if(cmd_err != NULL) { close(error_pipe[0]); close(error_pipe[1]); } deleteStringArray( args_array ); return -1; } if(pid == 0) { close(stdout_pipes[0]); close(stdin_pipes[1]); dup2(stdout_pipes[1], STDOUT_FILENO); dup2(stdin_pipes[0], STDIN_FILENO); if(merge_stderr_with_stdout) dup2(stdout_pipes[1], STDERR_FILENO); else if(cmd_err != NULL) { close(error_pipe[0]); dup2(error_pipe[1], STDERR_FILENO); } uid_t euid = geteuid(); gid_t egid = getegid(); seteuid( 0 ); setgroups( 1, &egid ); setgid( egid ); setuid( euid ); install_sig_handler(SIGPIPE, SIG_DFL); sigset_t sigs; sigfillset(&sigs); sigprocmask(SIG_UNBLOCK, &sigs, NULL); MyString cmd = args_array[0]; if ( use_privsep ) { ArgList al; psforkexec.in_child(cmd, al); deleteStringArray( args_array ); args_array = al.GetStringArray(); } execvp(cmd.Value(), args_array); vmprintf(D_ALWAYS, "Could not execute %s: %s\n", args_array[0], strerror(errno)); exit(-1); } close(stdin_pipes[0]); close(stdout_pipes[1]); fp_for_stdin = fdopen(stdin_pipes[1], "w"); fp = fdopen(stdout_pipes[0], "r"); if(cmd_err != NULL) { close(error_pipe[1]); childerr = fdopen(error_pipe[0],"r"); if(childerr == 0) { vmprintf(D_ALWAYS, "Could not open pipe for reading child error output: %s\n", strerror(errno)); close(error_pipe[0]); close(stdin_pipes[1]); close(stdout_pipes[0]); fclose(fp); fclose(fp_for_stdin); deleteStringArray( args_array ); return -1; } } if ( use_privsep ) { FILE* _fp = psforkexec.parent_begin(); privsep_exec_set_uid(_fp, job_user_uid); privsep_exec_set_path(_fp, args_array[0]); privsep_exec_set_args(_fp, args); Env env; env.MergeFrom(environ); privsep_exec_set_env(_fp, env); privsep_exec_set_iwd(_fp, "."); privsep_exec_set_inherit_fd(_fp, 1); privsep_exec_set_inherit_fd(_fp, 2); privsep_exec_set_inherit_fd(_fp, 0); if (!psforkexec.parent_end()) { vmprintf(D_ALWAYS, "my_popenv failure on %s\n", args_array[0]); fclose(fp); fclose(fp_for_stdin); if (childerr) { fclose(childerr); } deleteStringArray( args_array ); return -1; } } deleteStringArray( args_array ); #endif set_priv( prev ); if ( fp == NULL ) { MyString args_string; args.GetArgsStringForDisplay( &args_string, 0 ); vmprintf( D_ALWAYS, "Failed to execute command: %s\n", args_string.Value() ); if (childerr) fclose(childerr); return -1; } if(cmd_in != NULL) { cmd_in->rewind(); char * tmp; while((tmp = cmd_in->next()) != NULL) { fprintf(fp_for_stdin, "%s\n", tmp); fflush(fp_for_stdin); } } if (fp_for_stdin) { // So that we will not be waiting for output while the // script waits for stdin to be closed. fclose(fp_for_stdin); } if ( my_cmd_out == NULL ) { my_cmd_out = new StringList(); } while ( fgets( buff, sizeof(buff), fp ) != NULL ) { line += buff; if ( line.chomp() ) { my_cmd_out->append( line.Value() ); line = ""; } } if(cmd_err != NULL) { while(fgets(buff, sizeof(buff), childerr) != NULL) { line += buff; if(line.chomp()) { cmd_err->append(line.Value()); line = ""; } } fclose(childerr); } #if defined(WIN32) result = my_pclose( fp ); #else // Why close first? Just in case the child process is waiting // on a read, and we have nothing more to send it. It will // now receive a SIGPIPE. fclose(fp); if(waitpid(pid, &result, 0) < 0) { vmprintf(D_ALWAYS, "Unable to wait: %s\n", strerror(errno)); if ( cmd_out == NULL ) { delete my_cmd_out; } return -1; } #endif if( result != 0 ) { MyString args_string; args.GetArgsStringForDisplay(&args_string,0); vmprintf(D_ALWAYS, "Command returned non-zero: %s\n", args_string.Value()); my_cmd_out->rewind(); const char *next_line; while ( (next_line = my_cmd_out->next()) ) { vmprintf( D_ALWAYS, " %s\n", next_line ); } } if ( cmd_out == NULL ) { delete my_cmd_out; } return result; }
int main (int argc, char *argv[]) { #if !defined(WIN32) install_sig_handler(SIGPIPE, (SIG_HANDLER)SIG_IGN ); #endif // initialize to read from config file myDistro->Init( argc, argv ); myName = argv[0]; config(); dprintf_config_tool_on_error(0); // The arguments take two passes to process --- the first pass // figures out the mode, after which we can instantiate the required // query object. We add implied constraints from the command line in // the second pass. firstPass (argc, argv); // if the mode has not been set, it is STARTD_NORMAL if (mode == MODE_NOTSET) { setMode (MODE_STARTD_NORMAL, 0, DEFAULT); } // instantiate query object if (!(query = new CondorQuery (type))) { dprintf_WriteOnErrorBuffer(stderr, true); fprintf (stderr, "Error: Out of memory\n"); exit (1); } // if a first-pass setMode set a mode_constraint, apply it now to the query object if (mode_constraint && ! explicit_format) { query->addANDConstraint(mode_constraint); } // set pretty print style implied by the type of entity being queried // but do it with default priority, so that explicitly requested options // can override it switch (type) { #ifdef HAVE_EXT_POSTGRESQL case QUILL_AD: setPPstyle(PP_QUILL_NORMAL, 0, DEFAULT); break; #endif /* HAVE_EXT_POSTGRESQL */ case DEFRAG_AD: setPPstyle(PP_GENERIC_NORMAL, 0, DEFAULT); break; case STARTD_AD: setPPstyle(PP_STARTD_NORMAL, 0, DEFAULT); break; case SCHEDD_AD: setPPstyle(PP_SCHEDD_NORMAL, 0, DEFAULT); break; case MASTER_AD: setPPstyle(PP_MASTER_NORMAL, 0, DEFAULT); break; case CKPT_SRVR_AD: setPPstyle(PP_CKPT_SRVR_NORMAL, 0, DEFAULT); break; case COLLECTOR_AD: setPPstyle(PP_COLLECTOR_NORMAL, 0, DEFAULT); break; case STORAGE_AD: setPPstyle(PP_STORAGE_NORMAL, 0, DEFAULT); break; case NEGOTIATOR_AD: setPPstyle(PP_NEGOTIATOR_NORMAL, 0, DEFAULT); break; case GRID_AD: setPPstyle(PP_GRID_NORMAL, 0, DEFAULT); break; case GENERIC_AD: setPPstyle(PP_GENERIC, 0, DEFAULT); break; case ANY_AD: setPPstyle(PP_ANY_NORMAL, 0, DEFAULT); break; default: setPPstyle(PP_VERBOSE, 0, DEFAULT); } // set the constraints implied by the mode switch (mode) { #ifdef HAVE_EXT_POSTGRESQL case MODE_QUILL_NORMAL: #endif /* HAVE_EXT_POSTGRESQL */ case MODE_DEFRAG_NORMAL: case MODE_STARTD_NORMAL: case MODE_MASTER_NORMAL: case MODE_CKPT_SRVR_NORMAL: case MODE_SCHEDD_NORMAL: case MODE_SCHEDD_SUBMITTORS: case MODE_COLLECTOR_NORMAL: case MODE_NEGOTIATOR_NORMAL: case MODE_STORAGE_NORMAL: case MODE_GENERIC_NORMAL: case MODE_ANY_NORMAL: case MODE_GRID_NORMAL: case MODE_HAD_NORMAL: break; case MODE_OTHER: // tell the query object what the type we're querying is query->setGenericQueryType(genericType); free(genericType); genericType = NULL; break; case MODE_STARTD_AVAIL: // For now, -avail shows you machines avail to anyone. sprintf (buffer, "%s == \"%s\"", ATTR_STATE, state_to_string(unclaimed_state)); if (diagnose) { printf ("Adding constraint [%s]\n", buffer); } query->addORConstraint (buffer); break; case MODE_STARTD_RUN: sprintf (buffer, "%s == \"%s\"", ATTR_STATE, state_to_string(claimed_state)); if (diagnose) { printf ("Adding constraint [%s]\n", buffer); } query->addORConstraint (buffer); break; case MODE_STARTD_COD: sprintf (buffer, "%s > 0", ATTR_NUM_COD_CLAIMS ); if (diagnose) { printf ("Adding constraint [%s]\n", buffer); } query->addORConstraint (buffer); break; default: break; } if(javaMode) { sprintf( buffer, "%s == TRUE", ATTR_HAS_JAVA ); if (diagnose) { printf ("Adding constraint [%s]\n", buffer); } query->addANDConstraint (buffer); projList.AppendArg(ATTR_HAS_JAVA); projList.AppendArg(ATTR_JAVA_MFLOPS); projList.AppendArg(ATTR_JAVA_VENDOR); projList.AppendArg(ATTR_JAVA_VERSION); } if(offlineMode) { query->addANDConstraint( "size( OfflineUniverses ) != 0" ); projList.AppendArg( "OfflineUniverses" ); // // Since we can't add a regex to a projection, explicitly list all // the attributes we know about. // projList.AppendArg( "HasVM" ); projList.AppendArg( "VMOfflineReason" ); projList.AppendArg( "VMOfflineTime" ); } if(absentMode) { sprintf( buffer, "%s == TRUE", ATTR_ABSENT ); if (diagnose) { printf( "Adding constraint %s\n", buffer ); } query->addANDConstraint( buffer ); projList.AppendArg( ATTR_ABSENT ); projList.AppendArg( ATTR_LAST_HEARD_FROM ); projList.AppendArg( ATTR_CLASSAD_LIFETIME ); } if(vmMode) { sprintf( buffer, "%s == TRUE", ATTR_HAS_VM); if (diagnose) { printf ("Adding constraint [%s]\n", buffer); } query->addANDConstraint (buffer); projList.AppendArg(ATTR_VM_TYPE); projList.AppendArg(ATTR_VM_MEMORY); projList.AppendArg(ATTR_VM_NETWORKING); projList.AppendArg(ATTR_VM_NETWORKING_TYPES); projList.AppendArg(ATTR_VM_HARDWARE_VT); projList.AppendArg(ATTR_VM_AVAIL_NUM); projList.AppendArg(ATTR_VM_ALL_GUEST_MACS); projList.AppendArg(ATTR_VM_ALL_GUEST_IPS); projList.AppendArg(ATTR_VM_GUEST_MAC); projList.AppendArg(ATTR_VM_GUEST_IP); } // second pass: add regular parameters and constraints if (diagnose) { printf ("----------\n"); } secondPass (argc, argv); // initialize the totals object if (ppStyle == PP_CUSTOM && using_print_format) { if (pmHeadFoot & HF_NOSUMMARY) ppTotalStyle = PP_CUSTOM; } else { ppTotalStyle = ppStyle; } TrackTotals totals(ppTotalStyle); // fetch the query QueryResult q; if ((mode == MODE_STARTD_NORMAL) && (ppStyle == PP_STARTD_NORMAL)) { projList.AppendArg("Name"); projList.AppendArg("Machine"); projList.AppendArg("Opsys"); projList.AppendArg("Arch"); projList.AppendArg("State"); projList.AppendArg("Activity"); projList.AppendArg("LoadAvg"); projList.AppendArg("Memory"); projList.AppendArg("ActvtyTime"); projList.AppendArg("MyCurrentTime"); projList.AppendArg("EnteredCurrentActivity"); } else if( ppStyle == PP_VERBOSE ) { // Remove everything from the projection list if we're displaying // the "long form" of the ads. projList.Clear(); // but if -attributes was supplied, show only those attributes if ( ! dashAttributes.isEmpty()) { const char * s; dashAttributes.rewind(); while ((s = dashAttributes.next())) { projList.AppendArg(s); } } } if( projList.Count() > 0 ) { char **attr_list = projList.GetStringArray(); query->setDesiredAttrs(attr_list); deleteStringArray(attr_list); } // if diagnose was requested, just print the query ad if (diagnose) { ClassAd queryAd; // print diagnostic information about inferred internal state setMode ((Mode) 0, 0, NULL); setType (NULL, 0, NULL); setPPstyle ((ppOption) 0, 0, DEFAULT); printf ("----------\n"); q = query->getQueryAd (queryAd); fPrintAd (stdout, queryAd); printf ("----------\n"); fprintf (stderr, "Result of making query ad was: %d\n", q); exit (1); } // Address (host:port) is taken from requested pool, if given. char* addr = (NULL != pool) ? pool->addr() : NULL; Daemon* requested_daemon = pool; // If we're in "direct" mode, then we attempt to locate the daemon // associated with the requested subsystem (here encoded by value of mode) // In this case the host:port of pool (if given) denotes which // pool is being consulted if( direct ) { Daemon *d = NULL; switch( mode ) { case MODE_MASTER_NORMAL: d = new Daemon( DT_MASTER, direct, addr ); break; case MODE_STARTD_NORMAL: case MODE_STARTD_AVAIL: case MODE_STARTD_RUN: case MODE_STARTD_COD: d = new Daemon( DT_STARTD, direct, addr ); break; #ifdef HAVE_EXT_POSTGRESQL case MODE_QUILL_NORMAL: d = new Daemon( DT_QUILL, direct, addr ); break; #endif /* HAVE_EXT_POSTGRESQL */ case MODE_SCHEDD_NORMAL: case MODE_SCHEDD_SUBMITTORS: d = new Daemon( DT_SCHEDD, direct, addr ); break; case MODE_NEGOTIATOR_NORMAL: d = new Daemon( DT_NEGOTIATOR, direct, addr ); break; case MODE_CKPT_SRVR_NORMAL: case MODE_COLLECTOR_NORMAL: case MODE_LICENSE_NORMAL: case MODE_STORAGE_NORMAL: case MODE_GENERIC_NORMAL: case MODE_ANY_NORMAL: case MODE_OTHER: case MODE_GRID_NORMAL: case MODE_HAD_NORMAL: // These have to go to the collector, anyway. break; default: fprintf( stderr, "Error: Illegal mode %d\n", mode ); exit( 1 ); break; } // Here is where we actually override 'addr', if we can obtain // address of the requested daemon/subsys. If it can't be // located, then fail with error msg. // 'd' will be null (unset) if mode is one of above that must go to // collector (MODE_ANY_NORMAL, MODE_COLLECTOR_NORMAL, etc) if (NULL != d) { if( d->locate() ) { addr = d->addr(); requested_daemon = d; } else { const char* id = d->idStr(); if (NULL == id) id = d->name(); dprintf_WriteOnErrorBuffer(stderr, true); if (NULL == id) id = "daemon"; fprintf(stderr, "Error: Failed to locate %s\n", id); fprintf(stderr, "%s\n", d->error()); exit( 1 ); } } } ClassAdList result; CondorError errstack; if (NULL != ads_file) { MyString req; // query requirements q = query->getRequirements(req); const char * constraint = req.empty() ? NULL : req.c_str(); if (read_classad_file(ads_file, result, constraint)) { q = Q_OK; } } else if (NULL != addr) { // this case executes if pool was provided, or if in "direct" mode with // subsystem that corresponds to a daemon (above). // Here 'addr' represents either the host:port of requested pool, or // alternatively the host:port of daemon associated with requested subsystem (direct mode) q = query->fetchAds (result, addr, &errstack); } else { // otherwise obtain list of collectors and submit query that way CollectorList * collectors = CollectorList::create(); q = collectors->query (*query, result, &errstack); delete collectors; } // if any error was encountered during the query, report it and exit if (Q_OK != q) { dprintf_WriteOnErrorBuffer(stderr, true); // we can always provide these messages: fprintf( stderr, "Error: %s\n", getStrQueryResult(q) ); fprintf( stderr, "%s\n", errstack.getFullText(true).c_str() ); if ((NULL != requested_daemon) && ((Q_NO_COLLECTOR_HOST == q) || (requested_daemon->type() == DT_COLLECTOR))) { // Specific long message if connection to collector failed. const char* fullhost = requested_daemon->fullHostname(); if (NULL == fullhost) fullhost = "<unknown_host>"; const char* daddr = requested_daemon->addr(); if (NULL == daddr) daddr = "<unknown>"; char info[1000]; sprintf(info, "%s (%s)", fullhost, daddr); printNoCollectorContact( stderr, info, !expert ); } else if ((NULL != requested_daemon) && (Q_COMMUNICATION_ERROR == q)) { // more helpful message for failure to connect to some daemon/subsys const char* id = requested_daemon->idStr(); if (NULL == id) id = requested_daemon->name(); if (NULL == id) id = "daemon"; const char* daddr = requested_daemon->addr(); if (NULL == daddr) daddr = "<unknown>"; fprintf(stderr, "Error: Failed to contact %s at %s\n", id, daddr); } // fail exit (1); } if (noSort) { // do nothing } else if (sortSpecs.empty()) { // default classad sorting result.Sort((SortFunctionType)lessThanFunc); } else { // User requested custom sorting expressions: // insert attributes related to custom sorting result.Open(); while (ClassAd* ad = result.Next()) { for (vector<SortSpec>::iterator ss(sortSpecs.begin()); ss != sortSpecs.end(); ++ss) { ss->expr->SetParentScope(ad); classad::Value v; ss->expr->Evaluate(v); stringstream vs; // This will properly render all supported value types, // including undefined and error, although current semantic // pre-filters classads where sort expressions are undef/err: vs << ((v.IsStringValue())?"\"":"") << v << ((v.IsStringValue())?"\"":""); ad->AssignExpr(ss->keyAttr.c_str(), vs.str().c_str()); // Save the full expr in case user wants to examine on output: ad->AssignExpr(ss->keyExprAttr.c_str(), ss->arg.c_str()); } } result.Open(); result.Sort((SortFunctionType)customLessThanFunc); } // output result prettyPrint (result, &totals); delete query; return 0; }