Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 229 lines (192 sloc) 5.618 kb
2ca7eed actually add files
fogobogo authored
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
75b28b4 @falconindy implement more robust option parsing
authored
6 *
2ca7eed actually add files
fogobogo authored
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
75b28b4 @falconindy implement more robust option parsing
authored
11 *
2ca7eed actually add files
fogobogo authored
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15 * MA 02110-1301, USA.
16 */
17
75b28b4 @falconindy implement more robust option parsing
authored
18 #define _GNU_SOURCE
7cacf6f @falconindy sort includes
authored
19 #include <ctype.h>
20 #include <errno.h>
21 #include <getopt.h>
22 #include <signal.h>
2ca7eed actually add files
fogobogo authored
23 #include <stdio.h>
24 #include <stdlib.h>
d278a7f lots of small fixes.
fogobogo authored
25 #include <string.h>
2ca7eed actually add files
fogobogo authored
26 #include <sys/types.h>
7cacf6f @falconindy sort includes
authored
27 #include <sys/wait.h>
2ca7eed actually add files
fogobogo authored
28 #include <time.h>
29 #include <unistd.h>
30
f3cdafa @falconindy overhaul Makefile
authored
31 #ifndef SUSPEND_COMMAND
32 # define SUSPEND_COMMAND "pm-suspend"
33 #endif
035d3a5 call pm-suspend directly
fogobogo authored
34
771f47c @falconindy refactor help to accept a stream name
authored
35 extern char *program_invocation_short_name;
36
e309226 @falconindy fix -Wstrict-prototypes compiler warning
authored
37 static void
771f47c @falconindy refactor help to accept a stream name
authored
38 help(FILE *stream)
d278a7f lots of small fixes.
fogobogo authored
39 {
5539385 @falconindy use a single invocation of printf
authored
40 fprintf(stream, "usage: %s <timespec>\n\n"
41 " -h, --help display this help and exit\n\n"
42 "timespec can be any combination of hours, minutes, and seconds\n"
43 "specified by hH, mM, and sS, respecitively.\n\n"
44 "Examples:\n"
45 " %s 1h 20m 42S # 1 hour, 20 minutes, 42 seconds\n"
46 " %s 1h20M 2h # 3 hours, 20 minutes\n",
47 program_invocation_short_name,
48 program_invocation_short_name,
49 program_invocation_short_name);
771f47c @falconindy refactor help to accept a stream name
authored
50
51 exit(stream == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
d278a7f lots of small fixes.
fogobogo authored
52 }
53
1047f4f @falconindy already return to main with an error/success value
authored
54 static int
43751bc @falconindy replace system() with proper fork/exec
authored
55 do_suspend(void)
56 {
57 pid_t pid;
58 int status;
59
60 pid = vfork();
61 if(pid == -1) {
62 perror("fork");
1047f4f @falconindy already return to main with an error/success value
authored
63 return 1;
43751bc @falconindy replace system() with proper fork/exec
authored
64 }
65
66 if(pid == 0) {
67 execlp(SUSPEND_COMMAND, SUSPEND_COMMAND, NULL);
68 fprintf(stderr, "error: exec: %s\n", strerror(errno));
69 _exit(0);
70 }
71
72 while(wait(&status) != pid);
73 if(WIFEXITED(status) && WEXITSTATUS(status) != 0) {
74 fprintf(stderr, "error: %s exited with status %d\n", SUSPEND_COMMAND,
75 WEXITSTATUS(status));
1047f4f @falconindy already return to main with an error/success value
authored
76 return 1;
43751bc @falconindy replace system() with proper fork/exec
authored
77 }
1047f4f @falconindy already return to main with an error/success value
authored
78
79 return 0;
43751bc @falconindy replace system() with proper fork/exec
authored
80 }
2ca7eed actually add files
fogobogo authored
81
1047f4f @falconindy already return to main with an error/success value
authored
82 static int
75b28b4 @falconindy implement more robust option parsing
authored
83 parse_options(int argc, char **argv)
2ca7eed actually add files
fogobogo authored
84 {
75b28b4 @falconindy implement more robust option parsing
authored
85 int opt;
86 static struct option opts[] = {
87 { "help", no_argument, NULL, 'h' },
88 { 0, 0, 0, 0 }
89 };
90
91 while((opt = getopt_long(argc, argv, "h", opts, NULL)) != -1) {
92 switch(opt) {
93 case 'h':
771f47c @falconindy refactor help to accept a stream name
authored
94 help(stdout);
75b28b4 @falconindy implement more robust option parsing
authored
95 break;
96 default:
97 case '?':
1047f4f @falconindy already return to main with an error/success value
authored
98 return 1;
75b28b4 @falconindy implement more robust option parsing
authored
99 }
100 }
2ca7eed actually add files
fogobogo authored
101
75b28b4 @falconindy implement more robust option parsing
authored
102 /* optind is set globally */
1047f4f @falconindy already return to main with an error/success value
authored
103 return 0;
75b28b4 @falconindy implement more robust option parsing
authored
104 }
2ca7eed actually add files
fogobogo authored
105
4677b02 @falconindy avoid global hour, min, sec vars
authored
106 static int
107 parse_timefragment(const char *fragment, long *hour, long *min, long *sec)
75b28b4 @falconindy implement more robust option parsing
authored
108 {
109 const char *f;
110 long accum = 0;
111
112 for(f = fragment; *f != '\0'; f++) {
113 switch(*f) {
114 case 'h':
c0fbbac @falconindy support H, M, S
authored
115 case 'H':
4677b02 @falconindy avoid global hour, min, sec vars
authored
116 *hour += accum;
75b28b4 @falconindy implement more robust option parsing
authored
117 accum = 0;
118 break;
119 case 'm':
c0fbbac @falconindy support H, M, S
authored
120 case 'M':
4677b02 @falconindy avoid global hour, min, sec vars
authored
121 *min += accum;
75b28b4 @falconindy implement more robust option parsing
authored
122 accum = 0;
123 break;
124 case 's':
c0fbbac @falconindy support H, M, S
authored
125 case 'S':
4677b02 @falconindy avoid global hour, min, sec vars
authored
126 *sec += accum;
75b28b4 @falconindy implement more robust option parsing
authored
127 accum = 0;
128 break;
129 default:
130 if(isdigit(*f)) {
131 accum += (*f - 48);
132
133 /* look ahead */
134 if(isdigit(f[1])) {
135 accum *= 10;
136 }
137 } else {
138 fprintf(stderr, "illegal character in format: %c\n", *f);
4677b02 @falconindy avoid global hour, min, sec vars
authored
139 return 1;
75b28b4 @falconindy implement more robust option parsing
authored
140 }
141 }
142 }
143
144 return 0;
145 }
146
4677b02 @falconindy avoid global hour, min, sec vars
authored
147 static int
148 parse_timespec(int optind, int argc, char **argv, long *hour, long *min, long *sec)
75b28b4 @falconindy implement more robust option parsing
authored
149 {
4677b02 @falconindy avoid global hour, min, sec vars
authored
150 *hour = *min = *sec = 0;
151
75b28b4 @falconindy implement more robust option parsing
authored
152 while(optind < argc) {
4677b02 @falconindy avoid global hour, min, sec vars
authored
153 if(parse_timefragment(argv[optind], hour, min, sec) < 0) {
75b28b4 @falconindy implement more robust option parsing
authored
154 fprintf(stderr, "failed to parse time: %s\n", argv[optind]);
155 return 1;
156 }
157 optind++;
158 }
159
1047f4f @falconindy already return to main with an error/success value
authored
160 if((*hour + *min + *sec) == 0) {
161 fprintf(stderr, "error: duration must be non-zero\n");
162 return 1;
163 }
164
75b28b4 @falconindy implement more robust option parsing
authored
165 return 0;
166 }
167
03c4a64 @falconindy break out timer creation to separate function
authored
168 static int
4677b02 @falconindy avoid global hour, min, sec vars
authored
169 create_alarm(struct itimerspec *wakeup, long seconds)
75b28b4 @falconindy implement more robust option parsing
authored
170 {
2ca7eed actually add files
fogobogo authored
171 timer_t id;
172
03c4a64 @falconindy break out timer creation to separate function
authored
173 /* init timer */
174 if(timer_create(CLOCK_REALTIME_ALARM, NULL, &id) != 0) {
175 perror("error: failed to create timer");
176 return 1;
177 }
178
179 memset(wakeup, 0, sizeof(struct itimerspec));
180
181 /* init itimerspec */
182 if(clock_gettime(CLOCK_REALTIME_ALARM, &wakeup->it_value)) {
183 perror("error: failed to get time from RTC");
184 return 1;
185 }
186
187 /* set itimerspec to some future time */
4677b02 @falconindy avoid global hour, min, sec vars
authored
188 wakeup->it_value.tv_sec += seconds;
03c4a64 @falconindy break out timer creation to separate function
authored
189
190 if(timer_settime(id, TIMER_ABSTIME, wakeup, NULL)) {
191 perror("error: failed to set wakeup time");
192 return 1;
193 }
194
195 return 0;
196 }
197
198 int
199 main(int argc, char *argv[])
200 {
2ca7eed actually add files
fogobogo authored
201 struct itimerspec wakeup;
4677b02 @falconindy avoid global hour, min, sec vars
authored
202 long hour, min, sec;
2ca7eed actually add files
fogobogo authored
203
204 if(argc <= 1) {
1047f4f @falconindy already return to main with an error/success value
authored
205 fprintf(stderr, "error: no timespec specified (use -h or --help for help)\n");
771f47c @falconindy refactor help to accept a stream name
authored
206 help(stderr);
2ca7eed actually add files
fogobogo authored
207 }
208
1047f4f @falconindy already return to main with an error/success value
authored
209 if(parse_options(argc, argv) != 0) {
b44207f @falconindy return from main, instead of calling exit
authored
210 return EXIT_FAILURE;
2ca7eed actually add files
fogobogo authored
211 }
212
1047f4f @falconindy already return to main with an error/success value
authored
213 if(parse_timespec(optind, argc, argv, &hour, &min, &sec) != 0) {
b44207f @falconindy return from main, instead of calling exit
authored
214 return EXIT_FAILURE;
d278a7f lots of small fixes.
fogobogo authored
215 }
2ca7eed actually add files
fogobogo authored
216
4677b02 @falconindy avoid global hour, min, sec vars
authored
217 if(create_alarm(&wakeup, (hour * 3600) + (min * 60) + sec) != 0) {
03c4a64 @falconindy break out timer creation to separate function
authored
218 return EXIT_FAILURE;
5b34b08 add error checks
fogobogo authored
219 }
2ca7eed actually add files
fogobogo authored
220
1047f4f @falconindy already return to main with an error/success value
authored
221 if(do_suspend() != 0) {
222 return EXIT_FAILURE;
223 }
2ca7eed actually add files
fogobogo authored
224
b44207f @falconindy return from main, instead of calling exit
authored
225 return EXIT_SUCCESS;
2ca7eed actually add files
fogobogo authored
226 }
227
3cd8f54 @falconindy add vim modeline
authored
228 /* vim: set et ts=4 sw=4: */
Something went wrong with that request. Please try again.