int entermsg(struct DayDream_Message *msg, int reply, char *params) { char ebuf[1024]; int hola; int msgfd; char *s; struct DayDream_Message header; char *lineedmem; int recoff; if (toupper(current_msgbase->MSGBASE_FN_FLAGS) == 'E' && ((access1 & (1L << SECB_FIDOMESSAGE)) == 0)) { DDPut(sd[emnofidomsgstr]); return 0; } if (toupper(current_msgbase->MSGBASE_FN_FLAGS) == 'N' && ((access2 & (1L << SECB_SENDNETMAIL)) == 0)) { DDPut(sd[emnonetmsgstr]); return 0; } changenodestatus("Entering a message"); if (msg) { memcpy(&header, msg, sizeof(struct DayDream_Message)); } else { s = (char *) &header; memset(&header, 0, sizeof(struct DayDream_Message)); if (params) strncpy(header.MSG_RECEIVER, params, 25); } if (current_msgbase->MSGBASE_FLAGS & (1L << 0) && current_msgbase->MSGBASE_FLAGS & (1L << 1)) { DDPut(sd[emnomsgsstr]); return 0; } DDPut(sd[emhead1str]); DDPut(current_msgbase->MSGBASE_NAME); ebuf[0] = 0; strlcat(ebuf, sd[emhead2str], sizeof ebuf); hola = 61 - strlen(current_msgbase->MSGBASE_NAME); while (hola) { strlcat(ebuf, "-", sizeof ebuf); hola--; } DDPut(ebuf); ddprintf(sd[emhead3str], highest); DDPut(sd[emhead4str]); if ((current_msgbase->MSGBASE_FLAGS & (1L << 0)) || (header.MSG_FLAGS & (1L << 0))) { DDPut(sd[emprvstr]); header.MSG_FLAGS |= (1L << 0); } else { DDPut(sd[empubstr]); } header.MSG_CREATION = time(0); DDPut(sd[emhead5str]); DDPut(ctime(&header.MSG_CREATION)); DDPut(sd[emhead6str]); if (current_msgbase->MSGBASE_FLAGS & (1L << 2)) { strlcpy(header.MSG_AUTHOR, user.user_handle, sizeof header.MSG_AUTHOR); } else { strlcpy(header.MSG_AUTHOR, user.user_realname, sizeof header.MSG_AUTHOR); } DDPut(header.MSG_AUTHOR); for (;;) { askrec: DDPut(sd[emhead7str]); if (!(Prompt(header.MSG_RECEIVER, 25, 0))) return 0; if (header.MSG_RECEIVER[0] == 0 || (!strcasecmp(header.MSG_RECEIVER, "all")) || (!strcasecmp(header.MSG_RECEIVER, "all users"))) { if (current_msgbase->MSGBASE_FLAGS & (1L << 0)) { DDPut(sd[emhead8str]); HotKey(0); header.MSG_RECEIVER[0] = 0; } else { DDPut(sd[emhead9str]); header.MSG_RECEIVER[0] = 0; break; } } else if (!strcasecmp(header.MSG_RECEIVER, "eall")) { if (current_msgbase->MSGBASE_FLAGS & (1L << 0)) { DDPut(sd[emhead8str]); HotKey(0); header.MSG_RECEIVER[0] = 0; } else if (access1 & (1L << SECB_EALLMESSAGE)) { header.MSG_RECEIVER[0] = -1; DDPut(sd[emhead10str]); break; } else { DDPut(sd[emnopoststr]); HotKey(0); header.MSG_RECEIVER[0] = 0; } } else { if (toupper(current_msgbase->MSGBASE_FN_FLAGS) == 'L') { struct userbase user; if (!strcasecmp(header.MSG_RECEIVER, "sysop")) { recoff = 0; } else { recoff = findusername(header.MSG_RECEIVER); } if (recoff == -1 || getubentbyid(recoff, &user) == -1) { DDPut(sd[emnouserstr]); HotKey(0); goto askrec; } if (!checkconfaccess(conference()->conf.CONF_NUMBER, &user)) { DDPut(sd[emnoaccessstr]); HotKey(0); } DDPut("[5;12H [5;12H"); if (current_msgbase->MSGBASE_FLAGS & (1L << 2)) { strlcpy(header.MSG_RECEIVER, user.user_handle, sizeof header.MSG_RECEIVER); } else { strlcpy(header.MSG_RECEIVER, user.user_realname, sizeof header.MSG_RECEIVER); } DDPut(header.MSG_RECEIVER); break; } else break; } } DDPut(sd[emsubjectstr]); if (!(Prompt(header.MSG_SUBJECT, 67, 0))) return 0; if (header.MSG_SUBJECT[0] == 0) { DDPut(sd[emabortedstr]); return 0; } DDPut("[11;1H [11;1H"); if (header.MSG_RECEIVER[0] == 0 || header.MSG_RECEIVER[0] == -1 || header.MSG_FLAGS & (1L << 0) || current_msgbase->MSGBASE_FLAGS & (1L << 1)) { } else { DDPut(sd[emisprivatestr]); hola = HotKey(HOT_NOYES); if (hola == 0) return 0; if (hola == 1) header.MSG_FLAGS |= MSG_FLAGS_PRIVATE; } if ((header.MSG_FLAGS & (1L << 0)) == 0 && (access1 & (1L << SECB_PUBLICMESSAGE)) == 0) { DDPut(sd[emnopubstr]); return 0; } if (toupper(current_msgbase->MSGBASE_FN_FLAGS) == 'N') { if (header.MSG_FN_DEST_NET) { snprintf(ebuf, sizeof ebuf, "%d:%d/%d.%d", header.MSG_FN_DEST_ZONE, header.MSG_FN_DEST_NET, header.MSG_FN_DEST_NODE, header.MSG_FN_DEST_POINT); } else { *ebuf = 0; } DDPut(sd[emnetaddstr]); if (!(Prompt(ebuf, 30, 0))) return 0; if (!str2addr(ebuf, &header.MSG_FN_DEST_ZONE, &header.MSG_FN_DEST_NET, &header.MSG_FN_DEST_NODE, &header.MSG_FN_DEST_POINT)) return 0; if(access2 & (1L << SECB_CRASH)) { DDPut(sd[emnetcrashstr]); if(HotKey(HOT_NOYES) == 1) { header.MSG_FLAGS |= MSG_FLAGS_CRASH; } } DDPut(sd[emnetkillstr]); if(HotKey(HOT_YESNO) == 1) { header.MSG_FLAGS |= MSG_FLAGS_KILL_SENT; } } *header.MSG_ATTACH = 0; if (current_msgbase->MSGBASE_FLAGS & (1L << 5)) { if ((header.MSG_FLAGS & (1L << 0)) && (access2 & (1L << SECB_PVTATTACH))) { *header.MSG_ATTACH = 1; } else if (((header.MSG_FLAGS & (1L << 0)) == 0) && (access2 & (1L << SECB_PUBATTACH))) { *header.MSG_ATTACH = 1; } } if (reply) { if (!askqlines()) { snprintf(ebuf, sizeof ebuf, "%s/daydream%d.msg", DDTMP, node); unlink(ebuf); } DDPut("\n\n"); } /* XXX: size should be replaced by a constant! */ lineedmem = (char *) xmalloc(80 * 500); hola = edfile(lineedmem, 80 * 500, reply, &header); if (hola == 0) { char fabuf[1024]; DDPut(sd[emaborted2str]); free(lineedmem); if (cleantemp() == -1) { DDPut(sd[tempcleanerrstr]); return 0; } snprintf(fabuf, sizeof fabuf, "%s/attachs.%d", DDTMP, node); unlink(fabuf); return 0; } DDPut(sd[emsavingstr]); getmsgptrs(); highest++; header.MSG_NUMBER = highest; if (setmsgptrs() == 0) { free(lineedmem); return 0; } if (*header.MSG_ATTACH) { char fabuf[1024]; FILE *fd; snprintf(fabuf, sizeof fabuf, "%s/attachs.%d", DDTMP, node); if ((fd = fopen(fabuf, "r"))) { char hoobab[1024]; snprintf(hoobab, sizeof hoobab, "%s/messages/base%3.3d/fa%5.5d", conference()->conf.CONF_PATH, current_msgbase->MSGBASE_NUMBER, header.MSG_NUMBER); mkdir(hoobab, 0777); setperm(hoobab, 0777); while (fgetsnolf(hoobab, 1024, fd)) { char sr[1024]; char de[1024]; snprintf(sr, sizeof sr, "%s/%s", currnode->MULTI_TEMPORARY, hoobab); snprintf(de, sizeof de, "%s/messages/base%3.3d/fa%5.5d/%s", conference()->conf.CONF_PATH, current_msgbase->MSGBASE_NUMBER, header.MSG_NUMBER, hoobab); newrename(sr, de); } fclose(fd); snprintf(hoobab, sizeof hoobab, "%s/messages/base%3.3d/msf%5.5d", conference()->conf.CONF_PATH, current_msgbase->MSGBASE_NUMBER, header.MSG_NUMBER); newrename(fabuf, hoobab); } else { *header.MSG_ATTACH = 0; } } if (toupper(current_msgbase->MSGBASE_FN_FLAGS) != 'L') { header.MSG_FN_ORIG_ZONE = current_msgbase->MSGBASE_FN_ZONE; header.MSG_FN_ORIG_NET = current_msgbase->MSGBASE_FN_NET; header.MSG_FN_ORIG_NODE = current_msgbase->MSGBASE_FN_NODE; header.MSG_FN_ORIG_POINT = current_msgbase->MSGBASE_FN_POINT; header.MSG_FLAGS |= (1L << 2); } if ((msgfd = ddmsg_open_base(conference()->conf.CONF_PATH, current_msgbase->MSGBASE_NUMBER, O_RDWR | O_CREAT, 0666)) == -1) { DDPut(sd[emwriteerrstr]); free(lineedmem); return 0; } fsetperm(msgfd, 0666); lseek(msgfd, 0, SEEK_END); safe_write(msgfd, &header, sizeof(struct DayDream_Message)); ddmsg_close_base(msgfd); if ((msgfd = ddmsg_open_msg(conference()->conf.CONF_PATH, current_msgbase->MSGBASE_NUMBER, header.MSG_NUMBER, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { DDPut(sd[emwriteerrstr]); free(lineedmem); return 0; } fsetperm(msgfd, 0666); if (toupper(current_msgbase->MSGBASE_FN_FLAGS) == 'E') { char ub[128]; int uq; strlcpy(ub, current_msgbase->MSGBASE_FN_TAG, sizeof ub); strupr(ub); snprintf(ebuf, sizeof ebuf, "AREA:%s\n", ub); safe_write(msgfd, ebuf, strlen(ebuf)); if ((uq = getfidounique())) { snprintf(ebuf, sizeof ebuf, "\001MSGID: %d:%d/%d.%d %8.8x\n", current_msgbase->MSGBASE_FN_ZONE, current_msgbase->MSGBASE_FN_NET, current_msgbase->MSGBASE_FN_NODE, current_msgbase->MSGBASE_FN_POINT, uq); safe_write(msgfd, ebuf, strlen(ebuf)); if (header.MSG_ORIGINAL) { if (getreplyid(header.MSG_ORIGINAL, ebuf, sizeof ebuf)) safe_write(msgfd, ebuf, strlen(ebuf)); } } } else if (toupper(current_msgbase->MSGBASE_FN_FLAGS) == 'N') { snprintf(ebuf, sizeof ebuf, "\001INTL %d:%d/%d %d:%d/%d\n", header.MSG_FN_DEST_ZONE, header.MSG_FN_DEST_NET, header.MSG_FN_DEST_NODE, header.MSG_FN_ORIG_ZONE, header.MSG_FN_ORIG_NET, header.MSG_FN_ORIG_NODE); safe_write(msgfd, ebuf, strlen(ebuf)); if (header.MSG_FN_DEST_POINT) { snprintf(ebuf, sizeof ebuf, "\001TOPT %d\n", header.MSG_FN_DEST_POINT); safe_write(msgfd, ebuf, strlen(ebuf)); } if (header.MSG_FN_ORIG_POINT) { snprintf(ebuf, sizeof ebuf, "\001FMPT %d\n", header.MSG_FN_ORIG_POINT); safe_write(msgfd, ebuf, strlen(ebuf)); } } s = lineedmem; while (hola) { snprintf(ebuf, sizeof ebuf, "%s\n", s); safe_write(msgfd, ebuf, strlen(ebuf)); hola--; s = &s[80]; } // place holder, user auto-sig goes here // snprintf(ebuf, sizeof ebuf, "signature here"); // safe_write(msgfd, ebuf, strlen(ebuf)); if (toupper(current_msgbase->MSGBASE_FN_FLAGS) == 'E') { snprintf(ebuf, sizeof ebuf, "\n--- DayDream BBS/UNIX (" UNAME ") %s\n * Origin: %s (%d:%d/%d)\nSEEN-BY: %d/%d\n", versionstring, current_msgbase->MSGBASE_FN_ORIGIN, current_msgbase->MSGBASE_FN_ZONE, current_msgbase->MSGBASE_FN_NET, current_msgbase->MSGBASE_FN_NODE, current_msgbase->MSGBASE_FN_NET, current_msgbase->MSGBASE_FN_NODE); safe_write(msgfd, ebuf, strlen(ebuf)); } else if (toupper(current_msgbase->MSGBASE_FN_FLAGS) != 'L') { snprintf(ebuf, sizeof ebuf, "\n--- DayDream BBS/UNIX (" UNAME ") %s\n", versionstring); safe_write(msgfd, ebuf, strlen(ebuf)); } ddmsg_close_msg(msgfd); DDPut(sd[emdonestr]); free(lineedmem); if (header.MSG_FLAGS & (1L << 0)) { user.user_pvtmessages++; clog.cl_pvtmessages++; } else { user.user_pubmessages++; clog.cl_pubmessages++; } return 1; }
static int _handle_signal_task_local(int fd, stepd_step_rec_t *job, uid_t uid) { int rc = SLURM_SUCCESS; int signal; int ltaskid; /* local task index */ safe_read(fd, &signal, sizeof(int)); safe_read(fd, <askid, sizeof(int)); debug("_handle_signal_task_local for step=%u.%u uid=%d signal=%d", job->jobid, job->stepid, (int) uid, signal); if (uid != job->uid && !_slurm_authorized_user(uid)) { debug("kill req from uid %ld for job %u.%u owned by uid %ld", (long)uid, job->jobid, job->stepid, (long)job->uid); rc = EPERM; goto done; } /* * Sanity checks */ if (ltaskid < 0 || ltaskid >= job->node_tasks) { debug("step %u.%u invalid local task id %d", job->jobid, job->stepid, ltaskid); rc = SLURM_ERROR; goto done; } if (!job->task || !job->task[ltaskid]) { debug("step %u.%u no task info for task id %d", job->jobid, job->stepid, ltaskid); rc = SLURM_ERROR; goto done; } if (job->task[ltaskid]->pid <= 1) { debug("step %u.%u invalid pid %d for task %d", job->jobid, job->stepid, job->task[ltaskid]->pid, ltaskid); rc = SLURM_ERROR; goto done; } /* * Signal the task */ slurm_mutex_lock(&suspend_mutex); if (suspended) { rc = ESLURMD_STEP_SUSPENDED; slurm_mutex_unlock(&suspend_mutex); goto done; } if (kill(job->task[ltaskid]->pid, signal) == -1) { rc = -1; verbose("Error sending signal %d to %u.%u, pid %d: %m", signal, job->jobid, job->stepid, job->task[ltaskid]->pid); } else { verbose("Sent signal %d to %u.%u, pid %d", signal, job->jobid, job->stepid, job->task[ltaskid]->pid); } slurm_mutex_unlock(&suspend_mutex); done: /* Send the return code */ safe_write(fd, &rc, sizeof(int)); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
static int _handle_checkpoint_tasks(int fd, stepd_step_rec_t *job, uid_t uid) { int rc = SLURM_SUCCESS; time_t timestamp; int len; char *image_dir = NULL; debug3("_handle_checkpoint_tasks for job %u.%u", job->jobid, job->stepid); safe_read(fd, ×tamp, sizeof(time_t)); safe_read(fd, &len, sizeof(int)); if (len) { image_dir = xmalloc (len); safe_read(fd, image_dir, len); /* '\0' terminated */ } debug3(" uid = %d", uid); if (uid != job->uid && !_slurm_authorized_user(uid)) { debug("checkpoint req from uid %ld for job %u.%u " "owned by uid %ld", (long)uid, job->jobid, job->stepid, (long)job->uid); rc = EPERM; goto done; } if (job->ckpt_timestamp && timestamp == job->ckpt_timestamp) { debug("duplicate checkpoint req for job %u.%u, " "timestamp %ld. discarded.", job->jobid, job->stepid, (long)timestamp); rc = ESLURM_ALREADY_DONE; /* EINPROGRESS? */ goto done; } /* * Sanity checks */ if (job->pgid <= (pid_t)1) { debug ("step %u.%u invalid [jmgr_pid:%d pgid:%u]", job->jobid, job->stepid, job->jmgr_pid, job->pgid); rc = ESLURMD_JOB_NOTRUNNING; goto done; } slurm_mutex_lock(&suspend_mutex); if (suspended) { rc = ESLURMD_STEP_SUSPENDED; slurm_mutex_unlock(&suspend_mutex); goto done; } /* set timestamp in case another request comes */ job->ckpt_timestamp = timestamp; /* TODO: do we need job->ckpt_dir any more, * except for checkpoint/xlch? */ /* if (! image_dir) { */ /* image_dir = xstrdup(job->ckpt_dir); */ /* } */ /* call the plugin to send the request */ if (checkpoint_signal_tasks(job, image_dir) != SLURM_SUCCESS) { rc = -1; verbose("Error sending checkpoint request to %u.%u: %s", job->jobid, job->stepid, slurm_strerror(rc)); } else { verbose("Sent checkpoint request to %u.%u", job->jobid, job->stepid); } slurm_mutex_unlock(&suspend_mutex); done: /* Send the return code */ safe_write(fd, &rc, sizeof(int)); xfree(image_dir); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
static int _handle_suspend(int fd, stepd_step_rec_t *job, uid_t uid) { static int launch_poe = -1; int rc = SLURM_SUCCESS; int errnum = 0; uint16_t job_core_spec = (uint16_t) NO_VAL; safe_read(fd, &job_core_spec, sizeof(uint16_t)); debug("_handle_suspend for step:%u.%u uid:%ld core_spec:%u", job->jobid, job->stepid, (long)uid, job_core_spec); if (!_slurm_authorized_user(uid)) { debug("job step suspend request from uid %ld for job %u.%u ", (long)uid, job->jobid, job->stepid); rc = -1; errnum = EPERM; goto done; } _wait_for_job_init(job); if (job->cont_id == 0) { debug ("step %u.%u invalid container [cont_id:%"PRIu64"]", job->jobid, job->stepid, job->cont_id); rc = -1; errnum = ESLURMD_JOB_NOTRUNNING; goto done; } acct_gather_suspend_poll(); if (launch_poe == -1) { char *launch_type = slurm_get_launch_type(); if (!xstrcmp(launch_type, "launch/poe")) launch_poe = 1; else launch_poe = 0; xfree(launch_type); } /* * Signal the container */ slurm_mutex_lock(&suspend_mutex); if (suspended) { rc = -1; errnum = ESLURMD_STEP_SUSPENDED; slurm_mutex_unlock(&suspend_mutex); goto done; } else { if (!job->batch && switch_g_job_step_pre_suspend(job)) error("switch_g_job_step_pre_suspend: %m"); /* SIGTSTP is sent first to let MPI daemons stop their tasks, * then wait 2 seconds, then send SIGSTOP to the spawned * process's container to stop everything else. * * In some cases, 1 second has proven insufficient. Longer * delays may help insure that all MPI tasks have been stopped * (that depends upon the MPI implementaiton used), but will * also permit longer time periods when more than one job can * be running on each resource (not good). */ if (launch_poe == 0) { /* IBM MPI seens to periodically hang upon receipt * of SIGTSTP. */ if (proctrack_g_signal(job->cont_id, SIGTSTP) < 0) { verbose("Error suspending %u.%u (SIGTSTP): %m", job->jobid, job->stepid); } else sleep(2); } if (proctrack_g_signal(job->cont_id, SIGSTOP) < 0) { verbose("Error suspending %u.%u (SIGSTOP): %m", job->jobid, job->stepid); } else { verbose("Suspended %u.%u", job->jobid, job->stepid); } suspended = true; } if (!job->batch && switch_g_job_step_post_suspend(job)) error("switch_g_job_step_post_suspend: %m"); if (!job->batch && core_spec_g_suspend(job->cont_id, job_core_spec)) error("core_spec_g_suspend: %m"); slurm_mutex_unlock(&suspend_mutex); done: /* Send the return code and errno */ safe_write(fd, &rc, sizeof(int)); safe_write(fd, &errnum, sizeof(int)); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
static int _handle_completion(int fd, stepd_step_rec_t *job, uid_t uid) { int rc = SLURM_SUCCESS; int errnum = 0; int first; int last; jobacctinfo_t *jobacct = NULL; int step_rc; char* buf; int len; Buf buffer; bool lock_set = false; debug("_handle_completion for job %u.%u", job->jobid, job->stepid); debug3(" uid = %d", uid); if (!_slurm_authorized_user(uid)) { debug("step completion message from uid %ld for job %u.%u ", (long)uid, job->jobid, job->stepid); rc = -1; errnum = EPERM; /* Send the return code and errno */ safe_write(fd, &rc, sizeof(int)); safe_write(fd, &errnum, sizeof(int)); return SLURM_SUCCESS; } safe_read(fd, &first, sizeof(int)); safe_read(fd, &last, sizeof(int)); safe_read(fd, &step_rc, sizeof(int)); /* * We must not use getinfo over a pipe with slurmd here * Indeed, slurmstepd does a large use of setinfo over a pipe * with slurmd and doing the reverse can result in a deadlock * scenario with slurmd : * slurmd(lockforread,write)/slurmstepd(write,lockforread) * Do pack/unpack instead to be sure of independances of * slurmd and slurmstepd */ safe_read(fd, &len, sizeof(int)); buf = xmalloc(len); safe_read(fd, buf, len); buffer = create_buf(buf, len); jobacctinfo_unpack(&jobacct, SLURM_PROTOCOL_VERSION, PROTOCOL_TYPE_SLURM, buffer, 1); free_buf(buffer); /* * Record the completed nodes */ slurm_mutex_lock(&step_complete.lock); lock_set = true; if (! step_complete.wait_children) { rc = -1; errnum = ETIMEDOUT; /* not used anyway */ goto timeout; } /* SlurmUser or root can craft a launch without a valid credential * ("srun --no-alloc ...") and no tree information can be built * without the hostlist from the credential. */ if (step_complete.rank >= 0) { #if 0 char bits_string[128]; debug2("Setting range %d (bit %d) through %d(bit %d)", first, first-(step_complete.rank+1), last, last-(step_complete.rank+1)); bit_fmt(bits_string, sizeof(bits_string), step_complete.bits); debug2(" before bits: %s", bits_string); #endif bit_nset(step_complete.bits, first - (step_complete.rank+1), last - (step_complete.rank+1)); #if 0 bit_fmt(bits_string, sizeof(bits_string), step_complete.bits); debug2(" after bits: %s", bits_string); #endif } step_complete.step_rc = MAX(step_complete.step_rc, step_rc); /************* acct stuff ********************/ jobacctinfo_aggregate(step_complete.jobacct, jobacct); timeout: jobacctinfo_destroy(jobacct); /*********************************************/ /* Send the return code and errno, we do this within the locked * region to ensure that the stepd doesn't exit before we can * perform this send. */ safe_write(fd, &rc, sizeof(int)); safe_write(fd, &errnum, sizeof(int)); slurm_cond_signal(&step_complete.cond); slurm_mutex_unlock(&step_complete.lock); return SLURM_SUCCESS; rwfail: if (lock_set) { slurm_cond_signal(&step_complete.cond); slurm_mutex_unlock(&step_complete.lock); } return SLURM_FAILURE; }
static int _handle_signal_container(int fd, slurmd_job_t *job, uid_t uid) { int rc = SLURM_SUCCESS; int errnum = 0; int sig; static int msg_sent = 0; debug("_handle_signal_container for job %u.%u", job->jobid, job->stepid); safe_read(fd, &sig, sizeof(int)); debug3(" uid = %d", uid); if (uid != job->uid && !_slurm_authorized_user(uid)) { debug("kill container req from uid %ld for job %u.%u " "owned by uid %ld", (long)uid, job->jobid, job->stepid, (long)job->uid); rc = -1; errnum = EPERM; goto done; } /* * Sanity checks */ if (job->cont_id == 0) { debug ("step %u.%u invalid container [cont_id:%"PRIu64"]", job->jobid, job->stepid, job->cont_id); rc = -1; errnum = ESLURMD_JOB_NOTRUNNING; goto done; } if ((job->nodeid == 0) && (msg_sent == 0) && (job->state < SLURMSTEPD_STEP_ENDING)) { time_t now = time(NULL); char entity[24], time_str[24]; if (job->stepid == SLURM_BATCH_SCRIPT) { snprintf(entity, sizeof(entity), "JOB %u", job->jobid); } else { snprintf(entity, sizeof(entity), "STEP %u.%u", job->jobid, job->stepid); } slurm_make_time_str(&now, time_str, sizeof(time_str)); /* Not really errors, * but we want messages displayed by default */ if (sig == SIG_TIME_LIMIT) { error("*** %s CANCELLED AT %s DUE TO TIME LIMIT ***", entity, time_str); msg_sent = 1; } else if (sig == SIG_PREEMPTED) { error("*** %s CANCELLED AT %s DUE TO PREEMPTION ***", entity, time_str); msg_sent = 1; } else if (sig == SIG_NODE_FAIL) { error("*** %s CANCELLED AT %s DUE TO NODE FAILURE ***", entity, time_str); msg_sent = 1; } else if (sig == SIG_FAILURE) { error("*** %s FAILED (non-zero exit code or other " "failure mode) ***", entity); msg_sent = 1; } else if ((sig == SIGTERM) || (sig == SIGKILL)) { error("*** %s CANCELLED AT %s ***", entity, time_str); msg_sent = 1; } } if ((sig == SIG_TIME_LIMIT) || (sig == SIG_NODE_FAIL) || (sig == SIG_PREEMPTED) || (sig == SIG_FAILURE)) goto done; if (sig == SIG_DEBUG_WAKE) { int i; for (i = 0; i < job->node_tasks; i++) pdebug_wake_process(job, job->task[i]->pid); goto done; } if (sig == SIG_ABORT) { sig = SIGKILL; job->aborted = true; } pthread_mutex_lock(&suspend_mutex); if (suspended && (sig != SIGKILL)) { rc = -1; errnum = ESLURMD_STEP_SUSPENDED; pthread_mutex_unlock(&suspend_mutex); goto done; } /* * Signal the container */ if (slurm_container_signal(job->cont_id, sig) < 0) { rc = -1; errnum = errno; verbose("Error sending signal %d to %u.%u: %m", sig, job->jobid, job->stepid); } else { verbose("Sent signal %d to %u.%u", sig, job->jobid, job->stepid); } pthread_mutex_unlock(&suspend_mutex); done: /* Send the return code and errnum */ safe_write(fd, &rc, sizeof(int)); safe_write(fd, &errnum, sizeof(int)); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
static int _handle_terminate(int fd, stepd_step_rec_t *job, uid_t uid) { int rc = SLURM_SUCCESS; int errnum = 0; stepd_step_task_info_t *task; uint32_t i; debug("_handle_terminate for step=%u.%u uid=%d", job->jobid, job->stepid, uid); step_terminate_monitor_start(job->jobid, job->stepid); if (uid != job->uid && !_slurm_authorized_user(uid)) { debug("terminate req from uid %ld for job %u.%u " "owned by uid %ld", (long)uid, job->jobid, job->stepid, (long)job->uid); rc = -1; errnum = EPERM; goto done; } /* * Sanity checks */ if (job->cont_id == 0) { debug ("step %u.%u invalid container [cont_id:%"PRIu64"]", job->jobid, job->stepid, job->cont_id); rc = -1; errnum = ESLURMD_JOB_NOTRUNNING; goto done; } /* cycle thru the tasks and mark those that have not * called abort and/or terminated as killed_by_cmd */ for (i = 0; i < job->node_tasks; i++) { if (NULL == (task = job->task[i])) { continue; } if (task->aborted || task->exited) { continue; } /* mark that this task is going to be killed by * cmd so we ignore its exit status - otherwise, * we will probably report the final exit status * as SIGKILL */ task->killed_by_cmd = true; } /* * Signal the container with SIGKILL */ slurm_mutex_lock(&suspend_mutex); if (suspended) { debug("Terminating suspended job step %u.%u", job->jobid, job->stepid); suspended = false; } if (proctrack_g_signal(job->cont_id, SIGKILL) < 0) { if (errno != ESRCH) { /* No error if process already gone */ rc = -1; errnum = errno; } verbose("Error sending SIGKILL signal to %u.%u: %m", job->jobid, job->stepid); } else { verbose("Sent SIGKILL signal to %u.%u", job->jobid, job->stepid); } slurm_mutex_unlock(&suspend_mutex); done: /* Send the return code and errnum */ safe_write(fd, &rc, sizeof(int)); safe_write(fd, &errnum, sizeof(int)); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
static int decompress_fd_xz(int fdi, int fdo) { #ifdef HAVE_LZMA uint8_t buf_in[BUFSIZ]; uint8_t buf_out[BUFSIZ]; lzma_stream strm = LZMA_STREAM_INIT; lzma_ret ret = lzma_stream_decoder(&strm, UINT64_MAX, 0); if (ret != LZMA_OK) { close(fdi); close(fdo); log_error("Failed to initialize XZ decoder: code %d", ret); return -ENOMEM; } lzma_action action = LZMA_RUN; strm.next_out = buf_out; strm.avail_out = sizeof(buf_out); for (;;) { if (strm.avail_in == 0 && action == LZMA_RUN) { strm.next_in = buf_in; strm.avail_in = safe_read(fdi, buf_in, sizeof(buf_in)); if (strm.avail_in < 0) { perror_msg("Failed to read source core file"); close(fdi); close(fdo); lzma_end(&strm); return -1; } if (strm.avail_in == 0) action = LZMA_FINISH; } ret = lzma_code(&strm, action); if (strm.avail_out == 0 || ret == LZMA_STREAM_END) { const ssize_t n = sizeof(buf_out) - strm.avail_out; if (n != safe_write(fdo, buf_out, n)) { perror_msg("Failed to write decompressed data"); close(fdi); close(fdo); lzma_end(&strm); return -1; } if (ret == LZMA_STREAM_END) { log_debug("Successfully decompressed coredump."); break; } strm.next_out = buf_out; strm.avail_out = sizeof(buf_out); } } return 0; #else /*HAVE_LZMA*/ const char *cmd[] = { "xzcat", "-d", "-", NULL }; return decompress_using_fork_execvp(cmd, fdi, fdo); #endif /*HAVE_LZMA*/ }
static int decompress_fd_lz4(int fdi, int fdo) { #ifdef HAVE_LZ4 enum { LZ4_DEC_BUF_SIZE = 64*1024u }; LZ4F_decompressionContext_t ctx = NULL; LZ4F_errorCode_t c; char *buf = NULL; char *src = NULL; int r = 0; struct stat fdist; c = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); if (LZ4F_isError(c)) { log_debug("Failed to initialized LZ4: %s", LZ4F_getErrorName(c)); r = -ENOMEM; goto cleanup; } buf = malloc(LZ4_DEC_BUF_SIZE); if (!buf) { r = -errno; goto cleanup; } if (fstat(fdi, &fdist) < 0) { r = -errno; log_debug("Failed to stat the input fd"); goto cleanup; } src = mmap(NULL, fdist.st_size, PROT_READ, MAP_PRIVATE, fdi, 0); if (!src) { r = -errno; log_debug("Failed to mmap the input fd"); goto cleanup; } off_t total_in = 0; while (fdist.st_size != total_in) { size_t used = fdist.st_size - total_in; size_t produced = LZ4_DEC_BUF_SIZE; c = LZ4F_decompress(ctx, buf, &produced, src + total_in, &used, NULL); if (LZ4F_isError(c)) { log_debug("Failed to decode LZ4 block: %s", LZ4F_getErrorName(c)); r = -EBADMSG; goto cleanup; } r = safe_write(fdo, buf, produced); if (r < 0) { log_debug("Failed to write decoded block"); goto cleanup; } total_in += used; } r = 0; cleanup: if (ctx != NULL) LZ4F_freeDecompressionContext(ctx); if (buf != NULL) free(buf); if (src != NULL) munmap(src, fdist.st_size); return r; #else /*HAVE_LZ4*/ const char *cmd[] = { "lz4", "-cd", "-", NULL}; return decompress_using_fork_execvp(cmd, fdi, fdo); #endif /*HAVE_LZ4*/ }
static int fcgi_read_request(fcgi_request *req) { fcgi_header hdr; int len, padding; unsigned char buf[FCGI_MAX_LENGTH+8]; req->keep = 0; req->in_len = 0; req->out_hdr = NULL; req->out_pos = req->out_buf; zend_hash_init(&req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 1); if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || hdr.version < FCGI_VERSION_1) { return 0; } len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; padding = hdr.paddingLength; while (hdr.type == FCGI_STDIN && len == 0) { if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || hdr.version < FCGI_VERSION_1) { return 0; } len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; padding = hdr.paddingLength; } req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0; if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) { char *val; if (safe_read(req, buf, len+padding) != len+padding) { return 0; } req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN); switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) { case FCGI_RESPONDER: val = strdup("RESPONDER"); zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL); break; case FCGI_AUTHORIZER: val = strdup("AUTHORIZER"); zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL); break; case FCGI_FILTER: val = strdup("FILTER"); zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL); break; default: return 0; } if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || hdr.version < FCGI_VERSION_1) { return 0; } len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; padding = hdr.paddingLength; while (hdr.type == FCGI_PARAMS && len > 0) { if (safe_read(req, buf, len+padding) != len+padding) { req->keep = 0; return 0; } if (!fcgi_get_params(req, buf, buf+len)) { req->keep = 0; return 0; } if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) || hdr.version < FCGI_VERSION_1) { req->keep = 0; return 0; } len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0; padding = hdr.paddingLength; } } else if (hdr.type == FCGI_GET_VALUES) { int j; unsigned char *p = buf + sizeof(fcgi_header); if (safe_read(req, buf, len+padding) != len+padding) { req->keep = 0; return 0; } if (!fcgi_get_params(req, buf, buf+len)) { req->keep = 0; return 0; } for (j = 0; j < sizeof(fcgi_mgmt_vars)/sizeof(fcgi_mgmt_vars[0]); j++) { if (zend_hash_exists(&req->env, fcgi_mgmt_vars[j].name, fcgi_mgmt_vars[j].name_len+1) == 0) { sprintf((char*)p, "%c%c%s%c", fcgi_mgmt_vars[j].name_len, 1, fcgi_mgmt_vars[j].name, fcgi_mgmt_vars[j].val); p += fcgi_mgmt_vars[j].name_len + 3; } } len = p - buf - sizeof(fcgi_header); len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len); if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) { req->keep = 0; return 0; } return 0; } else { return 0; } return 1; }
int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len) { int limit, rest; if (len <= 0) { return 0; } if (req->out_hdr && req->out_hdr->type != type) { close_packet(req); } #if 0 /* Unoptimized, but clear version */ rest = len; while (rest > 0) { limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf); if (!req->out_hdr) { if (limit < sizeof(fcgi_header)) { if (!fcgi_flush(req, 0)) { return -1; } } open_packet(req, type); } limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf); if (rest < limit) { memcpy(req->out_pos, str, rest); req->out_pos += rest; return len; } else { memcpy(req->out_pos, str, limit); req->out_pos += limit; rest -= limit; str += limit; if (!fcgi_flush(req, 0)) { return -1; } } } #else /* Optimized version */ limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf); if (!req->out_hdr) { limit -= sizeof(fcgi_header); if (limit < 0) limit = 0; } if (len < limit) { if (!req->out_hdr) { open_packet(req, type); } memcpy(req->out_pos, str, len); req->out_pos += len; } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) { if (!req->out_hdr) { open_packet(req, type); } if (limit > 0) { memcpy(req->out_pos, str, limit); req->out_pos += limit; } if (!fcgi_flush(req, 0)) { return -1; } if (len > limit) { open_packet(req, type); memcpy(req->out_pos, str + limit, len - limit); req->out_pos += len - limit; } } else { int pos = 0; int pad; close_packet(req); while ((len - pos) > 0xffff) { open_packet(req, type); fcgi_make_header(req->out_hdr, type, req->id, 0xfff8); req->out_hdr = NULL; if (!fcgi_flush(req, 0)) { return -1; } if (safe_write(req, str + pos, 0xfff8) != 0xfff8) { req->keep = 0; return -1; } pos += 0xfff8; } pad = (((len - pos) + 7) & ~7) - (len - pos); rest = pad ? 8 - pad : 0; open_packet(req, type); fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest); req->out_hdr = NULL; if (!fcgi_flush(req, 0)) { return -1; } if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) { req->keep = 0; return -1; } if (pad) { open_packet(req, type); memcpy(req->out_pos, str + len - rest, rest); req->out_pos += rest; } } #endif return len; }
int recv_sideband(const char *me, int in_stream, int out, int err) { unsigned pf = strlen(PREFIX); unsigned sf; char buf[LARGE_PACKET_MAX + 2*FIX_SIZE]; char *suffix, *term; int skip_pf = 0; memcpy(buf, PREFIX, pf); term = getenv("TERM"); if (term && strcmp(term, "dumb")) suffix = ANSI_SUFFIX; else suffix = DUMB_SUFFIX; sf = strlen(suffix); while (1) { int band, len; len = packet_read_line(in_stream, buf + pf, LARGE_PACKET_MAX); if (len == 0) break; if (len < 1) { len = sprintf(buf, "%s: protocol error: no band designator\n", me); safe_write(err, buf, len); return SIDEBAND_PROTOCOL_ERROR; } band = buf[pf] & 0xff; len--; switch (band) { case 3: buf[pf] = ' '; buf[pf+1+len] = '\n'; safe_write(err, buf, pf+1+len+1); return SIDEBAND_REMOTE_ERROR; case 2: buf[pf] = ' '; do { char *b = buf; int brk = 0; /* * If the last buffer didn't end with a line * break then we should not print a prefix * this time around. */ if (skip_pf) { b += pf+1; } else { len += pf+1; brk += pf+1; } /* Look for a line break. */ for (;;) { brk++; if (brk > len) { brk = 0; break; } if (b[brk-1] == '\n' || b[brk-1] == '\r') break; } /* * Let's insert a suffix to clear the end * of the screen line if a line break was * found. Also, if we don't skip the * prefix, then a non-empty string must be * present too. */ if (brk > (skip_pf ? 0 : (pf+1 + 1))) { char save[FIX_SIZE]; memcpy(save, b + brk, sf); b[brk + sf - 1] = b[brk - 1]; memcpy(b + brk - 1, suffix, sf); safe_write(err, b, brk + sf); memcpy(b + brk, save, sf); len -= brk; } else { int l = brk ? brk : len; safe_write(err, b, l); len -= l; } skip_pf = !brk; memmove(buf + pf+1, b + brk, len); } while (len); continue; case 1: safe_write(out, buf + pf+1, len); continue; default: len = sprintf(buf, "%s: protocol error: bad band #%d\n", me, band); safe_write(err, buf, len); return SIDEBAND_PROTOCOL_ERROR; } } return 0; }
static void crash_catcher(int signum, siginfo_t *siginfo, void *context) { ucontext_t *ucontext = (ucontext_t*)context; pid_t dbg_pid; int fd[2]; /* Make sure the effective uid is the real uid */ if(getuid() != geteuid()) { raise(signum); return; } safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1); if(pipe(fd) == -1) { safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1); raise(signum); return; } crash_info.signum = signum; crash_info.pid = getpid(); crash_info.has_siginfo = !!siginfo; if(siginfo) crash_info.siginfo = *siginfo; if(cc_user_info) cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf)); /* Fork off to start a crash handler */ switch((dbg_pid=fork())) { /* Error */ case -1: safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1); raise(signum); return; case 0: dup2(fd[0], STDIN_FILENO); close(fd[0]); close(fd[1]); execl(argv0, argv0, crash_switch, NULL); safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1); _exit(1); default: #ifdef __linux__ prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0); #endif safe_write(fd[1], &crash_info, sizeof(crash_info)); close(fd[0]); close(fd[1]); /* Wait; we'll be killed when gdb is done */ do { int status; if(waitpid(dbg_pid, &status, 0) == dbg_pid && (WIFEXITED(status) || WIFSIGNALED(status))) { /* The debug process died before it could kill us */ raise(signum); break; } } while(1); } }
int main(void) { int32_t nready; uint8_t index_to; struct timeval timeout; /* settaggio della connessione TCP con l'applicazine fissa */ to_app = setup_conn(SOCK_STREAM, AF_INET, LOCAL_LISTEN_PORT, (int8_t*) "INADDR_ANY", 0, 0, 1); /* accettazione della connessione proveniente dall'applicazione fissa */ new_app_fd = listen_accept(to_app, &app_side); /* settaggio della connessione UDP con il monitor */ udp_gate = setup_conn(SOCK_DGRAM, AF_INET, LOCAL_UDP_PORT, (int8_t*) "INADDR_ANY", 0, 0, 0); /* inizializzazione strutture */ make_list(&port_list); clear_buffer(down_packets); clear_buffer(up_packets); udp_clear_buffer(to_app_packets); srand(getpid()); /* inizializzazioni di default */ last_uploaded = ID_START; actual_zero.tv_usec = actual_zero.tv_sec = 0; us_zero.tv_usec = us_zero.tv_sec = 0; index_to = BUFF_PACK_SIZE; /* no timeout inizialmente */ m_id_ports.type = 'C'; m_id_ports.message = 0; last_notify = last_seq = 0; good_percentual = GOOD_P; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&s_readfds); FD_ZERO(&s_writefds); FD_SET(new_app_fd, &readfds); /* tanto prima aspetta un pacchetto da noi */ FD_SET(udp_gate, &readfds); maxfds = (udp_gate > new_app_fd ? udp_gate : new_app_fd); for (;;) { s_readfds = readfds; s_writefds = writefds; nready = select(maxfds + 1, &s_readfds, &s_writefds, NULL, (index_to == BUFF_PACK_SIZE ? NULL : (&timeout))); if ((nready == ERROR) && (errno != EINTR)) { fprintf(stderr, "fatal error performing select. errno %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (FD_ISSET(new_app_fd, &s_readfds)) { uint8_t oldestpack, index; /* buffering dei pacchetti provenienti dall' applicazione */ drop_expired(down_packets); safe_read(new_app_fd, DATA_BUFF_SIZE, data_app_fixed); /* evitiamo il possibile traboccamento di down_packets */ if ((index = index_free_pack(down_packets)) == BUFF_PACK_SIZE) { oldestpack = oldest_pack(down_packets); clear_pack(down_packets, oldestpack); index = oldestpack; } memcpy(&(down_packets[index].udp_data.id_packet), data_app_fixed, sizeof(uint32_t)); memcpy(&(down_packets[index].udp_data.data), &(data_app_fixed[4]), DATA_BUFF_SIZE - sizeof(uint32_t)); down_packets[index].udp_data.type_packet = STANDARD; gettimeofday(&(down_packets[index].arrived), NULL); if (s_2_i(&us_zero) == 0) us_zero = down_packets[index].arrived; down_packets[index].udp_data.the_mighty_fix = s_2_i(&(down_packets[index].arrived)) - (s_2_i(&us_zero) + (INTER_PACKET * (down_packets[index].udp_data.id_packet - ID_FIRST_SENT))); down_packets[index].flag_to_send = NEW_ENTRY_FLAG; FD_SET(udp_gate, &writefds); } if (FD_ISSET(udp_gate, &s_writefds)) { uint8_t index; struct errno_port ep; double rand_n; if ((index = first_pack_to_send(down_packets)) != BUFF_PACK_SIZE) { /* spedizione del pacchetto verso il monitor */ ep.type_errno = EXIT_FAILURE; while ((ep.type_errno != EXIT_SUCCESS) && (ep.type_errno != EAGAIN) && (port_list != NULL)) { gettimeofday(&(down_packets[index].time_last_send), NULL); down_packets[index].udp_data.time_buffered = BUFFERED_TIME(down_packets[index]); ep = send_the_pack((int32_t*) &(down_packets[index]), STANDARD, udp_gate, port_list); /* printf("utilizzato porta id: %u\n", ep.id_port); */ } #ifdef O_DEBUG if (ep.type_errno == EXIT_SUCCESS) { printf("spedito il pacchetto con id %d\n", down_packets[index].udp_data.id_packet); } #endif RANDOM_N(rand_n); if ((rand_n > (good_percentual - 0)) && (down_packets[index].n_resending > 0)) { down_packets[index].flag_to_send = NACK_FLAG; /* forza la riconsiderazione del pacchetto */ down_packets[index].n_resending--; } if ((index = first_pack_to_send(down_packets)) == BUFF_PACK_SIZE) FD_CLR(udp_gate, &writefds); } else { FD_CLR(udp_gate, &writefds); } } if (FD_ISSET(udp_gate, &s_readfds)) { udp_packet tmp; struct sockaddr_in mon_side; /* ricezione dei dal monitor */ general_recvfrom((int32_t *) &(tmp), sizeof(udp_packet), udp_gate, &mon_side); if (check_port(port_list, ntohs(mon_side.sin_port)) == FALSE) /* inserimento di una, forse, nuova porta monitor */ insert_port(&port_list, ntohs(mon_side.sin_port)); switch (tmp.type_packet) { case STANDARD: { #ifdef O_DEBUG printf("id pacchetto ricevuto: %d\n", tmp.id_packet); #endif up_packets[BUFF_PACK_SIZE - 1].udp_data = tmp; /* speranza che sia vuoto per la legge di Gigio */ gettimeofday(&(up_packets[BUFF_PACK_SIZE - 1].delivered), NULL); if ((actual_zero.tv_usec == 0) && (actual_zero.tv_sec == 0)) /* nuovo zero dell'opposto balancer */ i_2_s(s_2_i(&(up_packets[BUFF_PACK_SIZE - 1].delivered)) - (INTER_PACKET * tmp.id_packet), &actual_zero); mighty_f_revenge(up_packets, BUFF_PACK_SIZE - 1, &actual_zero, 0); if (tmp.id_packet == (last_uploaded + 1)) { /* e' il successivo */ clear_pack(up_packets, BUFF_PACK_SIZE - 1); to_app_packets[index_udpfree_pack(to_app_packets)] = tmp; last_uploaded = tmp.id_packet; /* aggiorno ultimo upload */ check_inline_pack(up_packets, to_app_packets, &last_uploaded, tmp.id_packet); FD_SET(new_app_fd, &writefds); } else { if (tmp.id_packet > last_uploaded) { sort_buffer(up_packets); } else /* in ritado abissale, drop */ clear_pack(up_packets, BUFF_PACK_SIZE - 1); } break; } default : { /* pacchetto di notifica */ port_monitoring *ptmp = NULL; stat_notify *trick = (stat_notify*) &tmp; #ifdef O_DEBUG_N printf("pacchetto id: %d\n", tmp.id_packet); printf("pacchetto di notifica con porta id: %d\n", trick->id_port); #endif if ((last_notify < trick->id_notify) || (last_seq == trick->id_sequence)) { /* non e' in ritardo abissale */ if ((trick->id_sequence < last_seq) || (trick->id_sequence > last_seq)) { /* nuova sequenza di notifiche */ m_id_ports.message = trick->type_packet - NOTIFY_F; last_seq = trick->id_sequence; } last_notify = trick->id_notify; m_id_ports.message--; /* nuova notifica della stessa sequenza, decrementa contatore */ m_id_ports.ports[m_id_ports.message] = trick->id_port + 1000; ptmp = find_port(port_list, trick->id_port + 1000); /* abbiamo spedito ID lato mobile, vogliamo quello fixed */ if (ptmp == NULL) { /* porta di cui il fixed non era a conoscenza */ if (m_id_ports.message == 0) { /* non ci sono piu' pacchetti di notifica, costruzione della lista delle porte aperte * e reset-default per la prossima volta */ m_id_ports.message = trick->type_packet - NOTIFY_F; /* lunghezza lista porte del mobile */ build_act_ports(&port_list, &m_id_ports); m_id_ports.message = 0; /* reset per la prossima notifica */ break; } insert_port(&port_list, trick->id_port + 1000); break; /* esce forzatamente dallo switch */ } ptmp->not_to_fixed = *trick; /* aggiorna la notifica */ ptmp->last_tot_packets = ptmp->tot_packets - ptmp->medium_tot_packets; good_percentual = partial_pp_lost(port_list); ptmp->ack_packets += ptmp->not_to_fixed.n_received; ptmp->nack_packets = ptmp->tot_packets - ptmp->ack_packets; ptmp->medium_tot_packets = ptmp->tot_packets; mighty_f_ports(&port_list); /* calcolo performance delle porte */ if (m_id_ports.message == 0) { /* non ci sono piu' pacchetti di notifica, costruzione della lista delle porte aperte * e reset-default per la prossima volta */ m_id_ports.message = trick->type_packet - NOTIFY_F; /* lunghezza lista porte del mobile */ build_act_ports(&port_list, &m_id_ports); m_id_ports.message = 0; /* reset per la prossima notifica */ } } } } } if (FD_ISSET(new_app_fd, &s_writefds)) { memcpy(data_app_fixed, &(to_app_packets[0].id_packet), sizeof(uint32_t)); memcpy(&(data_app_fixed[4]), &(to_app_packets[0].data), DATA_BUFF_SIZE - sizeof(uint32_t)); safe_write(new_app_fd, DATA_BUFF_SIZE, data_app_fixed); udp_shift_pack(to_app_packets, 0); /* clear e shift */ if (to_app_packets[0].type_packet == FALSE) /* non ce ne sono piu' */ FD_CLR(new_app_fd, &writefds); } if (nready == 0) { /* timeout espirato, nessun fd pronto */ if (check_inline_pack(up_packets, to_app_packets, &last_uploaded, up_packets[0].udp_data.id_packet - 1)) FD_SET(new_app_fd, &writefds); } index_to = BUFF_PACK_SIZE; timeout.tv_sec = timeout.tv_usec = 0; index_to = manage_timeout(up_packets, &timeout); } return 0; }
static int _handle_suspend(int fd, slurmd_job_t *job, uid_t uid) { int rc = SLURM_SUCCESS; int errnum = 0; debug("_handle_suspend for job %u.%u", job->jobid, job->stepid); debug3(" uid = %d", uid); if (!_slurm_authorized_user(uid)) { debug("job step suspend request from uid %ld for job %u.%u ", (long)uid, job->jobid, job->stepid); rc = -1; errnum = EPERM; goto done; } if (job->cont_id == 0) { debug ("step %u.%u invalid container [cont_id:%"PRIu64"]", job->jobid, job->stepid, job->cont_id); rc = -1; errnum = ESLURMD_JOB_NOTRUNNING; goto done; } jobacct_gather_g_suspend_poll(); /* * Signal the container */ pthread_mutex_lock(&suspend_mutex); if (suspended) { rc = -1; errnum = ESLURMD_STEP_SUSPENDED; pthread_mutex_unlock(&suspend_mutex); goto done; } else { /* SIGTSTP is sent first to let MPI daemons stop their tasks, * then wait 2 seconds, then send SIGSTOP to the spawned * process's container to stop everything else. * * In some cases, 1 second has proven insufficient. Longer * delays may help insure that all MPI tasks have been stopped * (that depends upon the MPI implementaiton used), but will * also permit longer time periods when more than one job can * be running on each resource (not good). */ if (slurm_container_signal(job->cont_id, SIGTSTP) < 0) { verbose("Error suspending %u.%u (SIGTSTP): %m", job->jobid, job->stepid); } else sleep(2); if (slurm_container_signal(job->cont_id, SIGSTOP) < 0) { verbose("Error suspending %u.%u (SIGSTOP): %m", job->jobid, job->stepid); } else { verbose("Suspended %u.%u", job->jobid, job->stepid); } suspended = true; } pthread_mutex_unlock(&suspend_mutex); done: /* Send the return code and errno */ safe_write(fd, &rc, sizeof(int)); safe_write(fd, &errnum, sizeof(int)); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
/* * Process TaskProlog output * "export NAME=value" adds environment variables * "unset NAME" clears an environment variable * "print <whatever>" writes that to the job's stdout */ static void _proc_stdout(char *buf, stepd_step_rec_t *job) { bool end_buf = false; int len; char *buf_ptr, *name_ptr, *val_ptr; char *end_line, *equal_ptr; char ***env = &job->env; buf_ptr = buf; while (buf_ptr[0]) { end_line = strchr(buf_ptr, '\n'); if (!end_line) { end_line = buf_ptr + strlen(buf_ptr); end_buf = true; } if (!strncmp(buf_ptr, "print ", 6)) { buf_ptr += 6; while (isspace(buf_ptr[0])) buf_ptr++; len = end_line - buf_ptr + 1; safe_write(1, buf_ptr, len); } else if (!strncmp(buf_ptr, "export ",7)) { name_ptr = buf_ptr + 7; while (isspace(name_ptr[0])) name_ptr++; equal_ptr = strchr(name_ptr, '='); if (!equal_ptr || (equal_ptr > end_line)) goto rwfail; val_ptr = equal_ptr + 1; while (isspace(equal_ptr[-1])) equal_ptr--; equal_ptr[0] = '\0'; end_line[0] = '\0'; if (!strcmp(name_ptr, "SLURM_PROLOG_CPU_MASK")) { job->cpu_bind_type = CPU_BIND_MASK; xfree(job->cpu_bind); job->cpu_bind = xstrdup(val_ptr); if (task_g_pre_launch(job)) { error("Failed SLURM_PROLOG_CPU_MASK " "setup"); exit(1); } } debug("export name:%s:val:%s:", name_ptr, val_ptr); if (setenvf(env, name_ptr, "%s", val_ptr)) { error("Unable to set %s environment variable", buf_ptr); } equal_ptr[0] = '='; if (end_buf) end_line[0] = '\0'; else end_line[0] = '\n'; } else if (!strncmp(buf_ptr, "unset ", 6)) { name_ptr = buf_ptr + 6; while (isspace(name_ptr[0])) name_ptr++; if ((name_ptr[0] == '\n') || (name_ptr[0] == '\0')) goto rwfail; while (isspace(end_line[-1])) end_line--; end_line[0] = '\0'; debug(" unset name:%s:", name_ptr); unsetenvp(*env, name_ptr); if (end_buf) end_line[0] = '\0'; else end_line[0] = '\n'; } rwfail: /* process rest of script output */ if (end_buf) break; buf_ptr = end_line + 1; } return; }
static int _handle_signal_process_group(int fd, slurmd_job_t *job, uid_t uid) { int rc = SLURM_SUCCESS; int signal; debug3("_handle_signal_process_group for job %u.%u", job->jobid, job->stepid); safe_read(fd, &signal, sizeof(int)); debug3(" uid = %d", uid); if (uid != job->uid && !_slurm_authorized_user(uid)) { debug("kill req from uid %ld for job %u.%u owned by uid %ld", (long)uid, job->jobid, job->stepid, (long)job->uid); rc = EPERM; goto done; } /* * Sanity checks */ if (job->pgid <= (pid_t)1) { debug ("step %u.%u invalid [jmgr_pid:%d pgid:%u]", job->jobid, job->stepid, job->jmgr_pid, job->pgid); rc = ESLURMD_JOB_NOTRUNNING; goto done; } /* * Signal the process group */ pthread_mutex_lock(&suspend_mutex); if (suspended && (signal != SIGKILL)) { rc = ESLURMD_STEP_SUSPENDED; pthread_mutex_unlock(&suspend_mutex); goto done; } /* * Print a message in the step output before killing when * SIGTERM or SIGKILL are sent */ if ((signal == SIGTERM) || (signal == SIGKILL)) { time_t now = time(NULL); char entity[24], time_str[24]; if (job->stepid == SLURM_BATCH_SCRIPT) { snprintf(entity, sizeof(entity), "JOB %u", job->jobid); } else { snprintf(entity, sizeof(entity), "STEP %u.%u", job->jobid, job->stepid); } slurm_make_time_str(&now, time_str, sizeof(time_str)); error("*** %s KILLED AT %s WITH SIGNAL %u ***", entity, time_str, signal); } if (killpg(job->pgid, signal) == -1) { rc = -1; verbose("Error sending signal %d to %u.%u, pgid %d: %m", signal, job->jobid, job->stepid, job->pgid); } else { verbose("Sent signal %d to %u.%u, pgid %d", signal, job->jobid, job->stepid, job->pgid); } pthread_mutex_unlock(&suspend_mutex); done: /* Send the return code */ safe_write(fd, &rc, sizeof(int)); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
int chat_main(int argc UNUSED_PARAM, char **argv) { int record_fd = -1; bool echo = 0; // collection of device replies which cause unconditional termination llist_t *aborts = NULL; // inactivity period int timeout = DEFAULT_CHAT_TIMEOUT; // maximum length of abort string #if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN size_t max_abort_len = 0; #else #define max_abort_len MAX_ABORT_LEN #endif #if ENABLE_FEATURE_CHAT_TTY_HIFI struct termios tio0, tio; #endif // directive names enum { DIR_HANGUP = 0, DIR_ABORT, #if ENABLE_FEATURE_CHAT_CLR_ABORT DIR_CLR_ABORT, #endif DIR_TIMEOUT, DIR_ECHO, DIR_SAY, DIR_RECORD, }; // make x* functions fail with correct exitcode xfunc_error_retval = ERR_IO; // trap vanilla signals to prevent process from being killed suddenly bb_signals(0 + (1 << SIGHUP) + (1 << SIGINT) + (1 << SIGTERM) + (1 << SIGPIPE) , signal_handler); #if ENABLE_FEATURE_CHAT_TTY_HIFI //TODO: use set_termios_to_raw() tcgetattr(STDIN_FILENO, &tio); tio0 = tio; cfmakeraw(&tio); tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio); #endif #if ENABLE_FEATURE_CHAT_SWALLOW_OPTS getopt32(argv, "vVsSE"); argv += optind; #else argv++; // goto first arg #endif // handle chat expect-send pairs while (*argv) { // directive given? process it int key = index_in_strings( "HANGUP\0" "ABORT\0" #if ENABLE_FEATURE_CHAT_CLR_ABORT "CLR_ABORT\0" #endif "TIMEOUT\0" "ECHO\0" "SAY\0" "RECORD\0" , *argv ); if (key >= 0) { bool onoff; // cache directive value char *arg = *++argv; if (!arg) { #if ENABLE_FEATURE_CHAT_TTY_HIFI tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); #endif bb_show_usage(); } // OFF -> 0, anything else -> 1 onoff = (0 != strcmp("OFF", arg)); // process directive if (DIR_HANGUP == key) { // turn SIGHUP on/off signal(SIGHUP, onoff ? signal_handler : SIG_IGN); } else if (DIR_ABORT == key) { // append the string to abort conditions #if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN size_t len = strlen(arg); if (len > max_abort_len) max_abort_len = len; #endif llist_add_to_end(&aborts, arg); #if ENABLE_FEATURE_CHAT_CLR_ABORT } else if (DIR_CLR_ABORT == key) { llist_t *l; // remove the string from abort conditions // N.B. gotta refresh maximum length too... # if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN max_abort_len = 0; # endif for (l = aborts; l; l = l->link) { # if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN size_t len = strlen(l->data); # endif if (strcmp(arg, l->data) == 0) { llist_unlink(&aborts, l); continue; } # if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN if (len > max_abort_len) max_abort_len = len; # endif } #endif } else if (DIR_TIMEOUT == key) { // set new timeout // -1 means OFF timeout = atoi(arg) * 1000; // 0 means default // >0 means value in msecs if (!timeout) timeout = DEFAULT_CHAT_TIMEOUT; } else if (DIR_ECHO == key) { // turn echo on/off // N.B. echo means dumping device input/output to stderr echo = onoff; } else if (DIR_RECORD == key) { // turn record on/off // N.B. record means dumping device input to a file // close previous record_fd if (record_fd > 0) close(record_fd); // N.B. do we have to die here on open error? record_fd = (onoff) ? xopen(arg, O_WRONLY|O_CREAT|O_TRUNC) : -1; } else if (DIR_SAY == key) { // just print argument verbatim // TODO: should we use full_write() to avoid unistd/stdio conflict? bb_error_msg("%s", arg); } // next, please! argv++; // ordinary expect-send pair! } else { //----------------------- // do expect //----------------------- int expect_len; size_t buf_len = 0; size_t max_len = max_abort_len; struct pollfd pfd; #if ENABLE_FEATURE_CHAT_NOFAIL int nofail = 0; #endif char *expect = *argv++; // sanity check: shall we really expect something? if (!expect) goto expect_done; #if ENABLE_FEATURE_CHAT_NOFAIL // if expect starts with - if ('-' == *expect) { // swallow - expect++; // and enter nofail mode nofail++; } #endif #ifdef ___TEST___BUF___ // test behaviour with a small buffer # undef COMMON_BUFSIZE # define COMMON_BUFSIZE 6 #endif // expand escape sequences in expect expect_len = unescape(expect, &expect_len /*dummy*/); if (expect_len > max_len) max_len = expect_len; // sanity check: // we should expect more than nothing but not more than input buffer // TODO: later we'll get rid of fixed-size buffer if (!expect_len) goto expect_done; if (max_len >= COMMON_BUFSIZE) { exitcode = ERR_MEM; goto expect_done; } // get reply pfd.fd = STDIN_FILENO; pfd.events = POLLIN; while (!exitcode && poll(&pfd, 1, timeout) > 0 && (pfd.revents & POLLIN) ) { llist_t *l; ssize_t delta; #define buf bb_common_bufsiz1 setup_common_bufsiz(); // read next char from device if (safe_read(STDIN_FILENO, buf+buf_len, 1) > 0) { // dump device input if RECORD fname if (record_fd > 0) { full_write(record_fd, buf+buf_len, 1); } // dump device input if ECHO ON if (echo) { // if (buf[buf_len] < ' ') { // full_write(STDERR_FILENO, "^", 1); // buf[buf_len] += '@'; // } full_write(STDERR_FILENO, buf+buf_len, 1); } buf_len++; // move input frame if we've reached higher bound if (buf_len > COMMON_BUFSIZE) { memmove(buf, buf+buf_len-max_len, max_len); buf_len = max_len; } } // N.B. rule of thumb: values being looked for can // be found only at the end of input buffer // this allows to get rid of strstr() and memmem() // TODO: make expect and abort strings processed uniformly // abort condition is met? -> bail out for (l = aborts, exitcode = ERR_ABORT; l; l = l->link, ++exitcode) { size_t len = strlen(l->data); delta = buf_len-len; if (delta >= 0 && !memcmp(buf+delta, l->data, len)) goto expect_done; } exitcode = ERR_OK; // expected reply received? -> goto next command delta = buf_len - expect_len; if (delta >= 0 && !memcmp(buf+delta, expect, expect_len)) goto expect_done; #undef buf } /* while (have data) */ // device timed out or unexpected reply received exitcode = ERR_TIMEOUT; expect_done: #if ENABLE_FEATURE_CHAT_NOFAIL // on success and when in nofail mode // we should skip following subsend-subexpect pairs if (nofail) { if (!exitcode) { // find last send before non-dashed expect while (*argv && argv[1] && '-' == argv[1][0]) argv += 2; // skip the pair // N.B. do we really need this?! if (!*argv++ || !*argv++) break; } // nofail mode also clears all but IO errors (or signals) if (ERR_IO != exitcode) exitcode = ERR_OK; } #endif // bail out unless we expected successfully if (exitcode) break; //----------------------- // do send //----------------------- if (*argv) { #if ENABLE_FEATURE_CHAT_IMPLICIT_CR int nocr = 0; // inhibit terminating command with \r #endif char *loaded = NULL; // loaded command size_t len; char *buf = *argv++; // if command starts with @ // load "real" command from file named after @ if ('@' == *buf) { // skip the @ and any following white-space trim(++buf); buf = loaded = xmalloc_xopen_read_close(buf, NULL); } // expand escape sequences in command len = unescape(buf, &nocr); // send command alarm(timeout); pfd.fd = STDOUT_FILENO; pfd.events = POLLOUT; while (len && !exitcode && poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLOUT) ) { #if ENABLE_FEATURE_CHAT_SEND_ESCAPES // "\\d" means 1 sec delay, "\\p" means 0.01 sec delay // "\\K" means send BREAK char c = *buf; if ('\\' == c) { c = *++buf; if ('d' == c) { sleep(1); len--; continue; } if ('p' == c) { usleep(10000); len--; continue; } if ('K' == c) { tcsendbreak(STDOUT_FILENO, 0); len--; continue; } buf--; } if (safe_write(STDOUT_FILENO, buf, 1) != 1) break; len--; buf++; #else len -= full_write(STDOUT_FILENO, buf, len); #endif } /* while (can write) */ alarm(0); // report I/O error if there still exists at least one non-sent char if (len) exitcode = ERR_IO; // free loaded command (if any) if (loaded) free(loaded); #if ENABLE_FEATURE_CHAT_IMPLICIT_CR // or terminate command with \r (if not inhibited) else if (!nocr) xwrite(STDOUT_FILENO, "\r", 1); #endif // bail out unless we sent command successfully if (exitcode) break; } /* if (*argv) */ } } /* while (*argv) */ #if ENABLE_FEATURE_CHAT_TTY_HIFI tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); #endif return exitcode; }
static int safe_puts(char * s) { return safe_write(s, strlen(s)); }
int writePcmData (PcmDevice *pcm, const unsigned char *buffer, int count) { return safe_write(pcm->socket, buffer, count) != -1; }
static int _handle_attach(int fd, stepd_step_rec_t *job, uid_t uid) { srun_info_t *srun; int rc = SLURM_SUCCESS; debug("_handle_attach for job %u.%u", job->jobid, job->stepid); srun = xmalloc(sizeof(srun_info_t)); srun->key = (srun_key_t *)xmalloc(SLURM_IO_KEY_SIZE); debug("sizeof(srun_info_t) = %d, sizeof(slurm_addr_t) = %d", (int) sizeof(srun_info_t), (int) sizeof(slurm_addr_t)); safe_read(fd, &srun->ioaddr, sizeof(slurm_addr_t)); safe_read(fd, &srun->resp_addr, sizeof(slurm_addr_t)); safe_read(fd, srun->key, SLURM_IO_KEY_SIZE); safe_read(fd, &srun->protocol_version, sizeof(int)); if (!srun->protocol_version) srun->protocol_version = (uint16_t)NO_VAL; /* * Check if jobstep is actually running. */ if (job->state != SLURMSTEPD_STEP_RUNNING) { rc = ESLURMD_JOB_NOTRUNNING; goto done; } /* * At the moment, it only makes sense for the slurmd to make this * call, so only _slurm_authorized_user is allowed. */ if (!_slurm_authorized_user(uid)) { error("uid %ld attempt to attach to job %u.%u owned by %ld", (long) uid, job->jobid, job->stepid, (long)job->uid); rc = EPERM; goto done; } list_prepend(job->sruns, (void *) srun); rc = io_client_connect(srun, job); debug(" back from io_client_connect, rc = %d", rc); done: /* Send the return code */ safe_write(fd, &rc, sizeof(int)); debug(" in _handle_attach rc = %d", rc); if (rc == SLURM_SUCCESS) { /* Send response info */ uint32_t *pids, *gtids; int len, i; debug(" in _handle_attach sending response info"); len = job->node_tasks * sizeof(uint32_t); pids = xmalloc(len); gtids = xmalloc(len); if (job->task != NULL) { for (i = 0; i < job->node_tasks; i++) { if (job->task[i] == NULL) continue; pids[i] = (uint32_t)job->task[i]->pid; gtids[i] = job->task[i]->gtid; } } safe_write(fd, &job->node_tasks, sizeof(uint32_t)); safe_write(fd, pids, len); safe_write(fd, gtids, len); xfree(pids); xfree(gtids); for (i = 0; i < job->node_tasks; i++) { if (job->task[i] && job->task[i]->argv) { len = strlen(job->task[i]->argv[0]) + 1; safe_write(fd, &len, sizeof(int)); safe_write(fd, job->task[i]->argv[0], len); } else { len = 0; safe_write(fd, &len, sizeof(int)); } } } return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
void exit_write(char *str) { safe_write(STDOUT, str); exit(EXIT_FAILURE); }
static int _handle_resume(int fd, stepd_step_rec_t *job, uid_t uid) { int rc = SLURM_SUCCESS; int errnum = 0; uint16_t job_core_spec = (uint16_t) NO_VAL; safe_read(fd, &job_core_spec, sizeof(uint16_t)); debug("_handle_resume for step:%u.%u uid:%ld core_spec:%u", job->jobid, job->stepid, (long)uid, job_core_spec); if (!_slurm_authorized_user(uid)) { debug("job step resume request from uid %ld for job %u.%u ", (long)uid, job->jobid, job->stepid); rc = -1; errnum = EPERM; goto done; } if (job->cont_id == 0) { debug ("step %u.%u invalid container [cont_id:%"PRIu64"]", job->jobid, job->stepid, job->cont_id); rc = -1; errnum = ESLURMD_JOB_NOTRUNNING; goto done; } acct_gather_resume_poll(); /* * Signal the container */ slurm_mutex_lock(&suspend_mutex); if (!suspended) { rc = -1; errnum = ESLURMD_STEP_NOTSUSPENDED; slurm_mutex_unlock(&suspend_mutex); goto done; } else { if (!job->batch && switch_g_job_step_pre_resume(job)) error("switch_g_job_step_pre_resume: %m"); if (!job->batch && core_spec_g_resume(job->cont_id, job_core_spec)) error("core_spec_g_resume: %m"); if (proctrack_g_signal(job->cont_id, SIGCONT) < 0) { verbose("Error resuming %u.%u: %m", job->jobid, job->stepid); } else { verbose("Resumed %u.%u", job->jobid, job->stepid); } suspended = false; } if (!job->batch && switch_g_job_step_post_resume(job)) error("switch_g_job_step_post_resume: %m"); /* set the cpu frequencies if cpu_freq option used */ if (job->cpu_freq_min != NO_VAL || job->cpu_freq_max != NO_VAL || job->cpu_freq_gov != NO_VAL) { cpu_freq_set(job); } slurm_mutex_unlock(&suspend_mutex); done: /* Send the return code and errno */ safe_write(fd, &rc, sizeof(int)); safe_write(fd, &errnum, sizeof(int)); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
static int receive(/*int read_fd, */int file_fd) { unsigned char blockBuf[1024]; unsigned blockLength = 0; unsigned errors = 0; unsigned wantBlockNo = 1; unsigned length = 0; int do_crc = 1; char reply_char; unsigned timeout = TIMEOUT_LONG; /* Flush pending input */ tcflush(read_fd, TCIFLUSH); /* Ask for CRC; if we get errors, we will go with checksum */ reply_char = 'C'; full_write(write_fd, &reply_char, 1); for (;;) { int blockBegin; int blockNo, blockNoOnesCompl; int cksum_or_crc; unsigned expected; int i, j; blockBegin = read_byte(timeout); if (blockBegin < 0) goto timeout; /* If last block, remove padding */ if (blockBegin == EOT) { /* Data blocks can be padded with ^Z characters */ /* This code tries to detect and remove them */ if (blockLength >= 3 && blockBuf[blockLength - 1] == PAD && blockBuf[blockLength - 2] == PAD && blockBuf[blockLength - 3] == PAD ) { while (blockLength && blockBuf[blockLength - 1] == PAD ) { blockLength--; } } } /* Write previously received block */ errno = 0; if (full_write(file_fd, blockBuf, blockLength) != blockLength) { bb_perror_msg(bb_msg_write_error); goto fatal; } timeout = TIMEOUT; reply_char = NAK; switch (blockBegin) { case SOH: case STX: break; case EOT: reply_char = ACK; full_write(write_fd, &reply_char, 1); return length; default: goto error; } /* Block no */ blockNo = read_byte(TIMEOUT); if (blockNo < 0) goto timeout; /* Block no, in one's complement form */ blockNoOnesCompl = read_byte(TIMEOUT); if (blockNoOnesCompl < 0) goto timeout; if (blockNo != (255 - blockNoOnesCompl)) { bb_error_msg("bad block ones compl"); goto error; } blockLength = (blockBegin == SOH) ? 128 : 1024; for (i = 0; i < blockLength; i++) { int cc = read_byte(TIMEOUT); if (cc < 0) goto timeout; blockBuf[i] = cc; } cksum_or_crc = read_byte(TIMEOUT); if (cksum_or_crc < 0) goto timeout; if (do_crc) { cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT); if (cksum_or_crc < 0) goto timeout; } if (blockNo == ((wantBlockNo - 1) & 0xff)) { /* a repeat of the last block is ok, just ignore it. */ /* this also ignores the initial block 0 which is */ /* meta data. */ blockLength = 0; goto next; } if (blockNo != (wantBlockNo & 0xff)) { bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo); goto error; } expected = 0; if (do_crc) { for (i = 0; i < blockLength; i++) { expected = expected ^ blockBuf[i] << 8; for (j = 0; j < 8; j++) { if (expected & 0x8000) expected = (expected << 1) ^ 0x1021; else expected = (expected << 1); } } expected &= 0xffff; } else { for (i = 0; i < blockLength; i++) expected += blockBuf[i]; expected &= 0xff; } if (cksum_or_crc != expected) { bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x" : "checksum error, expected 0x%02x, got 0x%02x", expected, cksum_or_crc); goto error; } wantBlockNo++; length += blockLength; next: errors = 0; reply_char = ACK; full_write(write_fd, &reply_char, 1); continue; error: timeout: blockLength = 0; errors++; if (errors == MAXERRORS) { /* Abort */ /* If were asking for crc, try again w/o crc */ if (reply_char == 'C') { reply_char = NAK; errors = 0; do_crc = 0; goto timeout; } bb_error_msg("too many errors; giving up"); fatal: /* 5 CAN followed by 5 BS. Don't try too hard... */ safe_write(write_fd, "\030\030\030\030\030\010\010\010\010\010", 10); return -1; } /* Flush pending input */ tcflush(read_fd, TCIFLUSH); full_write(write_fd, &reply_char, 1); } /* for (;;) */ }
static void * _handle_accept(void *arg) { /*struct request_params *param = (struct request_params *)arg;*/ int fd = ((struct request_params *)arg)->fd; stepd_step_rec_t *job = ((struct request_params *)arg)->job; int req; int len; Buf buffer = NULL; void *auth_cred; int rc; uid_t uid; gid_t gid; char *auth_info; debug3("Entering _handle_accept (new thread)"); xfree(arg); safe_read(fd, &req, sizeof(int)); if (req != REQUEST_CONNECT) { error("First message must be REQUEST_CONNECT"); goto fail; } safe_read(fd, &len, sizeof(int)); buffer = init_buf(len); safe_read(fd, get_buf_data(buffer), len); /* Unpack and verify the auth credential */ auth_cred = g_slurm_auth_unpack(buffer); if (auth_cred == NULL) { error("Unpacking authentication credential: %s", g_slurm_auth_errstr(g_slurm_auth_errno(NULL))); free_buf(buffer); goto fail; } auth_info = slurm_get_auth_info(); rc = g_slurm_auth_verify(auth_cred, NULL, 2, auth_info); if (rc != SLURM_SUCCESS) { error("Verifying authentication credential: %s", g_slurm_auth_errstr(g_slurm_auth_errno(auth_cred))); xfree(auth_info); (void) g_slurm_auth_destroy(auth_cred); FREE_NULL_BUFFER(buffer); goto fail; } /* Get the uid & gid from the credential, then destroy it. */ uid = g_slurm_auth_get_uid(auth_cred, auth_info); gid = g_slurm_auth_get_gid(auth_cred, auth_info); xfree(auth_info); debug3(" Identity: uid=%d, gid=%d", uid, gid); g_slurm_auth_destroy(auth_cred); FREE_NULL_BUFFER(buffer); rc = SLURM_PROTOCOL_VERSION; safe_write(fd, &rc, sizeof(int)); while (1) { rc = _handle_request(fd, job, uid, gid); if (rc != SLURM_SUCCESS) break; } if (close(fd) == -1) error("Closing accepted fd: %m"); slurm_mutex_lock(&message_lock); message_connections--; slurm_cond_signal(&message_cond); slurm_mutex_unlock(&message_lock); debug3("Leaving _handle_accept"); return NULL; fail: rc = SLURM_FAILURE; safe_write(fd, &rc, sizeof(int)); rwfail: if (close(fd) == -1) error("Closing accepted fd after error: %m"); debug("Leaving _handle_accept on an error"); FREE_NULL_BUFFER(buffer); return NULL; }
int logger(struct ProxyContext_ * const context, const int crit, const char * const format, ...) { static char previous_line[MAX_LOG_LINE]; static time_t last_log_ts = (time_t) 0; static unsigned int burst_counter = 0U; char line[MAX_LOG_LINE]; va_list va; const char *urgency; time_t now = time(NULL); size_t len; int log_fd; #ifndef DEBUG if (crit == LOG_DEBUG) { return 0; } #endif switch (crit) { case LOG_INFO: urgency = "[INFO] "; break; case LOG_WARNING: urgency = "[WARNING] "; break; case LOG_ERR: urgency = "[ERROR] "; break; case LOG_NOTICE: urgency = "[NOTICE] "; break; case LOG_DEBUG: urgency = "[DEBUG] "; break; default: urgency = ""; } va_start(va, format); len = (size_t) evutil_vsnprintf(line, sizeof line, format, va); va_end(va); if (len >= sizeof line) { assert(sizeof line > (size_t) 0U); len = sizeof line - (size_t) 1U; } line[len++] = 0; #ifndef _WIN32 if (context != NULL && context->log_fd == -1 && context->daemonize) { syslog(crit, "%s", line); return 0; } #endif if (memcmp(previous_line, line, len) == 0) { burst_counter++; if (burst_counter > LOGGER_ALLOWED_BURST_FOR_IDENTICAL_LOG_ENTRIES && now - last_log_ts < LOGGER_DELAY_BETWEEN_IDENTICAL_LOG_ENTRIES) { return 1; } } else { burst_counter = 0U; } last_log_ts = now; assert(sizeof previous_line >= sizeof line); memcpy(previous_line, line, len); if (context == NULL || context->log_fd == -1) { log_fd = STDERR_FILENO; } else { log_fd = context->log_fd; } #ifndef _WIN32 safe_write(log_fd, urgency, strlen(urgency), LOG_WRITE_TIMEOUT); safe_write(log_fd, line, strlen(line), LOG_WRITE_TIMEOUT); safe_write(log_fd, "\n", (size_t) 1U, LOG_WRITE_TIMEOUT); #else (void) log_fd; printf("%s%s\n", urgency, line); fflush(stdout); #endif return 0; }
static int _handle_signal_container(int fd, stepd_step_rec_t *job, uid_t uid) { int rc = SLURM_SUCCESS; int errnum = 0; int sig; static int msg_sent = 0; char *ptr = NULL; int target_node_id = 0; stepd_step_task_info_t *task; uint32_t i; uint32_t flag; uint32_t signal; safe_read(fd, &signal, sizeof(int)); flag = signal >> 24; sig = signal & 0xfff; debug("_handle_signal_container for step=%u.%u uid=%d signal=%d", job->jobid, job->stepid, (int) uid, sig); if ((uid != job->uid) && !_slurm_authorized_user(uid)) { error("signal container req from uid %ld for step=%u.%u " "owned by uid %ld", (long)uid, job->jobid, job->stepid, (long)job->uid); rc = -1; errnum = EPERM; goto done; } /* * Sanity checks */ if (job->cont_id == 0) { debug ("step %u.%u invalid container [cont_id:%"PRIu64"]", job->jobid, job->stepid, job->cont_id); rc = -1; errnum = ESLURMD_JOB_NOTRUNNING; goto done; } if ((sig == SIGTERM) || (sig == SIGKILL)) { /* cycle thru the tasks and mark those that have not * called abort and/or terminated as killed_by_cmd */ for (i = 0; i < job->node_tasks; i++) { if (NULL == (task = job->task[i])) { continue; } if (task->aborted || task->exited) { continue; } /* mark that this task is going to be killed by * cmd so we ignore its exit status - otherwise, * we will probably report the final exit status * as SIGKILL */ task->killed_by_cmd = true; } } ptr = getenvp(job->env, "SLURM_STEP_KILLED_MSG_NODE_ID"); if (ptr) target_node_id = atoi(ptr); if ((job->stepid != SLURM_EXTERN_CONT) && (job->nodeid == target_node_id) && (msg_sent == 0) && (job->state < SLURMSTEPD_STEP_ENDING)) { time_t now = time(NULL); char entity[24], time_str[24]; if (job->stepid == SLURM_BATCH_SCRIPT) { snprintf(entity, sizeof(entity), "JOB %u", job->jobid); } else { snprintf(entity, sizeof(entity), "STEP %u.%u", job->jobid, job->stepid); } slurm_make_time_str(&now, time_str, sizeof(time_str)); /* Not really errors, * but we want messages displayed by default */ if (sig == SIG_TIME_LIMIT) { error("*** %s ON %s CANCELLED AT %s DUE TO TIME LIMIT ***", entity, job->node_name, time_str); msg_sent = 1; } else if (sig == SIG_PREEMPTED) { error("*** %s ON %s CANCELLED AT %s DUE TO PREEMPTION ***", entity, job->node_name, time_str); msg_sent = 1; } else if (sig == SIG_NODE_FAIL) { error("*** %s ON %s CANCELLED AT %s DUE TO NODE " "FAILURE, SEE SLURMCTLD LOG FOR DETAILS ***", entity, job->node_name, time_str); msg_sent = 1; } else if (sig == SIG_REQUEUED) { error("*** %s ON %s CANCELLED AT %s DUE TO JOB REQUEUE ***", entity, job->node_name, time_str); msg_sent = 1; } else if (sig == SIG_FAILURE) { error("*** %s ON %s FAILED (non-zero exit code or other " "failure mode) ***", entity, job->node_name); msg_sent = 1; } else if (sig == SIG_UME) { error("*** %s ON %s UNCORRECTABLE MEMORY ERROR AT %s ***", entity, job->node_name, time_str); } else if ((sig == SIGTERM) || (sig == SIGKILL)) { error("*** %s ON %s CANCELLED AT %s ***", entity, job->node_name, time_str); msg_sent = 1; } } if ((sig == SIG_TIME_LIMIT) || (sig == SIG_NODE_FAIL) || (sig == SIG_PREEMPTED) || (sig == SIG_FAILURE) || (sig == SIG_REQUEUED) || (sig == SIG_UME)) goto done; if (sig == SIG_ABORT) { sig = SIGKILL; job->aborted = true; } slurm_mutex_lock(&suspend_mutex); if (suspended && (sig != SIGKILL)) { rc = -1; errnum = ESLURMD_STEP_SUSPENDED; slurm_mutex_unlock(&suspend_mutex); goto done; } if (sig == SIG_DEBUG_WAKE) { int i; for (i = 0; i < job->node_tasks; i++) pdebug_wake_process(job, job->task[i]->pid); slurm_mutex_unlock(&suspend_mutex); goto done; } if (flag & KILL_JOB_BATCH && job->stepid == SLURM_BATCH_SCRIPT) { /* We should only signal the batch script * and nothing else, the job pgid is the * equal to the pid of the batch script. */ if (kill(job->pgid, sig) < 0) { error("%s: failed signal %d container pid" "%u job %u.%u %m", __func__, sig, job->pgid, job->jobid, job->stepid); rc = SLURM_ERROR; errnum = errno; slurm_mutex_unlock(&suspend_mutex); goto done; } rc = SLURM_SUCCESS; errnum = 0; verbose("%s: sent signal %d to container pid %u job %u.%u", __func__, sig, job->pgid, job->jobid, job->stepid); slurm_mutex_unlock(&suspend_mutex); goto done; } /* * Signal the container */ if (proctrack_g_signal(job->cont_id, sig) < 0) { rc = -1; errnum = errno; verbose("Error sending signal %d to %u.%u: %m", sig, job->jobid, job->stepid); } else { verbose("Sent signal %d to %u.%u", sig, job->jobid, job->stepid); } slurm_mutex_unlock(&suspend_mutex); done: /* Send the return code and errnum */ safe_write(fd, &rc, sizeof(int)); safe_write(fd, &errnum, sizeof(int)); return SLURM_SUCCESS; rwfail: return SLURM_FAILURE; }
/* Write some buf1 data to pty, processing IACs. * Update wridx1 and size1. Return < 0 on error. * Buggy if IAC is present but incomplete: skips them. */ static ssize_t safe_write_to_pty_decode_iac(struct tsession *ts) { unsigned wr; ssize_t rc; unsigned char *buf; unsigned char *found; buf = TS_BUF1(ts) + ts->wridx1; wr = MIN(BUFSIZE - ts->wridx1, ts->size1); /* wr is at least 1 here */ if (ts->buffered_IAC_for_pty) { /* Last time we stopped on a "dangling" IAC byte. * We removed it from the buffer back then. * Now pretend it's still there, and jump to IAC processing. */ ts->buffered_IAC_for_pty = 0; wr++; ts->size1++; buf--; /* Yes, this can point before the buffer. It's ok */ ts->wridx1--; goto handle_iac; } found = memchr(buf, IAC, wr); if (found != buf) { /* There is a "prefix" of non-IAC chars. * Write only them, and return. */ if (found) wr = found - buf; /* We map \r\n ==> \r for pragmatic reasons: * many client implementations send \r\n when * the user hits the CarriageReturn key. * See RFC 1123 3.3.1 Telnet End-of-Line Convention. */ rc = wr; found = memchr(buf, '\r', wr); if (found) rc = found - buf + 1; rc = safe_write(ts->ptyfd, buf, rc); if (rc <= 0) return rc; if (rc < wr /* don't look past available data */ && buf[rc-1] == '\r' /* need this: imagine that write was _short_ */ && (buf[rc] == '\n' || buf[rc] == '\0') ) { rc++; } goto update_and_return; } /* buf starts with IAC char. Process that sequence. * Example: we get this from our own (bbox) telnet client: * read(5, "\377\374\1""\377\373\37""\377\372\37\0\262\0@\377\360""\377\375\1""\377\375\3"): * IAC WONT ECHO, IAC WILL NAWS, IAC SB NAWS <cols> <rows> IAC SE, IAC DO SGA * Another example (telnet-0.17 from old-netkit): * read(4, "\377\375\3""\377\373\30""\377\373\37""\377\373 ""\377\373!""\377\373\"""\377\373'" * "\377\375\5""\377\373#""\377\374\1""\377\372\37\0\257\0I\377\360""\377\375\1"): * IAC DO SGA, IAC WILL TTYPE, IAC WILL NAWS, IAC WILL TSPEED, IAC WILL LFLOW, IAC WILL LINEMODE, IAC WILL NEW_ENVIRON, * IAC DO STATUS, IAC WILL XDISPLOC, IAC WONT ECHO, IAC SB NAWS <cols> <rows> IAC SE, IAC DO ECHO */ if (wr <= 1) { /* Only the single IAC byte is in the buffer, eat it * and set a flag "process the rest of the sequence * next time we are here". */ //bb_error_msg("dangling IAC!"); ts->buffered_IAC_for_pty = 1; rc = 1; goto update_and_return; } handle_iac: /* 2-byte commands (240..250 and 255): * IAC IAC (255) Literal 255. Supported. * IAC SE (240) End of subnegotiation. Treated as NOP. * IAC NOP (241) NOP. Supported. * IAC BRK (243) Break. Like serial line break. TODO via tcsendbreak()? * IAC AYT (246) Are you there. Send back evidence that AYT was seen. TODO (send NOP back)? * These don't look useful: * IAC DM (242) Data mark. What is this? * IAC IP (244) Suspend, interrupt or abort the process. (Ancient cousin of ^C). * IAC AO (245) Abort output. "You can continue running, but do not send me the output". * IAC EC (247) Erase character. The receiver should delete the last received char. * IAC EL (248) Erase line. The receiver should delete everything up tp last newline. * IAC GA (249) Go ahead. For half-duplex lines: "now you talk". * Implemented only as part of NAWS: * IAC SB (250) Subnegotiation of an option follows. */ if (buf[1] == IAC) { /* Literal 255 (emacs M-DEL) */ //bb_error_msg("255!"); rc = safe_write(ts->ptyfd, &buf[1], 1); /* * If we went through buffered_IAC_for_pty==1 path, * bailing out on error like below messes up the buffer. * EAGAIN is highly unlikely here, other errors will be * repeated on next write, let's just skip error check. */ #if 0 if (rc <= 0) return rc; #endif rc = 2; goto update_and_return; } if (buf[1] >= 240 && buf[1] <= 249) { /* NOP (241). Ignore (putty keepalive, etc) */ /* All other 2-byte commands also treated as NOPs here */ rc = 2; goto update_and_return; } if (wr <= 2) { /* BUG: only 2 bytes of the IAC is in the buffer, we just eat them. * This is not a practical problem since >2 byte IACs are seen only * in initial negotiation, when buffer is empty */ rc = 2; goto update_and_return; } if (buf[1] == SB) { if (buf[2] == TELOPT_NAWS) { /* IAC SB, TELOPT_NAWS, 4-byte, IAC SE */ struct winsize ws; if (wr <= 6) { /* BUG: incomplete, can't process */ rc = wr; goto update_and_return; } memset(&ws, 0, sizeof(ws)); /* pixel sizes are set to 0 */ ws.ws_col = (buf[3] << 8) | buf[4]; ws.ws_row = (buf[5] << 8) | buf[6]; ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); rc = 7; /* trailing IAC SE will be eaten separately, as 2-byte NOP */ goto update_and_return; } /* else: other subnegs not supported yet */ } /* Assume it is a 3-byte WILL/WONT/DO/DONT 251..254 command and skip it */ #if DEBUG fprintf(stderr, "Ignoring IAC %s,%s\n", TELCMD(buf[1]), TELOPT(buf[2])); #endif rc = 3; update_and_return: ts->wridx1 += rc; if (ts->wridx1 >= BUFSIZE) /* actually == BUFSIZE */ ts->wridx1 = 0; ts->size1 -= rc; /* * Hack. We cannot process IACs which wrap around buffer's end. * Since properly fixing it requires writing bigger code, * we rely instead on this code making it virtually impossible * to have wrapped IAC (people don't type at 2k/second). * It also allows for bigger reads in common case. */ if (ts->size1 == 0) { /* very typical */ //bb_error_msg("zero size1"); ts->rdidx1 = 0; ts->wridx1 = 0; return rc; } wr = ts->wridx1; if (wr != 0 && wr < ts->rdidx1) { /* Buffer is not wrapped yet. * We can easily move it to the beginning. */ //bb_error_msg("moved %d", wr); memmove(TS_BUF1(ts), TS_BUF1(ts) + wr, ts->size1); ts->rdidx1 -= wr; ts->wridx1 = 0; } return rc; }
static void segv_handler(int sig) { static int crashing = 0; void* array[64]; size_t size; // So we don't recurse! if(crashing) exit(101); crashing = 1; int fd = STDERR_FILENO; if(getenv("RBX_PAUSE_ON_CRASH")) { std::cerr << "\n========== CRASH (" << getpid(); std::cerr << "), pausing for 60 seconds to attach debugger\n"; sleep(60); } // If there is a report_path setup.. if(report_path[0]) { fd = open(report_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); // If we can't open this path, use stderr. if(fd == -1) fd = STDERR_FILENO; } // print out all the frames to stderr static const char header[] = "Rubinius Crash Report #rbxcrashreport\n\n" "Error: signal "; safe_write(fd, header, sizeof(header)); write_sig(fd, sig); safe_write(fd, "\n\n[[Backtrace]]\n"); // get void*'s for all entries on the stack size = backtrace(array, 64); backtrace_symbols_fd(array, size, fd); // Try to get the output to flush... safe_write(fd, "\n[[System Info]]\n"); safe_write(fd, "sysname: "); safe_write(fd, machine_info.sysname); safe_write(fd, "\n"); safe_write(fd, "nodename: "); safe_write(fd, machine_info.nodename); safe_write(fd, "\n"); safe_write(fd, "release: "); safe_write(fd, machine_info.release); safe_write(fd, "\n"); safe_write(fd, "version: "); safe_write(fd, machine_info.version); safe_write(fd, "\n"); safe_write(fd, "machine: "); safe_write(fd, machine_info.machine); safe_write(fd, "\n"); // If we didn't write to stderr, then close the file down and // write info to stderr about reporting the error. if(fd != STDERR_FILENO) { close(fd); safe_write(2, "\n---------------------------------------------\n"); safe_write(2, "CRASH: A fatal error has occurred.\n\nBacktrace:\n"); backtrace_symbols_fd(array, size, 2); safe_write(2, "\n\n"); safe_write(2, "Wrote full error report to: "); safe_write(2, report_path); safe_write(2, "\nRun 'rbx report' to submit this crash report!\n"); } exit(100); }
void garden_print(int fd) { char line[512]; #ifdef HAVE_PATRICIA void cb (prefix_t *prefix, void *data) { struct node_pass_through_list *nd = (struct node_pass_through_list *)data; garden_print_list(fd, nd->ptlist, nd->ptcnt); } #endif safe_snprintf(line, sizeof line, "static garden (%d/%d):\n", _options.num_pass_throughs, MAX_PASS_THROUGHS); if (!safe_write(fd, line, strlen(line))) /* error */ ; #ifdef HAVE_PATRICIA if (dhcp->ptree) { patricia_process(dhcp->ptree, cb); } else #endif garden_print_list(fd, _options.pass_throughs, _options.num_pass_throughs); safe_snprintf(line, sizeof line, "dynamic garden (%d/%d):\n", dhcp->num_pass_throughs, MAX_PASS_THROUGHS); if (!safe_write(fd, line, strlen(line))) /* error */ ; #ifdef HAVE_PATRICIA if (dhcp->ptree_dyn) { patricia_process(dhcp->ptree_dyn, cb); } else #endif garden_print_list(fd, dhcp->pass_throughs, dhcp->num_pass_throughs); #ifdef ENABLE_AUTHEDALLOWED safe_snprintf(line, sizeof line, "authed garden (%d/%d):\n", _options.num_authed_pass_throughs, MAX_PASS_THROUGHS); if (!safe_write(fd, line, strlen(line))) /* error */; #ifdef HAVE_PATRICIA if (dhcp->ptree_authed) { patricia_process(dhcp->ptree_authed, cb); } else #endif garden_print_list(fd, _options.authed_pass_throughs, _options.num_authed_pass_throughs); #endif #ifdef ENABLE_SESSGARDEN chilli_appconn_run(garden_print_appconn, &fd); #endif }