int raw_export_start(RawExport *e, const char *path, int fd, ImportCompressType compress) { _cleanup_close_ int sfd = -1, tfd = -1; int r; assert(e); assert(path); assert(fd >= 0); assert(compress < _IMPORT_COMPRESS_TYPE_MAX); assert(compress != IMPORT_COMPRESS_UNKNOWN); if (e->output_fd >= 0) return -EBUSY; r = fd_nonblock(fd, true); if (r < 0) return r; r = free_and_strdup(&e->path, path); if (r < 0) return r; sfd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (sfd < 0) return -errno; if (fstat(sfd, &e->st) < 0) return -errno; r = stat_verify_regular(&e->st); if (r < 0) return r; /* Try to take a reflink snapshot of the file, if we can t make the export atomic */ tfd = reflink_snapshot(sfd, path); if (tfd >= 0) e->input_fd = TAKE_FD(tfd); else e->input_fd = TAKE_FD(sfd); r = import_compress_init(&e->compress, compress); if (r < 0) return r; r = sd_event_add_io(e->event, &e->output_event_source, fd, EPOLLOUT, raw_export_on_output, e); if (r == -EPERM) { r = sd_event_add_defer(e->event, &e->output_event_source, raw_export_on_defer, e); if (r < 0) return r; r = sd_event_source_set_enabled(e->output_event_source, SD_EVENT_ON); } if (r < 0) return r; e->output_fd = fd; return r; }
static int run(int argc, char *argv[]) { _cleanup_close_ int fd = -1, saved_stderr = -1; int r; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) return r; fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); if (fd < 0) return log_error_errno(fd, "Failed to create stream fd: %m"); saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); r = rearrange_stdio(STDIN_FILENO, fd, fd); /* Invalidates fd on succcess + error! */ TAKE_FD(fd); if (r < 0) return log_error_errno(r, "Failed to rearrange stdout/stderr: %m"); if (argc <= optind) (void) execl("/bin/cat", "/bin/cat", NULL); else (void) execvp(argv[optind], argv + optind); r = -errno; /* Let's try to restore a working stderr, so we can print the error message */ if (saved_stderr >= 0) (void) dup3(saved_stderr, STDERR_FILENO, 0); return log_error_errno(r, "Failed to execute process: %m"); }
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { union sockaddr_union src = { .in6.sin6_family = AF_INET6, .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT), .in6.sin6_scope_id = index, }; _cleanup_close_ int s = -1; int r; assert(index > 0); assert(local_address); src.in6.sin6_addr = *local_address; s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP); if (s < 0) return -errno; r = setsockopt_int(s, IPPROTO_IPV6, IPV6_V6ONLY, true); if (r < 0) return r; r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, false); if (r < 0) return r; r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true); if (r < 0) return r; r = bind(s, &src.sa, sizeof(src.in6)); if (r < 0) return -errno; return TAKE_FD(s); } int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, const void *packet, size_t len) { union sockaddr_union dest = { .in6.sin6_family = AF_INET6, .in6.sin6_port = htobe16(DHCP6_PORT_SERVER), }; int r; assert(server_address); memcpy(&dest.in6.sin6_addr, server_address, sizeof(dest.in6.sin6_addr)); r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in6)); if (r < 0) return -errno; return 0; }
static int raw_pull_maybe_convert_qcow2(RawPull *i) { _cleanup_close_ int converted_fd = -1; _cleanup_free_ char *t = NULL; int r; assert(i); assert(i->raw_job); r = qcow2_detect(i->raw_job->disk_fd); if (r < 0) return log_error_errno(r, "Failed to detect whether this is a QCOW2 image: %m"); if (r == 0) return 0; /* This is a QCOW2 image, let's convert it */ r = tempfn_random(i->final_path, NULL, &t); if (r < 0) return log_oom(); converted_fd = open(t, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664); if (converted_fd < 0) return log_error_errno(errno, "Failed to create %s: %m", t); r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) log_warning_errno(r, "Failed to set file attributes on %s: %m", t); log_info("Unpacking QCOW2 file."); r = qcow2_convert(i->raw_job->disk_fd, converted_fd); if (r < 0) { unlink(t); return log_error_errno(r, "Failed to convert qcow2 image: %m"); } (void) unlink(i->temp_path); free_and_replace(i->temp_path, t); safe_close(i->raw_job->disk_fd); i->raw_job->disk_fd = TAKE_FD(converted_fd); return 1; }
static int save_external_coredump( const char *context[_CONTEXT_MAX], int input_fd, char **ret_filename, int *ret_node_fd, int *ret_data_fd, uint64_t *ret_size, bool *ret_truncated) { _cleanup_free_ char *fn = NULL, *tmp = NULL; _cleanup_close_ int fd = -1; uint64_t rlimit, process_limit, max_size; struct stat st; uid_t uid; int r; assert(context); assert(ret_filename); assert(ret_node_fd); assert(ret_data_fd); assert(ret_size); r = parse_uid(context[CONTEXT_UID], &uid); if (r < 0) return log_error_errno(r, "Failed to parse UID: %m"); r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit); if (r < 0) return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]); if (rlimit < page_size()) { /* Is coredumping disabled? Then don't bother saving/processing the coredump. * Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses * ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */ log_info("Resource limits disable core dumping for process %s (%s).", context[CONTEXT_PID], context[CONTEXT_COMM]); return -EBADSLT; } process_limit = MAX(arg_process_size_max, storage_size_max()); if (process_limit == 0) { log_debug("Limits for coredump processing and storage are both 0, not dumping core."); return -EBADSLT; } /* Never store more than the process configured, or than we actually shall keep or process */ max_size = MIN(rlimit, process_limit); r = make_filename(context, &fn); if (r < 0) return log_error_errno(r, "Failed to determine coredump file name: %m"); mkdir_p_label("/var/lib/systemd/coredump", 0755); fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp); if (fd < 0) return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn); r = copy_bytes(input_fd, fd, max_size, 0); if (r < 0) { log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]); goto fail; } *ret_truncated = r == 1; if (*ret_truncated) log_struct(LOG_INFO, LOG_MESSAGE("Core file was truncated to %zu bytes.", max_size), "SIZE_LIMIT=%zu", max_size, "MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR); if (fstat(fd, &st) < 0) { log_error_errno(errno, "Failed to fstat core file %s: %m", coredump_tmpfile_name(tmp)); goto fail; } if (lseek(fd, 0, SEEK_SET) == (off_t) -1) { log_error_errno(errno, "Failed to seek on %s: %m", coredump_tmpfile_name(tmp)); goto fail; } #if HAVE_XZ || HAVE_LZ4 /* If we will remove the coredump anyway, do not compress. */ if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) { _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL; _cleanup_close_ int fd_compressed = -1; fn_compressed = strappend(fn, COMPRESSED_EXT); if (!fn_compressed) { log_oom(); goto uncompressed; } fd_compressed = open_tmpfile_linkable(fn_compressed, O_RDWR|O_CLOEXEC, &tmp_compressed); if (fd_compressed < 0) { log_error_errno(fd_compressed, "Failed to create temporary file for coredump %s: %m", fn_compressed); goto uncompressed; } r = compress_stream(fd, fd_compressed, -1); if (r < 0) { log_error_errno(r, "Failed to compress %s: %m", coredump_tmpfile_name(tmp_compressed)); goto fail_compressed; } r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid); if (r < 0) goto fail_compressed; /* OK, this worked, we can get rid of the uncompressed version now */ if (tmp) unlink_noerrno(tmp); *ret_filename = TAKE_PTR(fn_compressed); /* compressed */ *ret_node_fd = TAKE_FD(fd_compressed); /* compressed */ *ret_data_fd = TAKE_FD(fd); /* uncompressed */ *ret_size = (uint64_t) st.st_size; /* uncompressed */ return 0; fail_compressed: if (tmp_compressed) (void) unlink(tmp_compressed); } uncompressed: #endif r = fix_permissions(fd, tmp, fn, context, uid); if (r < 0) goto fail; *ret_filename = TAKE_PTR(fn); *ret_data_fd = TAKE_FD(fd); *ret_node_fd = -1; *ret_size = (uint64_t) st.st_size; return 0; fail: if (tmp) (void) unlink(tmp); return r; }
static int setup_machine_raw(uint64_t size, sd_bus_error *error) { _cleanup_free_ char *tmp = NULL; _cleanup_close_ int fd = -1; struct statvfs ss; pid_t pid = 0; int r; /* We want to be able to make use of btrfs-specific file * system features, in particular subvolumes, reflinks and * quota. Hence, if we detect that /var/lib/machines.raw is * not located on btrfs, let's create a loopback file, place a * btrfs file system into it, and mount it to * /var/lib/machines. */ fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); if (fd >= 0) return TAKE_FD(fd); if (errno != ENOENT) return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m"); r = tempfn_xxxxxx("/var/lib/machines.raw", NULL, &tmp); if (r < 0) return r; (void) mkdir_p_label("/var/lib", 0755); fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600); if (fd < 0) return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m"); if (fstatvfs(fd, &ss) < 0) { r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m"); goto fail; } if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) { r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines."); goto fail; } if (ftruncate(fd, size) < 0) { r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m"); goto fail; } r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid); if (r < 0) { sd_bus_error_set_errnof(error, r, "Failed to fork mkfs.btrfs: %m"); goto fail; } if (r == 0) { /* Child */ fd = safe_close(fd); execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL); if (errno == ENOENT) _exit(99); _exit(EXIT_FAILURE); } r = wait_for_terminate_and_check("mkfs", pid, 0); pid = 0; if (r < 0) { sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m"); goto fail; } if (r == 99) { r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing"); goto fail; } if (r != EXIT_SUCCESS) { r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", r); goto fail; } r = rename_noreplace(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw"); if (r < 0) { sd_bus_error_set_errnof(error, r, "Failed to move /var/lib/machines.raw into place: %m"); goto fail; } return TAKE_FD(fd); fail: unlink_noerrno(tmp); if (pid > 1) kill_and_sigcont(pid, SIGKILL); return r; }
int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) { struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ /* Sender Hardware Address must be different from our own */ BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])),/* A <- 4 bytes of client's MAC */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */ BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])),/* A <- remainder of client's MAC */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ /* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */ BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */ BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ }; struct sock_fprog fprog = { .len = ELEMENTSOF(filter), .filter = (struct sock_filter*) filter }; union sockaddr_union link = { .ll.sll_family = AF_PACKET, .ll.sll_protocol = htobe16(ETH_P_ARP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }; _cleanup_close_ int s = -1; int r; assert(ifindex > 0); s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (s < 0) return -errno; r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); if (r < 0) return -errno; r = bind(s, &link.sa, sizeof(link.ll)); if (r < 0) return -errno; return TAKE_FD(s); } static int arp_send_packet(int fd, int ifindex, be32_t pa, const struct ether_addr *ha, bool announce) { union sockaddr_union link = { .ll.sll_family = AF_PACKET, .ll.sll_protocol = htobe16(ETH_P_ARP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }; struct ether_arp arp = { .ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */ .ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */ .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */ .ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */ .ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */ }; int r; assert(fd >= 0); assert(pa != 0); assert(ha); memcpy(&arp.arp_sha, ha, ETH_ALEN); memcpy(&arp.arp_tpa, &pa, sizeof(pa)); if (announce) memcpy(&arp.arp_spa, &pa, sizeof(pa)); r = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll)); if (r < 0) return -errno; return 0; } int arp_send_probe(int fd, int ifindex, be32_t pa, const struct ether_addr *ha) { return arp_send_packet(fd, ifindex, pa, ha, false); } int arp_send_announcement(int fd, int ifindex, be32_t pa, const struct ether_addr *ha) { return arp_send_packet(fd, ifindex, pa, ha, true); }