-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
218 lines (190 loc) · 5.74 KB
/
main.cpp
File metadata and controls
218 lines (190 loc) · 5.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
buttonshutdown-daemon - When the push button connected to wiringPi GPIO pin 0 is pushed
and released this daemon initiates a system shutdown. If the button is held down
for 2 secs or longer, a restart is initiated.
Written By: Sanjeev Sharma (http://sanje2v.wordpress.com/)
Modified By: Scott Edlin https://github.com/edlins
License: Freeware
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <signal.h>
#include <pigpio.h>
#define DAEMON_NAME "pibuttonpower"
#define PID_FILE "/var/run/" DAEMON_NAME ".pid"
char *pinstr;
int pinnum;
/* Function prototypes */
void Daemon_Stop(int signum);
void Button_Pressed(int gpio, int level, uint32_t tick);
/* ------------------ Start Here ----------------------- */
int main(int argc, char *argv[])
{
int c;
while ((c = getopt(argc, argv, "p:")) != -1)
{
int this_optind = optind ? optind : 1;
switch (c)
{
case 'p':
pinstr = optarg;
pinnum = strtol(pinstr, NULL, 10);
break;
case '?':
if (optopt == 'c')
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
return 1;
default:
abort();
}
}
if (pinstr == NULL)
{
fprintf(stderr, "Error: pin must be specified with -p <wiringPiPin>\n");
return 1;
}
if ((pinnum < 1) || (pinnum > 31))
{
fprintf(stderr, "Error: pin %d is not between 1 and 20\n", pinnum);
return 1;
}
/* Logging */
setlogmask(LOG_UPTO(LOG_INFO));
openlog(DAEMON_NAME, LOG_CONS | LOG_PERROR, LOG_USER);
syslog(LOG_INFO, "Daemon starting up on pin %d", pinnum);
/* This daemon can only run as root. So make sure that it is. */
if (geteuid() != 0)
{
syslog(LOG_ERR, "This daemon can only be run by root user, exiting");
exit(EXIT_FAILURE);
}
/* Ensure only one copy */
/*
Common user should be able to read the pid file so that they
need not use 'sudo' with 'service buttonshutdown-daemon status'
to read daemon status. The correct PID file permission should be:
1. Read & Write permission for owner
2. Read permission for group and others
*/
const int PIDFILE_PERMISSION = 0644;
int pidFilehandle = open(PID_FILE, O_RDWR | O_CREAT, PIDFILE_PERMISSION);
if (pidFilehandle == -1)
{
/* Couldn't open lock file */
syslog(LOG_ERR, "Could not open PID lock file %s, exiting", PID_FILE);
exit(EXIT_FAILURE);
}
/* Try to lock file */
if (lockf(pidFilehandle, F_TLOCK, 0) == -1)
{
/* Couldn't get lock on lock file */
syslog(LOG_ERR, "Could not lock PID lock file %s, exiting", PID_FILE);
exit(EXIT_FAILURE);
}
/* Our process ID and Session ID */
pid_t pid, sid;
/* Fork off the parent process */
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0)
exit(EXIT_SUCCESS);
/* Get and format PID */
char szPID[16];
sprintf(szPID, "%d\n", getpid()); // Call 'getpid()', don't use 'pid' variable
/* write pid to lockfile */
write(pidFilehandle, szPID, strlen(szPID));
/* Change the file mode mask */
umask(0);
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) /* Log the failure */
{
syslog(LOG_ERR, "setsid() failed with %d\n", sid);
exit(EXIT_FAILURE);
}
/* Change the current working directory */
if (chdir("/") < 0) /* Log the failure */
{
syslog(LOG_ERR, "chdir() failed with a negative value");
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* Daemon-specific initializations */
/* Add a process termination handler for
handling daemon stop requests */
signal(SIGTERM, &Daemon_Stop);
int init = gpioInitialise();
if (init < 0)
{
syslog(LOG_ERR, "gpioInitialise failed with %d\n", init);
exit(init);
}
else
{
syslog(LOG_INFO, "gpioInitialise succeeded with %d\n", init);
}
/* Setup pin mode and interrupt handler */
gpioSetMode(pinnum, PI_INPUT);
gpioSetPullUpDown(pinnum, PI_PUD_UP);
if (gpioSetAlertFunc(pinnum, Button_Pressed) != 0)
{
syslog(LOG_ERR, "Unable to set interrupt handler for specified pin, exiting");
exit(EXIT_FAILURE);
}
/*
The Big Loop
1. When pressed for less than 2 secs, shutdown system
2. When pressed for 2 secs or more, restart system
*/
while (true)
{
/*
Daemon hearbeat
Just wait until there's an interrupt or system shutdown
*/
sleep(60);
}
}
void Daemon_Stop(int signum)
{
/* 'SIGTERM' was issued, system is telling this daemon to stop */
syslog(LOG_INFO, "Stopping daemon");
exit(EXIT_SUCCESS);
}
void Button_Pressed(int gpio, int level, uint32_t tick)
{
/* Handle button pressed interrupts */
/* Disable further interrupts */
gpioSetAlertFunc(pinnum, NULL);
/* Just wait for user to release the button */
sleep(2);
switch (gpioRead(pinnum))
{
case PI_HIGH:
syslog(LOG_INFO, "Shutting down system");
if (execl("/sbin/poweroff", "poweroff", NULL) == -1)
syslog(LOG_ERR, "'poweroff' program failed to run with error: %d", errno);
// NOTE: Execution will not reach here if 'execl()' succeeds
break;
case PI_LOW:
syslog(LOG_INFO, "Restarting system");
if (execl("/sbin/shutdown", "shutdown", "-r", "now", NULL) == -1)
syslog(LOG_ERR, "'shutdown' program failed to run with error: %d", errno);
// NOTE: Execution will not reach here if 'execl()' succeeds
break;
}
exit(EXIT_SUCCESS);
}