1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <ddk/debug.h>
6 #include <zircon/device/device.h>
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12
usage(void)13 static void usage(void) {
14 fprintf(stderr,
15 "Usage: driverctl <path> <command> [options]\n"
16 "\n"
17 "where path is path to driver file in /dev\n"
18 "\n"
19 "Command \"log\":\n"
20 " options are zero or more of:\n"
21 " \"error\" or \"e\": DDK_LOG_ERROR\n"
22 " \"warn\" or \"w\": DDK_LOG_WARN\n"
23 " \"info\" or \"i\": DDK_LOG_INFO\n"
24 " \"trace\" or \"t\": DDK_LOG_TRACE\n"
25 " \"spew\" or \"s\": DDK_LOG_SPEW\n"
26 " \"debug1\" or \"d1\": DDK_LOG_DEBUG1\n"
27 " \"debug2\" or \"d2\": DDK_LOG_DEBUG2\n"
28 " \"debug3\" or \"d3\": DDK_LOG_DEBUG3\n"
29 " \"debug4\" or \"d4\": DDK_LOG_DEBUG4\n"
30 "\n"
31 " With no options provided, driverctl log will print the current log flags for the driver.\n"
32 " A flag may have a '+' or '-' prepended. In that case the flag will be toggled\n"
33 " on (+) or off(-) without affecting other flags.\n"
34 " If toggled flags are used, all flags must be toggled.\n"
35 "\n"
36 " Examples:\n"
37 "\n"
38 " Set log flags to DDK_LOG_ERROR | DDK_LOG_INFO | DDK_LOG_TRACE:\n"
39 " $ driverctl <path> log error info trace\n"
40 " or:\n"
41 " $ driverctl <path> log e i t\n"
42 "\n"
43 " Turn on DDK_LOG_TRACE and DDK_LOG_SPEW:\n"
44 " $ driverctl <path> log +trace +spew\n"
45 " or:\n"
46 " $ driverctl <path> log +t +s\n"
47 "\n"
48 " Turn off DDK_LOG_SPEW:\n"
49 " $ driverctl <path> log -spew\n"
50 " or:\n"
51 " $ driverctl <path> log -s\n"
52 );
53 }
54
main(int argc,char ** argv)55 int main(int argc, char **argv) {
56 int ret = 0;
57
58 if (argc < 3) {
59 usage();
60 return -1;
61 }
62
63 const char* path = argv[1];
64 if (!strcmp(path, "-h")) {
65 usage();
66 return 0;
67 }
68
69 const char* command = argv[2];
70 if (strcmp(command, "log")) {
71 fprintf(stderr, "Unsupported command %s\n", command);
72 usage();
73 return -1;
74 }
75
76 int fd = open(path, O_RDWR);
77 if (fd < 0) {
78 fprintf(stderr, "could not open %s\n", path);
79 return -1;
80 }
81
82 if (argc == 3) {
83 uint32_t flags;
84 ret = ioctl_device_get_log_flags(fd, &flags);
85 if (ret < 0) {
86 fprintf(stderr, "ioctl_device_get_log_flags failed for %s\n", path);
87 } else {
88 printf("Log flags:");
89 if (flags & DDK_LOG_ERROR) {
90 printf(" ERROR");
91 }
92 if (flags & DDK_LOG_WARN) {
93 printf(" WARN");
94 }
95 if (flags & DDK_LOG_INFO) {
96 printf(" INFO");
97 }
98 if (flags & DDK_LOG_TRACE) {
99 printf(" TRACE");
100 }
101 if (flags & DDK_LOG_SPEW) {
102 printf(" SPEW");
103 }
104 if (flags & DDK_LOG_DEBUG1) {
105 printf(" DEBUG1");
106 }
107 if (flags & DDK_LOG_DEBUG2) {
108 printf(" DEBUG2");
109 }
110 if (flags & DDK_LOG_DEBUG3) {
111 printf(" DEBUG3");
112 }
113 if (flags & DDK_LOG_DEBUG4) {
114 printf(" DEBUG4");
115 }
116 printf("\n");
117 }
118 goto out;
119 }
120
121 driver_log_flags_t flags = {0, 0};
122 char* toggle_arg = NULL;
123 char* non_toggle_arg = NULL;
124
125 for (int i = 3; i < argc; i++) {
126 char* arg = argv[i];
127 char toggle = arg[0];
128 uint32_t flag = 0;
129
130 // check for leading + or -
131 if (toggle == '+' || toggle == '-') {
132 toggle_arg = arg;
133 arg++;
134 } else {
135 non_toggle_arg = arg;
136 }
137
138 if (toggle_arg && non_toggle_arg) {
139 fprintf(stderr, "Cannot mix toggled flag \"%s\" with non-toggle flag \"%s\"\n",
140 toggle_arg, non_toggle_arg);
141 usage();
142 ret = -1;
143 goto out;
144 }
145
146 if (!strcasecmp(arg, "e") || !strcasecmp(arg, "error")) {
147 flag = DDK_LOG_ERROR;
148 } else if (!strcasecmp(arg, "w") || !strcasecmp(arg, "warn")) {
149 flag = DDK_LOG_WARN;
150 } else if (!strcasecmp(arg, "i") || !strcasecmp(arg, "info")) {
151 flag = DDK_LOG_INFO;
152 } else if (!strcasecmp(arg, "t") || !strcasecmp(arg, "trace")) {
153 flag = DDK_LOG_TRACE;
154 } else if (!strcasecmp(arg, "s") || !strcasecmp(arg, "spew")) {
155 flag = DDK_LOG_SPEW;
156 } else if (!strcasecmp(arg, "d1") || !strcasecmp(arg, "debug1")) {
157 flag = DDK_LOG_DEBUG1;
158 } else if (!strcasecmp(arg, "d2") || !strcasecmp(arg, "debug2")) {
159 flag = DDK_LOG_DEBUG2;
160 } else if (!strcasecmp(arg, "d3") || !strcasecmp(arg, "debug3")) {
161 flag = DDK_LOG_DEBUG3;
162 } else if (!strcasecmp(arg, "d4") || !strcasecmp(arg, "debug4")) {
163 flag = DDK_LOG_DEBUG4;
164 } else {
165 fprintf(stderr, "unknown flag %s\n", arg);
166 ret = -1;
167 goto out;
168 }
169
170 if (toggle == '+') {
171 flags.set |= flag;
172 } else if (toggle == '-') {
173 flags.clear |= flag;
174 } else {
175 flags.set |= flag;
176 }
177 }
178
179 if (!toggle_arg) {
180 // clear all flags not explicitly set if we aren't using flag toggles
181 flags.clear = ~flags.set;
182 }
183
184 ret = ioctl_device_set_log_flags(fd, &flags);
185 if (ret < 0) {
186 fprintf(stderr, "ioctl_device_set_log_flags failed for %s\n", path);
187 }
188
189 out:
190 close(fd);
191 return ret;
192 }
193