예제 #1
0
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);
}
예제 #2
0
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)
예제 #3
0
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;
}
예제 #4
0
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)
예제 #5
0
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);
}