1 /**
2 * Copyright (C) 2015 Aaron Ball <nullspoon@iohq.net>
3 *
4 * Terminus is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Terminus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with terminus. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21 #include <math.h>
22
23
24 /**
25 * Converts the given day count to seconds (multiplies by the number of seconds
26 * in a day, 86400).
27 *
28 * @param days Day count to convert to seconds
29 *
30 * @return long Number of total seconds in the given day duration
31 */
32 long days_to_seconds(int days) {
33 return days * 86400;
34 }
35
36
37 /**
38 * Converts the given "string integer" to a long datatype. This is useful for
39 * programs that take command line arguments from the user and they need to
40 * treats those arguments like actual numbers.
41 *
42 * @param intstr Integer string
43 *
44 * @return long The integer represented by the given string
45 */
46 long ctoi(char* intstr) {
47 // TODO: This doesn't work yet
48 int i = 0;
49 long out = 0;
50
51 while(intstr[i] != '\0') {
52 //printf("%d\n", intstr[i] - 48);
53 if(intstr[i] == '0') {
54 out += pow(10,i);
55 } else {
56 out += (intstr[i] - 48) + pow(10,i);
57 }
58 i++;
59 }
60 return out;
61 }
62
63
64 /**
65 * TODO
66 */
67 int get_user_home(char* out) {
68 if(getenv("HOME") != NULL) {
69 strcpy(out, getenv("HOME"));
70 return 0;
71 } else {
72 return 1;
73 }
74 }
75
76
77 /**
78 * Writes the current timestamp to the specified lastlogin file
79 *
80 * @param path Path to the lastlogin file
81 *
82 * @return int Status of the write operation
83 */
84 int write_lastlogin(char* path) {
85 FILE* f = fopen(path, "w+");
86
87 // Exit if file cannot be opened for writing
88 if(f == NULL) { return 1; }
89
90 // Write the current time
91 fprintf(f, "%d", time(NULL));
92
93 fclose(f);
94 return 0;
95 }
96
97
98 /**
99 * Gets the time_t value contained in the specified lastlogin file.
100 *
101 * @param lastlogin_path Path to the lastlogin file to be read
102 * @param lastlogin Output time_t variable
103 *
104 * @return int Status of reading the lastlogin file
105 */
106 int get_lastlogin(char* lastlogin_path, time_t* lastlogin) {
107 // File pointer to lastlogin file (used for reading and writing)
108 FILE* lastlogin_file;
109 // String contents of the lastlogin file
110 char lastlogin_str[32];
111
112 // Attempt read lastlogin file contents
113 lastlogin_file = fopen(lastlogin_path, "r");
114
115 if(lastlogin_file == NULL) {
116 return 1;
117 } else {
118 // Read the lastlogin file and set its value to lastlogin
119 fgets(lastlogin_str, 32, lastlogin_file);
120 *lastlogin = atoi(lastlogin_str);
121 fclose(lastlogin_file);
122 }
123 return 0;
124 }
125
126
127 /**
128 * Executes the specified command, printing the output.
129 * Note that this does read the calling shell's environmental variables, and so
130 * absolute paths are not necessary if the command targets an executable in
131 * PATH.
132 *
133 * @param cmd Command to be executed and output to be printed
134 *
135 * @return int Execution status of the command
136 * Note that if the command fails execution at start, -1 is
137 * returned.
138 */
139 int exec_cmd(char* cmd) {
140 FILE* p = popen(cmd, "r");
141 if(p == NULL) { return -1; }
142
143 // Buffer for each line
144 char line[256];
145 // For each line, print the output
146 while (fgets(line, sizeof(line)-1, p) != NULL) {
147 printf("%s", line);
148 }
149
150 return pclose(p);
151 }
152
153
154 /**
155 * Ye olde main function
156 */
157 int main(int argc, char* argv[]) {
158 char home[128];
159 int days;
160 char* cmd;
161 // Expected path to lastlogin file
162 char lastlogin_path[256];
163 // Time-related variables
164 time_t now;
165 time_t threshold;
166 time_t lastlogin;
167
168 if(argc < 3) {
169 printf(
170 "Please specify a timeout threshold (in days) as well as a command\n"
171 "or commands to be run if the threshold is exceeded.\n\n"
172 "[1mExample:[0m\n"
173 " terminus 5 '<command to execute>'\n\n"
174 "This example will execute the given command if the user has not\n"
175 "logged in in the last 5 days.\n\n"
176 );
177 return 1;
178 }
179
180 // Get program arguments
181 days = atoi(argv[1]);
182 cmd = argv[2];
183
184 // Compose path to lastlogin file
185 get_user_home(home);
186 strcpy(lastlogin_path, home);
187 strcat(lastlogin_path, "/.lastlogin");
188
189 // Set time-related values
190 now = time(NULL);
191 threshold = days_to_seconds(days);
192 if(get_lastlogin(lastlogin_path, &lastlogin) == 1) {
193 // Create lastlogin file since it doesn't exist
194 printf("Lastlogin file could not be read. Writing\n");
195 if(write_lastlogin(lastlogin_path) == 1) {
196 printf("Failure writing lastlogin\n");
197 return 1;
198 }
199 // Go ahead and set lastlogin time, since writing it means we're using
200 // "now".
201 lastlogin = time(NULL);
202 }
203
204 // Determine if I'm dead
205 if((now - lastlogin) > threshold) {
206 printf("You're dead!\n");
207 exec_cmd(cmd);
208 } else {
209 if(write_lastlogin(lastlogin_path) == 1) {
210 printf("Failure writing lastlogin\n");
211 return 1;
212 }
213 printf("You're not dead!\n");
214 }
215
216 return 0;
217 }
|