Merge branch develop-3.10 into develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / Setup.cpp
1 /**
2  * Copyright (C) ARM Limited 2014. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include "Setup.h"
10
11 #include <dirent.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/utsname.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23
24 #include "Config.h"
25 #include "DynBuf.h"
26 #include "Logging.h"
27
28 bool getLinuxVersion(int version[3]) {
29         // Check the kernel version
30         struct utsname utsname;
31         if (uname(&utsname) != 0) {
32                 logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
33                 return false;
34         }
35
36         version[0] = 0;
37         version[1] = 0;
38         version[2] = 0;
39
40         int part = 0;
41         char *ch = utsname.release;
42         while (*ch >= '0' && *ch <= '9' && part < 3) {
43                 version[part] = 10*version[part] + *ch - '0';
44
45                 ++ch;
46                 if (*ch == '.') {
47                         ++part;
48                         ++ch;
49                 }
50         }
51
52         return true;
53 }
54
55 static int pgrep_gator(DynBuf *const printb) {
56         DynBuf b;
57
58         DIR *proc = opendir("/proc");
59         if (proc == NULL) {
60                 logg->logError(__FILE__, __LINE__, "gator: error: opendir failed");
61                 handleException();
62         }
63
64         int self = getpid();
65
66         struct dirent *dirent;
67         while ((dirent = readdir(proc)) != NULL) {
68                 char *endptr;
69                 const int pid = strtol(dirent->d_name, &endptr, 10);
70                 if (*endptr != '\0' || (pid == self)) {
71                         // Ignore proc items that are not integers like ., cpuinfo, etc...
72                         continue;
73                 }
74
75                 if (!printb->printf("/proc/%i/stat", pid)) {
76                         logg->logError(__FILE__, __LINE__, "gator: error: DynBuf::printf failed");
77                         handleException();
78                 }
79
80                 if (!b.read(printb->getBuf())) {
81                         // This is not a fatal error - the thread just doesn't exist any more
82                         continue;
83                 }
84
85                 char *comm = strchr(b.getBuf(), '(');
86                 if (comm == NULL) {
87                         logg->logError(__FILE__, __LINE__, "gator: error: parsing stat begin failed");
88                         handleException();
89                 }
90                 ++comm;
91                 char *const str = strrchr(comm, ')');
92                 if (str == NULL) {
93                         logg->logError(__FILE__, __LINE__, "gator: error: parsing stat end failed");
94                         handleException();
95                 }
96                 *str = '\0';
97
98                 if (strncmp(comm, "gator", 5) == 0) {
99                         // Assume there is only one gator process
100                         return pid;
101                 }
102         }
103
104         closedir(proc);
105
106         return -1;
107 }
108
109 int update(const char *const gatorPath) {
110         printf("gator: starting\n");
111
112         int version[3];
113         if (!getLinuxVersion(version)) {
114                 logg->logError(__FILE__, __LINE__, "gator: error: getLinuxVersion failed");
115                 handleException();
116         }
117
118         if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) {
119                 logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
120                 handleException();
121         }
122
123         if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) {
124                 logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device.");
125                 handleException();
126         }
127
128         if (access("/sys/module/gator", F_OK) == 0) {
129                 logg->logError(__FILE__, __LINE__, "gator: error: Streamline has detected that the gator kernel module is loaded on your device. Please build an updated version of gator.ko and gatord and install them on your device.");
130                 handleException();
131         }
132
133         if (geteuid() != 0) {
134                 printf("gator: trying sudo\n");
135                 execlp("sudo", "sudo", gatorPath, "-u", NULL);
136                 // Streamline will provide the password if needed
137
138                 printf("gator: trying su\n");
139                 char buf[1<<10];
140                 snprintf(buf, sizeof(buf), "%s -u", gatorPath);
141                 execlp("su", "su", "-", "-c", buf, NULL);
142                 // Streamline will provide the password if needed
143
144                 logg->logError(__FILE__, __LINE__, "gator: error: Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username.");
145                 handleException();
146         }
147         printf("gator: now root\n");
148
149         // setenforce 0 not needed for userspace gator
150
151         // Kill existing gator
152         DynBuf gatorStatPath;
153         int gator_main = pgrep_gator(&gatorStatPath);
154         if (gator_main > 0) {
155                 if (kill(gator_main, SIGTERM) != 0) {
156                         logg->logError(__FILE__, __LINE__, "gator: error: kill SIGTERM failed");
157                         handleException();
158                 }
159                 for (int i = 0; ; ++i) {
160                         if (access(gatorStatPath.getBuf(), F_OK) != 0) {
161                                 break;
162                         }
163                         if (i == 5) {
164                                 if (kill(gator_main, SIGKILL) != 0) {
165                                         logg->logError(__FILE__, __LINE__, "gator: error: kill SIGKILL failed");
166                                         handleException();
167                                 }
168                         } else if (i >= 10) {
169                                 logg->logError(__FILE__, __LINE__, "gator: error: unable to kill running gator");
170                                 handleException();
171                         }
172                         sleep(1);
173                 }
174         }
175         printf("gator: no gatord running\n");
176
177         rename("gatord", "gatord.old");
178         rename("gator.ko", "gator.ko.old");
179
180         // Rename gatord.YYYYMMDDHHMMSSMMMM to gatord
181         char *newGatorPath = strdup(gatorPath);
182         char *dot = strrchr(newGatorPath, '.');
183         if (dot != NULL) {
184                 *dot = '\0';
185                 if (rename(gatorPath, newGatorPath) != 0) {
186                         logg->logError(__FILE__, __LINE__, "gator: error: rename failed");
187                         handleException();
188                 }
189         }
190
191         // Fork and start gatord (redirect stdout and stderr)
192         int child = fork();
193         if (child < 0) {
194                 logg->logError(__FILE__, __LINE__, "gator: error: fork failed");
195                 handleException();
196         } else if (child == 0) {
197                 int inFd = open("/dev/null", O_RDONLY | O_CLOEXEC);
198                 if (inFd < 0) {
199                         logg->logError(__FILE__, __LINE__, "gator: error: open of /dev/null failed");
200                         handleException();
201                 }
202                 int outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
203                 if (outFd < 0) {
204                         logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.out failed");
205                         handleException();
206                 }
207                 int errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
208                 if (errFd < 0) {
209                         logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.err failed");
210                         handleException();
211                 }
212                 if (dup2(inFd, STDIN_FILENO) < 0) {
213                         logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdin failed");
214                         handleException();
215                 }
216                 if (dup2(outFd, STDOUT_FILENO) < 0) {
217                         logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdout failed");
218                         handleException();
219                 }
220                 if (dup2(errFd, STDERR_FILENO) < 0) {
221                         logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stderr failed");
222                         handleException();
223                 }
224                 execlp(newGatorPath, newGatorPath, "-a", NULL);
225                 logg->logError(__FILE__, __LINE__, "gator: error: execlp failed");
226                 handleException();
227         }
228
229         printf("gator: done\n");
230
231         return 0;
232 }