static void process_extended_fstatvfs(u_int32_t id) { int handle, fd; struct statvfs st; handle = get_handle(); debug("request %u: fstatvfs \"%s\" (handle %u)", id, handle_to_name(handle), handle); if ((fd = handle_to_fd(handle)) < 0) { send_status(id, SSH2_FX_FAILURE); return; } if (fstatvfs(fd, &st) != 0) send_status(id, errno_to_portable(errno)); else send_statvfs(id, &st); }
long fpathconf(int fd, int name) { struct statvfs fs; struct stat st; int ret; if (fd < 0) { __set_errno(EBADF); return -1; } ret = fstat(fd, &st); if (ret < 0) return ret; ret = fstatvfs(fd, &fs); if (ret < 0) return ret; return __pathconf_common(&fs, &st, name); }
static void process_extended_fstatvfs(u_int32_t id) { int r, handle, fd; struct statvfs st; if ((r = get_handle(iqueue, &handle)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: fstatvfs \"%s\" (handle %u)", id, handle_to_name(handle), handle); if ((fd = handle_to_fd(handle)) < 0) { send_status(id, SSH2_FX_FAILURE); return; } if (fstatvfs(fd, &st) != 0) send_status(id, errno_to_portable(errno)); else send_statvfs(id, &st); }
/** * Funkce inicializující strukturu statvfs * * struct statvfs { * unsigned long f_bsize; file system block size * unsigned long f_frsize; fragment size * fsblkcnt_t f_blocks; size of fs in f_frsize units * fsblkcnt_t f_bfree; # free blocks * fsblkcnt_t f_bavail; # free blocks for unprivileged users * fsfilcnt_t f_files; # inodes * fsfilcnt_t f_ffree; # free inodes * fsfilcnt_t f_favail; # free inodes for unprivileged users * unsigned long f_fsid; file system ID * unsigned long f_flag; mount flags * unsigned long f_namemax; maximum filename length * }; * * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored */ void FileSystem::initStatvfs() { memset(&archive_statvfs, 0, sizeof(struct statvfs)); struct statvfs buf; if (fstatvfs(archive_file, &buf) != 0) return; // Volné místo zjistíme podle "underlying" filesystému archive_statvfs.f_bavail = archive_statvfs.f_bfree = buf.f_frsize * buf.f_bavail; archive_statvfs.f_bsize = 1; // Velikost vfs v blocích archive_statvfs.f_blocks = buf.f_bavail; archive_statvfs.f_files = file_map.size() - 1; // - root node archive_statvfs.f_namemax = 255; return; }
/* Return information about the filesystem on which FD resides. */ int __fstatvfs64 (int fd, struct statvfs64 *buf) { struct statfs64 fsbuf; int res = __fstatfs64 (fd, &fsbuf); #ifndef __ASSUME_STATFS64 if (res < 0 && errno == ENOSYS) { struct statvfs buf32; res = fstatvfs (fd, &buf32); if (res == 0) { buf->f_bsize = buf32.f_bsize; buf->f_frsize = buf32.f_frsize; buf->f_blocks = buf32.f_blocks; buf->f_bfree = buf32.f_bfree; buf->f_bavail = buf32.f_bavail; buf->f_files = buf32.f_files; buf->f_ffree = buf32.f_ffree; buf->f_favail = buf32.f_favail; buf->f_fsid = buf32.f_fsid; buf->f_flag = buf32.f_flag; buf->f_namemax = buf32.f_namemax; memcpy (buf->__f_spare, buf32.__f_spare, sizeof (buf32.__f_spare)); } } #endif if (res == 0) { /* Convert the result. */ struct stat64 st; __internal_statvfs64 (NULL, buf, &fsbuf, fstat64 (fd, &st) == -1 ? NULL : &st); } return res; }
RTR3DECL(int) RTFileQueryFsSizes(RTFILE hFile, PRTFOFF pcbTotal, RTFOFF *pcbFree, uint32_t *pcbBlock, uint32_t *pcbSector) { struct statvfs StatVFS; RT_ZERO(StatVFS); if (fstatvfs(RTFileToNative(hFile), &StatVFS)) return RTErrConvertFromErrno(errno); /* * Calc the returned values. */ if (pcbTotal) *pcbTotal = (RTFOFF)StatVFS.f_blocks * StatVFS.f_frsize; if (pcbFree) *pcbFree = (RTFOFF)StatVFS.f_bavail * StatVFS.f_frsize; if (pcbBlock) *pcbBlock = StatVFS.f_frsize; /* no idea how to get the sector... */ if (pcbSector) *pcbSector = 512; return VINF_SUCCESS; }
/* Return information about the filesystem on which FD resides. */ int __fstatvfs64 (int fd, struct statvfs64 *buf) { struct statvfs buf32; if (fstatvfs (fd, &buf32) < 0) return -1; buf->f_bsize = buf32.f_bsize; buf->f_frsize = buf32.f_frsize; buf->f_blocks = buf32.f_blocks; buf->f_bfree = buf32.f_bfree; buf->f_bavail = buf32.f_bavail; buf->f_files = buf32.f_files; buf->f_ffree = buf32.f_ffree; buf->f_favail = buf32.f_favail; buf->f_fsid = buf32.f_fsid; buf->f_flag = buf32.f_flag; buf->f_namemax = buf32.f_namemax; memcpy (buf->__f_spare, buf32.__f_spare, sizeof (buf32.__f_spare)); return 0; }
static int do_test (void) { char *buf; int fd; FILE *fp; int ch; struct stat st1; struct stat st2; buf = (char *) malloc (strlen (test_dir) + sizeof "/tst-atime.XXXXXX"); if (buf == NULL) { printf ("cannot allocate memory: %m\n"); return 1; } stpcpy (stpcpy (buf, test_dir), "/tst-atime.XXXXXX"); fd = mkstemp (buf); if (fd == -1) { printf ("cannot open temporary file: %m\n"); return 1; } #ifdef ST_NOATIME /* Make sure the filesystem doesn't have the noatime option set. If statvfs is not available just continue. */ struct statvfs sv; int e = fstatvfs (fd, &sv); if (e != ENOSYS) { if (e != 0) { printf ("cannot statvfs '%s': %m\n", buf); return 1; } if ((sv.f_flag & ST_NOATIME) != 0) { puts ("Bah! The filesystem is mounted with noatime"); return 0; } } #endif /* Make sure it gets removed. */ add_temp_file (buf); if (write (fd, "some string\n", 12) != 12) { printf ("cannot write temporary file: %m\n"); return 1; } if (lseek (fd, 0, SEEK_SET) == (off_t) -1) { printf ("cannot reposition temporary file: %m\n"); return 1; } fp = fdopen (fd, "r"); if (fp == NULL) { printf ("cannot create stream: %m\n"); return 1; } if (fstat (fd, &st1) == -1) { printf ("first stat failed: %m\n"); return 1; } sleep (2); ch = fgetc (fp); if (ch != 's') { printf ("did not read correct character: got '%c', expected 's'\n", ch); return 1; } if (fstat (fd, &st2) == -1) { printf ("second stat failed: %m\n"); return 1; } if (st1.st_atime > st2.st_atime) { puts ("second atime smaller"); return 1; } else if (st1.st_atime == st2.st_atime) { puts ("atime has not changed"); return 1; } fclose (fp); return 0; }
/* XXX This function really should be cancellable (for the benefit of * virt-sparsify). However currently the library can only handle * cancellation for FileIn/FileOut operations. */ int do_zero_free_space (const char *dir) { size_t len = strlen (dir); char filename[sysroot_len+len+14]; /* sysroot + dir + "/" + 8.3 + "\0" */ int fd; unsigned skip = 0; struct statvfs statbuf; fsblkcnt_t bfree_initial; /* Choose a randomly named 8.3 file. Because of the random name, * this won't conflict with existing files, and it should be * compatible with any filesystem type inc. FAT. */ snprintf (filename, sysroot_len+len+14, "%s%s/XXXXXXXX.XXX", sysroot, dir); if (random_name (filename) == -1) { reply_with_perror ("random_name"); return -1; } if (verbose) printf ("random filename: %s\n", filename); /* Open file and fill with zeroes until we run out of space. */ fd = open (filename, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600); if (fd == -1) { reply_with_perror ("open: %s", filename); return -1; } /* To estimate progress in this operation, we're going to track * free blocks in this filesystem down to zero. */ if (fstatvfs (fd, &statbuf) == -1) { reply_with_perror ("fstatvfs"); close (fd); return -1; } bfree_initial = statbuf.f_bfree; for (;;) { if (write (fd, zero_buf, sizeof zero_buf) == -1) { if (errno == ENOSPC) /* expected error */ break; reply_with_perror ("write: %s", filename); close (fd); unlink (filename); return -1; } skip++; if ((skip & 256) == 0 && fstatvfs (fd, &statbuf) == 0) notify_progress (bfree_initial - statbuf.f_bfree, bfree_initial); } /* Make sure the file is completely written to disk. */ close (fd); /* expect this to give an error, don't check it */ sync_disks (); notify_progress (bfree_initial, bfree_initial); /* Remove the file. */ if (unlink (filename) == -1) { reply_with_perror ("unlink: %s", filename); return -1; } return 0; }
static int getentropy_fallback(void *buf, size_t len) { uint8_t results[SHA512_DIGEST_LENGTH]; int save_errno = errno, e, pgs = sysconf(_SC_PAGESIZE), faster = 0, repeat; static int cnt; struct timespec ts; struct timeval tv; perfstat_cpu_total_t cpustats; #ifdef _AIX61 perfstat_cpu_total_wpar_t cpustats_wpar; #endif perfstat_partition_total_t lparstats; perfstat_disk_total_t diskinfo; perfstat_netinterface_total_t netinfo; struct rusage ru; sigset_t sigset; struct stat st; SHA512_CTX ctx; static pid_t lastpid; pid_t pid; size_t i, ii, m; char *p; pid = getpid(); if (lastpid == pid) { faster = 1; repeat = 2; } else { faster = 0; lastpid = pid; repeat = REPEAT; } for (i = 0; i < len; ) { int j; SHA512_Init(&ctx); for (j = 0; j < repeat; j++) { HX((e = gettimeofday(&tv, NULL)) == -1, tv); if (e != -1) { cnt += (int)tv.tv_sec; cnt += (int)tv.tv_usec; } HX(perfstat_cpu_total(NULL, &cpustats, sizeof(cpustats), 1) == -1, cpustats); #ifdef _AIX61 HX(perfstat_cpu_total_wpar(NULL, &cpustats_wpar, sizeof(cpustats_wpar), 1) == -1, cpustats_wpar); #endif HX(perfstat_partition_total(NULL, &lparstats, sizeof(lparstats), 1) == -1, lparstats); HX(perfstat_disk_total(NULL, &diskinfo, sizeof(diskinfo), 1) == -1, diskinfo); HX(perfstat_netinterface_total(NULL, &netinfo, sizeof(netinfo), 1) == -1, netinfo); for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) HX(clock_gettime(cl[ii], &ts) == -1, ts); HX((pid = getpid()) == -1, pid); HX((pid = getsid(pid)) == -1, pid); HX((pid = getppid()) == -1, pid); HX((pid = getpgid(0)) == -1, pid); HX((e = getpriority(0, 0)) == -1, e); if (!faster) { ts.tv_sec = 0; ts.tv_nsec = 1; (void) nanosleep(&ts, NULL); } HX(sigpending(&sigset) == -1, sigset); HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, sigset); HF(getentropy); /* an addr in this library */ HF(printf); /* an addr in libc */ p = (char *)&p; HD(p); /* an addr on stack */ p = (char *)&errno; HD(p); /* the addr of errno */ if (i == 0) { struct sockaddr_storage ss; struct statvfs stvfs; struct termios tios; socklen_t ssl; off_t off; /* * Prime-sized mappings encourage fragmentation; * thus exposing some address entropy. */ struct mm { size_t npg; void *p; } mm[] = { { 17, MAP_FAILED }, { 3, MAP_FAILED }, { 11, MAP_FAILED }, { 2, MAP_FAILED }, { 5, MAP_FAILED }, { 3, MAP_FAILED }, { 7, MAP_FAILED }, { 1, MAP_FAILED }, { 57, MAP_FAILED }, { 3, MAP_FAILED }, { 131, MAP_FAILED }, { 1, MAP_FAILED }, }; for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { HX(mm[m].p = mmap(NULL, mm[m].npg * pgs, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, (off_t)0), mm[m].p); if (mm[m].p != MAP_FAILED) { size_t mo; /* Touch some memory... */ p = mm[m].p; mo = cnt % (mm[m].npg * pgs - 1); p[mo] = 1; cnt += (int)((long)(mm[m].p) / pgs); } /* Check cnts and times... */ for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) { HX((e = clock_gettime(cl[ii], &ts)) == -1, ts); if (e != -1) cnt += (int)ts.tv_nsec; } HX((e = getrusage(RUSAGE_SELF, &ru)) == -1, ru); if (e != -1) { cnt += (int)ru.ru_utime.tv_sec; cnt += (int)ru.ru_utime.tv_usec; } } for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { if (mm[m].p != MAP_FAILED) munmap(mm[m].p, mm[m].npg * pgs); mm[m].p = MAP_FAILED; } HX(stat(".", &st) == -1, st); HX(statvfs(".", &stvfs) == -1, stvfs); HX(stat("/", &st) == -1, st); HX(statvfs("/", &stvfs) == -1, stvfs); HX((e = fstat(0, &st)) == -1, st); if (e == -1) { if (S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { HX(fstatvfs(0, &stvfs) == -1, stvfs); HX((off = lseek(0, (off_t)0, SEEK_CUR)) < 0, off); } if (S_ISCHR(st.st_mode)) { HX(tcgetattr(0, &tios) == -1, tios); } else if (S_ISSOCK(st.st_mode)) { memset(&ss, 0, sizeof ss); ssl = sizeof(ss); HX(getpeername(0, (void *)&ss, &ssl) == -1, ss); } } HX((e = getrusage(RUSAGE_CHILDREN, &ru)) == -1, ru); if (e != -1) { cnt += (int)ru.ru_utime.tv_sec; cnt += (int)ru.ru_utime.tv_usec; } } else { /* Subsequent hashes absorb previous result */ HD(results); } HX((e = gettimeofday(&tv, NULL)) == -1, tv); if (e != -1) { cnt += (int)tv.tv_sec; cnt += (int)tv.tv_usec; } HD(cnt); } SHA512_Final(results, &ctx); memcpy((char *)buf + i, results, min(sizeof(results), len - i)); i += min(sizeof(results), len - i); } explicit_bzero(&ctx, sizeof ctx); explicit_bzero(results, sizeof results); if (gotdata(buf, len) == 0) { errno = save_errno; return 0; /* satisfied */ } errno = EIO; return -1; }
void server_process_native_file( Server *s, int fd, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) { struct stat st; bool sealed; int r; /* Data is in the passed fd, since it didn't fit in a * datagram. */ assert(s); assert(fd >= 0); /* If it's a memfd, check if it is sealed. If so, we can just * use map it and use it, and do not need to copy the data * out. */ sealed = memfd_get_sealed(fd) > 0; if (!sealed && (!ucred || ucred->uid != 0)) { _cleanup_free_ char *sl = NULL, *k = NULL; const char *e; /* If this is not a sealed memfd, and the peer is unknown or * unprivileged, then verify the path. */ if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) { log_oom(); return; } r = readlink_malloc(sl, &k); if (r < 0) { log_error_errno(r, "readlink(%s) failed: %m", sl); return; } e = path_startswith(k, "/dev/shm/"); if (!e) e = path_startswith(k, "/tmp/"); if (!e) e = path_startswith(k, "/var/tmp/"); if (!e) { log_error("Received file outside of allowed directories. Refusing."); return; } if (!filename_is_valid(e)) { log_error("Received file in subdirectory of allowed directories. Refusing."); return; } } if (fstat(fd, &st) < 0) { log_error_errno(errno, "Failed to stat passed file, ignoring: %m"); return; } if (!S_ISREG(st.st_mode)) { log_error("File passed is not regular. Ignoring."); return; } if (st.st_size <= 0) return; if (st.st_size > ENTRY_SIZE_MAX) { log_error("File passed too large. Ignoring."); return; } if (sealed) { void *p; size_t ps; /* The file is sealed, we can just map it and use it. */ ps = PAGE_ALIGN(st.st_size); p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0); if (p == MAP_FAILED) { log_error_errno(errno, "Failed to map memfd, ignoring: %m"); return; } server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len); assert_se(munmap(p, ps) >= 0); } else { _cleanup_free_ void *p = NULL; struct statvfs vfs; ssize_t n; if (fstatvfs(fd, &vfs) < 0) { log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m"); return; } /* Refuse operating on file systems that have * mandatory locking enabled, see: * * https://github.com/systemd/systemd/issues/1822 */ if (vfs.f_flag & ST_MANDLOCK) { log_error("Received file descriptor from file system with mandatory locking enable, refusing."); return; } /* Make the fd non-blocking. On regular files this has * the effect of bypassing mandatory locking. Of * course, this should normally not be necessary given * the check above, but let's better be safe than * sorry, after all NFS is pretty confusing regarding * file system flags, and we better don't trust it, * and so is SMB. */ r = fd_nonblock(fd, true); if (r < 0) { log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m"); return; } /* The file is not sealed, we can't map the file here, since * clients might then truncate it and trigger a SIGBUS for * us. So let's stupidly read it */ p = malloc(st.st_size); if (!p) { log_oom(); return; } n = pread(fd, p, st.st_size, 0); if (n < 0) log_error_errno(errno, "Failed to read file, ignoring: %m"); else if (n > 0) server_process_native_message(s, p, n, ucred, tv, label, label_len); } }
static int getentropy_fallback(void *buf, size_t len) { uint8_t results[SHA512_DIGEST_LENGTH]; int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat; static int cnt; struct timespec ts; struct timeval tv; struct rusage ru; sigset_t sigset; struct stat st; SHA512_CTX ctx; static pid_t lastpid; pid_t pid; size_t i, ii, m; char *p; struct tcpstat tcpstat; struct udpstat udpstat; struct ipstat ipstat; u_int64_t mach_time; unsigned int idata; void *addr; pid = getpid(); if (lastpid == pid) { faster = 1; repeat = 2; } else { faster = 0; lastpid = pid; repeat = REPEAT; } for (i = 0; i < len; ) { int j; SHA512_Init(&ctx); for (j = 0; j < repeat; j++) { HX((e = gettimeofday(&tv, NULL)) == -1, tv); if (e != -1) { cnt += (int)tv.tv_sec; cnt += (int)tv.tv_usec; } mach_time = mach_absolute_time(); HD(mach_time); ii = sizeof(addr); HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]), &addr, &ii, NULL, 0) == -1, addr); ii = sizeof(idata); HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]), &idata, &ii, NULL, 0) == -1, idata); ii = sizeof(tcpstat); HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]), &tcpstat, &ii, NULL, 0) == -1, tcpstat); ii = sizeof(udpstat); HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]), &udpstat, &ii, NULL, 0) == -1, udpstat); ii = sizeof(ipstat); HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]), &ipstat, &ii, NULL, 0) == -1, ipstat); HX((pid = getpid()) == -1, pid); HX((pid = getsid(pid)) == -1, pid); HX((pid = getppid()) == -1, pid); HX((pid = getpgid(0)) == -1, pid); HX((e = getpriority(0, 0)) == -1, e); if (!faster) { ts.tv_sec = 0; ts.tv_nsec = 1; (void) nanosleep(&ts, NULL); } HX(sigpending(&sigset) == -1, sigset); HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, sigset); HF(getentropy); /* an addr in this library */ HF(printf); /* an addr in libc */ p = (char *)&p; HD(p); /* an addr on stack */ p = (char *)&errno; HD(p); /* the addr of errno */ if (i == 0) { struct sockaddr_storage ss; struct statvfs stvfs; struct termios tios; struct statfs stfs; socklen_t ssl; off_t off; /* * Prime-sized mappings encourage fragmentation; * thus exposing some address entropy. */ struct mm { size_t npg; void *p; } mm[] = { { 17, MAP_FAILED }, { 3, MAP_FAILED }, { 11, MAP_FAILED }, { 2, MAP_FAILED }, { 5, MAP_FAILED }, { 3, MAP_FAILED }, { 7, MAP_FAILED }, { 1, MAP_FAILED }, { 57, MAP_FAILED }, { 3, MAP_FAILED }, { 131, MAP_FAILED }, { 1, MAP_FAILED }, }; for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { HX(mm[m].p = mmap(NULL, mm[m].npg * pgs, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, (off_t)0), mm[m].p); if (mm[m].p != MAP_FAILED) { size_t mo; /* Touch some memory... */ p = mm[m].p; mo = cnt % (mm[m].npg * pgs - 1); p[mo] = 1; cnt += (int)((long)(mm[m].p) / pgs); } /* Check cnts and times... */ mach_time = mach_absolute_time(); HD(mach_time); cnt += (int)mach_time; HX((e = getrusage(RUSAGE_SELF, &ru)) == -1, ru); if (e != -1) { cnt += (int)ru.ru_utime.tv_sec; cnt += (int)ru.ru_utime.tv_usec; } } for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { if (mm[m].p != MAP_FAILED) munmap(mm[m].p, mm[m].npg * pgs); mm[m].p = MAP_FAILED; } HX(stat(".", &st) == -1, st); HX(statvfs(".", &stvfs) == -1, stvfs); HX(statfs(".", &stfs) == -1, stfs); HX(stat("/", &st) == -1, st); HX(statvfs("/", &stvfs) == -1, stvfs); HX(statfs("/", &stfs) == -1, stfs); HX((e = fstat(0, &st)) == -1, st); if (e == -1) { if (S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { HX(fstatvfs(0, &stvfs) == -1, stvfs); HX(fstatfs(0, &stfs) == -1, stfs); HX((off = lseek(0, (off_t)0, SEEK_CUR)) < 0, off); } if (S_ISCHR(st.st_mode)) { HX(tcgetattr(0, &tios) == -1, tios); } else if (S_ISSOCK(st.st_mode)) { memset(&ss, 0, sizeof ss); ssl = sizeof(ss); HX(getpeername(0, (void *)&ss, &ssl) == -1, ss); } } HX((e = getrusage(RUSAGE_CHILDREN, &ru)) == -1, ru); if (e != -1) { cnt += (int)ru.ru_utime.tv_sec; cnt += (int)ru.ru_utime.tv_usec; } } else { /* Subsequent hashes absorb previous result */ HD(results); } HX((e = gettimeofday(&tv, NULL)) == -1, tv); if (e != -1) { cnt += (int)tv.tv_sec; cnt += (int)tv.tv_usec; } HD(cnt); } SHA512_Final(results, &ctx); memcpy((char *)buf + i, results, min(sizeof(results), len - i)); i += min(sizeof(results), len - i); } explicit_bzero(&ctx, sizeof ctx); explicit_bzero(results, sizeof results); if (gotdata(buf, len) == 0) { errno = save_errno; return (0); /* satisfied */ } errno = EIO; return (-1); }
static int getentropy_fallback(void *buf, size_t len) { uint8_t results[SHA512_DIGEST_LENGTH]; int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat; static int cnt; struct timespec ts; struct timeval tv; struct rusage ru; sigset_t sigset; struct stat st; SHA512_CTX ctx; static pid_t lastpid; pid_t pid; size_t i, ii, m; char *p; pid = getpid(); if (lastpid == pid) { faster = 1; repeat = 2; } else { faster = 0; lastpid = pid; repeat = REPEAT; } for (i = 0; i < len; ) { int j; SHA512_Init(&ctx); for (j = 0; j < repeat; j++) { HX((e = gettimeofday(&tv, NULL)) == -1, tv); if (e != -1) { cnt += (int)tv.tv_sec; cnt += (int)tv.tv_usec; } dl_iterate_phdr(getentropy_phdr, &ctx); for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) HX(clock_gettime(cl[ii], &ts) == -1, ts); HX((pid = getpid()) == -1, pid); HX((pid = getsid(pid)) == -1, pid); HX((pid = getppid()) == -1, pid); HX((pid = getpgid(0)) == -1, pid); HX((e = getpriority(0, 0)) == -1, e); if (!faster) { ts.tv_sec = 0; ts.tv_nsec = 1; (void) nanosleep(&ts, NULL); } HX(sigpending(&sigset) == -1, sigset); HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, sigset); #if 0 HF(main); /* an addr in program */ #endif HF(getentropy); /* an addr in this library */ HF(printf); /* an addr in libc */ p = (char *)&p; HD(p); /* an addr on stack */ p = (char *)&errno; HD(p); /* the addr of errno */ if (i == 0) { struct sockaddr_storage ss; struct statvfs stvfs; struct termios tios; struct statfs stfs; socklen_t ssl; off_t off; /* * Prime-sized mappings encourage fragmentation; * thus exposing some address entropy. */ struct mm { size_t npg; void *p; } mm[] = { { 17, MAP_FAILED }, { 3, MAP_FAILED }, { 11, MAP_FAILED }, { 2, MAP_FAILED }, { 5, MAP_FAILED }, { 3, MAP_FAILED }, { 7, MAP_FAILED }, { 1, MAP_FAILED }, { 57, MAP_FAILED }, { 3, MAP_FAILED }, { 131, MAP_FAILED }, { 1, MAP_FAILED }, }; for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { HX(mm[m].p = mmap(NULL, mm[m].npg * pgs, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, (off_t)0), mm[m].p); if (mm[m].p != MAP_FAILED) { size_t mo; /* Touch some memory... */ p = mm[m].p; mo = cnt % (mm[m].npg * pgs - 1); p[mo] = 1; cnt += (int)((long)(mm[m].p) / pgs); } /* Check cnts and times... */ for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) { HX((e = clock_gettime(cl[ii], &ts)) == -1, ts); if (e != -1) cnt += (int)ts.tv_nsec; } HX((e = getrusage(RUSAGE_SELF, &ru)) == -1, ru); if (e != -1) { cnt += (int)ru.ru_utime.tv_sec; cnt += (int)ru.ru_utime.tv_usec; } } for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { if (mm[m].p != MAP_FAILED) munmap(mm[m].p, mm[m].npg * pgs); mm[m].p = MAP_FAILED; } HX(stat(".", &st) == -1, st); HX(statvfs(".", &stvfs) == -1, stvfs); HX(statfs(".", &stfs) == -1, stfs); HX(stat("/", &st) == -1, st); HX(statvfs("/", &stvfs) == -1, stvfs); HX(statfs("/", &stfs) == -1, stfs); HX((e = fstat(0, &st)) == -1, st); if (e == -1) { if (S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { HX(fstatvfs(0, &stvfs) == -1, stvfs); HX(fstatfs(0, &stfs) == -1, stfs); HX((off = lseek(0, (off_t)0, SEEK_CUR)) < 0, off); } if (S_ISCHR(st.st_mode)) { HX(tcgetattr(0, &tios) == -1, tios); } else if (S_ISSOCK(st.st_mode)) { memset(&ss, 0, sizeof ss); ssl = sizeof(ss); HX(getpeername(0, (void *)&ss, &ssl) == -1, ss); } } HX((e = getrusage(RUSAGE_CHILDREN, &ru)) == -1, ru); if (e != -1) { cnt += (int)ru.ru_utime.tv_sec; cnt += (int)ru.ru_utime.tv_usec; } } else { /* Subsequent hashes absorb previous result */ HD(results); } HX((e = gettimeofday(&tv, NULL)) == -1, tv); if (e != -1) { cnt += (int)tv.tv_sec; cnt += (int)tv.tv_usec; } HD(cnt); } #ifdef HAVE_GETAUXVAL #ifdef AT_RANDOM /* Not as random as you think but we take what we are given */ p = (char *) getauxval(AT_RANDOM); if (p) HR(p, 16); #endif #ifdef AT_SYSINFO_EHDR p = (char *) getauxval(AT_SYSINFO_EHDR); if (p) HR(p, pgs); #endif #ifdef AT_BASE p = (char *) getauxval(AT_BASE); if (p) HD(p); #endif #endif SHA512_Final(results, &ctx); memcpy((char *)buf + i, results, min(sizeof(results), len - i)); i += min(sizeof(results), len - i); } memset(results, 0, sizeof results); if (gotdata(buf, len) == 0) { errno = save_errno; return 0; /* satisfied */ } errno = EIO; return -1; }
int journal_directory_vacuum( const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec) { _cleanup_closedir_ DIR *d = NULL; int r = 0; struct vacuum_info *list = NULL; unsigned n_list = 0, i; size_t n_allocated = 0; uint64_t sum = 0, freed = 0; usec_t retention_limit = 0; assert(directory); if (max_use <= 0 && max_retention_usec <= 0) return 0; if (max_retention_usec > 0) { retention_limit = now(CLOCK_REALTIME); if (retention_limit > max_retention_usec) retention_limit -= max_retention_usec; else max_retention_usec = retention_limit = 0; } d = opendir(directory); if (!d) return -errno; for (;;) { int k; struct dirent *de; union dirent_storage buf; size_t q; struct stat st; char *p; unsigned long long seqnum = 0, realtime; sd_id128_t seqnum_id; bool have_seqnum; k = readdir_r(d, &buf.de, &de); if (k != 0) { r = -k; goto finish; } if (!de) break; if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) continue; if (!S_ISREG(st.st_mode)) continue; q = strlen(de->d_name); if (endswith(de->d_name, ".journal")) { /* Vacuum archived files */ if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) continue; if (de->d_name[q-8-16-1] != '-' || de->d_name[q-8-16-1-16-1] != '-' || de->d_name[q-8-16-1-16-1-32-1] != '@') continue; p = strdup(de->d_name); if (!p) { r = -ENOMEM; goto finish; } de->d_name[q-8-16-1-16-1] = 0; if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) { free(p); continue; } if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) { free(p); continue; } have_seqnum = true; } else if (endswith(de->d_name, ".journal~")) { unsigned long long tmp; /* Vacuum corrupted files */ if (q < 1 + 16 + 1 + 16 + 8 + 1) continue; if (de->d_name[q-1-8-16-1] != '-' || de->d_name[q-1-8-16-1-16-1] != '@') continue; p = strdup(de->d_name); if (!p) { r = -ENOMEM; goto finish; } if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { free(p); continue; } have_seqnum = false; } else /* We do not vacuum active files or unknown files! */ continue; if (journal_file_empty(dirfd(d), p)) { /* Always vacuum empty non-online files. */ uint64_t size = 512UL * (uint64_t) st.st_blocks; if (unlinkat(dirfd(d), p, 0) >= 0) { log_info("Deleted empty journal %s/%s (%"PRIu64" bytes).", directory, p, size); freed += size; } else if (errno != ENOENT) log_warning("Failed to delete %s/%s: %m", directory, p); free(p); continue; } patch_realtime(directory, p, &st, &realtime); GREEDY_REALLOC(list, n_allocated, n_list + 1); list[n_list].filename = p; list[n_list].usage = 512UL * (uint64_t) st.st_blocks; list[n_list].seqnum = seqnum; list[n_list].realtime = realtime; list[n_list].seqnum_id = seqnum_id; list[n_list].have_seqnum = have_seqnum; sum += list[n_list].usage; n_list ++; } qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare); for (i = 0; i < n_list; i++) { struct statvfs ss; if (fstatvfs(dirfd(d), &ss) < 0) { r = -errno; goto finish; } if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) && (max_use <= 0 || sum <= max_use)) break; if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) { log_debug("Deleted archived journal %s/%s (%"PRIu64" bytes).", directory, list[i].filename, list[i].usage); freed += list[i].usage; if (list[i].usage < sum) sum -= list[i].usage; else sum = 0; } else if (errno != ENOENT) log_warning("Failed to delete %s/%s: %m", directory, list[i].filename); } if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec)) *oldest_usec = list[i].realtime; finish: for (i = 0; i < n_list; i++) free(list[i].filename); free(list); log_debug("Vacuuming done, freed %"PRIu64" bytes", freed); return r; }
int main(int argc, char *argv[]) { // pointer to file name string char *name; // allocate tm structure to store retrieved time struct tm time; // allocate space to hold a string with retrieved time (ASCII text) char asctime_str[35]; // container for complete set of file permission bits (binary) unsigned int mode; // container for the three bits of user permissions unsigned int umode; // container for the three bits of group permissions unsigned int gmode; // container for the three bits of owner permission unsigned int omode; // human readable file permissions (ASCII text) char perm_bits_str[] = "---------"; // file descriptor unsigned int fd; // structure to contain the result of the fstat call (info on this file) struct stat file_info; // structure to contain the result of the vfstat call (info on file system) struct statvfs fs_info; // used to save the return value of realpath char resolved_path[PATH_MAX]; char* ret_path; // check number of arguments for appropriate usage if (2 != argc) { printf(" usage: %s [file_name]\n", argv[0]); exit(-11); } // post-condition: argv[1] contains name of file to use // try to open file fd = open(argv[1], O_RDONLY); if (-1 == fd) { perror("Failed to open read only file - "); exit(-1); } // use fstatvfs to learn details about the file system if (fstatvfs(fd, &fs_info) == 0) { printf("== FILE SYSTEM INFO ============================\n"); printf(" file system fstatvfs() call successful\n"); printf(" file system block size: %d\n", 0); // TO-DO printf(" max. file name length: %d\n", 0); // TO-DO } else { printf("%s: File system fstatvfs call failed\n", argv[0]); exit(-1); } // post-condition: maximum length of file name string is known // use calloc to allocate space for file name string name = calloc(fs_info.f_namemax, 1); if (NULL == name) { perror("Problem in calloc - "); exit(-1); } // copy file name into name variable using secure version of string copy strncpy(name, argv[1], 500); // use fstat to get information on specific file if (fstat(fd, &file_info) == 0) { printf("\n== FILE INFO ============================\n"); printf(" file fstat() call successful\n"); // mode comes from the lower 9 bits in file_info.st_mode mode = file_info.st_mode & 0x1FF; printf(" file protection bits = 0%o\n", mode); // umode comes from the high 3 bits in mode umode = 0; // TO-DO // gmode comes from the middle 3 bits in mode gmode = 0; // TO-DO // omode comes from the low 3 bits in mode omode = 0; // TO-DO // once you have set umode, gmode, and omode, the code below // will construct the right string for you and display it // construct string with file protection information if (umode & 0x4) perm_bits_str[0] = 'r'; if (umode & 0x2) perm_bits_str[1] = 'w'; if (umode & 0x1) perm_bits_str[2] = 'x'; if (gmode & 0x4) perm_bits_str[3] = 'r'; if (gmode & 0x2) perm_bits_str[4] = 'w'; if (gmode & 0x1) perm_bits_str[5] = 'x'; if (omode & 0x4) perm_bits_str[6] = 'r'; if (omode & 0x2) perm_bits_str[7] = 'w'; if (omode & 0x1) perm_bits_str[8] = 'x'; printf(" file protection string = %s\n", perm_bits_str); printf(" file protection mode (u:g:o) = %o:%o:%o\n", umode, gmode, omode); printf(" owner user name = %s\n",""); // TO-DO: man getpwuid printf(" owner group name = %s\n", ""); // TO-DO: man getgrgid // TO-DO: print "mode = x", where x may be: // "regular file" // "directory" // "character device" // "block device" // "symbolic link" // "socket" // "fifo" // "unknown" if (S_ISREG(file_info.st_mode)) { printf(" mode = regular file\n"); } else { // see TO-DO above } ret_path = realpath(name, resolved_path); if (NULL != ret_path) printf(" absolute path = %s\n", ret_path); else { perror(" couldn't resolve path"); exit(-1); } // fill in the time the last write was made to file localtime_r(&(file_info.st_mtime), &time); asctime_r(&time, asctime_str); printf(" time of last modification: %s\n", asctime_str); fflush(stdout); close(fd); exit(0); } else printf(" fstat call failed\n"); return 0; }
// disable shm in pulseaudio void pulseaudio_init(void) { struct stat s; // do we have pulseaudio in the system? if (stat("/etc/pulse/client.conf", &s) == -1) { if (arg_debug) printf("/etc/pulse/client.conf not found\n"); return; } // create the new user pulseaudio directory if (mkdir(RUN_PULSE_DIR, 0700) == -1) errExit("mkdir"); // mount it nosuid, noexec, nodev fs_noexec(RUN_PULSE_DIR); // create the new client.conf file char *pulsecfg = NULL; if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1) errExit("asprintf"); if (copy_file("/etc/pulse/client.conf", pulsecfg, -1, -1, 0644)) // root needed errExit("copy_file"); FILE *fp = fopen(pulsecfg, "a"); if (!fp) errExit("fopen"); fprintf(fp, "%s", "\nenable-shm = no\n"); SET_PERMS_STREAM(fp, getuid(), getgid(), 0644); fclose(fp); // hand over the directory to the user if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700)) errExit("set_perms"); // create ~/.config/pulse directory if not present char *homeusercfg; if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1) errExit("asprintf"); if (lstat(homeusercfg, &s) == -1) { if (create_empty_dir_as_user(homeusercfg, 0700)) fs_logger2("create", homeusercfg); } else if (!S_ISDIR(s.st_mode)) { if (S_ISLNK(s.st_mode)) fprintf(stderr, "Error: %s is a symbolic link\n", homeusercfg); else fprintf(stderr, "Error: %s is not a directory\n", homeusercfg); exit(1); } free(homeusercfg); if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1) errExit("asprintf"); if (lstat(homeusercfg, &s) == -1) { if (create_empty_dir_as_user(homeusercfg, 0700)) fs_logger2("create", homeusercfg); } else if (!S_ISDIR(s.st_mode)) { if (S_ISLNK(s.st_mode)) fprintf(stderr, "Error: %s is a symbolic link\n", homeusercfg); else fprintf(stderr, "Error: %s is not a directory\n", homeusercfg); exit(1); } // if we have ~/.config/pulse mount the new directory, else set environment variable. if (stat(homeusercfg, &s) == 0) { // get a file descriptor for ~/.config/pulse, fails if there is any symlink int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); if (fd == -1) errExit("safe_fd"); // confirm the actual mount destination is owned by the user if (fstat(fd, &s) == -1) errExit("fstat"); if (s.st_uid != getuid()) { fprintf(stderr, "Error: %s is not owned by the current user\n", homeusercfg); exit(1); } // preserve a read-only mount struct statvfs vfs; if (fstatvfs(fd, &vfs) == -1) errExit("fstatvfs"); if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY) fs_rdonly(RUN_PULSE_DIR); // mount via the link in /proc/self/fd char *proc; if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) errExit("asprintf"); if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0) errExit("mount pulseaudio"); fs_logger2("tmpfs", homeusercfg); free(proc); close(fd); // check /proc/self/mountinfo to confirm the mount is ok MountData *mptr = get_last_mount(); if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) errLogExit("invalid pulseaudio mount"); char *p; if (asprintf(&p, "%s/client.conf", homeusercfg) == -1) errExit("asprintf"); fs_logger2("create", p); free(p); } else { // set environment if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0) errExit("setenv"); } free(pulsecfg); free(homeusercfg); }
static void *filesystem_open(const char *name, int oflag, mode_t mode, void *context, size_t *size, int *err) { struct stat stats; struct statvfs buf; const char *root_folder; char *folder; gboolean root; int fd = open(name, oflag, mode); uint64_t avail; if (fd < 0) { if (err) *err = -errno; return NULL; } if (fstat(fd, &stats) < 0) { if (err) *err = -errno; goto failed; } root_folder = obex_option_root_folder(); folder = g_path_get_dirname(name); root = g_strcmp0(folder, root_folder); g_free(folder); if (!root || obex_option_symlinks()) { if (S_ISLNK(stats.st_mode)) { if (err) *err = -EPERM; goto failed; } } if (oflag == O_RDONLY) { if (size) *size = stats.st_size; goto done; } if (fstatvfs(fd, &buf) < 0) { if (err) *err = -errno; goto failed; } if (size == NULL) goto done; avail = (uint64_t) buf.f_bsize * buf.f_bavail; if (avail < *size) { if (err) *err = -ENOSPC; goto failed; } done: if (err) *err = 0; return GINT_TO_POINTER(fd); failed: close(fd); return NULL; }
int loadblocknums(char *boot, int devfd) { int i, fd; struct stat statbuf; struct statvfs statvfsbuf; struct fs *fs; char *buf; daddr_t blk, *ap; struct ufs1_dinode *ip; int ndb; /* * Open 2nd-level boot program and record the block numbers * it occupies on the filesystem represented by `devfd'. */ /* Make sure the (probably new) boot file is on disk. */ sync(); sleep(1); if ((fd = open(boot, O_RDONLY)) < 0) err(1, "open: %s", boot); if (fstatvfs(fd, &statvfsbuf) != 0) err(1, "statfs: %s", boot); if (strncmp(statvfsbuf.f_fstypename, "ffs", sizeof(statvfsbuf.f_fstypename)) && strncmp(statvfsbuf.f_fstypename, "ufs", sizeof(statvfsbuf.f_fstypename))) { errx(1, "%s: must be on an FFS filesystem", boot); } if (fsync(fd) != 0) err(1, "fsync: %s", boot); if (fstat(fd, &statbuf) != 0) err(1, "fstat: %s", boot); close(fd); /* Read superblock */ devread(devfd, sblock, (daddr_t)(BBSIZE / DEV_BSIZE), SBLOCKSIZE, "superblock"); fs = (struct fs *)sblock; /* Sanity-check super-block. */ if (fs->fs_magic != FS_UFS1_MAGIC) errx(1, "Bad magic number in superblock, must be UFS1"); if (fs->fs_inopb <= 0) err(1, "Bad inopb=%d in superblock", fs->fs_inopb); /* Read inode */ if ((buf = malloc(fs->fs_bsize)) == NULL) errx(1, "No memory for filesystem block"); blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino)); devread(devfd, buf, blk, fs->fs_bsize, "inode"); ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino); /* * Have the inode. Figure out how many blocks we need. */ ndb = howmany(ip->di_size, fs->fs_bsize); if (ndb > maxblocknum) errx(1, "Too many blocks"); *block_count_p = ndb; *block_size_p = fs->fs_bsize; if (verbose) printf("Will load %d blocks of size %d each.\n", ndb, fs->fs_bsize); /* * Get the block numbers; we don't handle fragments */ ap = ip->di_db; for (i = 0; i < NDADDR && *ap && ndb; i++, ap++, ndb--) { blk = fsbtodb(fs, *ap); if (verbose) printf("%d: %d\n", i, blk); block_table[i] = blk; } if (ndb == 0) return 0; /* * Just one level of indirections; there isn't much room * for more in the 1st-level bootblocks anyway. */ blk = fsbtodb(fs, ip->di_ib[0]); devread(devfd, buf, blk, fs->fs_bsize, "indirect block"); /* XXX ondisk32 */ ap = (int32_t *)buf; for (; i < NINDIR(fs) && *ap && ndb; i++, ap++, ndb--) { blk = fsbtodb(fs, *ap); if (verbose) printf("%d: %d\n", i, blk); block_table[i] = blk; } return 0; }
int main(void) { /* dummy variables to prevent null warnings */ char path[] = ""; char mode[] = ""; char buf[1]; struct stat st; struct statfs stfs; struct statvfs stvfs; fpos_t fpos; off_t off; struct rlimit rlim; glob_t glb; int result; DIR* dir; struct dirent direntry; struct dirent* pdirentry; struct dirent** ppdirentry; const struct dirent *pconstdirentry; dir = 0; result = alphasort(&pconstdirentry, &pconstdirentry); creat(path, 0); fgetpos(0, &fpos); fopen(path, mode); freopen(path, mode, 0); fseeko(0, 0, 0); fsetpos(0, &fpos); fstat(0, &st); fstatat(0, path, &st, 0); fstatfs(0, &stfs); fstatvfs(0, &stvfs); ftello(0); ftruncate(0, 0); ftw(path, ftw_stub, 0); getdirentries(0, buf, 0, &off); getrlimit(0, &rlim); glob(path, 0, glob_stub, &glb); lockf(0, 0, 0); lseek(0, 0, 0); lstat(path, &st); mkostemp(path, 0); mkstemp(path); mmap(buf, 0, 0, 0, 0, 0); nftw(path, nftw_stub, 0, 0); open(path, 0); open(path, 0, 0); openat(0, path, 0); openat(0, path, 0, 0); posix_fadvise(0, 0, 0, 0); posix_fallocate(0, 0, 0); pread(0, buf, 0, 0); pwrite(0, buf, 0, 0); readdir(dir); readdir_r(dir, &direntry, &pdirentry); scandir(path, &ppdirentry, scandir_filter_stub, scandir_compare_stub); sendfile(0, 0, &off, 0); setrlimit(0, &rlim); stat(path, &st); statfs(path, &stfs); statvfs(path, &stvfs); tmpfile(); truncate(path, 0); result = versionsort(&pconstdirentry, &pconstdirentry); return result; }
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; siginfo_t si; 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) { r = fd; fd = -1; return r; } 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; } pid = fork(); if (pid < 0) { r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m"); goto fail; } if (pid == 0) { /* Child */ (void) reset_all_signal_handlers(); (void) reset_signal_mask(); assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); fd = safe_close(fd); execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL); if (errno == ENOENT) return 99; _exit(EXIT_FAILURE); } r = wait_for_terminate(pid, &si); if (r < 0) { sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m"); goto fail; } pid = 0; if (si.si_code != CLD_EXITED) { r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs died abnormally."); goto fail; } if (si.si_status == 99) { r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing"); goto fail; } if (si.si_status != 0) { r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", si.si_status); 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; } r = fd; fd = -1; return r; fail: unlink_noerrno(tmp); if (pid > 1) kill_and_sigcont(pid, SIGKILL); return r; }
static void *common_filesystem_open(const char *name, int oflag, mode_t mode, void *context, size_t *size, int *err, const uint8_t *target, gsize target_size, const char *roots[]) { struct stat stats; struct statvfs buf; int fd, ret; uint64_t avail; enum access_op op; if (oflag & O_CREAT) op = ACCESS_OP_CREATE; else if ((oflag & O_WRONLY) || (oflag & O_RDWR)) op = ACCESS_OP_WRITE; else op = ACCESS_OP_READ; ret = access_check(target, target_size, op, name); if (ret < 0) { if (err) *err = ret; return NULL; } fd = open(name, oflag, mode); if (fd < 0) { if (err) *err = -errno; return NULL; } if (fstat(fd, &stats) < 0) { if (err) *err = -errno; goto failed; } ret = verify_path_many(name, roots); if (ret < 0) { if (err) *err = ret; goto failed; } if (oflag == O_RDONLY) { if (size) *size = stats.st_size; goto done; } if (fstatvfs(fd, &buf) < 0) { if (err) *err = -errno; goto failed; } if (size == NULL) goto done; avail = (uint64_t) buf.f_bsize * buf.f_bavail; if (avail < *size) { if (err) *err = -ENOSPC; goto failed; } done: if (err) *err = 0; return GINT_TO_POINTER(fd); failed: close(fd); return NULL; }
static int eat(const char *filename) { #define fail_if(cond) \ while (cond) \ { \ show_error(filename); \ if (fd != -1) \ close(fd); \ return -1; \ } #define check_io(i, j) \ while ((size_t) (i) != (size_t) (j)) \ { \ if ((i) >= 0) \ errno = EIO; \ fail_if(1); \ } const int fd = open(filename, O_RDWR); fail_if(fd == -1); const off_t file_size = lseek(fd, 0, SEEK_END); fail_if(file_size == -1); int rc; off_t offset; ssize_t r_bytes, w_bytes; offset = lseek(fd, 0, SEEK_SET); fail_if(offset == -1); if (block_size == 0) { struct statvfs st; rc = fstatvfs(fd, &st); fail_if(rc == -1); if (st.f_bsize == 0 || st.f_bsize >= block_size_limit) { errno = ERANGE; fail_if(1); } block_size = st.f_bsize; } const off_t n_blocks = (file_size + block_size - 1) / block_size; const size_t tail_size = (size_t) (1 + (file_size - 1) % block_size); switch (n_blocks) { case 2: r_bytes = read(fd, buffer, block_size); check_io(r_bytes, block_size); w_bytes = write(STDOUT_FILENO, buffer, block_size); check_io(w_bytes, block_size); case 1: r_bytes = read(fd, buffer, tail_size); check_io(r_bytes, tail_size); w_bytes = write(STDOUT_FILENO, buffer, (size_t) r_bytes); check_io(w_bytes, r_bytes); case 0: goto done; default: break; } struct stat stat; rc = fstat(fd, &stat); fail_if(rc == -1); if (stat.st_nlink > 1 && !opt_force) { errno = EMLINK; fail_if(1); } for (off_t i = 0; i < n_blocks / 2; i++) { r_bytes = read(fd, buffer, block_size); check_io(r_bytes, block_size); w_bytes = write(STDOUT_FILENO, buffer, block_size); check_io(w_bytes, block_size); if (i == 0 && opt_punch) { #if HAVE_FALLOC_FL_PUNCH_HOLE rc = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, offset, block_size); if (rc == 0) { offset = 0; while (1) { r_bytes = read(fd, buffer, block_size); if (r_bytes == 0) break; offset += r_bytes; fail_if(r_bytes == -1); w_bytes = write(STDOUT_FILENO, buffer, (size_t) r_bytes); check_io(w_bytes, r_bytes); rc = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, offset); fail_if(rc != 0); } goto done; } else #else errno = ENOTSUP; #endif { show_error(filename); if (opt_punch > 1) { fprintf(stderr, "hungrycat: %s: fallocate() failed\n", filename); close(fd); return 1; } else fprintf(stderr, "hungrycat: %s: fallocate() failed; falling back to ftruncate()\n", filename); } } offset = (n_blocks - i - 1) * block_size; r_bytes = pread(fd, buffer, block_size, offset); check_io(r_bytes, (i == 0 ? tail_size : block_size)); w_bytes = pwrite(fd, buffer, (size_t) r_bytes, i * block_size); check_io(r_bytes, w_bytes); rc = ftruncate(fd, offset); fail_if(rc == -1); } if ((n_blocks & 1) == 1) { r_bytes = read(fd, buffer, block_size); check_io(r_bytes, block_size); w_bytes = write(STDOUT_FILENO, buffer, block_size); check_io(w_bytes, block_size); rc = ftruncate(fd, (n_blocks / 2) * block_size); fail_if(rc == -1); } for (off_t i = (n_blocks / 2) - 1; i > 0; i--) { r_bytes = pread(fd, buffer, block_size, i * block_size); check_io(r_bytes, block_size); w_bytes = write(STDOUT_FILENO, buffer, block_size); check_io(w_bytes, block_size); rc = ftruncate(fd, i * block_size); fail_if(rc == -1); } assert(n_blocks > 0); r_bytes = pread(fd, buffer, tail_size, 0); check_io(r_bytes, tail_size); w_bytes = write(STDOUT_FILENO, buffer, (size_t) r_bytes); check_io(w_bytes, r_bytes); done: rc = unlink(filename); fail_if(rc == -1); rc = close(fd); { const int fd = -1; fail_if(rc == -1); } return 0; #undef fail_if }
static int fuse_unecm_statfs(const char *path, struct statvfs* stbuf) { LOG("STATFS [%s]\n", path); return fstatvfs(dir_fd, stbuf); }