int decompress_stream_xz(int fdf, int fdt, off_t max_bytes) { #ifdef HAVE_XZ _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT; lzma_ret ret; uint8_t buf[BUFSIZ], out[BUFSIZ]; lzma_action action = LZMA_RUN; assert(fdf >= 0); assert(fdt >= 0); ret = lzma_stream_decoder(&s, UINT64_MAX, 0); if (ret != LZMA_OK) { log_error("Failed to initialize XZ decoder: code %u", ret); return -ENOMEM; } for (;;) { if (s.avail_in == 0 && action == LZMA_RUN) { ssize_t n; n = read(fdf, buf, sizeof(buf)); if (n < 0) return -errno; if (n == 0) action = LZMA_FINISH; else { s.next_in = buf; s.avail_in = n; } } if (s.avail_out == 0) { s.next_out = out; s.avail_out = sizeof(out); } ret = lzma_code(&s, action); if (ret != LZMA_OK && ret != LZMA_STREAM_END) { log_error("Decompression failed: code %u", ret); return -EBADMSG; } if (s.avail_out == 0 || ret == LZMA_STREAM_END) { ssize_t n, k; n = sizeof(out) - s.avail_out; if (max_bytes != -1) { if (max_bytes < n) return -EFBIG; max_bytes -= n; } k = loop_write(fdt, out, n, false); if (k < 0) return k; if (ret == LZMA_STREAM_END) { log_debug("XZ decompression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)", s.total_in, s.total_out, (double) s.total_out / s.total_in * 100); return 0; } } } #else log_error("Cannot decompress file. Compiled without XZ support."); return -EPROTONOSUPPORT; #endif }
int compress_stream_xz(int fdf, int fdt, off_t max_bytes) { #ifdef HAVE_XZ _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT; lzma_ret ret; uint8_t buf[BUFSIZ], out[BUFSIZ]; lzma_action action = LZMA_RUN; assert(fdf >= 0); assert(fdt >= 0); ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64); if (ret != LZMA_OK) { log_error("Failed to initialize XZ encoder: code %u", ret); return -EINVAL; } for (;;) { if (s.avail_in == 0 && action == LZMA_RUN) { size_t m = sizeof(buf); ssize_t n; if (max_bytes != -1 && m > (size_t) max_bytes) m = max_bytes; n = read(fdf, buf, m); if (n < 0) return -errno; if (n == 0) action = LZMA_FINISH; else { s.next_in = buf; s.avail_in = n; if (max_bytes != -1) { assert(max_bytes >= n); max_bytes -= n; } } } if (s.avail_out == 0) { s.next_out = out; s.avail_out = sizeof(out); } ret = lzma_code(&s, action); if (ret != LZMA_OK && ret != LZMA_STREAM_END) { log_error("Compression failed: code %u", ret); return -EBADMSG; } if (s.avail_out == 0 || ret == LZMA_STREAM_END) { ssize_t n, k; n = sizeof(out) - s.avail_out; k = loop_write(fdt, out, n, false); if (k < 0) return k; if (ret == LZMA_STREAM_END) { log_debug("XZ compression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)", s.total_in, s.total_out, (double) s.total_out / s.total_in * 100); return 0; } } } #else return -EPROTONOSUPPORT; #endif }
int compress_stream_lz4(int fdf, int fdt, off_t max_bytes) { #ifdef HAVE_LZ4 _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *out = NULL; char *buf; LZ4_stream_t lz4_data = {}; le32_t header; size_t total_in = 0, total_out = sizeof(header); ssize_t n; assert(fdf >= 0); assert(fdt >= 0); buf1 = malloc(LZ4_BUFSIZE); buf2 = malloc(LZ4_BUFSIZE); out = malloc(LZ4_COMPRESSBOUND(LZ4_BUFSIZE)); if (!buf1 || !buf2 || !out) return log_oom(); buf = buf1; for (;;) { size_t m; int r; m = LZ4_BUFSIZE; if (max_bytes != -1 && m > (size_t) max_bytes - total_in) m = max_bytes - total_in; n = read(fdf, buf, m); if (n < 0) return -errno; if (n == 0) break; total_in += n; r = LZ4_compress_continue(&lz4_data, buf, out, n); if (r == 0) { log_error("LZ4 compression failed."); return -EBADMSG; } header = htole32(r); errno = 0; n = write(fdt, &header, sizeof(header)); if (n < 0) return -errno; if (n != sizeof(header)) return errno ? -errno : -EIO; n = loop_write(fdt, out, r, false); if (n < 0) return n; total_out += sizeof(header) + r; buf = buf == buf1 ? buf2 : buf1; } header = htole32(0); n = write(fdt, &header, sizeof(header)); if (n < 0) return -errno; if (n != sizeof(header)) return errno ? -errno : -EIO; log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)", total_in, total_out, (double) total_out / total_in * 100); return 0; #else return -EPROTONOSUPPORT; #endif }
int main(int argc, char *argv[]) { _cleanup_close_ int seed_fd = -1, random_fd = -1; _cleanup_free_ void* buf = NULL; size_t buf_size = 0; ssize_t k; int r; FILE *f; bool cleanup_seed_file = true; if (argc != 2) { log_error("This program requires one argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); /* Read pool size, if possible */ f = fopen("/proc/sys/kernel/random/poolsize", "re"); if (f) { if (fscanf(f, "%zu", &buf_size) > 0) { /* poolsize is in bits on 2.6, but we want bytes */ buf_size /= 8; } fclose(f); } if (buf_size <= POOL_SIZE_MIN) buf_size = POOL_SIZE_MIN; buf = malloc(buf_size); if (!buf) { r = log_oom(); goto finish; } r = mkdir_parents_label(RANDOM_SEED, 0755); if (r < 0) { log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m"); goto finish; } /* When we load the seed we read it and write it to the device * and then immediately update the saved seed with new data, * to make sure the next boot gets seeded differently. */ if (streq(argv[1], "load")) { seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); if (seed_fd < 0) { seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (seed_fd < 0) { log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m"); r = -errno; goto finish; } cleanup_seed_file = false; } random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { log_error_errno(errno, "Failed to open /dev/urandom: %m"); r = -errno; goto finish; } } k = loop_read(seed_fd, buf, buf_size, false); if (k <= 0) { if (r != 0) log_error_errno(errno, "Failed to read seed from " RANDOM_SEED ": %m"); r = k == 0 ? -EIO : (int) k; } else { lseek(seed_fd, 0, SEEK_SET); r = loop_write(random_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write seed to /dev/urandom: %m"); } } else if (streq(argv[1], "save")) { seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); if (seed_fd < 0) { log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m"); r = -errno; goto finish; } random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (random_fd < 0) { log_error_errno(errno, "Failed to open /dev/urandom: %m"); r = -errno; goto finish; } } else { log_error("Unknown verb %s.", argv[1]); r = -EINVAL; goto finish; } if (cleanup_seed_file) { /* This is just a safety measure. Given that we are root and * most likely created the file ourselves the mode and owner * should be correct anyway. */ fchmod(seed_fd, 0600); fchown(seed_fd, 0, 0); k = loop_read(random_fd, buf, buf_size, false); if (k <= 0) { log_error("Failed to read new seed from /dev/urandom: %s", r < 0 ? strerror(-r) : "EOF"); r = k == 0 ? -EIO : (int) k; } else { r = loop_write(seed_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write new random seed file: %m"); } } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static bool log2flash_fa(const char *fname, const char *fmt, va_list arglist) { bool retcode=false; // assume operation failed. int fd; time_t cur_time; time_t duration=0; struct tm *ptm; // structure to obtain date information char printbuf[MAX_WRITE_CHAR+2]; // size + '\n' + '\0' int bytes_to_write; int lock_to; // time out for flock() DPRINT( "log2flash_fa() called\n" ); fd = open(fname, O_RDWR|O_CREAT|O_NONBLOCK, 00644); if (fd == -1) { LOG_ERR("log2flash ERROR: Unable to open file."); goto EXIT; } lock_to = FLOCK_TIMEOUT; while( flock(fd, LOCK_EX | LOCK_NB) != 0 ) { sleep(1); lock_to--; if (lock_to < 0) { LOG_ERR("log2flash ERROR: lock timeout"); goto CLOSE_EXIT; } } if ( lseek(fd, 0, SEEK_END) == -1 ) { LOG_ERR("log2flash ERROR: unable to seek to the end of file. errno=%d", errno); goto CLOSE_EXIT; } cur_time=time(NULL); ptm=gmtime(&cur_time); // tm_year from 1900, tm_mon [0-11] // it takes 20 characters spaces. sprintf(printbuf, "%d-%02d-%02d %02d:%02d:%02d ", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); // generate the buffer string. vsnprintf(printbuf+20, MAX_WRITE_CHAR-20, fmt, arglist); bytes_to_write = strlen(printbuf); printbuf[bytes_to_write] = '\n'; bytes_to_write ++; DPRINT( printbuf ); // gather statistic struct stat f_stat; if ( fstat(fd, &f_stat) == -1 ) { LOG_ERR("log2flash ERROR: unable to gatter statistic for %s. errno=%d", fname, errno); goto CLOSE_EXIT; } // if write failed, goto CLOSE_EXIT if (loop_write(fd, printbuf, bytes_to_write) != true) goto CLOSE_EXIT; if ( f_stat.st_size + strlen(printbuf) > LOG_LIMIT) { // starting to rotate DPRINT( "File Size exceeded LOG_LIMIT - Perform rotation\n" ); char from[PATH_MAX]; char to[PATH_MAX]; for( int i=ROTATE_MAX; i>0; --i) { sprintf( from, "%s.%d", fname, i-1); sprintf( to, "%s.%d", fname, i); rename( from, to); } duration = time(NULL); Copy( fname, from, LOG_LIMIT ); unlink( fname ); duration -= time(NULL); if (FileIsExecutable(FTP_SCRIPT)) { char sBaseFile[PATH_MAX]; char sFileName[PATH_MAX]; sprintf(sBaseFile,NIVIS_TMP"activity.log"); AttachDatetime(sBaseFile,sFileName); Copy(from,sFileName); systemf_to(5, FTP_SCRIPT" %s &", sFileName); } } retcode=true; CLOSE_EXIT: flock(fd, LOCK_UN); close(fd); if (duration < -10) { //it really is negative :) we only convert it when we need to show it, below log2flash("Logfile rotation took quite long: %d seconds", -duration); } EXIT: return retcode; }
int main(int argc, char *argv[]) { _cleanup_close_ int seed_fd = -1, random_fd = -1; bool read_seed_file, write_seed_file; _cleanup_free_ void* buf = NULL; size_t buf_size = 0; struct stat st; ssize_t k; FILE *f; int r; if (argc != 2) { log_error("This program requires one argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); /* Read pool size, if possible */ f = fopen("/proc/sys/kernel/random/poolsize", "re"); if (f) { if (fscanf(f, "%zu", &buf_size) > 0) /* poolsize is in bits on 2.6, but we want bytes */ buf_size /= 8; fclose(f); } if (buf_size < POOL_SIZE_MIN) buf_size = POOL_SIZE_MIN; r = mkdir_parents_label(RANDOM_SEED, 0755); if (r < 0) { log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m"); goto finish; } /* When we load the seed we read it and write it to the device and then immediately update the saved seed with * new data, to make sure the next boot gets seeded differently. */ if (streq(argv[1], "load")) { int open_rw_error; seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); open_rw_error = -errno; if (seed_fd < 0) { write_seed_file = false; seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (seed_fd < 0) { bool missing = errno == ENOENT; log_full_errno(missing ? LOG_DEBUG : LOG_ERR, open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m"); r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR, errno, "Failed to open " RANDOM_SEED " for reading: %m"); if (missing) r = 0; goto finish; } } else write_seed_file = true; random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { write_seed_file = false; random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } } read_seed_file = true; } else if (streq(argv[1], "save")) { random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); if (seed_fd < 0) { r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m"); goto finish; } read_seed_file = false; write_seed_file = true; } else { log_error("Unknown verb '%s'.", argv[1]); r = -EINVAL; goto finish; } if (fstat(seed_fd, &st) < 0) { r = log_error_errno(errno, "Failed to stat() seed file " RANDOM_SEED ": %m"); goto finish; } /* If the seed file is larger than what we expect, then honour the existing size and save/restore as much as it says */ if ((uint64_t) st.st_size > buf_size) buf_size = MIN(st.st_size, POOL_SIZE_MAX); buf = malloc(buf_size); if (!buf) { r = log_oom(); goto finish; } if (read_seed_file) { sd_id128_t mid; int z; k = loop_read(seed_fd, buf, buf_size, false); if (k < 0) r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m"); else if (k == 0) { r = 0; log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding."); } else { (void) lseek(seed_fd, 0, SEEK_SET); r = loop_write(random_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write seed to /dev/urandom: %m"); } /* Let's also write the machine ID into the random seed. Why? As an extra protection against "golden * images" that are put together sloppily, i.e. images which are duplicated on multiple systems but * where the random seed file is not properly reset. Frequently the machine ID is properly reset on * those systems however (simply because it's easier to notice, if it isn't due to address clashes and * so on, while random seed equivalence is generally not noticed easily), hence let's simply write the * machined ID into the random pool too. */ z = sd_id128_get_machine(&mid); if (z < 0) log_debug_errno(z, "Failed to get machine ID, ignoring: %m"); else { z = loop_write(random_fd, &mid, sizeof(mid), false); if (z < 0) log_debug_errno(z, "Failed to write machine ID to /dev/urandom, ignoring: %m"); } } if (write_seed_file) { /* This is just a safety measure. Given that we are root and * most likely created the file ourselves the mode and owner * should be correct anyway. */ (void) fchmod(seed_fd, 0600); (void) fchown(seed_fd, 0, 0); k = loop_read(random_fd, buf, buf_size, false); if (k < 0) { r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m"); goto finish; } if (k == 0) { log_error("Got EOF while reading from /dev/urandom."); r = -EIO; goto finish; } r = loop_write(seed_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write new random seed file: %m"); } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int ima_setup(void) { #ifdef HAVE_IMA struct stat st; ssize_t policy_size = 0, written = 0; char *policy; _cleanup_close_ int policyfd = -1, imafd = -1; int result = 0; if (stat(IMA_POLICY_PATH, &st) < 0) return 0; policy_size = st.st_size; if (stat(IMA_SECFS_DIR, &st) < 0) { log_debug("IMA support is disabled in the kernel, ignoring."); return 0; } if (stat(IMA_SECFS_POLICY, &st) < 0) { log_error("Another IMA custom policy has already been loaded, " "ignoring."); return 0; } policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC); if (policyfd < 0) { log_error("Failed to open the IMA custom policy file %s (%m), " "ignoring.", IMA_POLICY_PATH); return 0; } imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC); if (imafd < 0) { log_error("Failed to open the IMA kernel interface %s (%m), " "ignoring.", IMA_SECFS_POLICY); goto out; } policy = mmap(NULL, policy_size, PROT_READ, MAP_PRIVATE, policyfd, 0); if (policy == MAP_FAILED) { log_error("mmap() failed (%m), freezing"); result = -errno; goto out; } written = loop_write(imafd, policy, (size_t)policy_size, false); if (written != policy_size) { log_error("Failed to load the IMA custom policy file %s (%m), " "ignoring.", IMA_POLICY_PATH); goto out_mmap; } log_info("Successfully loaded the IMA custom policy %s.", IMA_POLICY_PATH); out_mmap: munmap(policy, policy_size); out: if (result) return result; #endif /* HAVE_IMA */ return 0; }
int machine_id_setup(void) { int fd, r; bool writable; struct stat st; char id[34]; /* 32 + \n + \0 */ mode_t m; m = umask(0000); /* We create this 0444, to indicate that this isn't really * something you should ever modify. Of course, since the file * will be owned by root it doesn't matter much, but maybe * people look. */ if ((fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444)) >= 0) writable = true; else { if ((fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { umask(m); log_error("Cannot open /etc/machine-id: %m"); return -errno; } writable = false; } umask(m); if (fstat(fd, &st) < 0) { log_error("fstat() failed: %m"); r = -errno; goto finish; } if (S_ISREG(st.st_mode)) { if (loop_read(fd, id, 32, false) >= 32) { r = 0; goto finish; } } /* Hmm, so, the id currently stored is not useful, then let's * generate one */ if ((r = generate(id)) < 0) goto finish; if (S_ISREG(st.st_mode) && writable) { lseek(fd, 0, SEEK_SET); if (loop_write(fd, id, 33, false) == 33) { r = 0; goto finish; } } close_nointr_nofail(fd); fd = -1; /* Hmm, we couldn't write it? So let's write it to * /run/systemd/machine-id as a replacement */ mkdir_p("/run/systemd", 0755); if ((r = write_one_line_file("/run/systemd/machine-id", id)) < 0) { log_error("Cannot write /run/systemd/machine-id: %s", strerror(-r)); unlink("/run/systemd/machine-id"); goto finish; } /* And now, let's mount it over */ r = mount("/run/systemd/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0; unlink("/run/systemd/machine-id"); if (r < 0) log_error("Failed to mount /etc/machine-id: %s", strerror(-r)); else log_info("Installed transient /etc/machine-id file."); finish: if (fd >= 0) close_nointr_nofail(fd); return r; }
int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { bool try_sendfile = true; int r; assert(fdf >= 0); assert(fdt >= 0); /* Try btrfs reflinks first. */ if (try_reflink && max_bytes == (off_t) -1) { r = btrfs_reflink(fdf, fdt); if (r >= 0) return r; } for (;;) { size_t m = COPY_BUFFER_SIZE; ssize_t n; if (max_bytes != (off_t) -1) { if (max_bytes <= 0) return -EFBIG; if ((off_t) m > max_bytes) m = (size_t) max_bytes; } /* First try sendfile(), unless we already tried */ if (try_sendfile) { n = sendfile(fdt, fdf, NULL, m); if (n < 0) { if (errno != EINVAL && errno != ENOSYS) return -errno; try_sendfile = false; /* use fallback below */ } else if (n == 0) /* EOF */ break; else if (n > 0) /* Succcess! */ goto next; } /* As a fallback just copy bits by hand */ { char buf[m]; n = read(fdf, buf, m); if (n < 0) return -errno; if (n == 0) /* EOF */ break; r = loop_write(fdt, buf, (size_t) n, false); if (r < 0) return r; } next: if (max_bytes != (off_t) -1) { assert(max_bytes >= n); max_bytes -= n; } } return 0; }
int efi_set_variable( sd_id128_t vendor, const char *name, const void *value, size_t size) { struct var { uint32_t attr; char buf[]; } _packed_ * _cleanup_free_ buf = NULL; _cleanup_free_ char *p = NULL; _cleanup_close_ int fd = -1; bool saved_flags_valid = false; unsigned saved_flags; int r; assert(name); assert(value || size == 0); if (asprintf(&p, "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", name, SD_ID128_FORMAT_VAL(vendor)) < 0) return -ENOMEM; /* Newer efivarfs protects variables that are not in a whitelist with FS_IMMUTABLE_FL by default, to protect * them for accidental removal and modification. We are not changing these variables accidentally however, * hence let's unset the bit first. */ r = chattr_path(p, 0, FS_IMMUTABLE_FL, &saved_flags); if (r < 0 && r != -ENOENT) log_debug_errno(r, "Failed to drop FS_IMMUTABLE_FL flag from '%s', ignoring: %m", p); saved_flags_valid = r >= 0; if (size == 0) { if (unlink(p) < 0) { r = -errno; goto finish; } return 0; } fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644); if (fd < 0) { r = -errno; goto finish; } buf = malloc(sizeof(uint32_t) + size); if (!buf) { r = -ENOMEM; goto finish; } buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS; memcpy(buf->buf, value, size); r = loop_write(fd, buf, sizeof(uint32_t) + size, false); if (r < 0) goto finish; r = 0; finish: if (saved_flags_valid) { int q; /* Restore the original flags field, just in case */ if (fd < 0) q = chattr_path(p, saved_flags, FS_IMMUTABLE_FL, NULL); else q = chattr_fd(fd, saved_flags, FS_IMMUTABLE_FL, NULL); if (q < 0) log_debug_errno(q, "Failed to restore FS_IMMUTABLE_FL on '%s', ignoring: %m", p); } return r; }
int main(int argc, char *argv[]) { int seed_fd = -1, random_fd = -1; int ret = EXIT_FAILURE; void* buf; size_t buf_size = 0; ssize_t r; FILE *f; if (argc != 2) { log_error("This program requires one argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); log_parse_environment(); log_open(); /* Read pool size, if possible */ if ((f = fopen("/proc/sys/kernel/random/poolsize", "re"))) { fscanf(f, "%zu", &buf_size); fclose(f); } if (buf_size <= POOL_SIZE_MIN) buf_size = POOL_SIZE_MIN; if (!(buf = malloc(buf_size))) { log_error("Failed to allocate buffer."); goto finish; } if (mkdir_parents(RANDOM_SEED, 0755) < 0) { log_error("Failed to create directories parents of %s: %m", RANDOM_SEED); goto finish; } /* When we load the seed we read it and write it to the device * and then immediately update the saved seed with new data, * to make sure the next boot gets seeded differently. */ if (streq(argv[1], "load")) { if ((seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600)) < 0) { if ((seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { log_error("Failed to open random seed: %m"); goto finish; } } if ((random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600)) < 0) { if ((random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600)) < 0) { log_error("Failed to open /dev/urandom: %m"); goto finish; } } if ((r = loop_read(seed_fd, buf, buf_size, false)) <= 0) { if (r != 0) log_error("Failed to read seed file: %m"); } else { lseek(seed_fd, 0, SEEK_SET); if ((r = loop_write(random_fd, buf, (size_t) r, false)) <= 0) log_error("Failed to write seed to /dev/random: %s", r < 0 ? strerror(errno) : "short write"); } } else if (streq(argv[1], "save")) { if ((seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600)) < 0) { log_error("Failed to open random seed: %m"); goto finish; } if ((random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { log_error("Failed to open /dev/urandom: %m"); goto finish; } } else { log_error("Unknown verb %s.", argv[1]); goto finish; } /* This is just a safety measure. Given that we are root and * most likely created the file ourselves the mode and owner * should be correct anyway. */ fchmod(seed_fd, 0600); fchown(seed_fd, 0, 0); if ((r = loop_read(random_fd, buf, buf_size, false)) <= 0) log_error("Failed to read new seed from /dev/urandom: %s", r < 0 ? strerror(errno) : "EOF"); else { if ((r = loop_write(seed_fd, buf, (size_t) r, false)) <= 0) log_error("Failed to write new random seed file: %s", r < 0 ? strerror(errno) : "short write"); } ret = EXIT_SUCCESS; finish: if (random_fd >= 0) close_nointr_nofail(random_fd); if (seed_fd >= 0) close_nointr_nofail(seed_fd); free(buf); return ret; }
int vt_disallocate(const char *name) { int fd, r; unsigned u; /* Deallocate the VT if possible. If not possible * (i.e. because it is the active one), at least clear it * entirely (including the scrollback buffer) */ if (!startswith(name, "/dev/")) return -EINVAL; if (!tty_is_vc(name)) { /* So this is not a VT. I guess we cannot deallocate * it then. But let's at least clear the screen */ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); if (fd < 0) return fd; loop_write(fd, "\033[r" /* clear scrolling region */ "\033[H" /* move home */ "\033[2J", /* clear screen */ 10, false); safe_close(fd); return 0; } if (!startswith(name, "/dev/tty")) return -EINVAL; r = safe_atou(name+8, &u); if (r < 0) return r; if (u <= 0) return -EINVAL; /* Try to deallocate */ fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); if (fd < 0) return fd; r = ioctl(fd, VT_DISALLOCATE, u); safe_close(fd); if (r >= 0) return 0; if (errno != EBUSY) return -errno; /* Couldn't deallocate, so let's clear it fully with * scrollback */ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); if (fd < 0) return fd; loop_write(fd, "\033[r" /* clear scrolling region */ "\033[H" /* move home */ "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */ 10, false); safe_close(fd); return 0; }
_public_ int sd_journal_sendv(const struct iovec *iov, int n) { PROTECT_ERRNO; int fd, r; _cleanup_close_ int buffer_fd = -1; struct iovec *w; uint64_t *l; int i, j = 0; static const union sockaddr_union sa = { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/journal/socket", }; struct msghdr mh = { .msg_name = (struct sockaddr*) &sa.sa, .msg_namelen = SOCKADDR_UN_LEN(sa.un), }; ssize_t k; bool have_syslog_identifier = false; bool seal = true; assert_return(iov, -EINVAL); assert_return(n > 0, -EINVAL); w = newa(struct iovec, n * 5 + 3); l = newa(uint64_t, n); for (i = 0; i < n; i++) { char *c, *nl; if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) return -EINVAL; c = memchr(iov[i].iov_base, '=', iov[i].iov_len); if (_unlikely_(!c || c == iov[i].iov_base)) return -EINVAL; have_syslog_identifier = have_syslog_identifier || (c == (char *) iov[i].iov_base + 17 && startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER")); nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len); if (nl) { if (_unlikely_(nl < c)) return -EINVAL; /* Already includes a newline? Bummer, then * let's write the variable name, then a * newline, then the size (64bit LE), followed * by the data and a final newline */ w[j++] = IOVEC_MAKE(iov[i].iov_base, c - (char*) iov[i].iov_base); w[j++] = IOVEC_MAKE_STRING("\n"); l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1); w[j++] = IOVEC_MAKE(&l[i], sizeof(uint64_t)); w[j++] = IOVEC_MAKE(c + 1, iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1); } else /* Nothing special? Then just add the line and * append a newline */ w[j++] = iov[i]; w[j++] = IOVEC_MAKE_STRING("\n"); } if (!have_syslog_identifier && string_is_safe(program_invocation_short_name)) { /* Implicitly add program_invocation_short_name, if it * is not set explicitly. We only do this for * program_invocation_short_name, and nothing else * since everything else is much nicer to retrieve * from the outside. */ w[j++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER="); w[j++] = IOVEC_MAKE_STRING(program_invocation_short_name); w[j++] = IOVEC_MAKE_STRING("\n"); } fd = journal_fd(); if (_unlikely_(fd < 0)) return fd; mh.msg_iov = w; mh.msg_iovlen = j; k = sendmsg(fd, &mh, MSG_NOSIGNAL); if (k >= 0) return 0; /* Fail silently if the journal is not available */ if (errno == ENOENT) return 0; if (!IN_SET(errno, EMSGSIZE, ENOBUFS)) return -errno; /* Message doesn't fit... Let's dump the data in a memfd or * temporary file and just pass a file descriptor of it to the * other side. * * For the temporary files we use /dev/shm instead of /tmp * here, since we want this to be a tmpfs, and one that is * available from early boot on and where unprivileged users * can create files. */ buffer_fd = memfd_new(NULL); if (buffer_fd < 0) { if (buffer_fd == -ENOSYS) { buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC); if (buffer_fd < 0) return buffer_fd; seal = false; } else return buffer_fd; } n = writev(buffer_fd, w, j); if (n < 0) return -errno; if (seal) { r = memfd_set_sealed(buffer_fd); if (r < 0) return r; } r = send_one_fd_sa(fd, buffer_fd, mh.msg_name, mh.msg_namelen, 0); if (r == -ENOENT) /* Fail silently if the journal is not available */ return 0; return r; } static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) { PROTECT_ERRNO; size_t n, k; k = isempty(message) ? 0 : strlen(message) + 2; n = 8 + k + 256 + 1; for (;;) { char buffer[n]; char* j; errno = 0; j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k); if (errno == 0) { char error[STRLEN("ERRNO=") + DECIMAL_STR_MAX(int) + 1]; if (j != buffer + 8 + k) memmove(buffer + 8 + k, j, strlen(j)+1); memcpy(buffer, "MESSAGE=", 8); if (k > 0) { memcpy(buffer + 8, message, k - 2); memcpy(buffer + 8 + k - 2, ": ", 2); } xsprintf(error, "ERRNO=%i", _saved_errno_); assert_cc(3 == LOG_ERR); iov[skip+0] = IOVEC_MAKE_STRING("PRIORITY=3"); iov[skip+1] = IOVEC_MAKE_STRING(buffer); iov[skip+2] = IOVEC_MAKE_STRING(error); return sd_journal_sendv(iov, skip + 3); } if (errno != ERANGE) return -errno; n *= 2; } } _public_ int sd_journal_perror(const char *message) { struct iovec iovec[3]; return fill_iovec_perror_and_send(message, 0, iovec); } _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) { static const union sockaddr_union sa = { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/journal/stdout", }; _cleanup_close_ int fd = -1; char *header; size_t l; int r; assert_return(priority >= 0, -EINVAL); assert_return(priority <= 7, -EINVAL); fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); if (fd < 0) return -errno; r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return -errno; if (shutdown(fd, SHUT_RD) < 0) return -errno; (void) fd_inc_sndbuf(fd, SNDBUF_SIZE); identifier = strempty(identifier); l = strlen(identifier); header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2); memcpy(header, identifier, l); header[l++] = '\n'; header[l++] = '\n'; /* unit id */ header[l++] = '0' + priority; header[l++] = '\n'; header[l++] = '0' + !!level_prefix; header[l++] = '\n'; header[l++] = '0'; header[l++] = '\n'; header[l++] = '0'; header[l++] = '\n'; header[l++] = '0'; header[l++] = '\n'; r = loop_write(fd, header, l, false); if (r < 0) return r; r = fd; fd = -1; return r; } _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) { int r; va_list ap; va_start(ap, format); r = sd_journal_printv_with_location(priority, file, line, func, format, ap); va_end(ap); return r; } _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) { char buffer[8 + LINE_MAX], p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1]; struct iovec iov[5]; char *f; assert_return(priority >= 0, -EINVAL); assert_return(priority <= 7, -EINVAL); assert_return(format, -EINVAL); xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK); memcpy(buffer, "MESSAGE=", 8); vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); /* Strip trailing whitespace, keep prefixing whitespace */ (void) strstrip(buffer); /* Suppress empty lines */ if (isempty(buffer+8)) return 0; /* func is initialized from __func__ which is not a macro, but * a static const char[], hence cannot easily be prefixed with * CODE_FUNC=, hence let's do it manually here. */ ALLOCA_CODE_FUNC(f, func); iov[0] = IOVEC_MAKE_STRING(buffer); iov[1] = IOVEC_MAKE_STRING(p); iov[2] = IOVEC_MAKE_STRING(file); iov[3] = IOVEC_MAKE_STRING(line); iov[4] = IOVEC_MAKE_STRING(f); return sd_journal_sendv(iov, ELEMENTSOF(iov)); }
int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) { #ifdef HAVE_LZ4 _cleanup_free_ char *buf = NULL, *out = NULL; size_t buf_size = 0; LZ4_streamDecode_t lz4_data = {}; le32_t header; size_t total_in = sizeof(header), total_out = 0; assert(fdf >= 0); assert(fdt >= 0); out = malloc(4*LZ4_BUFSIZE); if (!out) return log_oom(); for (;;) { ssize_t n, m; int r; n = read(fdf, &header, sizeof(header)); if (n < 0) return -errno; if (n != sizeof(header)) return errno ? -errno : -EIO; m = le32toh(header); if (m == 0) break; /* We refuse to use a bigger decompression buffer than * the one used for compression by 4 times. This means * that compression buffer size can be enlarged 4 * times. This can be changed, but old binaries might * not accept buffers compressed by newer binaries then. */ if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) { log_error("Compressed stream block too big: %zd bytes", m); return -EBADMSG; } total_in += sizeof(header) + m; if (!GREEDY_REALLOC(buf, buf_size, m)) return log_oom(); errno = 0; n = loop_read(fdf, buf, m, false); if (n < 0) return n; if (n != m) return errno ? -errno : -EIO; r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE); if (r <= 0) log_error("LZ4 decompression failed."); total_out += r; if (max_bytes != -1 && total_out > (size_t) max_bytes) { log_debug("Decompressed stream longer than %zd bytes", max_bytes); return -EFBIG; } errno = 0; n = loop_write(fdt, out, r, false); if (n < 0) return n; if (n != r) return errno ? -errno : -EIO; } log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)", total_in, total_out, (double) total_out / total_in * 100); return 0; #else log_error("Cannot decompress file. Compiled without LZ4 support."); return -EPROTONOSUPPORT; #endif }