initd: allow overriding early PATH through build time define
[project/procd.git] / initd / zram.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <fcntl.h>
7
8 #include <sys/utsname.h>
9 #include <sys/mount.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
12 #include <sys/stat.h>
13
14 #include "../log.h"
15
16 #include "init.h"
17
18 #define KB(x) (x * 1024)
19
20 #define ZRAM_MOD_PATH "/lib/modules/%s/zram.ko"
21 #define EXT4_MOD_PATH "/lib/modules/%s/ext4.ko"
22
23 static long
24 proc_meminfo(void)
25 {
26         FILE *fp;
27         char line[256];
28         char *key;
29         long val = KB(16);
30
31         fp = fopen("/proc/meminfo", "r");
32         if (fp == NULL) {
33                 ERROR("Can't open /proc/meminfo: %s\n", strerror(errno));
34                 return errno;
35         }
36
37         while (fgets(line, sizeof(line), fp)) {
38                 key = strtok(line, ":");
39                 if (strcasecmp(key, "MemTotal"))
40                         continue;
41                 val = atol(strtok(NULL, " kB\n"));
42                 break;
43         }
44         fclose(fp);
45
46         if (val > KB(32))
47                 val = KB(32);
48
49         return val;
50 }
51
52 static int
53 early_insmod(char *module)
54 {
55         pid_t pid = fork();
56
57         if (!pid) {
58                 char *modprobe[] = { "/usr/sbin/modprobe", NULL, NULL };
59                 char *path;
60                 struct utsname ver;
61
62                 uname(&ver);
63                 path = alloca(sizeof(module) + strlen(ver.release) + 1);
64                 sprintf(path, module, ver.release);
65                 modprobe[1] = path;
66                 execvp(modprobe[0], modprobe);
67                 ERROR("Can't exec /usr/sbin/modprobe\n");
68                 exit(-1);
69         }
70
71         if (pid <= 0) {
72                 ERROR("Can't exec /usr/sbin/modprobe\n");
73                 return -1;
74         } else {
75                 waitpid(pid, NULL, 0);
76         }
77
78         return 0;
79 }
80
81
82 int
83 mount_zram_on_tmp(void)
84 {
85         char *mkfs[] = { "/usr/sbin/mkfs.ext4", "-b", "4096", "-F", "-L", "TEMP", "-m", "0", "/dev/zram0", NULL };
86         FILE *fp;
87         long zramsize;
88         pid_t pid;
89         int ret;
90
91         if (early_insmod(ZRAM_MOD_PATH) || early_insmod(EXT4_MOD_PATH)) {
92                 ERROR("failed to insmod zram support\n");
93                 return -1;
94         }
95
96         mkdev("*", 0600);
97
98         zramsize = proc_meminfo() / 2;
99         fp = fopen("/sys/block/zram0/disksize", "r+");
100         if (fp == NULL) {
101                 ERROR("Can't open /sys/block/zram0/disksize: %s\n", strerror(errno));
102                 return errno;
103         }
104         fprintf(fp, "%ld", KB(zramsize));
105         fclose(fp);
106
107         pid = fork();
108         if (!pid) {
109                 execvp(mkfs[0], mkfs);
110                 ERROR("Can't exec /sbin/mkfs.ext4\n");
111                 exit(-1);
112         } else if (pid <= 0) {
113                 ERROR("Can't exec /sbin/mkfs.ext4\n");
114                 return -1;
115         } else {
116                 waitpid(pid, NULL, 0);
117         }
118
119         ret = mount("/dev/zram0", "/tmp", "ext4", MS_NOSUID | MS_NODEV | MS_NOATIME, "errors=continue,noquota");
120         if (ret < 0) {
121                 ERROR("Can't mount /dev/zram0 on /tmp: %s\n", strerror(errno));
122                 return errno;
123         }
124
125         LOG("Using up to %ld kB of RAM as ZRAM storage on /mnt\n", zramsize);
126
127         return 0;
128 }