Skip to content

Commit 40205d7

Browse files
committed
machined: add OpenMachinePTY() bus call for allocating a PTY device within a container
Then, port "machinectl" over to make use of it.
1 parent 095dc59 commit 40205d7

File tree

4 files changed

+151
-111
lines changed

4 files changed

+151
-111
lines changed

src/machine/machine-dbus.c

Lines changed: 112 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,14 @@ int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void
319319

320320
r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
321321
if (r < 0)
322-
return sd_bus_error_set_errno(error, r);
322+
return r;
323323

324324
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
325-
return sd_bus_error_set_errno(error, -errno);
325+
return -errno;
326326

327327
child = fork();
328328
if (child < 0)
329-
return sd_bus_error_set_errno(error, -errno);
329+
return -errno;
330330

331331
if (child == 0) {
332332
_cleanup_close_ int fd = -1;
@@ -355,37 +355,137 @@ int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void
355355

356356
f = fdopen(pair[0], "re");
357357
if (!f)
358-
return sd_bus_error_set_errno(error, -errno);
358+
return -errno;
359359

360360
pair[0] = -1;
361361

362362
r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
363363
if (r < 0)
364-
return sd_bus_error_set_errno(error, r);
364+
return r;
365365

366366
r = wait_for_terminate(child, &si);
367367
if (r < 0)
368-
return sd_bus_error_set_errno(error, r);
368+
return r;
369369
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
370-
return sd_bus_error_set_errno(error, EIO);
370+
return -EIO;
371371

372372
r = sd_bus_message_new_method_return(message, &reply);
373373
if (r < 0)
374-
return sd_bus_error_set_errno(error, r);
374+
return r;
375375

376376
r = sd_bus_message_open_container(reply, 'a', "{ss}");
377377
if (r < 0)
378-
return sd_bus_error_set_errno(error, r);
378+
return r;
379379

380380
STRV_FOREACH_PAIR(k, v, l) {
381381
r = sd_bus_message_append(reply, "{ss}", *k, *v);
382382
if (r < 0)
383-
return sd_bus_error_set_errno(error, r);
383+
return r;
384384
}
385385

386386
r = sd_bus_message_close_container(reply);
387387
if (r < 0)
388-
return sd_bus_error_set_errno(error, r);
388+
return r;
389+
390+
return sd_bus_send(bus, reply, NULL);
391+
}
392+
393+
int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
394+
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
395+
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
396+
_cleanup_close_pair_ int pair[2] = { -1, -1 };
397+
_cleanup_close_ int master = -1;
398+
union {
399+
struct cmsghdr cmsghdr;
400+
uint8_t buf[CMSG_SPACE(sizeof(int))];
401+
} control = {};
402+
struct msghdr mh = {
403+
.msg_control = &control,
404+
.msg_controllen = sizeof(control),
405+
};
406+
Machine *m = userdata;
407+
struct cmsghdr *cmsg;
408+
siginfo_t si;
409+
pid_t child;
410+
int r;
411+
412+
assert(bus);
413+
assert(message);
414+
assert(m);
415+
416+
r = namespace_open(m->leader, &pidnsfd, &mntnsfd, NULL, &rootfd);
417+
if (r < 0)
418+
return r;
419+
420+
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
421+
return -errno;
422+
423+
child = fork();
424+
if (child < 0)
425+
return -errno;
426+
427+
if (child == 0) {
428+
pair[0] = safe_close(pair[0]);
429+
430+
r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
431+
if (r < 0)
432+
_exit(EXIT_FAILURE);
433+
434+
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC);
435+
if (master < 0)
436+
_exit(EXIT_FAILURE);
437+
438+
cmsg = CMSG_FIRSTHDR(&mh);
439+
cmsg->cmsg_level = SOL_SOCKET;
440+
cmsg->cmsg_type = SCM_RIGHTS;
441+
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
442+
memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
443+
444+
mh.msg_controllen = cmsg->cmsg_len;
445+
446+
if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
447+
_exit(EXIT_FAILURE);
448+
449+
_exit(EXIT_SUCCESS);
450+
}
451+
452+
pair[1] = safe_close(pair[1]);
453+
454+
r = wait_for_terminate(child, &si);
455+
if (r < 0)
456+
return r;
457+
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
458+
return -EIO;
459+
460+
if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
461+
return -errno;
462+
463+
for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
464+
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
465+
int *fds;
466+
unsigned n_fds;
467+
468+
fds = (int*) CMSG_DATA(cmsg);
469+
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
470+
471+
if (n_fds != 1) {
472+
close_many(fds, n_fds);
473+
return -EIO;
474+
}
475+
476+
master = fds[0];
477+
}
478+
479+
if (master < 0)
480+
return -EIO;
481+
482+
r = sd_bus_message_new_method_return(message, &reply);
483+
if (r < 0)
484+
return r;
485+
486+
r = sd_bus_message_append(reply, "hs", master, ptsname(master));
487+
if (r < 0)
488+
return r;
389489

390490
return sd_bus_send(bus, reply, NULL);
391491
}
@@ -407,6 +507,7 @@ const sd_bus_vtable machine_vtable[] = {
407507
SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
408508
SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
409509
SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
510+
SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
410511
SD_BUS_VTABLE_END
411512
};
412513

src/machine/machine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *use
104104
int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
105105
int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
106106
int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
107+
int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
107108

108109
int machine_send_signal(Machine *m, bool new_machine);
109110
int machine_send_create_reply(Machine *m, sd_bus_error *error);

src/machine/machinectl.c

Lines changed: 16 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,106 +1010,17 @@ static int bind_mount(int argc, char *argv[], void *userdata) {
10101010
return r;
10111011
}
10121012

1013-
static int openpt_in_namespace(pid_t pid, int flags) {
1014-
_cleanup_close_pair_ int pair[2] = { -1, -1 };
1015-
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
1016-
union {
1017-
struct cmsghdr cmsghdr;
1018-
uint8_t buf[CMSG_SPACE(sizeof(int))];
1019-
} control = {};
1020-
struct msghdr mh = {
1021-
.msg_control = &control,
1022-
.msg_controllen = sizeof(control),
1023-
};
1024-
struct cmsghdr *cmsg;
1025-
int master = -1, r;
1026-
pid_t child;
1027-
siginfo_t si;
1028-
1029-
assert(pid > 0);
1030-
1031-
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
1032-
if (r < 0)
1033-
return r;
1034-
1035-
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1036-
return -errno;
1037-
1038-
child = fork();
1039-
if (child < 0)
1040-
return -errno;
1041-
1042-
if (child == 0) {
1043-
pair[0] = safe_close(pair[0]);
1044-
1045-
r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
1046-
if (r < 0)
1047-
_exit(EXIT_FAILURE);
1048-
1049-
master = posix_openpt(flags);
1050-
if (master < 0)
1051-
_exit(EXIT_FAILURE);
1052-
1053-
cmsg = CMSG_FIRSTHDR(&mh);
1054-
cmsg->cmsg_level = SOL_SOCKET;
1055-
cmsg->cmsg_type = SCM_RIGHTS;
1056-
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1057-
memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
1058-
1059-
mh.msg_controllen = cmsg->cmsg_len;
1060-
1061-
if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
1062-
_exit(EXIT_FAILURE);
1063-
1064-
_exit(EXIT_SUCCESS);
1065-
}
1066-
1067-
pair[1] = safe_close(pair[1]);
1068-
1069-
r = wait_for_terminate(child, &si);
1070-
if (r < 0)
1071-
return r;
1072-
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1073-
return -EIO;
1074-
1075-
if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
1076-
return -errno;
1077-
1078-
for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
1079-
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
1080-
int *fds;
1081-
unsigned n_fds;
1082-
1083-
fds = (int*) CMSG_DATA(cmsg);
1084-
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
1085-
1086-
if (n_fds != 1) {
1087-
close_many(fds, n_fds);
1088-
return -EIO;
1089-
}
1090-
1091-
master = fds[0];
1092-
}
1093-
1094-
if (master < 0)
1095-
return -EIO;
1096-
1097-
return master;
1098-
}
1099-
11001013
static int login_machine(int argc, char *argv[], void *userdata) {
11011014
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
11021015
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
11031016
_cleanup_bus_close_unref_ sd_bus *container_bus = NULL;
11041017
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
11051018
_cleanup_event_unref_ sd_event *event = NULL;
1106-
_cleanup_close_ int master = -1;
11071019
_cleanup_free_ char *getty = NULL;
1020+
int master = -1, r, ret = 0;
11081021
sd_bus *bus = userdata;
11091022
const char *pty, *p;
1110-
pid_t leader;
11111023
sigset_t mask;
1112-
int r, ret = 0;
11131024
char last_char = 0;
11141025

11151026
assert(bus);
@@ -1127,17 +1038,22 @@ static int login_machine(int argc, char *argv[], void *userdata) {
11271038
if (r < 0)
11281039
return log_error_errno(r, "Failed to attach bus to event loop: %m");
11291040

1130-
r = machine_get_leader(bus, argv[1], &leader);
1131-
if (r < 0)
1041+
r = sd_bus_call_method(bus,
1042+
"org.freedesktop.machine1",
1043+
"/org/freedesktop/machine1",
1044+
"org.freedesktop.machine1.Manager",
1045+
"OpenMachinePTY",
1046+
&error,
1047+
&reply,
1048+
"s", argv[1]);
1049+
if (r < 0) {
1050+
log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
11321051
return r;
1052+
}
11331053

1134-
master = openpt_in_namespace(leader, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
1135-
if (master < 0)
1136-
return log_error_errno(master, "Failed to acquire pseudo tty: %m");
1137-
1138-
pty = ptsname(master);
1139-
if (!pty)
1140-
return log_error_errno(errno, "Failed to get pty name: %m");
1054+
r = sd_bus_message_read(reply, "hs", &master, &pty);
1055+
if (r < 0)
1056+
return r;
11411057

11421058
p = startswith(pty, "/dev/pts/");
11431059
if (!p) {
@@ -1161,7 +1077,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
11611077
"/org/freedesktop/systemd1",
11621078
"org.freedesktop.systemd1.Manager",
11631079
"StartUnit",
1164-
&error, &reply,
1080+
&error, NULL,
11651081
"ss", getty, "replace");
11661082
if (r < 0) {
11671083
log_error("Failed to start getty service: %s", bus_error_message(&error, r));

src/machine/machined-dbus.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,27 @@ static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userda
515515
return sd_bus_send(bus, reply, NULL);
516516
}
517517

518+
static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
519+
Manager *m = userdata;
520+
Machine *machine;
521+
const char *name;
522+
int r;
523+
524+
assert(bus);
525+
assert(message);
526+
assert(m);
527+
528+
r = sd_bus_message_read(message, "s", &name);
529+
if (r < 0)
530+
return sd_bus_error_set_errno(error, r);
531+
532+
machine = hashmap_get(m->machines, name);
533+
if (!machine)
534+
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
535+
536+
return bus_machine_method_open_pty(bus, message, machine, error);
537+
}
538+
518539
const sd_bus_vtable manager_vtable[] = {
519540
SD_BUS_VTABLE_START(0),
520541
SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -530,6 +551,7 @@ const sd_bus_vtable manager_vtable[] = {
530551
SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
531552
SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
532553
SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
554+
SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
533555
SD_BUS_SIGNAL("MachineNew", "so", 0),
534556
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
535557
SD_BUS_VTABLE_END

0 commit comments

Comments
 (0)