/** * scrotty — Screenshot program for Linux's TTY * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #ifndef PATH_MAX # define PATH_MAX 4096 #endif #ifndef DEVDIR # define DEVDIR "/dev" #endif #ifndef SYSDIR # define SYSDIR "/sys" #endif #define LIST_0_9(P) P"0\n", P"1\n", P"2\n", P"3\n", P"4\n", P"5\n", P"6\n", P"7\n", P"8\n", P"9\n" static const char* inttable[] = { LIST_0_9(""), LIST_0_9("1"), LIST_0_9("2"), LIST_0_9("3"), LIST_0_9("4"), LIST_0_9("5"), LIST_0_9("6"), LIST_0_9("7"), LIST_0_9("8"), LIST_0_9("9"), LIST_0_9("10"), LIST_0_9("11"), LIST_0_9("12"), LIST_0_9("13"), LIST_0_9("14"), LIST_0_9("15"), LIST_0_9("16"), LIST_0_9("17"), LIST_0_9("18"), LIST_0_9("19"), LIST_0_9("20"), LIST_0_9("21"), LIST_0_9("22"), LIST_0_9("23"), LIST_0_9("24"), "250\n", "251\n", "252\n", "253\n", "254\n", "255\n" }; static int save_pnm(const char* fbpath, int fbno, int fd) { char buf[PATH_MAX]; FILE* file; int saved_errno, sizefd, fbfd, r, g, b; ssize_t got, off; sprintf(buf, SYSDIR "/class/graphics/fb%i/virtual_size", fbno); if (sizefd = open(buf, O_RDONLY), sizefd < 0) return -1; if (got = read(sizefd, buf, sizeof(buf) / sizeof(char) - 1), got < 0) return saved_errno = errno, close(sizefd), errno = saved_errno, -1; close(sizefd); buf[got] = '\0'; *strchr(buf, ',') = ' '; fbfd = open(fbpath, O_RDONLY); if (fbfd < 0) return -1; file = fdopen(fd, "w"); if (file == NULL) return saved_errno = errno, close(fbfd), errno = saved_errno, -1; fprintf(file, "P3\n%s255\n", buf); for (off = 0;;) { got = read(fbfd, buf + off, sizeof(buf) - off * sizeof(char)); if (got < 0) return saved_errno = errno, fclose(file), close(fbfd), errno = saved_errno, -1; if (got += off, got == 0) break; for (off = 0; off < got; off += 4) { r = buf[off + 2] & 255; g = buf[off + 1] & 255; b = buf[off + 0] & 255; fprintf(file, "%s%s%s", inttable[r], inttable[g], inttable[b]); } if (off != got) { off -= 4; memcpy(buf, buf + off, (got - off) * sizeof(char)); off = got - off; } else off = 0; } fflush(file); fclose(file); close(fbfd); return 0; } static int save(const char* fbpath, const char* imgpath, int fbno, const char* execname) { int pipe_rw[2]; pid_t pid, reaped; int saved_errno, status; if (pipe(pipe_rw) < 0) return -1; if (pid = fork(), pid == -1) return saved_errno = errno, close(pipe_rw[0]), close(pipe_rw[1]), errno = saved_errno, -1; if (pid == 0) { close(pipe_rw[1]); if (pipe_rw[0] != STDIN_FILENO) { close(STDIN_FILENO); dup2(pipe_rw[0], STDIN_FILENO); close(pipe_rw[0]); } execlp("convert", "convert", DEVDIR "/stdin", imgpath, NULL); perror(execname); exit(1); } close(pipe_rw[0]); if (save_pnm(fbpath, fbno, pipe_rw[1]) < 0) return saved_errno = errno, close(pipe_rw[1]), errno = saved_errno, -1; close(pipe_rw[1]); reaped = 0; while (reaped != pid) { reaped = waitpid(pid, &status, 0); if (reaped < 0) return -1; } return status == 0 ? 0 : -1; } int main(int argc, char* argv[]) { char fbpath[PATH_MAX]; char imgpath[PATH_MAX]; int i, fbno; (void) argc; for (fbno = 0;; fbno++) { sprintf(fbpath, DEVDIR "/fb%i", fbno); if (access(fbpath, F_OK)) break; sprintf(imgpath, "fb%i.png", fbno); if (access(imgpath, F_OK) == 0) for (i = 2;; i++) { sprintf(imgpath, "fb%i.png.%i", fbno, i); if (access(imgpath, F_OK)) break; } if (save(fbpath, imgpath, fbno, *argv) < 0) return perror(*argv), 1; fprintf(stderr, "Saved framebuffer %i to %s\n", fbno, imgpath); } return 0; }