glusterfs

Форк
0
576 строк · 13.7 Кб
1
/*
2
  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3
  This file is part of GlusterFS.
4

5
  This file is licensed to you under your choice of the GNU Lesser
6
  General Public License, version 3 or any later version (LGPLv3 or
7
  later), or the GNU General Public License, version 2 (GPLv2), in all
8
  cases as published by the Free Software Foundation.
9
*/
10

11
/*
12
 * Legacy implmentation of the runner_* API for platforms with broken
13
 * posix_spawn(), due to having older version of glibc library i.e, less
14
 * than 2.24
15
 */
16

17
#ifndef _GNU_SOURCE
18
#define _GNU_SOURCE
19
#endif
20

21
#include <stdio.h>
22
#include <unistd.h>
23
#include <stdlib.h>
24
#include <stdarg.h>
25
#include <string.h>
26
#include <errno.h>
27
#include <fcntl.h>
28
#include <dirent.h>
29
#include <assert.h>
30
#include <signal.h>
31
#include <sys/wait.h>
32
#include "glusterfs/syscall.h"
33

34
/*
35
 * Following defines are available for helping development:
36
 * RUN_STANDALONE and RUN_DO_DEMO.
37
 *
38
 * Compiling a standalone object file with no dependencies
39
 * on glusterfs:
40
 * $ cc -DRUN_STANDALONE -c run.c
41
 *
42
 * Compiling a demo program that exercises bits of run.c
43
 * functionality (linking to glusterfs):
44
 * $ cc -DRUN_DO_DEMO -orun run.c  `pkg-config --libs --cflags glusterfs-api`
45
 *
46
 * Compiling a demo program that exercises bits of run.c
47
 * functionality (with no dependence on glusterfs):
48
 *
49
 * $ cc -DRUN_DO_DEMO -DRUN_STANDALONE -orun run.c
50
 */
51
#if defined(RUN_STANDALONE) || defined(RUN_DO_DEMO)
52
int
53
close_fds_except(int *fdv, size_t count);
54
#define sys_read(f, b, c) read(f, b, c)
55
#define sys_write(f, b, c) write(f, b, c)
56
#define sys_close(f) close(f)
57
#define GF_CALLOC(n, s, t) calloc(n, s)
58
#define GF_ASSERT(cond) assert(cond)
59
#define GF_REALLOC(p, s) realloc(p, s)
60
#define GF_FREE(p) free(p)
61
#define gf_strdup(s) strdup(s)
62
#define gf_vasprintf(p, f, va) vasprintf(p, f, va)
63
#define gf_loglevel_t int
64
#define gf_msg_callingfn(dom, level, errnum, msgid, fmt, args...)              \
65
    printf("LOG: " fmt "\n", ##args)
66
#define LOG_DEBUG 0
67
#ifdef RUN_STANDALONE
68
#include <stdbool.h>
69
#include <sys/resource.h>
70
int
71
close_fds_except(int *fdv, size_t count)
72
{
73
    int i = 0;
74
    size_t j = 0;
75
    bool should_close = true;
76
    struct rlimit rl;
77
    int ret = -1;
78

79
    ret = getrlimit(RLIMIT_NOFILE, &rl);
80
    if (ret)
81
        return ret;
82

83
    for (i = 0; i < rl.rlim_cur; i++) {
84
        should_close = true;
85
        for (j = 0; j < count; j++) {
86
            if (i == fdv[j]) {
87
                should_close = false;
88
                break;
89
            }
90
        }
91
        if (should_close)
92
            sys_close(i);
93
    }
94
    return 0;
95
}
96
#endif
97
#ifdef __linux__
98
#define GF_LINUX_HOST_OS
99
#endif
100
#else /* ! RUN_STANDALONE || RUN_DO_DEMO */
101
#include "glusterfs/glusterfs.h"
102
#include "glusterfs/common-utils.h"
103
#include "glusterfs/libglusterfs-messages.h"
104
#endif
105

106
#include "glusterfs/run.h"
107
void
108
runinit(runner_t *runner)
109
{
110
    int i = 0;
111

112
    runner->argvlen = 64;
113
    runner->argv = GF_CALLOC(runner->argvlen, sizeof(*runner->argv),
114
                             gf_common_mt_run_argv);
115
    runner->runerr = runner->argv ? 0 : errno;
116
    runner->chpid = -1;
117
    for (i = 0; i < 3; i++) {
118
        runner->chfd[i] = -1;
119
        runner->chio[i] = NULL;
120
    }
121
}
122

123
FILE *
124
runner_chio(runner_t *runner, int fd)
125
{
126
    GF_ASSERT(fd > 0 && fd < 3);
127

128
    if ((fd > 0) && (fd < 3))
129
        return runner->chio[fd];
130

131
    return NULL;
132
}
133

134
static void
135
runner_insert_arg(runner_t *runner, char *arg)
136
{
137
    int i = 0;
138

139
    GF_ASSERT(arg);
140

141
    if (runner->runerr || !runner->argv)
142
        return;
143

144
    for (i = 0; i < runner->argvlen; i++) {
145
        if (runner->argv[i] == NULL)
146
            break;
147
    }
148
    GF_ASSERT(i < runner->argvlen);
149

150
    if (i == runner->argvlen - 1) {
151
        runner->argv = GF_REALLOC(runner->argv,
152
                                  runner->argvlen * 2 * sizeof(*runner->argv));
153
        if (!runner->argv) {
154
            runner->runerr = errno;
155
            return;
156
        }
157
        memset(/* "+" is aware of the type of its left side,
158
                * no need to multiply with type-size */
159
               runner->argv + runner->argvlen, 0,
160
               runner->argvlen * sizeof(*runner->argv));
161
        runner->argvlen *= 2;
162
    }
163

164
    runner->argv[i] = arg;
165
}
166

167
void
168
runner_add_arg(runner_t *runner, const char *arg)
169
{
170
    arg = gf_strdup(arg);
171
    if (!arg) {
172
        runner->runerr = errno;
173
        return;
174
    }
175

176
    runner_insert_arg(runner, (char *)arg);
177
}
178

179
static void
180
runner_va_add_args(runner_t *runner, va_list argp)
181
{
182
    const char *arg;
183

184
    while ((arg = va_arg(argp, const char *)))
185
        runner_add_arg(runner, arg);
186
}
187

188
void
189
runner_add_args(runner_t *runner, ...)
190
{
191
    va_list argp;
192

193
    va_start(argp, runner);
194
    runner_va_add_args(runner, argp);
195
    va_end(argp);
196
}
197

198
void
199
runner_argprintf(runner_t *runner, const char *format, ...)
200
{
201
    va_list argva;
202
    char *arg = NULL;
203
    int ret = 0;
204

205
    va_start(argva, format);
206
    ret = gf_vasprintf(&arg, format, argva);
207
    va_end(argva);
208

209
    if (ret < 0) {
210
        runner->runerr = errno;
211
        return;
212
    }
213

214
    runner_insert_arg(runner, arg);
215
}
216

217
void
218
runner_log(runner_t *runner, const char *dom, gf_loglevel_t lvl,
219
           const char *msg)
220
{
221
    char *buf = NULL;
222
    size_t len = 0;
223
    int i = 0;
224

225
    if (runner->runerr)
226
        return;
227

228
    for (i = 0;; i++) {
229
        if (runner->argv[i] == NULL)
230
            break;
231
        len += (strlen(runner->argv[i]) + 1);
232
    }
233

234
    buf = GF_CALLOC(1, len + 1, gf_common_mt_run_logbuf);
235
    if (!buf) {
236
        runner->runerr = errno;
237
        return;
238
    }
239
    for (i = 0;; i++) {
240
        if (runner->argv[i] == NULL)
241
            break;
242
        strcat(buf, runner->argv[i]);
243
        strcat(buf, " ");
244
    }
245
    if (len > 0)
246
        buf[len - 1] = '\0';
247

248
    gf_msg_callingfn(dom, lvl, 0, LG_MSG_RUNNER_LOG, "%s: %s", msg, buf);
249

250
    GF_FREE(buf);
251
}
252

253
void
254
runner_redir(runner_t *runner, int fd, int tgt_fd)
255
{
256
    GF_ASSERT(fd > 0 && fd < 3);
257

258
    if ((fd > 0) && (fd < 3))
259
        runner->chfd[fd] = (tgt_fd >= 0) ? tgt_fd : -2;
260
}
261

262
int
263
runner_start(runner_t *runner)
264
{
265
    int pi[3][2] = {{-1, -1}, {-1, -1}, {-1, -1}};
266
    int xpi[2];
267
    int ret = 0;
268
    int errno_priv = 0;
269
    int i = 0;
270
    sigset_t set;
271

272
    if (runner->runerr || !runner->argv) {
273
        errno = (runner->runerr) ? runner->runerr : EINVAL;
274
        return -1;
275
    }
276

277
    GF_ASSERT(runner->argv[0]);
278

279
    /* set up a channel to child to communicate back
280
     * possible execve(2) failures
281
     */
282
    ret = pipe(xpi);
283
    if (ret != -1)
284
        ret = fcntl(xpi[1], F_SETFD, FD_CLOEXEC);
285

286
    for (i = 0; i < 3; i++) {
287
        if (runner->chfd[i] != -2)
288
            continue;
289
        ret = pipe(pi[i]);
290
        if (ret != -1) {
291
            runner->chio[i] = fdopen(pi[i][i ? 0 : 1], i ? "r" : "w");
292
            if (!runner->chio[i])
293
                ret = -1;
294
        }
295
    }
296

297
    if (ret != -1)
298
        runner->chpid = fork();
299
    switch (runner->chpid) {
300
        case -1:
301
            errno_priv = errno;
302
            sys_close(xpi[0]);
303
            sys_close(xpi[1]);
304
            for (i = 0; i < 3; i++) {
305
                sys_close(pi[i][0]);
306
                sys_close(pi[i][1]);
307
            }
308
            errno = errno_priv;
309
            return -1;
310
        case 0:
311
            for (i = 0; i < 3; i++)
312
                sys_close(pi[i][i ? 0 : 1]);
313
            sys_close(xpi[0]);
314
            ret = 0;
315

316
            for (i = 0; i < 3; i++) {
317
                if (ret == -1)
318
                    break;
319
                switch (runner->chfd[i]) {
320
                    case -1:
321
                        /* no redir */
322
                        break;
323
                    case -2:
324
                        /* redir to pipe */
325
                        ret = dup2(pi[i][i ? 1 : 0], i);
326
                        break;
327
                    default:
328
                        /* redir to file */
329
                        ret = dup2(runner->chfd[i], i);
330
                }
331
            }
332

333
            if (ret != -1) {
334
                int fdv[4] = {0, 1, 2, xpi[1]};
335

336
                ret = close_fds_except(fdv, sizeof(fdv) / sizeof(*fdv));
337
            }
338

339
            if (ret != -1) {
340
                /* save child from inheriting our signal handling */
341
                sigemptyset(&set);
342
                sigprocmask(SIG_SETMASK, &set, NULL);
343

344
                execvp(runner->argv[0], runner->argv);
345
            }
346
            ret = sys_write(xpi[1], &errno, sizeof(errno));
347
            _exit(1);
348
    }
349

350
    errno_priv = errno;
351
    for (i = 0; i < 3; i++)
352
        sys_close(pi[i][i ? 1 : 0]);
353
    sys_close(xpi[1]);
354
    if (ret == -1) {
355
        for (i = 0; i < 3; i++) {
356
            if (runner->chio[i]) {
357
                fclose(runner->chio[i]);
358
                runner->chio[i] = NULL;
359
            }
360
        }
361
    } else {
362
        ret = sys_read(xpi[0], (char *)&errno_priv, sizeof(errno_priv));
363
        sys_close(xpi[0]);
364
        if (ret <= 0)
365
            return 0;
366
        GF_ASSERT(ret == sizeof(errno_priv));
367
    }
368
    errno = errno_priv;
369
    return -1;
370
}
371

372
int
373
runner_end_reuse(runner_t *runner)
374
{
375
    int i = 0;
376
    int ret = 1;
377
    int chstat = 0;
378

379
    if (runner->chpid > 0) {
380
        if (waitpid(runner->chpid, &chstat, 0) == runner->chpid) {
381
            if (WIFEXITED(chstat)) {
382
                ret = WEXITSTATUS(chstat);
383
            } else {
384
                ret = chstat;
385
            }
386
        }
387
    }
388

389
    for (i = 0; i < 3; i++) {
390
        if (runner->chio[i]) {
391
            fclose(runner->chio[i]);
392
            runner->chio[i] = NULL;
393
        }
394
    }
395

396
    return -ret;
397
}
398

399
int
400
runner_end(runner_t *runner)
401
{
402
    int i = 0;
403
    int ret = -1;
404
    char **p = NULL;
405

406
    ret = runner_end_reuse(runner);
407

408
    if (runner->argv) {
409
        for (p = runner->argv; *p; p++)
410
            GF_FREE(*p);
411
        GF_FREE(runner->argv);
412
    }
413
    for (i = 0; i < 3; i++)
414
        sys_close(runner->chfd[i]);
415

416
    return ret;
417
}
418

419
static int
420
runner_run_generic(runner_t *runner, int (*rfin)(runner_t *runner))
421
{
422
    int ret = 0;
423

424
    ret = runner_start(runner);
425
    if (ret)
426
        goto out;
427
    ret = rfin(runner);
428

429
out:
430
    return ret;
431
}
432

433
int
434
runner_run(runner_t *runner)
435
{
436
    return runner_run_generic(runner, runner_end);
437
}
438

439
int
440
runner_run_nowait(runner_t *runner)
441
{
442
    int pid;
443

444
    pid = fork();
445

446
    if (!pid) {
447
        setsid();
448
        _exit(runner_start(runner));
449
    }
450

451
    if (pid > 0)
452
        runner->chpid = pid;
453
    return runner_end(runner);
454
}
455

456
int
457
runner_run_reuse(runner_t *runner)
458
{
459
    return runner_run_generic(runner, runner_end_reuse);
460
}
461

462
int
463
runcmd(const char *arg, ...)
464
{
465
    runner_t runner;
466
    va_list argp;
467

468
    runinit(&runner);
469
    /* ISO C requires a named argument before '...' */
470
    runner_add_arg(&runner, arg);
471

472
    va_start(argp, arg);
473
    runner_va_add_args(&runner, argp);
474
    va_end(argp);
475

476
    return runner_run(&runner);
477
}
478

479
#ifdef RUN_DO_DEMO
480
static void
481
TBANNER(const char *txt)
482
{
483
    printf("######\n### demoing %s\n", txt);
484
}
485

486
int
487
main(int argc, char **argv)
488
{
489
    runner_t runner;
490
    char buf[80];
491
    char *wdbuf;
492
    ;
493
    int ret;
494
    int fd;
495
    long pathmax = pathconf("/", _PC_PATH_MAX);
496
    struct timeval tv = {
497
        0,
498
    };
499
    struct timeval *tvp = NULL;
500
    char *tfile;
501

502
    wdbuf = malloc(pathmax);
503
    assert(wdbuf);
504
    getcwd(wdbuf, pathmax);
505

506
    TBANNER("basic functionality: running \"echo a b\"");
507
    runcmd("echo", "a", "b", NULL);
508

509
    TBANNER("argv extension: running \"echo 1 2 ... 100\"");
510
    runcmd("echo", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
511
           "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22",
512
           "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33",
513
           "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44",
514
           "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55",
515
           "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66",
516
           "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77",
517
           "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88",
518
           "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
519
           "100", NULL);
520

521
    TBANNER(
522
        "add_args, argprintf, log, and popen-style functionality:\n"
523
        "    running a multiline echo command, emit a log about it,\n"
524
        "    redirect it to a pipe, read output lines\n"
525
        "    and print them prefixed with \"got: \"");
526
    runinit(&runner);
527
    runner_add_args(&runner, "echo", "pid:", NULL);
528
    runner_argprintf(&runner, "%d\n", getpid());
529
    runner_add_arg(&runner, "wd:");
530
    runner_add_arg(&runner, wdbuf);
531
    runner_redir(&runner, 1, RUN_PIPE);
532
    runner_start(&runner);
533
    runner_log(&runner, "(x)", LOG_DEBUG, "starting program");
534
    while (fgets(buf, sizeof(buf), runner_chio(&runner, 1)))
535
        printf("got: %s", buf);
536
    runner_end(&runner);
537

538
    TBANNER("execve error reporting: running a non-existent command");
539
    ret = runcmd("bafflavvitty", NULL);
540
    printf("%d %d [%s]\n", ret, errno, strerror(errno));
541

542
    TBANNER(
543
        "output redirection: running \"echo foo\" redirected "
544
        "to a temp file");
545
    tfile = strdup("/tmp/foofXXXXXX");
546
    assert(tfile);
547
    fd = mkstemp(tfile);
548
    assert(fd != -1);
549
    printf("redirecting to %s\n", tfile);
550
    runinit(&runner);
551
    runner_add_args(&runner, "echo", "foo", NULL);
552
    runner_redir(&runner, 1, fd);
553
    ret = runner_run(&runner);
554
    printf("runner_run returned: %d", ret);
555
    if (ret != 0)
556
        printf(", with errno %d [%s]", errno, strerror(errno));
557
    putchar('\n');
558

559
    /* sleep for seconds given as argument (0 means forever)
560
     * to allow investigation of post-execution state to
561
     * cbeck for resource leaks (eg. zombies).
562
     */
563
    if (argc > 1) {
564
        tv.tv_sec = strtoul(argv[1], NULL, 10);
565
        printf("### %s", "sleeping for");
566
        if (tv.tv_sec > 0) {
567
            printf(" %d seconds\n", tv.tv_sec);
568
            tvp = &tv;
569
        } else
570
            printf("%s\n", "ever");
571
        select(0, 0, 0, 0, tvp);
572
    }
573

574
    return 0;
575
}
576
#endif
577

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.