forked from wertarbyte/triggerhappy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmdsocket.c
152 lines (135 loc) · 3.42 KB
/
cmdsocket.c
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
/* Copyright 2010 Stefan Tomanek <stefan.tomanek+th@wertarbyte.de>
* You have permission to copy, modify, and redistribute under the
* terms of the GPLv3 or any later version.
* For full license terms, see COPYING.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
#endif
#include "devtag.h"
#include "devices.h"
#include "command.h"
#include "cmdsocket.h"
int bind_cmdsocket( char *name ) {
int cmd_fd;
#ifdef HAVE_SYSTEMD
if (sd_listen_fds(0) == 1) {
fprintf(stderr, SD_DEBUG "Found socket passed from systemd\n");
return SD_LISTEN_FDS_START + 0;
}
#endif
struct sockaddr_un addr;
/* remove any stale files */
struct stat sb;
int serr = stat(name, &sb);
if ( !serr && S_ISSOCK(sb.st_mode)) {
unlink(name);
}
cmd_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
strcpy(addr.sun_path, name);
addr.sun_family = AF_UNIX;
bind (cmd_fd, (struct sockaddr *) &addr,
strlen(addr.sun_path) + sizeof (addr.sun_family));
return cmd_fd;
}
int connect_cmdsocket( char *name ) {
int fd;
struct sockaddr_un server;
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
strcpy(server.sun_path, name);
server.sun_family = AF_UNIX;
connect(fd, (struct sockaddr *) &server,
strlen(server.sun_path) + sizeof (server.sun_family));
return fd;
}
struct command *read_command( int cmd_fd ) {
struct command *cmd = malloc(sizeof(struct command));
if (! cmd) {
fprintf(stderr, "Unable to allocate memory for command!\n");
return NULL;
}
int fd[1] = {-1};
char buffer[CMSG_SPACE(sizeof fd)];
struct iovec v = {
.iov_base = cmd,
.iov_len = sizeof(*cmd)
};
struct msghdr msg = {
.msg_iov = &v,
.msg_iovlen = 1,
.msg_control = buffer,
.msg_controllen = sizeof(buffer)
};
int done = recvmsg( cmd_fd, &msg, 0 );
if (done == -1) {
fprintf(stderr, "Error reading command.");
free(cmd);
return NULL;
}
struct cmsghdr *cmessage = CMSG_FIRSTHDR(&msg);
if (cmessage) {
memcpy(fd, CMSG_DATA(cmessage), sizeof fd);
/* place FD back in the command message */
cmd->fd = (int) fd[0];
}
return cmd;
}
int send_command( int cmd_fd, enum command_type type, char *param, int passfd, int exclusive, char *tag ) {
if (type == CMD_ADD && passfd == 1) {
type = CMD_PASSFD;
}
struct command cmd = {
.fd = -1,
.exclusive = exclusive,
.type = type,
.param = {0},
.tag = {0}
};
if (param != NULL) {
strncpy(cmd.param, param, TH_COMMAND_PARAM_LENGTH);
cmd.param[TH_COMMAND_PARAM_LENGTH-1] = '\0';
}
if (tag != NULL) {
strncpy(cmd.tag, tag, TH_DEVICE_TAG_LENGTH);
cmd.tag[TH_DEVICE_TAG_LENGTH-1] = '\0';
}
struct iovec v = {
.iov_base = &cmd,
.iov_len = sizeof(cmd)
};
struct msghdr m = {
.msg_iov = &v,
.msg_iovlen = 1
};
/* add FD */
int dev_fd[1] = { -1 };
char buffer[CMSG_SPACE(sizeof(dev_fd))];
if (passfd) {
int fd = open( param, O_RDONLY );
if (fd < 0) {
perror("open");
return 1;
}
dev_fd[0] = fd ;
m.msg_control = buffer;
m.msg_controllen = sizeof(buffer);
struct cmsghdr *cmessage = CMSG_FIRSTHDR(&m);
cmessage->cmsg_level = SOL_SOCKET;
cmessage->cmsg_type = SCM_RIGHTS;
cmessage->cmsg_len = CMSG_LEN(sizeof(dev_fd));
m.msg_controllen = cmessage->cmsg_len;
memcpy(CMSG_DATA(cmessage), dev_fd, sizeof dev_fd);
}
int done = sendmsg( cmd_fd, &m, 0 );
return (done == -1);
}