glusterfs

Форк
0
629 строк · 15.0 Кб
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
#ifndef _GNU_SOURCE
12
#define _GNU_SOURCE
13
#endif
14

15
#include <stdio.h>
16
#include <unistd.h>
17
#include <stdlib.h>
18
#include <stdarg.h>
19
#include <string.h>
20
#include <errno.h>
21
#include <fcntl.h>
22
#include <dirent.h>
23
#include <assert.h>
24
#include <signal.h>
25
#include <sys/wait.h>
26
#include <spawn.h>
27
#include "glusterfs/syscall.h"
28

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

77
    ret = getrlimit(RLIMIT_NOFILE, &rl);
78
    if (ret)
79
        return ret;
80

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

104
#include "glusterfs/run.h"
105
/* Using a fake/temporary fd i.e, 0, to safely close the
106
   open fds within 3 to MAX_FD by remapping the
107
   target fd. Otherwise, it leads to undefined reference
108
   in memory while closing them.
109
*/
110

111
static void
112
closer_posix_spawnp(int fd, void *prm)
113
{
114
    posix_spawn_file_actions_t *file_actionsp = prm;
115
    posix_spawn_file_actions_adddup2(file_actionsp, 0, fd);
116
    posix_spawn_file_actions_addclose(file_actionsp, fd);
117
}
118
void
119
runinit(runner_t *runner)
120
{
121
    int i = 0;
122

123
    runner->argvlen = 64;
124
    runner->argv = GF_CALLOC(runner->argvlen, sizeof(*runner->argv),
125
                             gf_common_mt_run_argv);
126
    runner->runerr = runner->argv ? 0 : errno;
127
    runner->chpid = -1;
128
    for (i = 0; i < 3; i++) {
129
        runner->chfd[i] = -1;
130
        runner->chio[i] = NULL;
131
    }
132
}
133

134
FILE *
135
runner_chio(runner_t *runner, int fd)
136
{
137
    GF_ASSERT(fd > 0 && fd < 3);
138

139
    if ((fd > 0) && (fd < 3))
140
        return runner->chio[fd];
141

142
    return NULL;
143
}
144

145
static void
146
runner_insert_arg(runner_t *runner, char *arg)
147
{
148
    int i = 0;
149

150
    GF_ASSERT(arg);
151

152
    if (runner->runerr || !runner->argv)
153
        return;
154

155
    for (i = 0; i < runner->argvlen; i++) {
156
        if (runner->argv[i] == NULL)
157
            break;
158
    }
159
    GF_ASSERT(i < runner->argvlen);
160

161
    if (i == runner->argvlen - 1) {
162
        runner->argv = GF_REALLOC(runner->argv,
163
                                  runner->argvlen * 2 * sizeof(*runner->argv));
164
        if (!runner->argv) {
165
            runner->runerr = errno;
166
            return;
167
        }
168
        memset(/* "+" is aware of the type of its left side,
169
                * no need to multiply with type-size */
170
               runner->argv + runner->argvlen, 0,
171
               runner->argvlen * sizeof(*runner->argv));
172
        runner->argvlen *= 2;
173
    }
174

175
    runner->argv[i] = arg;
176
}
177

178
void
179
runner_add_arg(runner_t *runner, const char *arg)
180
{
181
    arg = gf_strdup(arg);
182
    if (!arg) {
183
        runner->runerr = errno;
184
        return;
185
    }
186

187
    runner_insert_arg(runner, (char *)arg);
188
}
189

190
static void
191
runner_va_add_args(runner_t *runner, va_list argp)
192
{
193
    const char *arg;
194

195
    while ((arg = va_arg(argp, const char *)))
196
        runner_add_arg(runner, arg);
197
}
198

199
void
200
runner_add_args(runner_t *runner, ...)
201
{
202
    va_list argp;
203

204
    va_start(argp, runner);
205
    runner_va_add_args(runner, argp);
206
    va_end(argp);
207
}
208

209
void
210
runner_argprintf(runner_t *runner, const char *format, ...)
211
{
212
    va_list argva;
213
    char *arg = NULL;
214
    int ret = 0;
215

216
    va_start(argva, format);
217
    ret = gf_vasprintf(&arg, format, argva);
218
    va_end(argva);
219

220
    if (ret < 0) {
221
        runner->runerr = errno;
222
        return;
223
    }
224

225
    runner_insert_arg(runner, arg);
226
}
227

228
void
229
runner_log(runner_t *runner, const char *dom, gf_loglevel_t lvl,
230
           const char *msg)
231
{
232
    char *buf = NULL;
233
    size_t len = 0;
234
    int i = 0;
235

236
    if (runner->runerr)
237
        return;
238

239
    for (i = 0;; i++) {
240
        if (runner->argv[i] == NULL)
241
            break;
242
        len += (strlen(runner->argv[i]) + 1);
243
    }
244

245
    buf = GF_CALLOC(1, len + 1, gf_common_mt_run_logbuf);
246
    if (!buf) {
247
        runner->runerr = errno;
248
        return;
249
    }
250
    for (i = 0;; i++) {
251
        if (runner->argv[i] == NULL)
252
            break;
253
        strcat(buf, runner->argv[i]);
254
        strcat(buf, " ");
255
    }
256
    if (len > 0)
257
        buf[len - 1] = '\0';
258

259
    gf_msg_callingfn(dom, lvl, 0, LG_MSG_RUNNER_LOG, "%s: %s", msg, buf);
260

261
    GF_FREE(buf);
262
}
263

264
void
265
runner_redir(runner_t *runner, int fd, int tgt_fd)
266
{
267
    GF_ASSERT(fd > 0 && fd < 3);
268

269
    if ((fd > 0) && (fd < 3))
270
        runner->chfd[fd] = (tgt_fd >= 0) ? tgt_fd : -2;
271
}
272

273
int
274
runner_start(runner_t *runner)
275
{
276
    int pi[3][2] = {{-1, -1}, {-1, -1}, {-1, -1}};
277
    int xpi[2];
278
    int ret = 0;
279
    int errno_priv = 0;
280
    int i = 0;
281
    int status = 0;
282
    sigset_t set;
283

284
    posix_spawnattr_t attr;
285
    posix_spawnattr_t *attrp = NULL;
286
    posix_spawn_file_actions_t file_actions;
287
    posix_spawn_file_actions_t *file_actionsp = NULL;
288

289
    if (runner->runerr || !runner->argv) {
290
        errno = (runner->runerr) ? runner->runerr : EINVAL;
291
        return -1;
292
    }
293

294
    GF_ASSERT(runner->argv[0]);
295

296
    /* set up a channel to child to communicate back
297
     * possible execve(2) failures
298
     */
299
    ret = pipe(xpi);
300
    if (ret != -1)
301
        ret = fcntl(xpi[1], F_SETFD, FD_CLOEXEC);
302

303
    for (i = 0; i < 3; i++) {
304
        if (runner->chfd[i] != -2)
305
            continue;
306
        ret = pipe(pi[i]);
307
        if (ret != -1) {
308
            runner->chio[i] = fdopen(pi[i][i ? 0 : 1], i ? "r" : "w");
309
            if (!runner->chio[i])
310
                ret = -1;
311
        }
312
    }
313

314
    if (ret == -1)
315
        return -1;
316

317
    ret = posix_spawn_file_actions_init(&file_actions);
318
    if (ret != 0)
319
        return -1;
320

321
    for (i = 0; i < 3; i++)
322
        posix_spawn_file_actions_addclose(&file_actions, pi[i][i ? 0 : 1]);
323

324
    posix_spawn_file_actions_addclose(&file_actions, xpi[0]);
325
    ret = 0;
326
    for (i = 0; i < 3; i++) {
327
        if (ret == -1)
328
            return -1;
329
        switch (runner->chfd[i]) {
330
            case -1:
331
                // no redir
332
                break;
333
            case -2:
334
                // redir to pipe
335
                ret = posix_spawn_file_actions_adddup2(&file_actions,
336
                                                       pi[i][i ? 1 : 0], i);
337
                break;
338
            default:
339
                // redir to file
340
                ret = posix_spawn_file_actions_adddup2(&file_actions,
341
                                                       runner->chfd[i], i);
342
        }
343
    }
344

345
    if (ret != -1) {
346
        int fdv[4] = {0, 1, 2, xpi[1]};
347

348
        ret = close_fds_except_custom(fdv, sizeof(fdv) / sizeof(*fdv),
349
                                      &file_actions, closer_posix_spawnp);
350
    }
351

352
    if (ret == -1)
353
        return -1;
354

355
    file_actionsp = &file_actions;
356

357
    ret = posix_spawnattr_init(&attr);
358
    if (ret != 0)
359
        return -1;
360
    ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK);
361
    if (ret != 0)
362
        return -1;
363
    sigemptyset(&set);
364
    ret = posix_spawnattr_setsigmask(&attr, &set);
365
    if (ret != 0)
366
        return -1;
367

368
    attrp = &attr;
369

370
    status = posix_spawnp(&runner->chpid, runner->argv[0], file_actionsp, attrp,
371
                          runner->argv, environ);
372
    if (status != 0) {
373
        errno_priv = errno;
374
        sys_close(xpi[0]);
375
        sys_close(xpi[1]);
376
        for (i = 0; i < 3; i++) {
377
            sys_close(pi[i][0]);
378
            sys_close(pi[i][1]);
379
        }
380
        errno = errno_priv;
381
        return -1;
382
    }
383

384
    /* Destroy any objects that we created earlier */
385

386
    if (attrp != NULL) {
387
        ret = posix_spawnattr_destroy(attrp);
388
        if (ret != 0)
389
            return -1;
390
    }
391

392
    if (file_actionsp != NULL) {
393
        ret = posix_spawn_file_actions_destroy(file_actionsp);
394
        if (ret != 0)
395
            return -1;
396
    }
397

398
    ret = sys_write(xpi[1], &errno, sizeof(errno));
399
    errno_priv = errno;
400

401
    for (i = 0; i < 3; i++)
402
        sys_close(pi[i][i ? 1 : 0]);
403

404
    sys_close(xpi[1]);
405

406
    if (ret == -1) {
407
        for (i = 0; i < 3; i++) {
408
            if (runner->chio[i]) {
409
                fclose(runner->chio[i]);
410
                runner->chio[i] = NULL;
411
            }
412
        }
413
    } else {
414
        ret = sys_read(xpi[0], (char *)&errno_priv, sizeof(errno_priv));
415
        sys_close(xpi[0]);
416
        if (ret <= 0)
417
            return 0;
418
        GF_ASSERT(ret == sizeof(errno_priv));
419
    }
420
    errno = errno_priv;
421

422
    return status;
423
}
424

425
int
426
runner_end_reuse(runner_t *runner)
427
{
428
    int i = 0;
429
    int ret = 1;
430
    int chstat = 0;
431

432
    if (runner->chpid > 0) {
433
        if (waitpid(runner->chpid, &chstat, 0) == runner->chpid) {
434
            if (WIFEXITED(chstat)) {
435
                ret = WEXITSTATUS(chstat);
436
            } else {
437
                ret = chstat;
438
            }
439
        }
440
    }
441

442
    for (i = 0; i < 3; i++) {
443
        if (runner->chio[i]) {
444
            fclose(runner->chio[i]);
445
            runner->chio[i] = NULL;
446
        }
447
    }
448

449
    return -ret;
450
}
451

452
int
453
runner_end(runner_t *runner)
454
{
455
    int i = 0;
456
    int ret = -1;
457
    char **p = NULL;
458

459
    ret = runner_end_reuse(runner);
460

461
    if (runner->argv) {
462
        for (p = runner->argv; *p; p++)
463
            GF_FREE(*p);
464
        GF_FREE(runner->argv);
465
    }
466
    for (i = 0; i < 3; i++)
467
        sys_close(runner->chfd[i]);
468

469
    return ret;
470
}
471

472
static int
473
runner_run_generic(runner_t *runner, int (*rfin)(runner_t *runner))
474
{
475
    int ret = 0;
476

477
    ret = runner_start(runner);
478
    if (ret)
479
        goto out;
480
    ret = rfin(runner);
481

482
out:
483
    return ret;
484
}
485

486
int
487
runner_run(runner_t *runner)
488
{
489
    return runner_run_generic(runner, runner_end);
490
}
491

492
int
493
runner_run_nowait(runner_t *runner)
494
{
495
    int pid;
496

497
    pid = fork();
498

499
    if (!pid) {
500
        setsid();
501
        _exit(runner_start(runner));
502
    }
503

504
    if (pid > 0)
505
        runner->chpid = pid;
506
    return runner_end(runner);
507
}
508

509
int
510
runner_run_reuse(runner_t *runner)
511
{
512
    return runner_run_generic(runner, runner_end_reuse);
513
}
514

515
int
516
runcmd(const char *arg, ...)
517
{
518
    runner_t runner;
519
    va_list argp;
520

521
    runinit(&runner);
522
    /* ISO C requires a named argument before '...' */
523
    runner_add_arg(&runner, arg);
524

525
    va_start(argp, arg);
526
    runner_va_add_args(&runner, argp);
527
    va_end(argp);
528

529
    return runner_run(&runner);
530
}
531

532
#ifdef RUN_DO_DEMO
533
static void
534
TBANNER(const char *txt)
535
{
536
    printf("######\n### demoing %s\n", txt);
537
}
538

539
int
540
main(int argc, char **argv)
541
{
542
    runner_t runner;
543
    char buf[80];
544
    char *wdbuf;
545
    ;
546
    int ret;
547
    int fd;
548
    long pathmax = pathconf("/", _PC_PATH_MAX);
549
    struct timeval tv = {
550
        0,
551
    };
552
    struct timeval *tvp = NULL;
553
    char *tfile;
554

555
    wdbuf = malloc(pathmax);
556
    assert(wdbuf);
557
    getcwd(wdbuf, pathmax);
558

559
    TBANNER("basic functionality: running \"echo a b\"");
560
    runcmd("echo", "a", "b", NULL);
561

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

574
    TBANNER(
575
        "add_args, argprintf, log, and popen-style functionality:\n"
576
        "    running a multiline echo command, emit a log about it,\n"
577
        "    redirect it to a pipe, read output lines\n"
578
        "    and print them prefixed with \"got: \"");
579
    runinit(&runner);
580
    runner_add_args(&runner, "echo", "pid:", NULL);
581
    runner_argprintf(&runner, "%d\n", getpid());
582
    runner_add_arg(&runner, "wd:");
583
    runner_add_arg(&runner, wdbuf);
584
    runner_redir(&runner, 1, RUN_PIPE);
585
    runner_start(&runner);
586
    runner_log(&runner, "(x)", LOG_DEBUG, "starting program");
587
    while (fgets(buf, sizeof(buf), runner_chio(&runner, 1)))
588
        printf("got: %s", buf);
589
    runner_end(&runner);
590

591
    TBANNER("execve error reporting: running a non-existent command");
592
    ret = runcmd("bafflavvitty", NULL);
593
    printf("%d %d [%s]\n", ret, errno, strerror(errno));
594

595
    TBANNER(
596
        "output redirection: running \"echo foo\" redirected "
597
        "to a temp file");
598
    tfile = strdup("/tmp/foofXXXXXX");
599
    assert(tfile);
600
    fd = mkstemp(tfile);
601
    assert(fd != -1);
602
    printf("redirecting to %s\n", tfile);
603
    runinit(&runner);
604
    runner_add_args(&runner, "echo", "foo", NULL);
605
    runner_redir(&runner, 1, fd);
606
    ret = runner_run(&runner);
607
    printf("runner_run returned: %d", ret);
608
    if (ret != 0)
609
        printf(", with errno %d [%s]", errno, strerror(errno));
610
    putchar('\n');
611

612
    /* sleep for seconds given as argument (0 means forever)
613
     * to allow investigation of post-execution state to
614
     * cbeck for resource leaks (eg. zombies).
615
     */
616
    if (argc > 1) {
617
        tv.tv_sec = strtoul(argv[1], NULL, 10);
618
        printf("### %s", "sleeping for");
619
        if (tv.tv_sec > 0) {
620
            printf(" %d seconds\n", tv.tv_sec);
621
            tvp = &tv;
622
        } else
623
            printf("%s\n", "ever");
624
        select(0, 0, 0, 0, tvp);
625
    }
626

627
    return 0;
628
}
629
#endif
630

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

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

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

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