4f6c933b42ffe6d7bb1edcb3a11af3f9cd304e39
[platform/kernel/linux-rpi.git] / tools / testing / selftests / logger / logger.c
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <getopt.h>
4 #include <linux/logger.h>
5 #include <pthread.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/ioctl.h>
11 #include <sys/types.h>
12 #include <sys/uio.h>
13 #include <sys/wait.h>
14 #include <unistd.h>
15
16 #define handle_error_en(en, msg)                                        \
17         do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
18
19 #define BIT(nr)         ((1UL) << (nr))
20
21 void *tstart(void *arg)
22 {
23         int *fd = arg;
24         write(*fd, "child thread msg #1\nchild thread msg #2", 39);
25         return 0;
26 }
27
28 int dump_logger(const char *device)
29 {
30         int fd;
31         int ret = 0;
32         char buf[sizeof(struct logger_entry) + LOGGER_ENTRY_MAX_PAYLOAD];
33         struct logger_entry *e = (void *)buf;
34         int version = 2;
35
36         fd = open(device, O_RDONLY | O_NONBLOCK);
37         if (fd < 0) {
38                 perror("open");
39                 exit(EXIT_FAILURE);
40         }
41
42         ret = ioctl(fd, LOGGER_SET_VERSION, &version);
43         if (ret < 0) {
44                 perror("ioctl(SET_VERSION)");
45                 exit(EXIT_FAILURE);
46         }
47
48         while (1) {
49                 int tag_len;
50                 ret = read(fd, buf, sizeof(struct logger_entry) + LOGGER_ENTRY_MAX_PAYLOAD);
51                 if (ret < 0) {
52                         if (errno == EAGAIN)
53                                 ret = 0;
54                         else
55                                 perror("read");
56                         break;
57                 }
58
59                 if (e->hdr_size != sizeof(struct logger_entry)) {
60                         fprintf(stderr, "%d != %d\n", e->hdr_size, sizeof(struct logger_entry));
61                         fprintf(stderr, "read: Invalid data\n");
62                         ret = EXIT_FAILURE;
63                         break;
64                 }
65
66                 tag_len = strlen(e->msg + 1) + 2; /* 2: priority, NUL */
67                 fprintf(stdout, "[%5d.%6d] %s<%u>: %s\n", e->sec, e->nsec / 1000, &e->msg[1], e->msg[0], &e->msg[tag_len]);
68         };
69
70         return ret;
71 }
72
73 int main(int ac, char *av[]) {
74
75         char *device = "/dev/log_main";
76         char *msg = "The Foo";
77         char *tag = "stdio";
78         struct logger_set_tag struct_tag = {
79                 .len = 6,
80                 .ptr = (uintptr_t)tag,
81         };
82         int c, fd, s, ret;
83         pid_t child;
84         int dump = 0;
85         pthread_t tid;
86         struct iovec vec[3];
87         unsigned char prio = 4;
88         unsigned long test_mask = ~0UL;
89
90         while (1) {
91                 static struct option long_options[] = {
92                         {"priority",  required_argument, 0, 'p'},
93                         {"tag",       required_argument, 0, 't'},
94                         {"test-mask", required_argument, 0, 'm'},
95                         {"device",    required_argument, 0, 'd'},
96                         {0,           0,                 0, 0}
97                 };
98
99                 c = getopt_long(ac, av, "p:t:m:d:D", long_options, NULL);
100                 if (c == -1)
101                         break;
102
103                 switch (c) {
104                 case 'p':
105                         prio = (unsigned char) strtol(optarg, NULL, 10);
106                         break;
107                 case 't':
108                         tag = strdup(optarg);
109                         break;
110                 case 'm':
111                         test_mask = (unsigned long) strtol(optarg, NULL, 16);
112                         break;
113                 case 'd':
114                         device = strdup(optarg);
115                         break;
116                 case 'D':
117                         dump = 1;
118                         break;
119                 default:
120                         exit(1);
121                 }
122         }
123
124         if (dump)
125                 return dump_logger(device);
126
127         setlinebuf(stdout);
128         fd = open(device, O_WRONLY);
129         if (fd < 0) {
130                 perror("open");
131                 exit(EXIT_FAILURE);
132         }
133
134         if (test_mask & BIT(0)) {
135                 vec[0].iov_base = &prio;
136                 vec[0].iov_len = 1;
137                 vec[1].iov_base = tag;
138                 vec[1].iov_len = strlen(tag) + 1;
139                 vec[2].iov_base = msg;
140                 vec[2].iov_len = strlen(msg) + 1;
141
142                 writev(fd, vec, 3);
143                 if (test_mask & BIT(1)) {
144                         msg = "line #1\nline #2";
145                         vec[2].iov_base = msg;
146                         vec[2].iov_len = strlen(msg) + 1;
147
148                         writev(fd, vec, 3);
149                 }
150         }
151
152         ret = ioctl(fd, LOGGER_SET_PRIO, prio);
153         if (ret < 0) {
154                 perror("ioctl(SET_PRIO)");
155                 exit(EXIT_FAILURE);
156         }
157         ret = ioctl(fd, LOGGER_SET_TAG, &struct_tag);
158         if (ret < 0) {
159                 perror("ioctl(SET_TAG)");
160                 exit(EXIT_FAILURE);
161         }
162
163         if (test_mask & BIT(2)) {
164                 int count;
165                 count = write(fd, "The Foo From STDIO\n", 19);
166                 if (count != 19)
167                         fprintf(stderr, "%d != 19\n", count);
168
169                 write(fd, "LINE #1\nLINE #2", 15);
170                 write(fd, " CONTINUED\nONCE", 15);
171                 write(fd, " AGAIN\n", 7);
172         }
173
174         if (test_mask & BIT(3)) {
175                 msg = malloc(8000);
176                 if (!msg)
177                         return 1;
178
179                 for (int i = 0; i < 8000; i++)
180                         msg[i] = '!' + (i % 95);
181                 msg[7996] = 'E';
182                 msg[7997] = 'O';
183                 msg[7998] = 'F';
184                 msg[7999] = '\n';
185                 write(fd, msg, 8000);
186
187                 for (int i = 0; (test_mask & BIT(4)) && i < 40; i++)
188                         write(fd, msg, 8000);
189
190                 for (int i = 0; (test_mask & BIT(5)) && i < 8000; i++)
191                         write(fd, &msg[i], 1);
192
193                 free(msg);
194                 msg = NULL;
195         }
196
197         if (test_mask & BIT(6)) {
198                 child = fork();
199                 if (child < 0) {
200                         return -1;
201                 } else if (child == 0) {
202                         sleep(1);
203                         printf("child: %d\n", getpid());
204                         write(fd, "child 1\n", 8);
205                         sleep(1);
206                         write(fd, "child 2\n", 8);
207                         close(fd);
208                         return 0;
209                 }
210                 write(fd, "PARENT\n", 7);
211                 printf("PARENT: %d\n", getpid());
212                 wait(&s);
213         }
214
215         if (test_mask & BIT(7)) {
216                 s = pthread_create(&tid, NULL, &tstart, &fd);
217                 if (s != 0)
218                         handle_error_en(s, "pthread_create");
219                 sleep(1);
220                 write(fd, "PARENT THREAD\n", 14);
221
222                 s = pthread_join(tid, NULL);
223                 if (s != 0)
224                         handle_error_en(s, "pthread_join");
225         }
226
227         return 0;
228 }