Ejemplo n.º 1
0
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
}
Ejemplo n.º 2
0
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
}
Ejemplo n.º 3
0
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
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
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));
}
Ejemplo n.º 14
0
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
}