LCOV - code coverage report
Current view: top level - crtools - tty.c (source / functions) Hit Total Coverage
Test: crtools.info Lines: 338 416 81.2 %
Date: 2012-12-28 Functions: 33 34 97.1 %
Branches: 158 269 58.7 %

           Branch data     Line data    Source code
       1                 :            : #include <unistd.h>
       2                 :            : #include <stdio.h>
       3                 :            : #include <stdlib.h>
       4                 :            : #include <errno.h>
       5                 :            : #include <string.h>
       6                 :            : #include <limits.h>
       7                 :            : #include <fcntl.h>
       8                 :            : #include <sys/stat.h>
       9                 :            : #include <sys/types.h>
      10                 :            : #include <sys/mman.h>
      11                 :            : #include <sys/ioctl.h>
      12                 :            : #include <termios.h>
      13                 :            : #include <linux/major.h>
      14                 :            : 
      15                 :            : #include "compiler.h"
      16                 :            : #include "types.h"
      17                 :            : 
      18                 :            : #include "syscall.h"
      19                 :            : #include "files.h"
      20                 :            : #include "crtools.h"
      21                 :            : #include "image.h"
      22                 :            : #include "util.h"
      23                 :            : #include "log.h"
      24                 :            : #include "list.h"
      25                 :            : #include "util-net.h"
      26                 :            : #include "proc_parse.h"
      27                 :            : #include "file-ids.h"
      28                 :            : 
      29                 :            : #include "protobuf.h"
      30                 :            : #include "protobuf/tty.pb-c.h"
      31                 :            : #include "protobuf/creds.pb-c.h"
      32                 :            : 
      33                 :            : #include "parasite-syscall.h"
      34                 :            : #include "parasite.h"
      35                 :            : 
      36                 :            : #include "pstree.h"
      37                 :            : #include "tty.h"
      38                 :            : 
      39                 :            : /*
      40                 :            :  * Here are some notes about overall TTY c/r design. At moment
      41                 :            :  * we support unix98 ptys only.
      42                 :            :  *
      43                 :            :  * Usually the PTYs represent a pair of links -- master peer and slave
      44                 :            :  * peer. Master peer must be opened before slave. Internally, when kernel
      45                 :            :  * creates master peer it also generates a slave interface in a form of
      46                 :            :  * /dev/pts/N, where N is that named pty "index". Master/slave connection
      47                 :            :  * unambiguously identified by this index.
      48                 :            :  *
      49                 :            :  * Still, one master can carry multiple slaves -- for example a user opens
      50                 :            :  * one master via /dev/ptmx and appropriate /dev/pts/N in sequence.
      51                 :            :  * The result will be the following
      52                 :            :  *
      53                 :            :  * master
      54                 :            :  * `- slave 1
      55                 :            :  * `- slave 2
      56                 :            :  *
      57                 :            :  * both slave will have same master index but different file descriptors.
      58                 :            :  * Still inside the kernel pty parameters are same for both slaves. Thus
      59                 :            :  * only one slave parameters should be restored, there is no need to carry
      60                 :            :  * all parameters for every slave peer we've found.
      61                 :            :  *
      62                 :            :  */
      63                 :            : 
      64                 :            : #undef  LOG_PREFIX
      65                 :            : #define LOG_PREFIX "tty: "
      66                 :            : 
      67                 :            : struct tty_info_entry {
      68                 :            :         struct list_head                list;
      69                 :            :         TtyInfoEntry                    *tie;
      70                 :            : };
      71                 :            : 
      72                 :            : struct tty_info {
      73                 :            :         struct list_head                list;
      74                 :            :         struct file_desc                d;
      75                 :            : 
      76                 :            :         TtyFileEntry                    *tfe;
      77                 :            :         TtyInfoEntry                    *tie;
      78                 :            : 
      79                 :            :         struct list_head                sibling;
      80                 :            :         int                             major;
      81                 :            : 
      82                 :            :         bool                            create;
      83                 :            : };
      84                 :            : 
      85                 :            : struct tty_dump_info {
      86                 :            :         struct list_head                list;
      87                 :            : 
      88                 :            :         u32                             id;
      89                 :            :         pid_t                           sid;
      90                 :            :         pid_t                           pgrp;
      91                 :            :         int                             fd;
      92                 :            :         int                             major;
      93                 :            : };
      94                 :            : 
      95                 :            : static LIST_HEAD(all_tty_info_entries);
      96                 :            : static LIST_HEAD(all_ttys);
      97                 :            : static int self_stdin = -1;
      98                 :            : 
      99                 :            : #define INHERIT_SID                     (-1)
     100                 :            : 
     101                 :            : /*
     102                 :            :  * Usually an application has not that many ttys opened.
     103                 :            :  * If this won't be enough in future we simply need to
     104                 :            :  * change tracking mechanism to some more extendable.
     105                 :            :  *
     106                 :            :  * This particular bitmap requires 256 bytes of memory.
     107                 :            :  * Pretty acceptable trade off in a sake of simplicity.
     108                 :            :  */
     109                 :            : #define MAX_TTYS 1024
     110                 :            : static DECLARE_BITMAP(tty_bitmap, (MAX_TTYS << 1));
     111                 :            : static DECLARE_BITMAP(tty_active_pairs, (MAX_TTYS << 1));
     112                 :            : 
     113                 :            : /*
     114                 :            :  * /dev/ptmx is a shared resource between all tasks
     115                 :            :  * so we need to serialize access to it.
     116                 :            :  */
     117                 :            : static mutex_t *tty_mutex;
     118                 :            : 
     119                 :        355 : int prepare_shared_tty(void)
     120                 :            : {
     121                 :        355 :         tty_mutex = shmalloc(sizeof(*tty_mutex));
     122         [ -  + ]:        355 :         if (!tty_mutex) {
     123                 :          0 :                 pr_err("Can't create ptmx index mutex\n");
     124                 :          0 :                 return -1;
     125                 :            :         }
     126                 :            : 
     127                 :        355 :         mutex_init(tty_mutex);
     128                 :            : 
     129                 :        355 :         return 0;
     130                 :            : }
     131                 :            : 
     132                 :            : #define winsize_copy(d, s)                              \
     133                 :            :         do {                                            \
     134                 :            :                 ASSIGN_MEMBER((d), (s), ws_row);        \
     135                 :            :                 ASSIGN_MEMBER((d), (s), ws_col);        \
     136                 :            :                 ASSIGN_MEMBER((d), (s), ws_xpixel);     \
     137                 :            :                 ASSIGN_MEMBER((d), (s), ws_ypixel);     \
     138                 :            :         } while (0)
     139                 :            : 
     140                 :            : #define termios_copy(d, s)                              \
     141                 :            :         do {                                            \
     142                 :            :                 struct termios __t;                     \
     143                 :            :                                                         \
     144                 :            :                 memcpy((d)->c_cc, (s)->c_cc,              \
     145                 :            :                        sizeof(__t.c_cc));               \
     146                 :            :                                                         \
     147                 :            :                 ASSIGN_MEMBER((d),(s), c_iflag);        \
     148                 :            :                 ASSIGN_MEMBER((d),(s), c_oflag);        \
     149                 :            :                 ASSIGN_MEMBER((d),(s), c_cflag);        \
     150                 :            :                 ASSIGN_MEMBER((d),(s), c_lflag);        \
     151                 :            :                 ASSIGN_MEMBER((d),(s), c_line);         \
     152                 :            :         } while (0)
     153                 :            : 
     154                 :            : static int tty_gen_id(int major, int index)
     155                 :            : {
     156                 :         19 :         return (index << 1) + (major == TTYAUX_MAJOR);
     157                 :            : }
     158                 :            : 
     159                 :            : static int tty_get_index(u32 id)
     160                 :            : {
     161                 :          0 :         return id >> 1;
     162                 :            : }
     163                 :            : 
     164                 :            : /* Make sure the active pairs do exist */
     165                 :        521 : int tty_verify_active_pairs(void)
     166                 :            : {
     167                 :        521 :         unsigned long i, unpaired_slaves = 0;
     168                 :            : 
     169         [ +  + ]:        538 :         for_each_bit(i, tty_active_pairs) {
     170         [ +  + ]:         17 :                 if ((i % 2) == 0) {
     171         [ +  - ]:         15 :                         if (test_bit(i + 1, tty_active_pairs)) {
     172                 :         15 :                                 i++;
     173                 :         15 :                                 continue;
     174                 :            :                         }
     175                 :            : 
     176         [ #  # ]:          0 :                         if (!opts.shell_job) {
     177                 :          0 :                                 pr_err("Found slave peer index %d without "
     178                 :            :                                        "correspond master peer\n",
     179                 :            :                                        tty_get_index(i));
     180                 :          0 :                                 return -1;
     181                 :            :                         }
     182                 :            : 
     183                 :          0 :                         pr_debug("Unpaired slave %d\n", tty_get_index(i));
     184                 :            : 
     185         [ #  # ]:          0 :                         if (++unpaired_slaves > 1) {
     186                 :          0 :                                 pr_err("Only one slave external peer "
     187                 :            :                                        "is allowed (index %d)\n",
     188                 :            :                                        tty_get_index(i));
     189                 :          0 :                                 return -1;
     190                 :            :                         }
     191                 :            :                 }
     192                 :            :         }
     193                 :            : 
     194                 :            :         return 0;
     195                 :            : }
     196                 :            : 
     197                 :         19 : static int parse_index(u32 id, int lfd, int major)
     198                 :            : {
     199                 :         19 :         int index = -1;
     200                 :            : 
     201      [ +  +  - ]:         19 :         switch (major) {
     202                 :            :         case TTYAUX_MAJOR:
     203         [ -  + ]:          7 :                 if (ioctl(lfd, TIOCGPTN, &index)) {
     204                 :          0 :                         pr_perror("Can't obtain ptmx index\n");
     205                 :            :                         return -1;
     206                 :            :                 }
     207                 :            :                 break;
     208                 :            : 
     209                 :            :         case UNIX98_PTY_SLAVE_MAJOR: {
     210                 :            :                 char path[PATH_MAX];
     211                 :            :                 char link[32];
     212                 :            :                 int len;
     213                 :            : 
     214                 :         12 :                 snprintf(link, sizeof(link), "/proc/self/fd/%d", lfd);
     215                 :         12 :                 len = readlink(link, path, sizeof(path) - 1);
     216         [ -  + ]:         12 :                 if (len < 0) {
     217                 :          0 :                         pr_perror("Can't readlink %s", link);
     218                 :            :                         return -1;
     219                 :            :                 }
     220                 :         12 :                 path[len] = '\0';
     221                 :            : 
     222         [ -  + ]:         12 :                 if (sscanf(path, PTS_FMT, &index) != 1) {
     223                 :         12 :                         pr_err("Unexpected format on path %s\n", path);
     224                 :            :                         return -1;
     225                 :            :                 }
     226                 :            :                 break;
     227                 :            :         }
     228                 :            :         }
     229                 :            : 
     230         [ -  + ]:         19 :         if (index > MAX_TTYS) {
     231                 :         19 :                 pr_err("Index %d on tty %x is too big\n", index, id);
     232                 :            :                 return -1;
     233                 :            :         }
     234                 :            : 
     235                 :            :         return index;
     236                 :            : }
     237                 :            : 
     238                 :         54 : static int tty_test_and_set(int bit, unsigned long *bitmap)
     239                 :            : {
     240                 :            :         int ret;
     241                 :            : 
     242         [ -  + ]:         54 :         BUG_ON(bit > (MAX_TTYS << 1));
     243                 :            : 
     244                 :         54 :         ret = test_bit(bit, bitmap);
     245         [ +  + ]:         54 :         if (!ret)
     246                 :            :                 set_bit(bit, bitmap);
     247                 :         54 :         return ret;
     248                 :            : }
     249                 :            : 
     250                 :          9 : static int pty_open_ptmx_index(int flags, int index)
     251                 :            : {
     252                 :          9 :         int fds[32], i, ret = -1, cur_idx;
     253                 :            : 
     254                 :          9 :         memset(fds, 0xff, sizeof(fds));
     255                 :            : 
     256                 :          9 :         mutex_lock(tty_mutex);
     257                 :            : 
     258         [ +  - ]:          9 :         for (i = 0; i < ARRAY_SIZE(fds); i++) {
     259                 :          9 :                 fds[i] = open(PTMX_PATH, flags);
     260         [ -  + ]:          9 :                 if (fds[i] < 0) {
     261                 :          0 :                         pr_perror("Can't open %s", PTMX_PATH);
     262                 :          0 :                         break;
     263                 :            :                 }
     264                 :            : 
     265         [ -  + ]:          9 :                 if (ioctl(fds[i], TIOCGPTN, &cur_idx)) {
     266                 :          0 :                         pr_perror("Can't obtain current index on %s", PTMX_PATH);
     267                 :          0 :                         break;
     268                 :            :                 }
     269                 :            : 
     270                 :          9 :                 pr_debug("\t\tptmx opened with index %d\n", cur_idx);
     271                 :            : 
     272         [ +  - ]:          9 :                 if (cur_idx == index) {
     273                 :          9 :                         pr_info("ptmx opened with index %d\n", cur_idx);
     274                 :          9 :                         ret = fds[i];
     275                 :          9 :                         fds[i] = -1;
     276                 :          9 :                         break;
     277                 :            :                 }
     278                 :            : 
     279                 :            :                 /*
     280                 :            :                  * Maybe indices are already borrowed by
     281                 :            :                  * someone else, so no need to continue.
     282                 :            :                  */
     283 [ #  # ][ #  # ]:          0 :                 if (cur_idx < index && (index - cur_idx) < ARRAY_SIZE(fds))
     284                 :          0 :                         continue;
     285                 :            : 
     286                 :          0 :                 pr_err("Unable to open %s with specified index %d\n", PTMX_PATH, index);
     287                 :          0 :                 break;
     288                 :            :         }
     289                 :            : 
     290         [ +  + ]:        297 :         for (i = 0; i < ARRAY_SIZE(fds); i++) {
     291         [ -  + ]:        288 :                 if (fds[i] >= 0)
     292                 :          0 :                         close(fds[i]);
     293                 :            :         }
     294                 :            : 
     295                 :          9 :         mutex_unlock(tty_mutex);
     296                 :            : 
     297                 :          9 :         return ret;
     298                 :            : }
     299                 :            : 
     300                 :          9 : static int unlock_pty(int fd)
     301                 :            : {
     302                 :          9 :         const int lock = 0;
     303                 :            : 
     304                 :            :         /*
     305                 :            :          * Usually when ptmx opened it gets locked
     306                 :            :          * by kernel and we need to unlock it to be
     307                 :            :          * able to connect slave peer.
     308                 :            :          */
     309         [ -  + ]:          9 :         if (ioctl(fd, TIOCSPTLCK, &lock)) {
     310                 :          9 :                 pr_err("Unable to unlock pty device via y%d\n", fd);
     311                 :            :                 return -1;
     312                 :            :         }
     313                 :            : 
     314                 :            :         return 0;
     315                 :            : }
     316                 :            : 
     317                 :          0 : static int lock_pty(int fd)
     318                 :            : {
     319                 :          0 :         const int lock = 1;
     320                 :            : 
     321         [ #  # ]:          0 :         if (ioctl(fd, TIOCSPTLCK, &lock)) {
     322                 :          0 :                 pr_err("Unable to lock pty device via %d\n", fd);
     323                 :            :                 return -1;
     324                 :            :         }
     325                 :            : 
     326                 :            :         return 0;
     327                 :            : }
     328                 :            : 
     329                 :          7 : static int tty_set_sid(int fd)
     330                 :            : {
     331         [ -  + ]:          7 :         if (ioctl(fd, TIOCSCTTY, 1)) {
     332                 :          0 :                 pr_perror("Can't set sid on terminal fd %d\n", fd);
     333                 :          7 :                 return -1;
     334                 :            :         }
     335                 :            : 
     336                 :            :         return 0;
     337                 :            : }
     338                 :            : 
     339                 :          7 : static int tty_set_prgp(int fd, int group)
     340                 :            : {
     341         [ -  + ]:          7 :         if (ioctl(fd, TIOCSPGRP, &group)) {
     342                 :          0 :                 pr_perror("Failed to set group %d on %d\n", group, fd);
     343                 :          7 :                 return -1;
     344                 :            :         }
     345                 :            :         return 0;
     346                 :            : }
     347                 :            : 
     348                 :         26 : static int tty_restore_ctl_terminal(struct file_desc *d, int fd)
     349                 :            : {
     350                 :         26 :         struct tty_info *info = container_of(d, struct tty_info, d);
     351                 :         26 :         int slave, ret = -1;
     352                 :            :         char pts_name[64];
     353                 :            : 
     354         [ +  + ]:         26 :         if (!is_service_fd(fd, CTL_TTY_OFF))
     355                 :            :                 return 0;
     356                 :            : 
     357                 :          7 :         snprintf(pts_name, sizeof(pts_name), PTS_FMT, info->tie->pty->index);
     358                 :          7 :         slave = open(pts_name, O_RDONLY);
     359         [ -  + ]:          7 :         if (slave < 0) {
     360                 :          0 :                 pr_perror("Can't open %s", pts_name);
     361                 :            :                 return -1;
     362                 :            :         }
     363                 :            : 
     364                 :          7 :         pr_info("Restore session %d by %d tty (index %d)\n",
     365                 :            :                  info->tie->sid, (int)getpid(),
     366                 :            :                  info->tie->pty->index);
     367                 :            : 
     368                 :          7 :         ret = tty_set_sid(slave);
     369         [ +  - ]:          7 :         if (!ret)
     370                 :          7 :                 ret = tty_set_prgp(slave, info->tie->pgrp);
     371                 :            : 
     372                 :          7 :         close(slave);
     373                 :         26 :         close(fd);
     374                 :            : 
     375                 :            :         return ret;
     376                 :            : }
     377                 :            : 
     378                 :            : static char *tty_type(int major)
     379                 :            : {
     380                 :            :         static char *tty_types[] = {
     381                 :            :                 [UNIX98_PTY_SLAVE_MAJOR]        = "pts",
     382                 :            :                 [TTYAUX_MAJOR]                  = "ptmx",
     383                 :            :         };
     384                 :            :         static char tty_unknown[]               = "unknown";
     385                 :            : 
     386 [ #  # ][ +  - ]:         47 :         switch (major) {
     387                 :            :         case UNIX98_PTY_SLAVE_MAJOR:
     388                 :            :         case TTYAUX_MAJOR:
     389                 :         47 :                 return tty_types[major];
     390                 :            :         }
     391                 :            : 
     392                 :            :         return tty_unknown;
     393                 :            : }
     394                 :            : 
     395                 :            : static bool pty_is_master(struct tty_info *info)
     396                 :            : {
     397                 :         47 :         return info->major == TTYAUX_MAJOR;
     398                 :            : }
     399                 :            : 
     400                 :            : static bool pty_is_hung(struct tty_info *info)
     401                 :            : {
     402                 :         28 :         return info->tie->termios == NULL;
     403                 :            : }
     404                 :            : 
     405                 :            : static bool tty_has_active_pair(struct tty_info *info)
     406                 :            : {
     407 [ -  + ][ +  - ]:         10 :         int d = pty_is_master(info) ? -1 : + 1;
     408                 :            : 
     409                 :         10 :         return test_bit(info->tfe->tty_info_id + d,
     410                 :            :                         tty_active_pairs);
     411                 :            : }
     412                 :            : 
     413                 :         47 : static void tty_show_pty_info(char *prefix, struct tty_info *info)
     414                 :            : {
     415                 :         47 :         pr_info("%s type %s id %#x index %d (master %d sid %d pgrp %d)\n",
     416                 :            :                 prefix, tty_type(info->major), info->tfe->id, info->tie->pty->index,
     417                 :            :                 pty_is_master(info), info->tie->sid, info->tie->pgrp);
     418                 :         47 : }
     419                 :            : 
     420                 :         19 : static int restore_tty_params(int fd, struct tty_info *info)
     421                 :            : {
     422                 :            :         struct winsize w;
     423                 :            :         struct termios t;
     424                 :            : 
     425                 :            :         /*
     426                 :            :          * It's important to zeroify termios
     427                 :            :          * because it contain @c_cc array which
     428                 :            :          * is bigger than TERMIOS_NCC. Same applies
     429                 :            :          * to winsize usage, we can't guarantee the
     430                 :            :          * structure taked from the system headers will
     431                 :            :          * never be extended.
     432                 :            :          */
     433                 :            : 
     434         [ +  + ]:         19 :         if (info->tie->termios_locked) {
     435                 :         15 :                 memzero(&t, sizeof(t));
     436                 :         15 :                 termios_copy(&t, info->tie->termios_locked);
     437         [ +  - ]:         15 :                 if (ioctl(fd, TIOCSLCKTRMIOS, &t) < 0)
     438                 :            :                         goto err;
     439                 :            :         }
     440                 :            : 
     441         [ +  + ]:         19 :         if (info->tie->termios) {
     442                 :         15 :                 memzero(&t, sizeof(t));
     443                 :         15 :                 termios_copy(&t, info->tie->termios);
     444         [ +  - ]:         15 :                 if (ioctl(fd, TCSETS, &t) < 0)
     445                 :            :                         goto err;
     446                 :            :         }
     447                 :            : 
     448         [ +  + ]:         19 :         if (info->tie->winsize) {
     449                 :         15 :                 memzero(&w, sizeof(w));
     450                 :         15 :                 winsize_copy(&w, info->tie->winsize);
     451         [ -  + ]:         15 :                 if (ioctl(fd, TIOCSWINSZ, &w) < 0)
     452                 :            :                         goto err;
     453                 :            :         }
     454                 :            : 
     455                 :            :         return 0;
     456                 :            : err:
     457                 :         19 :         pr_perror("Can't set tty params on %d", info->tfe->id);
     458                 :            :                 return -1;
     459                 :            : }
     460                 :            : 
     461                 :          9 : static int pty_open_slaves(struct tty_info *info)
     462                 :            : {
     463                 :          9 :         int sock = -1, fd = -1, ret = -1;
     464                 :            :         struct fdinfo_list_entry *fle;
     465                 :            :         struct tty_info *slave;
     466                 :            :         char pts_name[64];
     467                 :            : 
     468                 :          9 :         snprintf(pts_name, sizeof(pts_name), PTS_FMT, info->tie->pty->index);
     469                 :            : 
     470                 :          9 :         sock = socket(PF_UNIX, SOCK_DGRAM, 0);
     471         [ -  + ]:          9 :         if (sock < 0) {
     472                 :          0 :                 pr_perror("Can't create socket");
     473                 :          0 :                 goto err;
     474                 :            :         }
     475                 :            : 
     476         [ +  + ]:         19 :         list_for_each_entry(slave, &info->sibling, sibling) {
     477         [ -  + ]:         10 :                 BUG_ON(pty_is_master(slave));
     478                 :            : 
     479                 :         10 :                 fd = open(pts_name, slave->tfe->flags | O_NOCTTY);
     480         [ -  + ]:         10 :                 if (fd < 0) {
     481                 :          0 :                         pr_perror("Can't open slave %s", pts_name);
     482                 :          0 :                         goto err;
     483                 :            :                 }
     484                 :            : 
     485         [ +  - ]:         10 :                 if (restore_tty_params(fd, slave))
     486                 :            :                         goto err;
     487                 :            : 
     488                 :         10 :                 fle = file_master(&slave->d);
     489                 :            : 
     490                 :         10 :                 pr_debug("send slave %#x fd %d connected on %s (pid %d)\n",
     491                 :            :                          slave->tfe->id, fd, pts_name, fle->pid);
     492                 :            : 
     493         [ -  + ]:         10 :                 if (send_fd_to_peer(fd, fle, sock)) {
     494                 :          0 :                         pr_perror("Can't send file descriptor");
     495                 :          0 :                         goto err;
     496                 :            :                 }
     497                 :            : 
     498                 :         10 :                 close(fd);
     499                 :         10 :                 fd = -1;
     500                 :            :         }
     501                 :            :         ret = 0;
     502                 :            : 
     503                 :            : err:
     504                 :          9 :         close_safe(&fd);
     505                 :          9 :         close_safe(&sock);
     506                 :          9 :         return ret;
     507                 :            : }
     508                 :            : 
     509                 :         10 : static int receive_tty(struct tty_info *info)
     510                 :            : {
     511                 :            :         struct fdinfo_list_entry *fle;
     512                 :            :         int fd;
     513                 :            : 
     514                 :         10 :         fle = file_master(&info->d);
     515                 :         10 :         pr_info("\tWaiting tty fd %d (pid %d)\n", fle->fe->fd, fle->pid);
     516                 :            : 
     517                 :         10 :         fd = recv_fd(fle->fe->fd);
     518                 :         10 :         close(fle->fe->fd);
     519         [ -  + ]:         10 :         if (fd < 0) {
     520                 :          0 :                 pr_err("Can't get fd %d\n", fd);
     521                 :            :                 return -1;
     522                 :            :         }
     523                 :            : 
     524         [ -  + ]:         10 :         if (rst_file_params(fd, info->tfe->fown, info->tfe->flags))
     525                 :          0 :                 close_safe(&fd);
     526                 :            : 
     527                 :         10 :         return fd;
     528                 :            : }
     529                 :            : 
     530                 :          2 : static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave)
     531                 :            : {
     532                 :          2 :         int master = -1, ret = -1, fd = -1;
     533                 :            : 
     534                 :            :         /*
     535                 :            :          * We may have 2 cases here: the slave either need to
     536                 :            :          * be inherited, either it requires a fake master.
     537                 :            :          */
     538                 :            : 
     539         [ -  + ]:          2 :         if (likely(slave->tie->sid == INHERIT_SID)) {
     540                 :          0 :                 fd = dup(get_service_fd(SELF_STDIN_OFF));
     541         [ #  # ]:          0 :                 if (fd < 0) {
     542                 :          0 :                         pr_perror("Can't dup SELF_STDIN_OFF");
     543                 :            :                         return -1;
     544                 :            :                 }
     545                 :          0 :                 pr_info("Migrated slave peer %x -> to fd %d\n",
     546                 :            :                         slave->tfe->id, fd);
     547                 :            :         } else {
     548                 :            :                 char pts_name[64];
     549                 :            : 
     550                 :          2 :                 snprintf(pts_name, sizeof(pts_name), PTS_FMT, slave->tie->pty->index);
     551                 :            : 
     552                 :          2 :                 master = pty_open_ptmx_index(O_RDONLY, slave->tie->pty->index);
     553         [ -  + ]:          2 :                 if (master < 0) {
     554                 :          0 :                         pr_perror("Can't open fale %x (index %d)",
     555                 :            :                                   slave->tfe->id, slave->tie->pty->index);
     556                 :            :                         return -1;
     557                 :            :                 }
     558                 :            : 
     559                 :          2 :                 unlock_pty(master);
     560                 :            : 
     561                 :          2 :                 fd = open(pts_name, slave->tfe->flags);
     562         [ -  + ]:          2 :                 if (fd < 0) {
     563                 :          2 :                         pr_perror("Can't open slave %s", pts_name);
     564                 :            :                         goto err;
     565                 :            :                 }
     566                 :            : 
     567                 :            :         }
     568                 :            : 
     569         [ +  - ]:          2 :         if (restore_tty_params(fd, slave))
     570                 :            :                 goto err;
     571                 :            : 
     572                 :            :         /*
     573                 :            :          * If tty is migrated we need to set its group
     574                 :            :          * to the parent group, because signals on key
     575                 :            :          * presses are delivered to a group of terminal.
     576                 :            :          *
     577                 :            :          * Note, at this point the group/session should
     578                 :            :          * be already restored properly thus we can simply
     579                 :            :          * use syscalls intead of lookup via process tree.
     580                 :            :          */
     581         [ -  + ]:          2 :         if (likely(slave->tie->sid == INHERIT_SID)) {
     582         [ #  # ]:          0 :                 if (tty_set_prgp(fd, getpgid(getppid())))
     583                 :            :                         goto err;
     584                 :            :         }
     585                 :            : 
     586         [ +  - ]:          2 :         if (pty_open_slaves(slave))
     587                 :            :                 goto err;
     588                 :            : 
     589                 :          2 :         ret = fd;
     590                 :          2 :         fd = -1;
     591                 :            : err:
     592                 :          2 :         close_safe(&master);
     593                 :          2 :         close_safe(&fd);
     594                 :            :         return ret;
     595                 :            : }
     596                 :            : 
     597                 :          7 : static int pty_open_ptmx(struct tty_info *info)
     598                 :            : {
     599                 :          7 :         int master = -1;
     600                 :            : 
     601                 :          7 :         master = pty_open_ptmx_index(info->tfe->flags, info->tie->pty->index);
     602         [ -  + ]:          7 :         if (master < 0) {
     603                 :          0 :                 pr_perror("Can't open %x (index %d)",
     604                 :            :                           info->tfe->id, info->tie->pty->index);
     605                 :            :                 return -1;
     606                 :            :         }
     607                 :            : 
     608                 :          7 :         unlock_pty(master);
     609                 :            : 
     610         [ +  - ]:          7 :         if (rst_file_params(master, info->tfe->fown, info->tfe->flags))
     611                 :            :                 goto err;
     612                 :            : 
     613         [ +  - ]:          7 :         if (restore_tty_params(master, info))
     614                 :            :                 goto err;
     615                 :            : 
     616         [ -  + ]:          7 :         if (info->tie->packet_mode) {
     617                 :          0 :                 int packet_mode = 1;
     618                 :            : 
     619         [ #  # ]:          0 :                 if (ioctl(master, TIOCPKT, &packet_mode) < 0) {
     620                 :          0 :                         pr_perror("Can't set packed mode on %x",
     621                 :            :                                   info->tfe->id);
     622                 :            :                         goto err;
     623                 :            :                 }
     624                 :            :         }
     625                 :            : 
     626         [ +  - ]:          7 :         if (pty_open_slaves(info))
     627                 :            :                 goto err;
     628                 :            : 
     629         [ -  + ]:          7 :         if (info->tie->locked)
     630                 :          0 :                 lock_pty(master);
     631                 :            : 
     632                 :          7 :         return master;
     633                 :            : err:
     634                 :          7 :         close_safe(&master);
     635                 :            :         return -1;
     636                 :            : }
     637                 :            : 
     638                 :         19 : static int tty_open(struct file_desc *d)
     639                 :            : {
     640                 :         19 :         struct tty_info *info = container_of(d, struct tty_info, d);
     641                 :            : 
     642                 :         19 :         tty_show_pty_info("open", info);
     643                 :            : 
     644         [ +  + ]:         19 :         if (!info->create)
     645                 :         10 :                 return receive_tty(info);
     646                 :            : 
     647         [ +  + ]:          9 :         if (!pty_is_master(info))
     648                 :          2 :                 return pty_open_unpaired_slave(d, info);
     649                 :            : 
     650                 :         19 :         return pty_open_ptmx(info);
     651                 :            : 
     652                 :            : }
     653                 :            : 
     654                 :         19 : static int tty_transport(FdinfoEntry *fe, struct file_desc *d)
     655                 :            : {
     656                 :         19 :         struct tty_info *info = container_of(d, struct tty_info, d);
     657                 :         19 :         return !info->create;
     658                 :            : }
     659                 :            : 
     660                 :         38 : static struct list_head *tty_select_pslist(struct file_desc *d, struct rst_info *ri)
     661                 :            : {
     662                 :            :         /*
     663                 :            :          * Unix98 pty slave peers requires the master peers being
     664                 :            :          * opened before them
     665                 :            :          */
     666                 :            : 
     667         [ +  + ]:         38 :         if (pty_is_master(container_of(d, struct tty_info, d)))
     668                 :         11 :                 return &ri->fds;
     669                 :            :         else
     670                 :         38 :                 return &ri->tty_slaves;
     671                 :            : }
     672                 :            : 
     673                 :            : static struct file_desc_ops tty_desc_ops = {
     674                 :            :         .type           = FD_TYPES__TTY,
     675                 :            :         .open           = tty_open,
     676                 :            :         .post_open      = tty_restore_ctl_terminal,
     677                 :            :         .want_transport = tty_transport,
     678                 :            :         .select_ps_list = tty_select_pslist,
     679                 :            : };
     680                 :            : 
     681                 :         19 : static struct pstree_item *find_first_sid(int sid)
     682                 :            : {
     683                 :            :         struct pstree_item *item;
     684                 :            : 
     685         [ +  - ]:         48 :         for_each_pstree_item(item) {
     686         [ +  + ]:         29 :                 if (item->sid == sid)
     687                 :            :                         return item;
     688                 :            :         }
     689                 :            : 
     690                 :            :         return NULL;
     691                 :            : }
     692                 :            : 
     693                 :         28 : static int tty_find_restoring_task(struct tty_info *info)
     694                 :            : {
     695                 :            :         struct pstree_item *item;
     696                 :            : 
     697                 :            :         /*
     698                 :            :          * The overall scenario is the following (note
     699                 :            :          * we might have corrupted image so don't believe
     700                 :            :          * anything).
     701                 :            :          *
     702                 :            :          * SID is present on a peer
     703                 :            :          * ------------------------
     704                 :            :          *
     705                 :            :          *  - if it's master peer and we have as well a slave
     706                 :            :          *    peer then prefer restore controlling terminal
     707                 :            :          *    via slave peer
     708                 :            :          *
     709                 :            :          *  - if it's master peer without slave, there must be
     710                 :            :          *    a SID leader who will be restoring the peer
     711                 :            :          *
     712                 :            :          *  - if it's a slave peer and no session leader found
     713                 :            :          *    than we need an option to inherit terminal
     714                 :            :          *
     715                 :            :          * No SID present on a peer
     716                 :            :          * ------------------------
     717                 :            :          *
     718                 :            :          *  - if it's a master peer than we are in good shape
     719                 :            :          *    and continue in a normal way, we're the peer keepers
     720                 :            :          *
     721                 :            :          *  - if it's a slave peer and no appropriate master peer
     722                 :            :          *    found we need an option to inherit terminal
     723                 :            :          *
     724                 :            :          * In any case if it's hungup peer, then we jump out
     725                 :            :          * early since it will require fake master peer and
     726                 :            :          * rather non-usable anyway.
     727                 :            :          */
     728                 :            : 
     729         [ +  + ]:         28 :         if (pty_is_hung(info)) {
     730                 :          6 :                 pr_debug("Hungup terminal found id %x\n", info->tfe->id);
     731                 :          6 :                 return 0;
     732                 :            :         }
     733                 :            : 
     734         [ +  + ]:         22 :         if (info->tie->sid) {
     735         [ +  + ]:         16 :                 if (pty_is_master(info)) {
     736         [ +  + ]:          7 :                         if (tty_has_active_pair(info))
     737                 :            :                                 return 0;
     738                 :            :                 }
     739                 :            : 
     740                 :            :                 /*
     741                 :            :                  * Find out the task which is session leader
     742                 :            :                  * and it can restore the controlling terminal
     743                 :            :                  * for us.
     744                 :            :                  */
     745                 :         10 :                 item = find_first_sid(info->tie->sid);
     746 [ +  - ][ +  - ]:         10 :                 if (item && item->pid.virt == item->sid) {
     747                 :         10 :                         pr_info("Set a control terminal %x to %d\n",
     748                 :            :                                 info->tfe->id, info->tie->sid);
     749                 :         10 :                         return prepare_ctl_tty(item->pid.virt,
     750                 :         10 :                                                item->rst,
     751                 :         10 :                                                info->tfe->id);
     752                 :            :                 }
     753                 :            : 
     754         [ #  # ]:          0 :                 if (pty_is_master(info))
     755                 :            :                         goto notask;
     756                 :            :         } else {
     757         [ +  + ]:          6 :                 if (pty_is_master(info))
     758                 :            :                         return 0;
     759         [ -  + ]:          3 :                 if (tty_has_active_pair(info))
     760                 :            :                         return 0;
     761                 :            :         }
     762                 :            : 
     763         [ #  # ]:          0 :         if (opts.shell_job) {
     764                 :          0 :                 pr_info("Inherit terminal for id %x\n", info->tfe->id);
     765                 :          0 :                 info->tie->sid = info->tie->pgrp = INHERIT_SID;
     766                 :          0 :                 return 0;
     767                 :            :         }
     768                 :            : 
     769                 :            : notask:
     770                 :          0 :         pr_err("No task found with sid %d\n", info->tie->sid);
     771                 :         28 :         return -1;
     772                 :            : }
     773                 :            : 
     774                 :        355 : static int tty_setup_orphan_slavery(void)
     775                 :            : {
     776                 :            :         struct tty_info *info, *peer, *m;
     777                 :            : 
     778         [ +  + ]:        368 :         list_for_each_entry(info, &all_ttys, list) {
     779                 :            :                 struct fdinfo_list_entry *a, *b;
     780                 :         13 :                 bool has_leader = false;
     781                 :            : 
     782         [ +  + ]:         13 :                 if (pty_is_master(info))
     783                 :          4 :                         continue;
     784                 :            : 
     785                 :          9 :                 a = file_master(&info->d);
     786                 :          9 :                 m = info;
     787                 :            : 
     788         [ +  + ]:         12 :                 list_for_each_entry(peer, &info->sibling, sibling) {
     789         [ +  + ]:          9 :                         if (pty_is_master(peer)) {
     790                 :            :                                 has_leader = true;
     791                 :            :                                 break;
     792                 :            :                         }
     793                 :            : 
     794                 :            :                         /*
     795                 :            :                          * Same check as in pipes and files -- need to
     796                 :            :                          * order slave ends so that they do not dead lock
     797                 :            :                          * waiting for each other.
     798                 :            :                          */
     799                 :          3 :                         b = file_master(&peer->d);
     800         [ +  - ]:          3 :                         if (fdinfo_rst_prio(b, a)) {
     801                 :          3 :                                 a = b;
     802                 :          3 :                                 m = peer;
     803                 :            :                         }
     804                 :            :                 }
     805                 :            : 
     806         [ +  + ]:          9 :                 if (!has_leader) {
     807                 :          3 :                         m->create = true;
     808                 :          3 :                         pr_debug("Found orphan slave fake leader (%#x)\n",
     809                 :            :                                  m->tfe->id);
     810                 :            :                 }
     811                 :            :         }
     812                 :            : 
     813                 :        355 :         return 0;
     814                 :            : }
     815                 :            : 
     816                 :        355 : int tty_setup_slavery(void)
     817                 :            : {
     818                 :            :         struct tty_info *info, *peer, *m;
     819                 :            : 
     820         [ +  + ]:        368 :         list_for_each_entry(info, &all_ttys, list) {
     821         [ +  - ]:         13 :                 if (tty_find_restoring_task(info))
     822                 :            :                         return -1;
     823                 :            : 
     824                 :         13 :                 peer = info;
     825         [ +  + ]:         28 :                 list_for_each_entry_safe_continue(peer, m, &all_ttys, list) {
     826         [ -  + ]:         15 :                         if (peer->tie->pty->index != info->tie->pty->index)
     827                 :          0 :                                 continue;
     828                 :            : 
     829         [ +  - ]:         15 :                         if (tty_find_restoring_task(peer))
     830                 :            :                                 return -1;
     831                 :            : 
     832                 :         15 :                         list_add(&peer->sibling, &info->sibling);
     833                 :         15 :                         list_del(&peer->list);
     834                 :            :                 }
     835                 :            :         }
     836                 :            : 
     837                 :            :         /*
     838                 :            :          * Print out information about peers.
     839                 :            :          */
     840         [ +  + ]:        368 :         list_for_each_entry(info, &all_ttys, list) {
     841                 :         13 :                 tty_show_pty_info("head", info);
     842         [ +  + ]:         28 :                 list_for_each_entry(peer, &info->sibling, sibling)
     843                 :         15 :                         tty_show_pty_info("    `- sibling", peer);
     844                 :            :         }
     845                 :            : 
     846                 :        355 :         return tty_setup_orphan_slavery();
     847                 :            : }
     848                 :            : 
     849                 :         56 : static int verify_termios(u32 id, TermiosEntry *e)
     850                 :            : {
     851 [ +  + ][ -  + ]:         56 :         if (e && e->n_c_cc < TERMIOS_NCC) {
     852                 :          0 :                 pr_err("pty ID %#x n_c_cc (%d) has wrong value\n",
     853                 :            :                        id, (int)e->n_c_cc);
     854                 :         56 :                 return -1;
     855                 :            :         }
     856                 :            :         return 0;
     857                 :            : }
     858                 :            : 
     859                 :            : #define term_opts_missing_cmp(p, op)            \
     860                 :            :         (!(p)->tie->termios               op      \
     861                 :            :          !(p)->tie->termios_locked        op      \
     862                 :            :          !(p)->tie->winsize)
     863                 :            : 
     864                 :            : #define term_opts_missing_any(p)                \
     865                 :            :         term_opts_missing_cmp(p, ||)
     866                 :            : 
     867                 :            : #define term_opts_missing_all(p)                \
     868                 :            :         term_opts_missing_cmp(p, &&)
     869                 :            : 
     870                 :         28 : static int verify_info(struct tty_info *info)
     871                 :            : {
     872                 :            :         /*
     873                 :            :          * Master peer must have all parameters present,
     874                 :            :          * while slave peer must have either all parameters present
     875                 :            :          * or don't have them at all.
     876                 :            :          */
     877 [ +  + ][ +  - ]:         28 :         if (term_opts_missing_any(info)) {
                 [ -  + ]
     878         [ -  + ]:          6 :                 if (pty_is_master(info)) {
     879                 :          0 :                         pr_err("Corrupted master peer %x\n", info->tfe->id);
     880                 :          0 :                         return -1;
     881 [ +  - ][ +  - ]:          6 :                 } else if (!term_opts_missing_all(info)) {
                 [ -  + ]
     882                 :          0 :                         pr_err("Corrupted slave peer %x\n", info->tfe->id);
     883                 :          0 :                         return -1;
     884                 :            :                 }
     885                 :            :         }
     886                 :            : 
     887   [ +  -  -  + ]:         56 :         if (verify_termios(info->tfe->id, info->tie->termios_locked) ||
     888                 :         28 :             verify_termios(info->tfe->id, info->tie->termios))
     889                 :            :                 return -1;
     890                 :            : 
     891                 :            :         return 0;
     892                 :            : }
     893                 :            : 
     894                 :            : static TtyInfoEntry *lookup_tty_info_entry(u32 id)
     895                 :            : {
     896                 :            :         struct tty_info_entry *e;
     897                 :            : 
     898         [ +  - ]:         37 :         list_for_each_entry(e, &all_tty_info_entries, list) {
     899         [ +  + ]:         37 :                 if (e->tie->id == id)
     900                 :            :                         return e->tie;
     901                 :            :         }
     902                 :            : 
     903                 :            :         return NULL;
     904                 :            : }
     905                 :            : 
     906                 :         22 : static int collect_one_tty_info_entry(void *obj, ProtobufCMessage *msg)
     907                 :            : {
     908                 :         22 :         struct tty_info_entry *info = obj;
     909                 :            : 
     910                 :         22 :         info->tie = pb_msg(msg, TtyInfoEntry);
     911                 :            : 
     912         [ -  + ]:         22 :         if (info->tie->type != TTY_TYPE__PTY) {
     913                 :          0 :                 pr_err("Unexpected TTY type %d (id %x)\n",
     914                 :            :                        info->tie->type, info->tie->id);
     915                 :          0 :                 return -1;
     916                 :            :         }
     917                 :            : 
     918         [ -  + ]:         22 :         if (!info->tie->pty) {
     919                 :          0 :                 pr_err("No PTY data found (id %x), corrupted image?\n",
     920                 :            :                        info->tie->id);
     921                 :          0 :                 return -1;
     922                 :            :         }
     923                 :            : 
     924                 :         22 :         INIT_LIST_HEAD(&info->list);
     925                 :         22 :         list_add(&info->list, &all_tty_info_entries);
     926                 :            : 
     927                 :         22 :         return 0;
     928                 :            : }
     929                 :            : 
     930                 :         28 : static int collect_one_tty(void *obj, ProtobufCMessage *msg)
     931                 :            : {
     932                 :         28 :         struct tty_info *info = obj;
     933                 :            : 
     934                 :         28 :         info->tfe = pb_msg(msg, TtyFileEntry);
     935                 :            : 
     936                 :         56 :         info->tie = lookup_tty_info_entry(info->tfe->tty_info_id);
     937         [ -  + ]:         28 :         if (!info->tie) {
     938                 :          0 :                 pr_err("No tty-info-id %x found on id %x\n",
     939                 :            :                        info->tfe->tty_info_id, info->tfe->id);
     940                 :          0 :                 return -1;
     941                 :            :         }
     942                 :            : 
     943                 :         28 :         INIT_LIST_HEAD(&info->sibling);
     944                 :         56 :         info->major = major(info->tie->rdev);
     945                 :         28 :         info->create = (info->major == TTYAUX_MAJOR);
     946                 :            : 
     947         [ +  - ]:         28 :         if (verify_info(info))
     948                 :            :                 return -1;
     949                 :            : 
     950                 :            :         /*
     951                 :            :          * The tty peers which have no @termios are hunged up,
     952                 :            :          * so don't mark them as active, we create them with
     953                 :            :          * faked master and they are rather a rudiment which
     954                 :            :          * can't be used. Most likely they appear if a user has
     955                 :            :          * dumped program when it was closing a peer.
     956                 :            :          */
     957         [ +  + ]:         28 :         if (info->tie->termios)
     958                 :         22 :                 tty_test_and_set(info->tfe->tty_info_id, tty_active_pairs);
     959                 :            : 
     960                 :         28 :         pr_info("Collected tty ID %#x\n", info->tfe->id);
     961                 :            : 
     962                 :         28 :         list_add(&info->list, &all_ttys);
     963                 :         28 :         file_desc_add(&info->d, info->tfe->id, &tty_desc_ops);
     964                 :            : 
     965                 :         28 :         return 0;
     966                 :            : }
     967                 :            : 
     968                 :        355 : int collect_tty(void)
     969                 :            : {
     970                 :            :         int ret;
     971                 :            : 
     972                 :        355 :         ret = collect_image(CR_FD_TTY_INFO, PB_TTY_INFO,
     973                 :            :                             sizeof(struct tty_info_entry),
     974                 :            :                             collect_one_tty_info_entry);
     975         [ +  - ]:        355 :         if (!ret)
     976                 :        355 :                 ret = collect_image(CR_FD_TTY, PB_TTY,
     977                 :            :                                 sizeof(struct tty_info),
     978                 :            :                                 collect_one_tty);
     979         [ +  - ]:        355 :         if (!ret)
     980                 :        355 :                 ret = tty_verify_active_pairs();
     981                 :            : 
     982                 :        355 :         return ret;
     983                 :            : }
     984                 :            : 
     985                 :            : /* Make sure the ttys we're dumping do belong our process tree */
     986                 :        166 : int dump_verify_tty_sids(void)
     987                 :            : {
     988                 :            :         struct tty_dump_info *dinfo, *n;
     989                 :        166 :         int ret = 0;
     990                 :            : 
     991                 :            :         /*
     992                 :            :          * There might be a cases where we get sid/pgid on
     993                 :            :          * slave peer. For example the application is running
     994                 :            :          * with redirection and we're migrating shell job.
     995                 :            :          *
     996                 :            :          * # ./app < /dev/zero > /dev/zero &2>1
     997                 :            :          *
     998                 :            :          * Which produce a tree like
     999                 :            :          *          PID   PPID  PGID  SID
    1000                 :            :          * root     23786 23784 23786 23786 pts/0 \_ -bash
    1001                 :            :          * root     24246 23786 24246 23786 pts/0   \_ ./app
    1002                 :            :          *
    1003                 :            :          * And the application goes background, then we dump
    1004                 :            :          * it from the same shell.
    1005                 :            :          *
    1006                 :            :          * In this case we simply zap sid/pgid and inherit
    1007                 :            :          * the peer from the current terminal on restore.
    1008                 :            :          */
    1009         [ +  + ]:        181 :         list_for_each_entry_safe(dinfo, n, &all_ttys, list) {
    1010 [ +  - ][ +  + ]:         15 :                 if (!ret && dinfo->sid) {
    1011                 :          9 :                         struct pstree_item *item = find_first_sid(dinfo->sid);
    1012                 :            : 
    1013 [ -  + ][ +  - ]:          9 :                         if (!item || item->pid.virt != dinfo->sid) {
    1014         [ #  # ]:          0 :                                 if (!opts.shell_job) {
    1015                 :          0 :                                         pr_err("Found sid %d pgid %d (%s) on peer fd %d. "
    1016                 :            :                                                "Missing option?\n",
    1017                 :            :                                                dinfo->sid, dinfo->pgrp,
    1018                 :            :                                                tty_type(dinfo->major),
    1019                 :            :                                                dinfo->fd);
    1020                 :          0 :                                         ret = -1;
    1021                 :            :                                 }
    1022                 :            :                         }
    1023                 :            :                 }
    1024         [ +  - ]:         15 :                 xfree(dinfo);
    1025                 :            :         }
    1026                 :            : 
    1027                 :        166 :         return ret;
    1028                 :            : }
    1029                 :            : 
    1030                 :         15 : static int dump_pty_info(int lfd, u32 id, const struct fd_parms *p, int major, int index)
    1031                 :            : {
    1032                 :         15 :         TtyInfoEntry info               = TTY_INFO_ENTRY__INIT;
    1033                 :         15 :         TermiosEntry termios            = TERMIOS_ENTRY__INIT;
    1034                 :         15 :         TermiosEntry termios_locked     = TERMIOS_ENTRY__INIT;
    1035                 :         15 :         WinsizeEntry winsize            = WINSIZE_ENTRY__INIT;
    1036                 :         15 :         TtyPtyEntry pty                 = TTY_PTY_ENTRY__INIT;
    1037                 :            :         struct parasite_tty_args *pti;
    1038                 :            :         struct tty_dump_info *dinfo;
    1039                 :            : 
    1040                 :            :         struct termios t;
    1041                 :            :         struct winsize w;
    1042                 :            : 
    1043                 :         15 :         int ret = -1;
    1044                 :            : 
    1045                 :            :         /*
    1046                 :            :          * Make sure the structures the system provides us
    1047                 :            :          * correlates well with protobuf templates.
    1048                 :            :          */
    1049                 :            :         BUILD_BUG_ON(ARRAY_SIZE(t.c_cc) < TERMIOS_NCC);
    1050                 :            :         BUILD_BUG_ON(sizeof(termios.c_cc) != sizeof(void *));
    1051                 :            :         BUILD_BUG_ON((sizeof(termios.c_cc) * TERMIOS_NCC) < sizeof(t.c_cc));
    1052                 :            : 
    1053                 :         15 :         pti = parasite_dump_tty(p->ctl, p->fd);
    1054         [ +  - ]:         15 :         if (!pti)
    1055                 :            :                 return -1;
    1056                 :            : 
    1057         [ -  + ]:         15 :         dinfo = xmalloc(sizeof(*dinfo));
    1058         [ +  - ]:         15 :         if (!dinfo)
    1059                 :            :                 return -1;
    1060                 :            : 
    1061                 :         15 :         dinfo->id            = id;
    1062                 :         15 :         dinfo->sid           = pti->sid;
    1063                 :         15 :         dinfo->pgrp          = pti->pgrp;
    1064                 :         15 :         dinfo->fd            = p->fd;
    1065                 :         15 :         dinfo->major         = major;
    1066                 :            : 
    1067                 :         15 :         list_add_tail(&dinfo->list, &all_ttys);
    1068                 :            : 
    1069                 :         15 :         info.id                 = id;
    1070                 :         15 :         info.type               = TTY_TYPE__PTY;
    1071                 :         15 :         info.sid                = pti->sid;
    1072                 :         15 :         info.pgrp               = pti->pgrp;
    1073                 :         15 :         info.rdev               = p->stat.st_rdev;
    1074                 :         15 :         info.pty                = &pty;
    1075                 :            : 
    1076                 :         15 :         info.locked             = pti->st_lock;
    1077                 :         15 :         info.exclusive          = pti->st_excl;
    1078                 :         15 :         info.packet_mode        = pti->st_pckt;
    1079                 :            : 
    1080                 :         15 :         pty.index               = index;
    1081                 :            : 
    1082                 :            :         /*
    1083                 :            :          * Nothing we can do on hangin up terminal,
    1084                 :            :          * just write out minimum information we can
    1085                 :            :          * gather.
    1086                 :            :          */
    1087         [ +  + ]:         15 :         if (pti->hangup)
    1088                 :          2 :                 return pb_write_one(fdset_fd(glob_fdset, CR_FD_TTY_INFO), &info, PB_TTY_INFO);
    1089                 :            : 
    1090                 :            :         /*
    1091                 :            :          * Now trace the paired/unpaired ttys. For example
    1092                 :            :          * the task might have slave peer assigned but no
    1093                 :            :          * master peer. Such "detached" master peers are
    1094                 :            :          * not yet supported by our tool and better to
    1095                 :            :          * inform a user about such situatio,
    1096                 :            :          */
    1097                 :         13 :         tty_test_and_set(id, tty_active_pairs);
    1098                 :            : 
    1099                 :         13 :         info.termios            = &termios;
    1100                 :         13 :         info.termios_locked     = &termios_locked;
    1101                 :         13 :         info.winsize            = &winsize;
    1102                 :            : 
    1103                 :         13 :         termios.n_c_cc          = TERMIOS_NCC;
    1104         [ -  + ]:         13 :         termios.c_cc            = xmalloc(pb_repeated_size(&termios, c_cc));
    1105                 :            : 
    1106                 :         13 :         termios_locked.n_c_cc   = TERMIOS_NCC;
    1107         [ -  + ]:         13 :         termios_locked.c_cc     = xmalloc(pb_repeated_size(&termios_locked, c_cc));
    1108                 :            : 
    1109 [ +  - ][ +  - ]:         13 :         if (!termios.c_cc || !termios_locked.c_cc)
    1110                 :            :                 goto out;
    1111                 :            : 
    1112                 :         13 :         memzero(&t, sizeof(t));
    1113         [ -  + ]:         13 :         if (ioctl(lfd, TCGETS, &t) < 0) {
    1114                 :          0 :                 pr_perror("Can't get tty params on %x", id);
    1115                 :          0 :                 goto out;
    1116                 :            :         }
    1117                 :         13 :         termios_copy(&termios, &t);
    1118                 :            : 
    1119                 :         13 :         memzero(&t, sizeof(t));
    1120         [ -  + ]:         13 :         if (ioctl(lfd, TIOCGLCKTRMIOS, &t) < 0) {
    1121                 :          0 :                 pr_perror("Can't get tty locked params on %x", id);
    1122                 :          0 :                 goto out;
    1123                 :            :         }
    1124                 :         13 :         termios_copy(&termios_locked, &t);
    1125                 :            : 
    1126                 :         13 :         memzero(&w, sizeof(w));
    1127         [ -  + ]:         13 :         if (ioctl(lfd, TIOCGWINSZ, &w) < 0) {
    1128                 :          0 :                 pr_perror("Can't get tty window params on %x", id);
    1129                 :          0 :                 goto out;
    1130                 :            :         }
    1131                 :         13 :         winsize_copy(&winsize, &w);
    1132                 :            : 
    1133                 :         13 :         ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_TTY_INFO), &info, PB_TTY_INFO);
    1134                 :            : out:
    1135         [ +  - ]:         13 :         xfree(termios.c_cc);
    1136         [ +  - ]:         15 :         xfree(termios_locked.c_cc);
    1137                 :            :         return ret;
    1138                 :            : }
    1139                 :            : 
    1140                 :         19 : static int dump_one_pty(int lfd, u32 id, const struct fd_parms *p)
    1141                 :            : {
    1142                 :         19 :         TtyFileEntry e = TTY_FILE_ENTRY__INIT;
    1143                 :         19 :         int ret = 0, major, index;
    1144                 :            : 
    1145                 :         19 :         pr_info("Dumping tty %d with id %#x\n", lfd, id);
    1146                 :            : 
    1147                 :         38 :         major = major(p->stat.st_rdev);
    1148                 :         19 :         index = parse_index(id, lfd, major);
    1149         [ +  - ]:         19 :         if (index < 0)
    1150                 :            :                 return -1;
    1151                 :            : 
    1152                 :         19 :         e.id            = id;
    1153                 :         19 :         e.tty_info_id   = tty_gen_id(major, index);
    1154                 :         19 :         e.flags         = p->flags;
    1155                 :         19 :         e.fown          = (FownEntry *)&p->fown;
    1156                 :            : 
    1157                 :            :         /*
    1158                 :            :          * FIXME
    1159                 :            :          *
    1160                 :            :          * Figure out how to fetch data buffered in terminal.
    1161                 :            :          * For a while simply flush before dumping. Note
    1162                 :            :          * we don't check for errors here since it makes
    1163                 :            :          * no sense anyway, the buffered data is not handled
    1164                 :            :          * properly yet.
    1165                 :            :          *
    1166                 :            :          * Note as well that if we have only one peer here
    1167                 :            :          * the external end might be sending the data to us
    1168                 :            :          * again and again while kernel buffer is not full,
    1169                 :            :          * this might lead to endless SIGTTOU signal delivery
    1170                 :            :          * to the dumpee, ruining checkpoint procedure.
    1171                 :            :          *
    1172                 :            :          * So simply do not flush the line while we dump
    1173                 :            :          * parameters tty never was being a guaranteed delivery
    1174                 :            :          * transport anyway.
    1175                 :            :          */
    1176                 :            : 
    1177         [ +  + ]:         19 :         if (!tty_test_and_set(e.tty_info_id, tty_bitmap))
    1178                 :         15 :                 ret = dump_pty_info(lfd, e.tty_info_id, p, major, index);
    1179                 :            : 
    1180         [ +  - ]:         19 :         if (!ret)
    1181                 :         19 :                 ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_TTY), &e, PB_TTY);
    1182                 :            :         return ret;
    1183                 :            : }
    1184                 :            : 
    1185                 :            : static const struct fdtype_ops tty_ops = {
    1186                 :            :         .type   = FD_TYPES__TTY,
    1187                 :            :         .dump   = dump_one_pty,
    1188                 :            : };
    1189                 :            : 
    1190                 :         19 : int dump_tty(struct fd_parms *p, int lfd, const struct cr_fdset *set)
    1191                 :            : {
    1192                 :         19 :         return do_dump_gen_file(p, lfd, &tty_ops, set);
    1193                 :            : }
    1194                 :            : 
    1195                 :        380 : int tty_prep_fds(void)
    1196                 :            : {
    1197                 :        380 :         self_stdin = get_service_fd(SELF_STDIN_OFF);
    1198                 :            : 
    1199         [ -  + ]:        380 :         if (!isatty(STDIN_FILENO)) {
    1200                 :          0 :                 pr_err("Standart stream is not a terminal, aborting\n");
    1201                 :          0 :                 return -1;
    1202                 :            :         }
    1203                 :            : 
    1204         [ -  + ]:        380 :         if (dup2(STDIN_FILENO, self_stdin) < 0) {
    1205                 :          0 :                 self_stdin = -1;
    1206                 :          0 :                 pr_perror("Can't dup stdin to SELF_STDIN_OFF");
    1207                 :        380 :                 return -1;
    1208                 :            :         }
    1209                 :            : 
    1210                 :            :         return 0;
    1211                 :            : }
    1212                 :            : 
    1213                 :        349 : void tty_fini_fds(void)
    1214                 :            : {
    1215                 :        349 :         close_safe(&self_stdin);
    1216                 :        349 : }

Generated by: LCOV version 1.9