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

Generated by: LCOV version 1.9