summaryrefslogtreecommitdiffstats
path: root/tests/bugs/write-behind/bug-1279730.c
blob: 706ae67b10266fd2bc2846d8b2c696685aee56f2 (plain)
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
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>

int
main(int argc, char *argv[])
{
    int fd = -1, ret = -1, len = 0;
    char *path = NULL,
         buf[128] =
             {
                 0,
             },
         *cmd = NULL;
    struct stat stbuf = {
        0,
    };
    int write_to_child[2] =
        {
            0,
        },
        write_to_parent[2] = {
            0,
        };

    path = argv[1];
    cmd = argv[2];

    assert(argc == 3);

    ret = pipe(write_to_child);
    if (ret < 0) {
        fprintf(stderr,
                "creation of write-to-child pipe failed "
                "(%s)\n",
                strerror(errno));
        goto out;
    }

    ret = pipe(write_to_parent);
    if (ret < 0) {
        fprintf(stderr,
                "creation of write-to-parent pipe failed "
                "(%s)\n",
                strerror(errno));
        goto out;
    }

    ret = fork();
    switch (ret) {
        case 0:
            close(write_to_child[1]);
            close(write_to_parent[0]);

            /* child, wait for instructions to execute command */
            ret = read(write_to_child[0], buf, 128);
            if (ret < 0) {
                fprintf(stderr, "child: read on pipe failed (%s)\n",
                        strerror(errno));
                goto out;
            }

            system(cmd);

            ret = write(write_to_parent[1], "1", 2);
            if (ret < 0) {
                fprintf(stderr, "child: write to pipe failed (%s)\n",
                        strerror(errno));
                goto out;
            }
            break;

        case -1:
            fprintf(stderr, "fork failed (%s)\n", strerror(errno));
            goto out;

        default:
            close(write_to_parent[1]);
            close(write_to_child[0]);

            fd = open(path, O_CREAT | O_RDWR | O_APPEND, S_IRWXU);
            if (fd < 0) {
                fprintf(stderr, "open failed (%s)\n", strerror(errno));
                goto out;
            }

            len = strlen("test-content") + 1;
            ret = write(fd, "test-content", len);

            if (ret < len) {
                fprintf(stderr, "write failed %d (%s)\n", ret, strerror(errno));
            }

            ret = pread(fd, buf, 128, 0);
            if ((ret == len) && (strcmp(buf, "test-content") == 0)) {
                fprintf(stderr,
                        "read should've failed as previous "
                        "write would've failed with EDQUOT, but its "
                        "successful");
                ret = -1;
                goto out;
            }

            ret = write(write_to_child[1], "1", 2);
            if (ret < 0) {
                fprintf(stderr, "parent: write to pipe failed (%s)\n",
                        strerror(errno));
                goto out;
            }

            ret = read(write_to_parent[0], buf, 128);
            if (ret < 0) {
                fprintf(stderr, "parent: read from pipe failed (%s)\n",
                        strerror(errno));
                goto out;
            }

            /* this will force a sync on cached-write and now that quota
               limit is increased, sync will be successful. ignore return
               value as fstat would fail with EDQUOT (picked up from
               cached-write because of previous sync failure.
            */
            fstat(fd, &stbuf);

            ret = pread(fd, buf, 128, 0);
            if (ret != len) {
                fprintf(stderr,
                        "post cmd read failed %d (data:%s) "
                        "(error:%s)\n",
                        ret, buf, strerror(errno));
                goto out;
            }

            if (strcmp(buf, "test-content")) {
                fprintf(stderr, "wrong data (%s)\n", buf);
                goto out;
            }
    }

    ret = 0;

out:
    return ret;
}