enum cmd_retval cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct cmd_run_shell_data *cdata; char *shellcmd; struct client *c; struct session *s = NULL; struct winlink *wl = NULL; struct window_pane *wp = NULL; struct format_tree *ft; if (args_has(args, 't')) wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); else { c = cmd_find_client(cmdq, NULL, 1); if (c != NULL && c->session != NULL) { s = c->session; wl = s->curw; wp = wl->window->active; } } ft = format_create(); if (s != NULL) format_session(ft, s); if (s != NULL && wl != NULL) format_winlink(ft, s, wl); if (wp != NULL) format_window_pane(ft, wp); shellcmd = format_expand(ft, args->argv[0]); format_free(ft); cdata = xmalloc(sizeof *cdata); cdata->cmd = shellcmd; cdata->bflag = args_has(args, 'b'); cdata->wp_id = wp != NULL ? (int) wp->id : -1; cdata->cmdq = cmdq; cmdq->references++; job_run(shellcmd, s, cmd_run_shell_callback, cmd_run_shell_free, cdata); if (cdata->bflag) return (CMD_RETURN_NORMAL); return (CMD_RETURN_WAIT); }
enum cmd_retval cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; struct winlink *wl; struct client *c; const char *cmd, *template; char *cause, *cp; int idx, last, detached, cwd, fd = -1; struct format_tree *ft; if (args_has(args, 'a')) { wl = cmd_find_window(cmdq, args_get(args, 't'), &s); if (wl == NULL) return (CMD_RETURN_ERROR); idx = wl->idx + 1; /* Find the next free index. */ for (last = idx; last < INT_MAX; last++) { if (winlink_find_by_index(&s->windows, last) == NULL) break; } if (last == INT_MAX) { cmdq_error(cmdq, "no free window indexes"); return (CMD_RETURN_ERROR); } /* Move everything from last - 1 to idx up a bit. */ for (; last > idx; last--) { wl = winlink_find_by_index(&s->windows, last - 1); server_link_window(s, wl, s, last, 0, 0, NULL); server_unlink_window(s, wl); } } else { if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &s)) == -2) return (CMD_RETURN_ERROR); } detached = args_has(args, 'd'); wl = NULL; if (idx != -1) wl = winlink_find_by_index(&s->windows, idx); if (wl != NULL && args_has(args, 'k')) { /* * Can't use session_detach as it will destroy session if this * makes it empty. */ notify_window_unlinked(s, wl->window); wl->flags &= ~WINLINK_ALERTFLAGS; winlink_stack_remove(&s->lastw, wl); winlink_remove(&s->windows, wl); /* Force select/redraw if current. */ if (wl == s->curw) { detached = 0; s->curw = NULL; } } if (args->argc == 0) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; if (args_has(args, 'c')) { ft = format_create(); if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, s->curw); format_window_pane(ft, s->curw->window->active); cp = format_expand(ft, args_get(args, 'c')); format_free(ft); fd = open(cp, O_RDONLY|O_DIRECTORY); free(cp); if (fd == -1) { cmdq_error(cmdq, "bad working directory: %s", strerror(errno)); return (CMD_RETURN_ERROR); } cwd = fd; } else if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; else cwd = s->cwd; if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause); if (wl == NULL) { cmdq_error(cmdq, "create window failed: %s", cause); free(cause); goto error; } if (!detached) { session_select(s, wl->idx); server_redraw_session_group(s); } else server_status_session_group(s); if (args_has(args, 'P')) { if ((template = args_get(args, 'F')) == NULL)
int write_stats_dump(PRFileDesc *fd, StatsHeaderNode *hdr) { int i = 0; StatsManager::lockStatsData(); const StatsHeader *hdrStats = &hdr->hdrStats; // Version PR_fprintf(fd, "\n%s\n", hdrStats->versionServer); // Uptime char buffer[25]; PRExplodedTime tm; PR_ExplodeTime(hdrStats->timeStarted, PR_LocalTimeParameters, &tm); PR_FormatTimeUSEnglish(buffer, sizeof(buffer), "%c", &tm); PR_fprintf(fd, "\nServer started %s\n", buffer); { StatsProcessNode *process = hdr->process; while (process) { const StatsProcessSlot *procStats = &process->procStats; PR_ExplodeTime(procStats->timeStarted, PR_LocalTimeParameters, &tm); PR_FormatTimeUSEnglish(buffer, sizeof(buffer), "%c", &tm); PR_fprintf(fd, "Process %d started %s\n", procStats->pid, buffer); process = process->next; } } // ConnectionQueue { StatsConnectionQueueSlot connqueues; memset(&connqueues, 0, sizeof(connqueues)); // Accumulate connection queue buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsConnectionQueueNode *connQueueNode = process->connQueue; while (connQueueNode) { const StatsConnectionQueueSlot *connqueue = &connQueueNode->connQueueStats; connqueues.countQueued += connqueue->countQueued; connqueues.peakQueued += connqueue->peakQueued; connqueues.maxQueued += connqueue->maxQueued; connqueues.countOverflows += connqueue->countOverflows; connqueues.countTotalQueued += connqueue->countTotalQueued; connqueues.ticksTotalQueued += connqueue->ticksTotalQueued; connqueues.countTotalConnections += connqueue->countTotalConnections; connqueues.countQueued1MinuteAverage += connqueue->countQueued1MinuteAverage; connqueues.countQueued5MinuteAverage += connqueue->countQueued5MinuteAverage; connqueues.countQueued15MinuteAverage += connqueue->countQueued15MinuteAverage; connQueueNode = connQueueNode->next; } process = process->next; } PRFloat64 count = (PRInt64)connqueues.countTotalQueued; PRFloat64 ticks = (PRInt64)connqueues.ticksTotalQueued; if (count < 1.0) count = 1.0; PR_fprintf(fd, "\nConnectionQueue:\n" "-----------------------------------------\n" "Current/Peak/Limit Queue Length %d/%d/%d\n" "Total Connections Queued %llu\n" "Average Queue Length (1, 5, 15 minutes) %4.2f, %4.2f, %4.2f\n" "Average Queueing Delay %.2f milliseconds\n", connqueues.countQueued, connqueues.peakQueued, connqueues.maxQueued, connqueues.countTotalQueued, connqueues.countQueued1MinuteAverage, connqueues.countQueued5MinuteAverage, connqueues.countQueued15MinuteAverage, ticks / count / hdrStats->ticksPerSecond * 1000.0); } // Listen sockets { StatsProcessNode *process = hdr->process; StatsListenNode *lsNode = (process) ? process->ls : 0; while (lsNode) { StatsListenSlot *ls = &lsNode->lsStats; PRNetAddr addr; memcpy(&addr, &ls->address, sizeof(ls->address)); char szAddress[512]; memset(szAddress, 0, sizeof(szAddress)); net_addr_to_string(&addr, szAddress, sizeof(szAddress)-1); PR_fprintf(fd, "\nListenSocket %s:\n" "------------------------\n" "Address %s://%s:%hu\n" "Acceptor Threads %d\n" "Default Virtual Server %s\n", ls->id, ls->flagSecure ? "https" : "http", szAddress, PR_ntohs(ls->address.inet.port), ls->countAcceptors, ls->defaultVsId ); lsNode = lsNode->next; } } // Keepalive Info { StatsKeepaliveBucket keepalives; memset(&keepalives, 0, sizeof(keepalives)); // Accumulate keepalive buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsKeepaliveBucket *procKeepAlive = NULL; procKeepAlive = &process->procStats.keepAliveBucket; StatsManagerUtil::accumulateKeepAlive(&keepalives, procKeepAlive); process = process->next; } PR_fprintf(fd, "\nKeepAliveInfo:\n" "--------------------\n" "KeepAliveCount %lu/%lu\n" "KeepAliveHits %llu\n" "KeepAliveFlushes %llu\n" "KeepAliveRefusals %llu\n" "KeepAliveTimeouts %llu\n" "KeepAliveTimeout %lu seconds\n", keepalives.countConnections, keepalives.maxConnections, keepalives.countHits, keepalives.countFlushes, keepalives.countRefusals, keepalives.countTimeouts, keepalives.secondsTimeout); } // Session Creation Info { PRUint32 countThreads = 0; PRUint32 countBusy = 0; PRUint32 countKeepAlive = 0; PRUint32 countKeepAliveThreads = 0; // Count the number of active threads StatsProcessNode *process = hdr->process; while (process) { StatsProcessSlot *procStats = &process->procStats; if (procStats->mode != STATS_PROCESS_EMPTY) { StatsThreadNode *thread = process->thread; while (thread) { const StatsThreadSlot *threadStats = &thread->threadStats; if (threadStats->mode != STATS_THREAD_EMPTY) { countThreads++; if (threadStats->mode == STATS_THREAD_KEEPALIVE) { countKeepAlive++; } else if (threadStats->mode != STATS_THREAD_IDLE) { countBusy++; } } thread = thread->next; } } // Get number of keepalive threads StatsKeepaliveBucket *procKeepAlive = NULL; procKeepAlive = &process->procStats.keepAliveBucket; countKeepAliveThreads += procKeepAlive->numThreads; process = process->next; } PR_fprintf(fd, "\nSessionCreationInfo:\n" "------------------------\n" "Active Sessions %lu\n" "Keep-Alive Sessions %lu\n" "Total Sessions Created %lu/%lu\n", countBusy, countKeepAlive, countThreads, (hdrStats->maxThreads * hdrStats->maxProcs + countKeepAliveThreads)); } // Cache Info { StatsCacheBucket caches; memset(&caches, 0, sizeof(caches)); // Accumulate cache buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsCacheBucket *procCache = NULL; procCache = &process->procStats.cacheBucket; StatsManagerUtil::accumulateCache(&caches, procCache); process = process->next; } if (caches.flagEnabled) { PR_fprintf(fd, "\nCacheInfo:\n" "-----------------------\n"); PRInt64 fileLookups = caches.countHits + caches.countMisses; PR_fprintf(fd, "File Cache Enabled yes\n" "File Cache Entries %lu/%lu\n" "File Cache Hit Ratio %llu/%lld (%6.2f%%)\n" "Maximum Age %d\n", caches.countEntries, caches.maxEntries, caches.countHits, fileLookups, percent(caches.countHits, fileLookups), caches.secondsMaxAge); PRInt64 accelRequests = caches.countAcceleratableRequests + caches.countUnacceleratableRequests; PRInt64 accelResponses = caches.countAcceleratableResponses + caches.countUnacceleratableResponses; PRInt64 accelLookups = caches.countAcceleratorHits + caches.countAcceleratorMisses; PR_fprintf(fd, "Accelerator Entries %lu/%lu\n" "Acceleratable Requests %llu/%lld (%6.2f%%)\n" "Acceleratable Responses %llu/%lld (%6.2f%%)\n" "Accelerator Hit Ratio %llu/%lld (%6.2f%%)\n", caches.countAcceleratorEntries, caches.maxEntries, caches.countAcceleratableRequests, accelRequests, percent(caches.countAcceleratableRequests, accelRequests), caches.countAcceleratableResponses, accelResponses, percent(caches.countAcceleratableResponses, accelResponses), caches.countAcceleratorHits, accelLookups, percent(caches.countAcceleratorHits, accelLookups)); } else { PR_fprintf(fd, "\nServer cache disabled\n"); } } // Thread pool info { StatsThreadPoolBucket pools[FUNC_MAXPOOLS]; const char *names[FUNC_MAXPOOLS]; memset(pools, 0, sizeof(pools)); memset(names, 0, sizeof(names)); // Accumulate thread pool buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsThreadPoolNode *pool = process->threadPool; for (i = 0; pool && (i < FUNC_MAXPOOLS); i++) { StatsManagerUtil::accumulateThreadPool(&pools[i], &pool->threadPoolStats); names[i] = STATS_GET_NAME(&pool->threadPoolStats); pool = pool->next; } process = process->next; } int poolFlag = 0; for (i = 0; i < FUNC_MAXPOOLS; i++) { if (names[i]) { if (!poolFlag) { poolFlag = 1; PR_fprintf(fd, "\nNative pools:\n" "----------------------------\n"); } PR_fprintf(fd, "%s:\n" "Idle/Peak/Limit %lu/%lu/%lu\n" "Work Queue Length/Peak/Limit %lu/%lu/%lu\n", names[i], pools[i].countThreadsIdle, pools[i].countThreads, pools[i].maxThreads, pools[i].countQueued, pools[i].peakQueued, pools[i].maxQueued); } } } // DNS info { StatsDnsBucket dnss; memset(&dnss, 0, sizeof(dnss)); // Accumulate DNS buckets for every process StatsProcessNode *process = hdr->process; while (process) { StatsManagerUtil::accumulateDNS(&dnss, &process->procStats.dnsBucket); process = process->next; } if (dnss.flagCacheEnabled) { PRUint32 totalhits = dnss.countCacheMisses + dnss.countCacheHits; float hitratio; if (totalhits > 0.0) hitratio = (float)dnss.countCacheHits / (float)totalhits; else hitratio = 0.0; PR_fprintf(fd, "\nDNSCacheInfo:\n" "------------------\n" "enabled yes\n" "CacheEntries %lu/%lu\n" "HitRatio %lu/%lu (%6.2f%%)\n", dnss.countCacheEntries, dnss.maxCacheEntries, dnss.countCacheHits, totalhits, hitratio * 100.0); } else { PR_fprintf(fd, "\nServer DNS cache disabled\n"); } if (dnss.flagAsyncEnabled) { PR_fprintf(fd, "\nAsyncDNS Data:\n" "------------------\n" "enabled yes\n" "NameLookups %lu\n" "AddrLookups %lu\n" "LookupsInProgress %lu\n", dnss.countAsyncNameLookups, dnss.countAsyncAddrLookups, dnss.countAsyncLookupsInProgress); } else { PR_fprintf(fd, "\nAsync DNS disabled\n"); } } // NSAPI Profile Info if (hdrStats->maxProfileBuckets) { int i; StatsProfileBucket *profiles = new StatsProfileBucket[hdrStats->maxProfileBuckets]; const char **names = new const char*[hdrStats->maxProfileBuckets]; const char **descs = new const char*[hdrStats->maxProfileBuckets]; memset(profiles, 0, sizeof(profiles[0]) * hdrStats->maxProfileBuckets); memset(names, 0, sizeof(names[0]) * hdrStats->maxProfileBuckets); memset(descs, 0, sizeof(descs[0]) * hdrStats->maxProfileBuckets); // Accumulate profiles for every thread StatsProcessNode *process = hdr->process; while (process) { StatsThreadNode *thread = process->thread; while (thread) { StatsProfileNode *profile = thread->profile; for (i = 0; i < hdrStats->maxProfileBuckets; i++) { StatsManagerUtil::accumulateProfile(&profiles[i], &profile->profileStats); names[i] = STATS_GET_NAME(&profile->profileStats); descs[i] = STATS_GET_DESCRIPTION(&profile->profileStats); profile = profile->next; } thread = thread->next; } process = process->next; } PRInt64 tr = profiles[STATS_PROFILE_ALL].countRequests; PRInt64 tc = profiles[STATS_PROFILE_ALL].countCalls; float td = (float)(PRInt64)profiles[STATS_PROFILE_ALL].ticksDispatch; float tf = (float)(PRInt64)profiles[STATS_PROFILE_ALL].ticksFunction; td /= hdrStats->ticksPerSecond; tf /= hdrStats->ticksPerSecond; float tt = td + tf; PR_fprintf(fd, "\nPerformance Counters:\n" "------------------------------------------------\n" " Average Total Percent\n\n" "Total number of requests: %10llu\n" "Request processing time: %7.4f %12.4f\n", tr, (tr > 0) ? (tt / (float)tr) : 0, tt); for (i = hdrStats->maxProfileBuckets-1; i >= STATS_PROFILE_DEFAULT; i--) { PRInt64 r = profiles[i].countRequests; PRInt64 c = profiles[i].countCalls; const char *name = names[i]; // Don't display cache-bucket if it's empty. This is a predefined // bucket that stored NSAPI accelerator cache statistics in // previous versions of the server. if (!c && i == STATS_PROFILE_CACHE && !strcmp(name, "cache-bucket")) { continue; } float d = (float)(PRInt64)profiles[i].ticksDispatch; float f = (float)(PRInt64)profiles[i].ticksFunction; d /= hdrStats->ticksPerSecond; f /= hdrStats->ticksPerSecond; float t = d + f; PR_fprintf(fd, "\n%s (%s)\n" "Number of Requests: %12llu (%6.2f%%)\n" "Number of Invocations: %12llu (%6.2f%%)\n" "Latency: %7.4f %12.4f (%6.2f%%)\n" "Function Processing Time: %7.4f %12.4f (%6.2f%%)\n" "Total Response Time: %7.4f %12.4f (%6.2f%%)\n", name, SAFESTRING(descs[i]), r, (tr > 0) ? (100.0 * r / (PRFloat64) tr) : 0, c, (tc > 0) ? (100.0 * c / (PRFloat64) tc) : 0, (r > 0)? (d / r): 0, d, (tt > 0)? (100 * d / tt): 0, (r > 0)? (f / r): 0, f, (tt > 0)? (100 * f / tt): 0, (r > 0)? (t / r): 0, t, (tt > 0)? (100 * t / tt): 0); } delete[] profiles; delete[] names; delete[] descs; } else { PR_fprintf(fd, "\nPerformance Statistics disabled\n"); } // Session info { StatsProcessNode *process; int x; int y; // Count the number of rows in our session table int nr = 0; for (process = hdr->process; process; process = process->next) { StatsThreadNode *thread; for (thread = process->thread; thread; thread = thread->next) nr++; } SessionRow *rows = new SessionRow[nr]; PRTime now = PR_Now(); // Collect stats from each session y = 0; for (process = hdr->process; process; process = process->next) { StatsThreadNode *thread; for (thread = process->thread; thread; thread = thread->next) { thread->lock(); PRUint32 mode = thread->threadStats.mode; if (mode != STATS_THREAD_EMPTY && mode != STATS_THREAD_IDLE && mode != STATS_THREAD_KEEPALIVE) { rows[y].columns[SESSION_COLUMN_PROCESS].printf("%u", process->procStats.pid); rows[y].columns[SESSION_COLUMN_STATUS] = StatsManager::getMode(&thread->threadStats); char addr[NET_ADDR_STRING_SIZE]; net_addr_to_string(&thread->threadStats.addressClient, addr, sizeof(addr)); rows[y].columns[SESSION_COLUMN_CLIENT] = addr; rows[y].timeRequestStarted = thread->threadStats.timeRequestStarted; if (rows[y].timeRequestStarted != 0) { PRTime microseconds = now - rows[y].timeRequestStarted; int seconds = (microseconds + PR_USEC_PER_SEC/2) / PR_USEC_PER_SEC; rows[y].columns[SESSION_COLUMN_AGE].printf("%d", seconds); } rows[y].columns[SESSION_COLUMN_VS] = thread->threadStats.vsId; rows[y].columns[SESSION_COLUMN_METHOD] = thread->threadStats.requestBucket.method; rows[y].columns[SESSION_COLUMN_URI] = thread->threadStats.requestBucket.uri; rows[y].columns[SESSION_COLUMN_FUNCTION] = STATS_GET_FUNCTION_NAME(&thread->threadStats); y++; } thread->unlock(); } } // We'll only display stats for active sessions PR_ASSERT(y <= nr); nr = y; // Each column is at least as wide as its label int widths[SESSION_COLUMN_COUNT]; for (x = 0; x < SESSION_COLUMN_COUNT; x++) widths[x] = session_column_labels[x].length(); // Ensure each column is wide enough to fit its largest value for (y = 0; y < nr; y++) { for (x = 0; x < SESSION_COLUMN_COUNT; x++) { if (widths[x] < rows[y].columns[x].length()) widths[x] = rows[y].columns[x].length(); } } // Leave at least 2 spaces between columns for (x = 0; x < SESSION_COLUMN_COUNT - 1; x++) widths[x] += 2; // Calculate total line width and individual column offsets int width = 0; int offsets[SESSION_COLUMN_COUNT]; for (x = 0 ; x < SESSION_COLUMN_COUNT; x++) { offsets[x] = width; width += widths[x]; } char *line = (char *) malloc(width + sizeof('\n')); // Output table heading and column labels PR_fprintf(fd, "\nSessions:\n"); memset(line, '-', width); line[width] = '\n'; PR_Write(fd, line, width + sizeof('\n')); PR_Write(fd, line, format_session(line, offsets, session_column_labels)); PR_Write(fd, "\n", 1); // Sort rows by age const SessionRow **sorted = new const SessionRow *[nr]; for (y = 0; y < nr; y++) sorted[y] = &rows[y]; qsort(sorted, nr, sizeof(sorted[0]), &session_cmp); // Output individual rows for (y = 0; y < nr; y++) PR_Write(fd, line, format_session(line, offsets, sorted[y]->columns)); delete [] sorted; free(line); delete [] rows; } StatsManager::unlockStatsData(); return REQ_PROCEED; }
enum cmd_retval cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s; struct winlink *wl; struct window *w; struct window_pane *wp, *new_wp = NULL; struct environ env; const char *cmd, *shell, *template; char *cause, *new_cause, *cp; u_int hlimit; int size, percentage, cwd, fd = -1; enum layout_type type; struct layout_cell *lc; struct client *c; struct format_tree *ft; if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) return (CMD_RETURN_ERROR); w = wl->window; server_unzoom_window(w); environ_init(&env); environ_copy(&global_environ, &env); environ_copy(&s->environ, &env); server_fill_environ(s, &env); if (args->argc == 0) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; if (args_has(args, 'c')) { ft = format_create(); if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, s->curw); format_window_pane(ft, s->curw->window->active); cp = format_expand(ft, args_get(args, 'c')); format_free(ft); fd = open(cp, O_RDONLY|O_DIRECTORY); free(cp); if (fd == -1) { cmdq_error(cmdq, "bad working directory: %s", strerror(errno)); return (CMD_RETURN_ERROR); } cwd = fd; } else if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; else cwd = s->cwd; type = LAYOUT_TOPBOTTOM; if (args_has(args, 'h')) type = LAYOUT_LEFTRIGHT; size = -1; if (args_has(args, 'l')) { size = args_strtonum(args, 'l', 0, INT_MAX, &cause); if (cause != NULL) { xasprintf(&new_cause, "size %s", cause); free(cause); cause = new_cause; goto error; } } else if (args_has(args, 'p')) { percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause); if (cause != NULL) { xasprintf(&new_cause, "percentage %s", cause); free(cause); cause = new_cause; goto error; } if (type == LAYOUT_TOPBOTTOM) size = (wp->sy * percentage) / 100; else size = (wp->sx * percentage) / 100; } hlimit = options_get_number(&s->options, "history-limit"); shell = options_get_string(&s->options, "default-shell"); if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; if ((lc = layout_split_pane(wp, type, size, 0)) == NULL) { cause = xstrdup("pane too small"); goto error; } new_wp = window_add_pane(w, hlimit); if (window_pane_spawn( new_wp, cmd, shell, cwd, &env, s->tio, &cause) != 0) goto error; layout_assign_pane(lc, new_wp); server_redraw_window(w); if (!args_has(args, 'd')) { window_set_active_pane(w, new_wp); session_select(s, wl->idx); server_redraw_session(s); } else server_status_session(s); environ_free(&env); if (args_has(args, 'P')) { if ((template = args_get(args, 'F')) == NULL)
enum cmd_retval cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, const char *cflag) { struct session *s; struct client *c; struct winlink *wl = NULL; struct window *w = NULL; struct window_pane *wp = NULL; const char *update; char *cause; u_int i; int fd; struct format_tree *ft; char *cp; if (RB_EMPTY(&sessions)) { cmdq_error(cmdq, "no sessions"); return (CMD_RETURN_ERROR); } if (tflag == NULL) { if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) return (CMD_RETURN_ERROR); } else if (tflag[strcspn(tflag, ":.")] != '\0') { if ((wl = cmd_find_pane(cmdq, tflag, &s, &wp)) == NULL) return (CMD_RETURN_ERROR); } else { if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) return (CMD_RETURN_ERROR); w = cmd_lookup_windowid(tflag); if (w == NULL && (wp = cmd_lookup_paneid(tflag)) != NULL) w = wp->window; if (w != NULL) wl = winlink_find_by_window(&s->windows, w); } if (cmdq->client == NULL) return (CMD_RETURN_NORMAL); if (wl != NULL) { if (wp != NULL) window_set_active_pane(wp->window, wp); session_set_current(s, wl); } if (cmdq->client->session != NULL) { if (dflag) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. */ for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session != s) continue; if (c == cmdq->client) continue; server_write_client(c, MSG_DETACH, c->session->name, strlen(c->session->name) + 1); } } if (cflag != NULL) { ft = format_create(); if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, s->curw); format_window_pane(ft, s->curw->window->active); cp = format_expand(ft, cflag); format_free(ft); fd = open(cp, O_RDONLY|O_DIRECTORY); free(cp); if (fd == -1) { cmdq_error(cmdq, "bad working directory: %s", strerror(errno)); return (CMD_RETURN_ERROR); } close(s->cwd); s->cwd = fd; } cmdq->client->session = s; notify_attached_session_changed(cmdq->client); session_update_activity(s); server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { if (server_client_open(cmdq->client, s, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); } if (cflag != NULL) { ft = format_create(); if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) format_client(ft, c); format_session(ft, s); format_winlink(ft, s, s->curw); format_window_pane(ft, s->curw->window->active); cp = format_expand(ft, cflag); format_free(ft); fd = open(cp, O_RDONLY|O_DIRECTORY); free(cp); if (fd == -1) { cmdq_error(cmdq, "bad working directory: %s", strerror(errno)); return (CMD_RETURN_ERROR); } close(s->cwd); s->cwd = fd; } if (rflag) cmdq->client->flags |= CLIENT_READONLY; if (dflag) { server_write_session(s, MSG_DETACH, s->name, strlen(s->name) + 1); } update = options_get_string(&s->options, "update-environment"); environ_update(update, &cmdq->client->environ, &s->environ); cmdq->client->session = s; notify_attached_session_changed(cmdq->client); session_update_activity(s); server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; server_write_ready(cmdq->client); cmdq->client_exit = 0; } recalculate_sizes(); server_update_socket(); return (CMD_RETURN_NORMAL); }