Annotation of embedaddon/tmux/cmd-new-session.c, revision 1.1

1.1     ! misho       1: /* $OpenBSD$ */
        !             2: 
        !             3: /*
        !             4:  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
        !            15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
        !            16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18: 
        !            19: #include <sys/types.h>
        !            20: 
        !            21: #include <errno.h>
        !            22: #include <fcntl.h>
        !            23: #include <stdlib.h>
        !            24: #include <string.h>
        !            25: #include <termios.h>
        !            26: #include <unistd.h>
        !            27: 
        !            28: #include "tmux.h"
        !            29: 
        !            30: /*
        !            31:  * Create a new session and attach to the current terminal unless -d is given.
        !            32:  */
        !            33: 
        !            34: #define NEW_SESSION_TEMPLATE "#{session_name}:"
        !            35: 
        !            36: static enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmdq_item *);
        !            37: 
        !            38: const struct cmd_entry cmd_new_session_entry = {
        !            39:        .name = "new-session",
        !            40:        .alias = "new",
        !            41: 
        !            42:        .args = { "Ac:dDEF:n:Ps:t:x:y:", 0, -1 },
        !            43:        .usage = "[-AdDEP] [-c start-directory] [-F format] [-n window-name] "
        !            44:                 "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
        !            45:                 "[-y height] [command]",
        !            46: 
        !            47:        .tflag = CMD_SESSION_CANFAIL,
        !            48: 
        !            49:        .flags = CMD_STARTSERVER,
        !            50:        .exec = cmd_new_session_exec
        !            51: };
        !            52: 
        !            53: const struct cmd_entry cmd_has_session_entry = {
        !            54:        .name = "has-session",
        !            55:        .alias = "has",
        !            56: 
        !            57:        .args = { "t:", 0, 0 },
        !            58:        .usage = CMD_TARGET_SESSION_USAGE,
        !            59: 
        !            60:        .tflag = CMD_SESSION,
        !            61: 
        !            62:        .flags = 0,
        !            63:        .exec = cmd_new_session_exec
        !            64: };
        !            65: 
        !            66: static enum cmd_retval
        !            67: cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
        !            68: {
        !            69:        struct args             *args = self->args;
        !            70:        struct client           *c = item->client;
        !            71:        struct session          *s, *as, *groupwith;
        !            72:        struct window           *w;
        !            73:        struct environ          *env;
        !            74:        struct termios           tio, *tiop;
        !            75:        struct session_group    *sg;
        !            76:        const char              *newname, *errstr, *template, *group, *prefix;
        !            77:        const char              *path, *cmd, *cwd, *to_free = NULL;
        !            78:        char                   **argv, *cause, *cp;
        !            79:        int                      detached, already_attached, idx, argc;
        !            80:        u_int                    sx, sy;
        !            81:        struct environ_entry    *envent;
        !            82:        struct cmd_find_state    fs;
        !            83: 
        !            84:        if (self->entry == &cmd_has_session_entry) {
        !            85:                /*
        !            86:                 * cmd_prepare() will fail if the session cannot be found,
        !            87:                 * hence always return success here.
        !            88:                 */
        !            89:                return (CMD_RETURN_NORMAL);
        !            90:        }
        !            91: 
        !            92:        if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
        !            93:                cmdq_error(item, "command or window name given with target");
        !            94:                return (CMD_RETURN_ERROR);
        !            95:        }
        !            96: 
        !            97:        newname = args_get(args, 's');
        !            98:        if (newname != NULL) {
        !            99:                if (!session_check_name(newname)) {
        !           100:                        cmdq_error(item, "bad session name: %s", newname);
        !           101:                        return (CMD_RETURN_ERROR);
        !           102:                }
        !           103:                if ((as = session_find(newname)) != NULL) {
        !           104:                        if (args_has(args, 'A')) {
        !           105:                                /*
        !           106:                                 * This item is now destined for
        !           107:                                 * attach-session. Because attach-session will
        !           108:                                 * have already been prepared, copy this
        !           109:                                 * session into its tflag so it can be used.
        !           110:                                 */
        !           111:                                cmd_find_from_session(&item->state.tflag, as);
        !           112:                                return (cmd_attach_session(item,
        !           113:                                    args_has(args, 'D'), 0, NULL,
        !           114:                                    args_has(args, 'E')));
        !           115:                        }
        !           116:                        cmdq_error(item, "duplicate session: %s", newname);
        !           117:                        return (CMD_RETURN_ERROR);
        !           118:                }
        !           119:        }
        !           120: 
        !           121:        /* Is this going to be part of a session group? */
        !           122:        group = args_get(args, 't');
        !           123:        if (group != NULL) {
        !           124:                groupwith = item->state.tflag.s;
        !           125:                if (groupwith == NULL) {
        !           126:                        if (!session_check_name(group)) {
        !           127:                                cmdq_error(item, "bad group name: %s", group);
        !           128:                                goto error;
        !           129:                        }
        !           130:                        sg = session_group_find(group);
        !           131:                } else
        !           132:                        sg = session_group_contains(groupwith);
        !           133:                if (sg != NULL)
        !           134:                        prefix = sg->name;
        !           135:                else if (groupwith != NULL)
        !           136:                        prefix = groupwith->name;
        !           137:                else
        !           138:                        prefix = group;
        !           139:        } else {
        !           140:                groupwith = NULL;
        !           141:                sg = NULL;
        !           142:                prefix = NULL;
        !           143:        }
        !           144: 
        !           145:        /* Set -d if no client. */
        !           146:        detached = args_has(args, 'd');
        !           147:        if (c == NULL)
        !           148:                detached = 1;
        !           149: 
        !           150:        /* Is this client already attached? */
        !           151:        already_attached = 0;
        !           152:        if (c != NULL && c->session != NULL)
        !           153:                already_attached = 1;
        !           154: 
        !           155:        /* Get the new session working directory. */
        !           156:        if (args_has(args, 'c')) {
        !           157:                cwd = args_get(args, 'c');
        !           158:                to_free = cwd = format_single(item, cwd, c, NULL, NULL, NULL);
        !           159:        } else if (c != NULL && c->session == NULL && c->cwd != NULL)
        !           160:                cwd = c->cwd;
        !           161:        else
        !           162:                cwd = ".";
        !           163: 
        !           164:        /*
        !           165:         * If this is a new client, check for nesting and save the termios
        !           166:         * settings (part of which is used for new windows in this session).
        !           167:         *
        !           168:         * tcgetattr() is used rather than using tty.tio since if the client is
        !           169:         * detached, tty_open won't be called. It must be done before opening
        !           170:         * the terminal as that calls tcsetattr() to prepare for tmux taking
        !           171:         * over.
        !           172:         */
        !           173:        if (!detached && !already_attached && c->tty.fd != -1) {
        !           174:                if (server_client_check_nested(item->client)) {
        !           175:                        cmdq_error(item, "sessions should be nested with care, "
        !           176:                            "unset $TMUX to force");
        !           177:                        return (CMD_RETURN_ERROR);
        !           178:                }
        !           179:                if (tcgetattr(c->tty.fd, &tio) != 0)
        !           180:                        fatal("tcgetattr failed");
        !           181:                tiop = &tio;
        !           182:        } else
        !           183:                tiop = NULL;
        !           184: 
        !           185:        /* Open the terminal if necessary. */
        !           186:        if (!detached && !already_attached) {
        !           187:                if (server_client_open(c, &cause) != 0) {
        !           188:                        cmdq_error(item, "open terminal failed: %s", cause);
        !           189:                        free(cause);
        !           190:                        goto error;
        !           191:                }
        !           192:        }
        !           193: 
        !           194:        /* Find new session size. */
        !           195:        if (c != NULL) {
        !           196:                sx = c->tty.sx;
        !           197:                sy = c->tty.sy;
        !           198:        } else {
        !           199:                sx = 80;
        !           200:                sy = 24;
        !           201:        }
        !           202:        if (detached && args_has(args, 'x')) {
        !           203:                sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr);
        !           204:                if (errstr != NULL) {
        !           205:                        cmdq_error(item, "width %s", errstr);
        !           206:                        goto error;
        !           207:                }
        !           208:        }
        !           209:        if (detached && args_has(args, 'y')) {
        !           210:                sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr);
        !           211:                if (errstr != NULL) {
        !           212:                        cmdq_error(item, "height %s", errstr);
        !           213:                        goto error;
        !           214:                }
        !           215:        }
        !           216:        if (sy > 0 && options_get_number(global_s_options, "status"))
        !           217:                sy--;
        !           218:        if (sx == 0)
        !           219:                sx = 1;
        !           220:        if (sy == 0)
        !           221:                sy = 1;
        !           222: 
        !           223:        /* Figure out the command for the new window. */
        !           224:        argc = -1;
        !           225:        argv = NULL;
        !           226:        if (!args_has(args, 't') && args->argc != 0) {
        !           227:                argc = args->argc;
        !           228:                argv = args->argv;
        !           229:        } else if (sg == NULL && groupwith == NULL) {
        !           230:                cmd = options_get_string(global_s_options, "default-command");
        !           231:                if (cmd != NULL && *cmd != '\0') {
        !           232:                        argc = 1;
        !           233:                        argv = (char **)&cmd;
        !           234:                } else {
        !           235:                        argc = 0;
        !           236:                        argv = NULL;
        !           237:                }
        !           238:        }
        !           239: 
        !           240:        path = NULL;
        !           241:        if (c != NULL && c->session == NULL)
        !           242:                envent = environ_find(c->environ, "PATH");
        !           243:        else
        !           244:                envent = environ_find(global_environ, "PATH");
        !           245:        if (envent != NULL)
        !           246:                path = envent->value;
        !           247: 
        !           248:        /* Construct the environment. */
        !           249:        env = environ_create();
        !           250:        if (c != NULL && !args_has(args, 'E'))
        !           251:                environ_update(global_s_options, c->environ, env);
        !           252: 
        !           253:        /* Create the new session. */
        !           254:        idx = -1 - options_get_number(global_s_options, "base-index");
        !           255:        s = session_create(prefix, newname, argc, argv, path, cwd, env, tiop,
        !           256:            idx, sx, sy, &cause);
        !           257:        environ_free(env);
        !           258:        if (s == NULL) {
        !           259:                cmdq_error(item, "create session failed: %s", cause);
        !           260:                free(cause);
        !           261:                goto error;
        !           262:        }
        !           263: 
        !           264:        /* Set the initial window name if one given. */
        !           265:        if (argc >= 0 && args_has(args, 'n')) {
        !           266:                w = s->curw->window;
        !           267:                window_set_name(w, args_get(args, 'n'));
        !           268:                options_set_number(w->options, "automatic-rename", 0);
        !           269:        }
        !           270: 
        !           271:        /*
        !           272:         * If a target session is given, this is to be part of a session group,
        !           273:         * so add it to the group and synchronize.
        !           274:         */
        !           275:        if (group != NULL) {
        !           276:                if (sg == NULL) {
        !           277:                        if (groupwith != NULL) {
        !           278:                                sg = session_group_new(groupwith->name);
        !           279:                                session_group_add(sg, groupwith);
        !           280:                        } else
        !           281:                                sg = session_group_new(group);
        !           282:                }
        !           283:                session_group_add(sg, s);
        !           284:                session_group_synchronize_to(s);
        !           285:                session_select(s, RB_MIN(winlinks, &s->windows)->idx);
        !           286:        }
        !           287:        notify_session("session-created", s);
        !           288: 
        !           289:        /*
        !           290:         * Set the client to the new session. If a command client exists, it is
        !           291:         * taking this session and needs to get MSG_READY and stay around.
        !           292:         */
        !           293:        if (!detached) {
        !           294:                if (!already_attached) {
        !           295:                        if (~c->flags & CLIENT_CONTROL)
        !           296:                                proc_send(c->peer, MSG_READY, -1, NULL, 0);
        !           297:                } else if (c->session != NULL)
        !           298:                        c->last_session = c->session;
        !           299:                c->session = s;
        !           300:                if (!item->repeat)
        !           301:                        server_client_set_key_table(c, NULL);
        !           302:                status_timer_start(c);
        !           303:                notify_client("client-session-changed", c);
        !           304:                session_update_activity(s, NULL);
        !           305:                gettimeofday(&s->last_attached_time, NULL);
        !           306:                server_redraw_client(c);
        !           307:        }
        !           308:        recalculate_sizes();
        !           309:        server_update_socket();
        !           310: 
        !           311:        /*
        !           312:         * If there are still configuration file errors to display, put the new
        !           313:         * session's current window into more mode and display them now.
        !           314:         */
        !           315:        if (cfg_finished)
        !           316:                cfg_show_causes(s);
        !           317: 
        !           318:        /* Print if requested. */
        !           319:        if (args_has(args, 'P')) {
        !           320:                if ((template = args_get(args, 'F')) == NULL)
        !           321:                        template = NEW_SESSION_TEMPLATE;
        !           322:                cp = format_single(item, template, c, s, NULL, NULL);
        !           323:                cmdq_print(item, "%s", cp);
        !           324:                free(cp);
        !           325:        }
        !           326: 
        !           327:        if (!detached)
        !           328:                c->flags |= CLIENT_ATTACHED;
        !           329: 
        !           330:        if (to_free != NULL)
        !           331:                free((void *)to_free);
        !           332: 
        !           333:        cmd_find_from_session(&fs, s);
        !           334:        hooks_insert(s->hooks, item, &fs, "after-new-session");
        !           335: 
        !           336:        return (CMD_RETURN_NORMAL);
        !           337: 
        !           338: error:
        !           339:        if (to_free != NULL)
        !           340:                free((void *)to_free);
        !           341:        return (CMD_RETURN_ERROR);
        !           342: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>