~ubuntu-branches/ubuntu/raring/joyent-mdata-client/raring-updates

« back to all changes in this revision

Viewing changes to plat/linux.c

  • Committer: Package Import Robot
  • Author(s): Ben Howard
  • Date: 2013-11-07 08:14:52 UTC
  • Revision ID: package-import@ubuntu.com-20131107081452-z0kajfx8fpi5prgg
Tags: upstream-0.0.1
ImportĀ upstreamĀ versionĀ 0.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2013, Joyent, Inc.
 
3
 * See LICENSE file for copyright and license details.
 
4
 */
 
5
 
 
6
#include <stdlib.h>
 
7
#include <stdio.h>
 
8
#include <err.h>
 
9
#include <string.h>
 
10
#include <strings.h>
 
11
#include <sys/types.h>
 
12
#include <sys/stat.h>
 
13
#include <fcntl.h>
 
14
#include <unistd.h>
 
15
#include <err.h>
 
16
#include <errno.h>
 
17
#include <termios.h>
 
18
#include <sys/socket.h>
 
19
#include <sys/un.h>
 
20
 
 
21
#include <sys/epoll.h>
 
22
 
 
23
#include "common.h"
 
24
#include "plat.h"
 
25
#include "dynstr.h"
 
26
#include "plat/unix_common.h"
 
27
 
 
28
#define SERIAL_DEVICE   "/dev/ttyS1"
 
29
 
 
30
typedef struct mdata_plat {
 
31
        int mpl_epoll;
 
32
        int mpl_conn;
 
33
} mdata_plat_t;
 
34
 
 
35
static int
 
36
raw_mode(int fd, char **errmsg)
 
37
{
 
38
        struct termios tios;
 
39
 
 
40
        if (tcgetattr(fd, &tios) == -1) {
 
41
                *errmsg = "could not set raw mode on serial device";
 
42
                return (-1);
 
43
        }
 
44
 
 
45
        tios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
 
46
        tios.c_oflag &= ~(OPOST);
 
47
        tios.c_cflag |= (CS8);
 
48
        tios.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
 
49
 
 
50
        /*
 
51
         * As described in "Case C: MIN = 0, TIME > 0" of termio(7I), this
 
52
         * configuration will block waiting for at least one character, or
 
53
         * the expiry of a 100 millisecond timeout:
 
54
         */
 
55
        tios.c_cc[VMIN] = 0;
 
56
        tios.c_cc[VTIME] = 1;
 
57
 
 
58
        if (tcsetattr(fd, TCSAFLUSH, &tios) == -1) {
 
59
                *errmsg = "could not get attributes from serial device";
 
60
                return (-1);
 
61
        }
 
62
 
 
63
        return (0);
 
64
}
 
65
 
 
66
static int
 
67
open_md(int *outfd, char **errmsg, int *permfail)
 
68
{
 
69
        int fd;
 
70
        char scrap[100];
 
71
        ssize_t sz;
 
72
        struct flock l;
 
73
 
 
74
        if ((fd = open(SERIAL_DEVICE, O_RDWR | O_EXCL |
 
75
            O_NOCTTY)) == -1) {
 
76
                *errmsg = "Could not open serial device.";
 
77
                if (errno != EAGAIN && errno != EBUSY && errno != EINTR)
 
78
                        *permfail = 1;
 
79
                return (-1);
 
80
        }
 
81
 
 
82
        /*
 
83
         * Lock the serial port for exclusive access:
 
84
         */
 
85
        l.l_type = F_WRLCK;
 
86
        l.l_whence = SEEK_SET;
 
87
        l.l_start = l.l_len = 0;
 
88
        if (fcntl(fd, F_SETLKW, &l) == -1) {
 
89
                fprintf(stderr, "could not lock: %s\n", strerror(errno));
 
90
                return (-1);
 
91
        }
 
92
 
 
93
        /*
 
94
         * Set raw mode on the serial port:
 
95
         */
 
96
        if (raw_mode(fd, errmsg) == -1) {
 
97
                (void) close(fd);
 
98
                *permfail = 1;
 
99
                return (-1);
 
100
        }
 
101
 
 
102
        /*
 
103
         * Because this is a shared serial line, we may be part way through
 
104
         * a response from the remote peer.  Read (and discard) data until we
 
105
         * cannot do so anymore:
 
106
         */
 
107
        do {
 
108
                sz = read(fd, &scrap, sizeof (scrap));
 
109
 
 
110
                if (sz == -1 && errno != EAGAIN) {
 
111
                        *errmsg = "Failed to flush serial port before use.";
 
112
                        (void) close(fd);
 
113
                        return (-1);
 
114
                }
 
115
 
 
116
        } while (sz > 0);
 
117
 
 
118
        *outfd = fd;
 
119
 
 
120
        return (0);
 
121
}
 
122
 
 
123
 
 
124
int
 
125
plat_send(mdata_plat_t *mpl, string_t *data)
 
126
{
 
127
        int len = dynstr_len(data);
 
128
 
 
129
        if (write(mpl->mpl_conn, dynstr_cstr(data), len) != len)
 
130
                return (-1);
 
131
 
 
132
        return (0);
 
133
}
 
134
 
 
135
int
 
136
plat_recv(mdata_plat_t *mpl, string_t *data, int timeout_ms)
 
137
{
 
138
        for (;;) {
 
139
                struct epoll_event event;
 
140
 
 
141
                if (epoll_wait(mpl->mpl_epoll, &event, 1, timeout_ms) == -1) {
 
142
                        fprintf(stderr, "epoll error: %d\n", errno);
 
143
                        if (errno == EINTR) {
 
144
                                return (-1);
 
145
                        }
 
146
                        err(1, "EPOLL_WAIT ERROR");
 
147
                }
 
148
 
 
149
                if (event.data.fd == 0 || event.events == 0) {
 
150
                        fprintf(stderr, "plat_recv timeout\n");
 
151
                        return (-1);
 
152
                }
 
153
 
 
154
                if (event.events & EPOLLIN) {
 
155
                        char buf[2];
 
156
                        ssize_t sz;
 
157
 
 
158
                        sz = read(mpl->mpl_conn, buf, 1);
 
159
                        if (sz == 0) {
 
160
                                fprintf(stderr, "WHAT, NO DATA?!\n");
 
161
                                continue;
 
162
                        }
 
163
 
 
164
                        if (buf[0] == '\n') {
 
165
                                return (0);
 
166
                        } else {
 
167
                                buf[1] = '\0';
 
168
                                dynstr_append(data, buf);
 
169
                        }
 
170
                }
 
171
                if (event.events & EPOLLERR) {
 
172
                        fprintf(stderr, "POLLERR\n");
 
173
                        return (-1);
 
174
                }
 
175
                if (event.events & EPOLLHUP) {
 
176
                        fprintf(stderr, "POLLHUP\n");
 
177
                        return (-1);
 
178
                }
 
179
        }
 
180
 
 
181
        return (-1);
 
182
}
 
183
 
 
184
void
 
185
plat_fini(mdata_plat_t *mpl __UNUSED)
 
186
{
 
187
        if (mpl != NULL) {
 
188
                if (mpl->mpl_epoll != -1)
 
189
                        (void) close(mpl->mpl_epoll);
 
190
                if (mpl->mpl_conn != -1)
 
191
                        (void) close(mpl->mpl_conn);
 
192
                free(mpl);
 
193
        }
 
194
}
 
195
 
 
196
static int
 
197
plat_send_reset(mdata_plat_t *mpl)
 
198
{
 
199
        int ret = -1;
 
200
        string_t *str = dynstr_new();
 
201
 
 
202
        dynstr_append(str, "\n");
 
203
        if (plat_send(mpl, str) != 0)
 
204
                goto bail;
 
205
        dynstr_reset(str);
 
206
 
 
207
        if (plat_recv(mpl, str, 2000) != 0)
 
208
                goto bail;
 
209
 
 
210
        if (strcmp(dynstr_cstr(str), "invalid command") != 0)
 
211
                goto bail;
 
212
 
 
213
        ret = 0;
 
214
 
 
215
bail:
 
216
        dynstr_free(str);
 
217
        return (ret);
 
218
}
 
219
 
 
220
int
 
221
plat_is_interactive(void)
 
222
{
 
223
        return (unix_is_interactive());
 
224
}
 
225
 
 
226
int
 
227
plat_init(mdata_plat_t **mplout, char **errmsg, int *permfail)
 
228
{
 
229
        mdata_plat_t *mpl = NULL;
 
230
        struct epoll_event event;
 
231
 
 
232
        if ((mpl = calloc(1, sizeof (*mpl))) == NULL) {
 
233
                *errmsg = "Could not allocate memory.";
 
234
                *permfail = 1;
 
235
                goto bail;
 
236
        }
 
237
        mpl->mpl_epoll = -1;
 
238
        mpl->mpl_conn = -1;
 
239
 
 
240
        if ((mpl->mpl_epoll = epoll_create(1)) == -1) {
 
241
                *errmsg = "Could not create epoll fd.";
 
242
                *permfail = 1;
 
243
                goto bail;
 
244
        }
 
245
 
 
246
        if (open_md(&mpl->mpl_conn, errmsg, permfail) != 0) {
 
247
                goto bail;
 
248
        }
 
249
 
 
250
        event.data.fd = mpl->mpl_conn;
 
251
        event.events = EPOLLIN | EPOLLERR | EPOLLHUP;
 
252
 
 
253
        if (epoll_ctl(mpl->mpl_epoll, EPOLL_CTL_ADD, mpl->mpl_conn,
 
254
            &event) == -1) {
 
255
                *errmsg = "Could not add conn to epoll context.";
 
256
                *permfail = 1;
 
257
                goto bail;
 
258
        }
 
259
 
 
260
        if (plat_send_reset(mpl) == -1) {
 
261
                *errmsg = "Could not do active reset.";
 
262
                goto bail;
 
263
        }
 
264
 
 
265
        *mplout = mpl;
 
266
 
 
267
        return (0);
 
268
 
 
269
bail:
 
270
        plat_fini(mpl);
 
271
        return (-1);
 
272
}