~siretart/lcd4linux/debian

« back to all changes in this revision

Viewing changes to plugin_exec.c

  • Committer: Reinhard Tartler
  • Date: 2011-04-27 17:24:15 UTC
  • mto: This revision was merged to the branch mainline in revision 750.
  • Revision ID: siretart@tauware.de-20110427172415-6n4aptmvmz0eztvm
Tags: upstream-0.11.0~svn1143
Import upstream version 0.11.0~svn1143

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: plugin_exec.c 840 2007-09-09 12:17:42Z michael $
 
2
 * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/plugin_exec.c $
 
3
 *
 
4
 * plugin for external processes
 
5
 *
 
6
 * Copyright (C) 2004 Michael Reinelt <michael@reinelt.co.at>
 
7
 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 
8
 *
 
9
 * based on the old 'exec' client which is
 
10
 * Copyright (C) 2001 Leopold T�tsch <lt@toetsch.at>
 
11
 *
 
12
 *
 
13
 * This file is part of LCD4Linux.
 
14
 *
 
15
 * LCD4Linux is free software; you can redistribute it and/or modify
 
16
 * it under the terms of the GNU General Public License as published by
 
17
 * the Free Software Foundation; either version 2, or (at your option)
 
18
 * any later version.
 
19
 *
 
20
 * LCD4Linux is distributed in the hope that it will be useful,
 
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
23
 * GNU General Public License for more details.
 
24
 *
 
25
 * You should have received a copy of the GNU General Public License
 
26
 * along with this program; if not, write to the Free Software
 
27
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
28
 *
 
29
 */
 
30
 
 
31
/* 
 
32
 * exported functions:
 
33
 *
 
34
 * int plugin_init_exec (void)
 
35
 *  adds functions to start external pocesses
 
36
 *
 
37
 */
 
38
 
 
39
 
 
40
#include "config.h"
 
41
 
 
42
#include <stdlib.h>
 
43
#include <stdio.h>
 
44
#include <unistd.h>
 
45
#include <string.h>
 
46
#include <errno.h>
 
47
 
 
48
#include "debug.h"
 
49
#include "plugin.h"
 
50
#include "hash.h"
 
51
#include "cfg.h"
 
52
#include "thread.h"
 
53
#include "qprintf.h"
 
54
 
 
55
 
 
56
#define NUM_THREADS 16
 
57
#define SHM_SIZE 4096
 
58
 
 
59
typedef struct {
 
60
    int delay;
 
61
    int mutex;
 
62
    pid_t pid;
 
63
    int shmid;
 
64
    char *cmd;
 
65
    char *key;
 
66
    char *ret;
 
67
} EXEC_THREAD;
 
68
 
 
69
static EXEC_THREAD Thread[NUM_THREADS];
 
70
static int max_thread = -1;
 
71
 
 
72
static HASH EXEC;
 
73
 
 
74
 
 
75
/* x^0 + x^5 + x^12 */
 
76
#define CRCPOLY 0x8408
 
77
 
 
78
static unsigned short CRC(const char *s)
 
79
{
 
80
    int i;
 
81
    unsigned short crc;
 
82
 
 
83
    /* seed value */
 
84
    crc = 0xffff;
 
85
 
 
86
    while (*s != '\0') {
 
87
        crc ^= *s++;
 
88
        for (i = 0; i < 8; i++)
 
89
            crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY : 0);
 
90
    }
 
91
    return crc;
 
92
}
 
93
 
 
94
 
 
95
static void exec_thread(void *data)
 
96
{
 
97
    EXEC_THREAD *Thread = (EXEC_THREAD *) data;
 
98
    FILE *pipe;
 
99
    char buffer[SHM_SIZE];
 
100
    int len;
 
101
 
 
102
    /* use a safe path */
 
103
    putenv("PATH=/usr/local/bin:/usr/bin:/bin");
 
104
 
 
105
    /* forever... */
 
106
    while (1) {
 
107
        pipe = popen(Thread->cmd, "r");
 
108
        if (pipe == NULL) {
 
109
            error("exec error: could not run pipe '%s': %s", Thread->cmd, strerror(errno));
 
110
            len = 0;
 
111
        } else {
 
112
            len = fread(buffer, 1, SHM_SIZE - 1, pipe);
 
113
            if (len <= 0) {
 
114
                error("exec error: could not read from pipe '%s': %s", Thread->cmd, strerror(errno));
 
115
                len = 0;
 
116
            }
 
117
            pclose(pipe);
 
118
        }
 
119
 
 
120
        /* force trailing zero */
 
121
        buffer[len] = '\0';
 
122
 
 
123
        /* remove trailing CR/LF */
 
124
        while (len > 0 && (buffer[len - 1] == '\n' || buffer[len - 1] == '\r')) {
 
125
            buffer[--len] = '\0';
 
126
        }
 
127
 
 
128
        /* lock shared memory */
 
129
        mutex_lock(Thread->mutex);
 
130
        /* write data */
 
131
        strncpy(Thread->ret, buffer, SHM_SIZE);
 
132
        /* unlock shared memory */
 
133
        mutex_unlock(Thread->mutex);
 
134
        usleep(Thread->delay);
 
135
    }
 
136
}
 
137
 
 
138
 
 
139
static void destroy_exec_thread(const int n)
 
140
{
 
141
    thread_destroy(Thread[n].pid);
 
142
 
 
143
    if (Thread[n].mutex != 0)
 
144
        mutex_destroy(Thread[n].mutex);
 
145
    if (Thread[n].cmd)
 
146
        free(Thread[n].cmd);
 
147
    if (Thread[n].key)
 
148
        free(Thread[n].key);
 
149
    if (Thread[n].ret)
 
150
        shm_destroy(Thread[n].shmid, Thread[n].ret);
 
151
 
 
152
    Thread[n].delay = 0;
 
153
    Thread[n].mutex = 0;
 
154
    Thread[n].pid = 0;
 
155
    Thread[n].shmid = 0;
 
156
    Thread[n].cmd = NULL;
 
157
    Thread[n].key = NULL;
 
158
    Thread[n].ret = NULL;
 
159
}
 
160
 
 
161
 
 
162
static int create_exec_thread(const char *cmd, const char *key, const int delay)
 
163
{
 
164
    char name[10];
 
165
 
 
166
    if (max_thread >= NUM_THREADS) {
 
167
        error("cannot create exec thread <%s>: thread buffer full!", cmd);
 
168
        return -1;
 
169
    }
 
170
 
 
171
    max_thread++;
 
172
    Thread[max_thread].delay = delay;
 
173
    Thread[max_thread].mutex = mutex_create();
 
174
    Thread[max_thread].pid = -1;
 
175
    Thread[max_thread].cmd = strdup(cmd);
 
176
    Thread[max_thread].key = strdup(key);
 
177
    Thread[max_thread].ret = NULL;
 
178
 
 
179
    /* create communication buffer */
 
180
    Thread[max_thread].shmid = shm_create((void **) &Thread[max_thread].ret, SHM_SIZE);
 
181
 
 
182
    /* catch error */
 
183
    if (Thread[max_thread].shmid < 0) {
 
184
        error("cannot create exec thread <%s>: shared memory allocation failed!", cmd);
 
185
        destroy_exec_thread(max_thread--);
 
186
        return -1;
 
187
    }
 
188
 
 
189
    /* create thread */
 
190
    qprintf(name, sizeof(name), "exec-%s", key);
 
191
    Thread[max_thread].pid = thread_create(name, exec_thread, &Thread[max_thread]);
 
192
 
 
193
    /* catch error */
 
194
    if (Thread[max_thread].pid < 0) {
 
195
        error("cannot create exec thread <%s>: fork failed?!", cmd);
 
196
        destroy_exec_thread(max_thread--);
 
197
        return -1;
 
198
    }
 
199
 
 
200
    return 0;
 
201
}
 
202
 
 
203
 
 
204
static int do_exec(const char *cmd, const char *key, int delay)
 
205
{
 
206
    int i, age;
 
207
 
 
208
    age = hash_age(&EXEC, key);
 
209
 
 
210
    if (age < 0) {
 
211
        hash_put(&EXEC, key, "");
 
212
        /* first-time call: create thread */
 
213
        if (delay < 10) {
 
214
            error("exec(%s): delay %d is too short! using 10 msec", cmd, delay);
 
215
            delay = 10;
 
216
        }
 
217
        if (create_exec_thread(cmd, key, 1000 * delay)) {
 
218
            return -1;
 
219
        }
 
220
        return 0;
 
221
    }
 
222
 
 
223
    /* reread every 10 msec only */
 
224
    if (age > 0 && age <= 10)
 
225
        return 0;
 
226
 
 
227
    /* find thread */
 
228
    for (i = 0; i <= max_thread; i++) {
 
229
        if (strcmp(key, Thread[i].key) == 0) {
 
230
            /* lock shared memory */
 
231
            mutex_lock(Thread[i].mutex);
 
232
            /* copy data */
 
233
            hash_put(&EXEC, key, Thread[i].ret);
 
234
            /* unlock shared memory */
 
235
            mutex_unlock(Thread[i].mutex);
 
236
            return 0;
 
237
        }
 
238
    }
 
239
 
 
240
    error("internal error: could not find thread exec-%s", key);
 
241
    return -1;
 
242
}
 
243
 
 
244
static void my_exec(RESULT * result, RESULT * arg1, RESULT * arg2)
 
245
{
 
246
    char *cmd, key[5], *val;
 
247
    int delay;
 
248
 
 
249
    cmd = R2S(arg1);
 
250
    delay = (int) R2N(arg2);
 
251
 
 
252
    qprintf(key, sizeof(key), "%x", CRC(cmd));
 
253
 
 
254
    if (do_exec(cmd, key, delay) < 0) {
 
255
        SetResult(&result, R_STRING, "");
 
256
        return;
 
257
    }
 
258
 
 
259
    val = hash_get(&EXEC, key, NULL);
 
260
    if (val == NULL)
 
261
        val = "";
 
262
 
 
263
    SetResult(&result, R_STRING, val);
 
264
}
 
265
 
 
266
 
 
267
int plugin_init_exec(void)
 
268
{
 
269
    hash_create(&EXEC);
 
270
    AddFunction("exec", 2, my_exec);
 
271
    return 0;
 
272
}
 
273
 
 
274
 
 
275
void plugin_exit_exec(void)
 
276
{
 
277
    int i;
 
278
 
 
279
    for (i = 0; i <= max_thread; i++) {
 
280
        destroy_exec_thread(i);
 
281
    }
 
282
 
 
283
    hash_destroy(&EXEC);
 
284
}