xref: /aosp_15_r20/external/toybox/toys/other/lsusb.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* lsusb.c - list available USB devices
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2013 Andre Renaud <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2013 Isaac Dunham <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker 
6*cf5a6c84SAndroid Build Coastguard Worker USE_LSUSB(NEWTOY(lsusb, "i:", TOYFLAG_USR|TOYFLAG_BIN))
7*cf5a6c84SAndroid Build Coastguard Worker USE_LSPCI(NEWTOY(lspci, "eDmkn@x@i:", TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker 
9*cf5a6c84SAndroid Build Coastguard Worker config LSPCI
10*cf5a6c84SAndroid Build Coastguard Worker   bool "lspci"
11*cf5a6c84SAndroid Build Coastguard Worker   default y
12*cf5a6c84SAndroid Build Coastguard Worker   help
13*cf5a6c84SAndroid Build Coastguard Worker     usage: lspci [-ekmn] [-i FILE]
14*cf5a6c84SAndroid Build Coastguard Worker 
15*cf5a6c84SAndroid Build Coastguard Worker     List PCI devices.
16*cf5a6c84SAndroid Build Coastguard Worker 
17*cf5a6c84SAndroid Build Coastguard Worker     -e	Extended (6 digit) class
18*cf5a6c84SAndroid Build Coastguard Worker     -i	ID database (default /etc/pci.ids[.gz])
19*cf5a6c84SAndroid Build Coastguard Worker     -k	Show kernel driver
20*cf5a6c84SAndroid Build Coastguard Worker     -m	Machine readable
21*cf5a6c84SAndroid Build Coastguard Worker     -n	Numeric output (-nn for both)
22*cf5a6c84SAndroid Build Coastguard Worker     -D	Print domain numbers
23*cf5a6c84SAndroid Build Coastguard Worker     -x	Hex dump of config space (64 bytes; -xxx for 256, -xxxx for 4096)
24*cf5a6c84SAndroid Build Coastguard Worker 
25*cf5a6c84SAndroid Build Coastguard Worker config LSUSB
26*cf5a6c84SAndroid Build Coastguard Worker   bool "lsusb"
27*cf5a6c84SAndroid Build Coastguard Worker   default y
28*cf5a6c84SAndroid Build Coastguard Worker   help
29*cf5a6c84SAndroid Build Coastguard Worker     usage: lsusb [-i]
30*cf5a6c84SAndroid Build Coastguard Worker 
31*cf5a6c84SAndroid Build Coastguard Worker     List USB hosts/devices.
32*cf5a6c84SAndroid Build Coastguard Worker 
33*cf5a6c84SAndroid Build Coastguard Worker     -i	ID database (default /etc/usb.ids[.gz])
34*cf5a6c84SAndroid Build Coastguard Worker */
35*cf5a6c84SAndroid Build Coastguard Worker 
36*cf5a6c84SAndroid Build Coastguard Worker #define FOR_lsusb
37*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
38*cf5a6c84SAndroid Build Coastguard Worker 
39*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
40*cf5a6c84SAndroid Build Coastguard Worker   char *i;
41*cf5a6c84SAndroid Build Coastguard Worker   long x, n;
42*cf5a6c84SAndroid Build Coastguard Worker 
43*cf5a6c84SAndroid Build Coastguard Worker   void *ids, *class;
44*cf5a6c84SAndroid Build Coastguard Worker   int count;
45*cf5a6c84SAndroid Build Coastguard Worker )
46*cf5a6c84SAndroid Build Coastguard Worker 
47*cf5a6c84SAndroid Build Coastguard Worker struct dev_ids {
48*cf5a6c84SAndroid Build Coastguard Worker   struct dev_ids *next, *child;
49*cf5a6c84SAndroid Build Coastguard Worker   int id;
50*cf5a6c84SAndroid Build Coastguard Worker   char name[];
51*cf5a6c84SAndroid Build Coastguard Worker };
52*cf5a6c84SAndroid Build Coastguard Worker 
53*cf5a6c84SAndroid Build Coastguard Worker struct scanloop {
54*cf5a6c84SAndroid Build Coastguard Worker   char *pattern;
55*cf5a6c84SAndroid Build Coastguard Worker   void *d1, *d2;
56*cf5a6c84SAndroid Build Coastguard Worker };
57*cf5a6c84SAndroid Build Coastguard Worker 
58*cf5a6c84SAndroid Build Coastguard Worker // Common function to read uevent file under /proc for both pci and usb
59*cf5a6c84SAndroid Build Coastguard Worker // note that %s is omitted (because pointer is into toybuf, avoiding copy).
scan_uevent(struct dirtree * new,int len,struct scanloop * sl)60*cf5a6c84SAndroid Build Coastguard Worker static int scan_uevent(struct dirtree *new, int len, struct scanloop *sl)
61*cf5a6c84SAndroid Build Coastguard Worker {
62*cf5a6c84SAndroid Build Coastguard Worker   int ii, saw = 0;
63*cf5a6c84SAndroid Build Coastguard Worker   off_t flen = sizeof(toybuf);
64*cf5a6c84SAndroid Build Coastguard Worker   char *ss, *yy;
65*cf5a6c84SAndroid Build Coastguard Worker 
66*cf5a6c84SAndroid Build Coastguard Worker   // Read data
67*cf5a6c84SAndroid Build Coastguard Worker   if (*new->name == '.') return 0;
68*cf5a6c84SAndroid Build Coastguard Worker   sprintf(toybuf, "%s/uevent", new->name);
69*cf5a6c84SAndroid Build Coastguard Worker   if (!readfileat(dirtree_parentfd(new), ss = toybuf, toybuf, &flen)) return 0;
70*cf5a6c84SAndroid Build Coastguard Worker 
71*cf5a6c84SAndroid Build Coastguard Worker   // Loop over lines
72*cf5a6c84SAndroid Build Coastguard Worker   while ((flen = strcspn(ss, "\n"))) {
73*cf5a6c84SAndroid Build Coastguard Worker     if (ss[flen]) ss[flen++] = 0;
74*cf5a6c84SAndroid Build Coastguard Worker     yy = ss+flen;
75*cf5a6c84SAndroid Build Coastguard Worker 
76*cf5a6c84SAndroid Build Coastguard Worker     // Try each pattern
77*cf5a6c84SAndroid Build Coastguard Worker     for (ii = 0; ii<len; ii++) {
78*cf5a6c84SAndroid Build Coastguard Worker       if (strchr(sl[ii].pattern, '%')) {
79*cf5a6c84SAndroid Build Coastguard Worker         if (2-!sl[ii].d2!=sscanf(ss, sl[ii].pattern, sl[ii].d1, sl[ii].d2))
80*cf5a6c84SAndroid Build Coastguard Worker           continue;
81*cf5a6c84SAndroid Build Coastguard Worker       } else if (strstart(&ss, sl[ii].pattern)) *(void **)sl[ii].d1 = ss;
82*cf5a6c84SAndroid Build Coastguard Worker       else continue;
83*cf5a6c84SAndroid Build Coastguard Worker       saw |= 1<<ii;
84*cf5a6c84SAndroid Build Coastguard Worker 
85*cf5a6c84SAndroid Build Coastguard Worker       break;
86*cf5a6c84SAndroid Build Coastguard Worker     }
87*cf5a6c84SAndroid Build Coastguard Worker     ss = yy;
88*cf5a6c84SAndroid Build Coastguard Worker   }
89*cf5a6c84SAndroid Build Coastguard Worker 
90*cf5a6c84SAndroid Build Coastguard Worker   return saw;
91*cf5a6c84SAndroid Build Coastguard Worker }
92*cf5a6c84SAndroid Build Coastguard Worker 
get_names(struct dev_ids * ids,int id1,int id2,char ** name1,char ** name2)93*cf5a6c84SAndroid Build Coastguard Worker static void get_names(struct dev_ids *ids, int id1, int id2,
94*cf5a6c84SAndroid Build Coastguard Worker   char **name1, char **name2)
95*cf5a6c84SAndroid Build Coastguard Worker {
96*cf5a6c84SAndroid Build Coastguard Worker   // Look up matching dev_ids (if any)
97*cf5a6c84SAndroid Build Coastguard Worker   *name1 = *name2 = "";
98*cf5a6c84SAndroid Build Coastguard Worker   for (; ids; ids = ids->next) {
99*cf5a6c84SAndroid Build Coastguard Worker     if (id1 != ids->id) continue;
100*cf5a6c84SAndroid Build Coastguard Worker     *name1 = ids->name;
101*cf5a6c84SAndroid Build Coastguard Worker     for (ids = ids->child; ids; ids = ids->next) {
102*cf5a6c84SAndroid Build Coastguard Worker       if (id2 != ids->id) continue;
103*cf5a6c84SAndroid Build Coastguard Worker       *name2 = ids->name;
104*cf5a6c84SAndroid Build Coastguard Worker       return;
105*cf5a6c84SAndroid Build Coastguard Worker     }
106*cf5a6c84SAndroid Build Coastguard Worker     return;
107*cf5a6c84SAndroid Build Coastguard Worker   }
108*cf5a6c84SAndroid Build Coastguard Worker }
109*cf5a6c84SAndroid Build Coastguard Worker 
110*cf5a6c84SAndroid Build Coastguard Worker // Search for pci.ids or usb.ids and return parsed structure or NULL
parse_dev_ids(char * name,struct dev_ids ** and)111*cf5a6c84SAndroid Build Coastguard Worker struct dev_ids *parse_dev_ids(char *name, struct dev_ids **and)
112*cf5a6c84SAndroid Build Coastguard Worker {
113*cf5a6c84SAndroid Build Coastguard Worker   char *path = "/etc:/vendor:/usr/share/hwdata:/usr/share/misc";
114*cf5a6c84SAndroid Build Coastguard Worker   struct string_list *sl = 0;
115*cf5a6c84SAndroid Build Coastguard Worker   FILE *fp;
116*cf5a6c84SAndroid Build Coastguard Worker   char *s, *ss, *sss;
117*cf5a6c84SAndroid Build Coastguard Worker   struct dev_ids *ids = 0, *new;
118*cf5a6c84SAndroid Build Coastguard Worker   int fd = -1;
119*cf5a6c84SAndroid Build Coastguard Worker 
120*cf5a6c84SAndroid Build Coastguard Worker   // Open compressed or uncompressed file
121*cf5a6c84SAndroid Build Coastguard Worker   signal(SIGCHLD, SIG_IGN);
122*cf5a6c84SAndroid Build Coastguard Worker   s = TT.i;
123*cf5a6c84SAndroid Build Coastguard Worker   if (!s) {
124*cf5a6c84SAndroid Build Coastguard Worker     sprintf(toybuf, "%s.gz", name);
125*cf5a6c84SAndroid Build Coastguard Worker     if ((sl = find_in_path(path, toybuf)) || (sl = find_in_path(path, name)))
126*cf5a6c84SAndroid Build Coastguard Worker       s = sl->str;
127*cf5a6c84SAndroid Build Coastguard Worker   }
128*cf5a6c84SAndroid Build Coastguard Worker   if (s && strend(s, ".gz")) xpopen((char *[]){"zcat", sl->str, 0}, &fd, 1);
129*cf5a6c84SAndroid Build Coastguard Worker   else if (s) fd = xopen(s, O_RDONLY);
130*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(sl, free);
131*cf5a6c84SAndroid Build Coastguard Worker   if (fd == -1) return 0;
132*cf5a6c84SAndroid Build Coastguard Worker 
133*cf5a6c84SAndroid Build Coastguard Worker   for (fp = fdopen(fd, "r"); (s = ss = xgetline(fp)); free(s)) {
134*cf5a6c84SAndroid Build Coastguard Worker     // TODO parse and use third level instead of skipping it here
135*cf5a6c84SAndroid Build Coastguard Worker     if (s[strspn(s, " \t")]=='#' || strstart(&ss, "\t\t")) continue;
136*cf5a6c84SAndroid Build Coastguard Worker 
137*cf5a6c84SAndroid Build Coastguard Worker     // Switch to device class list?
138*cf5a6c84SAndroid Build Coastguard Worker     if (strstart(&ss, "C ") && and) {
139*cf5a6c84SAndroid Build Coastguard Worker       *and = ids;
140*cf5a6c84SAndroid Build Coastguard Worker       and = 0;
141*cf5a6c84SAndroid Build Coastguard Worker     }
142*cf5a6c84SAndroid Build Coastguard Worker     fd = estrtol(sss = ss, &ss, 16);
143*cf5a6c84SAndroid Build Coastguard Worker     if (ss>sss && *ss++==' ') {
144*cf5a6c84SAndroid Build Coastguard Worker       while (isspace(*ss)) ss++;
145*cf5a6c84SAndroid Build Coastguard Worker       new = xmalloc(sizeof(*new)+strlen(ss)+1);
146*cf5a6c84SAndroid Build Coastguard Worker       new->child = 0;
147*cf5a6c84SAndroid Build Coastguard Worker       new->id = fd;
148*cf5a6c84SAndroid Build Coastguard Worker       strcpy(new->name, ss);
149*cf5a6c84SAndroid Build Coastguard Worker       if (!ids || *s!='\t') {
150*cf5a6c84SAndroid Build Coastguard Worker         new->next = ids;
151*cf5a6c84SAndroid Build Coastguard Worker         ids = new;
152*cf5a6c84SAndroid Build Coastguard Worker       } else {
153*cf5a6c84SAndroid Build Coastguard Worker         new->next = ids->child;
154*cf5a6c84SAndroid Build Coastguard Worker         ids->child = new;
155*cf5a6c84SAndroid Build Coastguard Worker       }
156*cf5a6c84SAndroid Build Coastguard Worker     }
157*cf5a6c84SAndroid Build Coastguard Worker   }
158*cf5a6c84SAndroid Build Coastguard Worker   fclose(fp);
159*cf5a6c84SAndroid Build Coastguard Worker 
160*cf5a6c84SAndroid Build Coastguard Worker   return ids;
161*cf5a6c84SAndroid Build Coastguard Worker }
162*cf5a6c84SAndroid Build Coastguard Worker 
list_usb(struct dirtree * new)163*cf5a6c84SAndroid Build Coastguard Worker static int list_usb(struct dirtree *new)
164*cf5a6c84SAndroid Build Coastguard Worker {
165*cf5a6c84SAndroid Build Coastguard Worker   int busnum = 0, devnum = 0, pid = 0, vid = 0;
166*cf5a6c84SAndroid Build Coastguard Worker   char *n1, *n2;
167*cf5a6c84SAndroid Build Coastguard Worker 
168*cf5a6c84SAndroid Build Coastguard Worker   if (!new->parent) return DIRTREE_RECURSE;
169*cf5a6c84SAndroid Build Coastguard Worker   if (7 == scan_uevent(new, 3, (struct scanloop[]){{"BUSNUM=%u", &busnum, 0},
170*cf5a6c84SAndroid Build Coastguard Worker     {"DEVNUM=%u", &devnum, 0}, {"PRODUCT=%x/%x", &pid, &vid}}))
171*cf5a6c84SAndroid Build Coastguard Worker   {
172*cf5a6c84SAndroid Build Coastguard Worker     get_names(TT.ids, pid, vid, &n1, &n2);
173*cf5a6c84SAndroid Build Coastguard Worker     printf("Bus %03d Device %03d: ID %04x:%04x %s %s\n",
174*cf5a6c84SAndroid Build Coastguard Worker       busnum, devnum, pid, vid, n1, n2);
175*cf5a6c84SAndroid Build Coastguard Worker   }
176*cf5a6c84SAndroid Build Coastguard Worker 
177*cf5a6c84SAndroid Build Coastguard Worker   return 0;
178*cf5a6c84SAndroid Build Coastguard Worker }
179*cf5a6c84SAndroid Build Coastguard Worker 
lsusb_main(void)180*cf5a6c84SAndroid Build Coastguard Worker void lsusb_main(void)
181*cf5a6c84SAndroid Build Coastguard Worker {
182*cf5a6c84SAndroid Build Coastguard Worker   // Parse http://www.linux-usb.org/usb.ids file (if available)
183*cf5a6c84SAndroid Build Coastguard Worker   TT.ids = parse_dev_ids("usb.ids", 0);
184*cf5a6c84SAndroid Build Coastguard Worker   dirtree_read("/sys/bus/usb/devices/", list_usb);
185*cf5a6c84SAndroid Build Coastguard Worker }
186*cf5a6c84SAndroid Build Coastguard Worker 
187*cf5a6c84SAndroid Build Coastguard Worker #define FOR_lspci
188*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
189*cf5a6c84SAndroid Build Coastguard Worker 
190*cf5a6c84SAndroid Build Coastguard Worker // TODO: -v
list_pci(struct dirtree * new)191*cf5a6c84SAndroid Build Coastguard Worker static int list_pci(struct dirtree *new)
192*cf5a6c84SAndroid Build Coastguard Worker {
193*cf5a6c84SAndroid Build Coastguard Worker   char *driver = 0, buf[16], *ss, *names[3];
194*cf5a6c84SAndroid Build Coastguard Worker   int cvd[3] = {0}, ii, revision = 0;
195*cf5a6c84SAndroid Build Coastguard Worker   off_t len = sizeof(toybuf);
196*cf5a6c84SAndroid Build Coastguard Worker   /* skip 0000: part by default */
197*cf5a6c84SAndroid Build Coastguard Worker   char *bus = strchr(new->name, ':') + 1;
198*cf5a6c84SAndroid Build Coastguard Worker 
199*cf5a6c84SAndroid Build Coastguard Worker // Output formats: -n, -nn, -m, -nm, -nnm, -k
200*cf5a6c84SAndroid Build Coastguard Worker 
201*cf5a6c84SAndroid Build Coastguard Worker   if (!new->parent) return DIRTREE_RECURSE;
202*cf5a6c84SAndroid Build Coastguard Worker   if (!bus || strlen(new->name)<6) return 0;
203*cf5a6c84SAndroid Build Coastguard Worker   TT.count = 0;
204*cf5a6c84SAndroid Build Coastguard Worker 
205*cf5a6c84SAndroid Build Coastguard Worker   // Load revision
206*cf5a6c84SAndroid Build Coastguard Worker   sprintf(toybuf, "%s/revision", new->name);
207*cf5a6c84SAndroid Build Coastguard Worker   if (readfileat(dirtree_parentfd(new), ss = toybuf, toybuf, &len)) {
208*cf5a6c84SAndroid Build Coastguard Worker     strstart(&ss, "0x");
209*cf5a6c84SAndroid Build Coastguard Worker     sscanf(ss, "%x", &revision);
210*cf5a6c84SAndroid Build Coastguard Worker   }
211*cf5a6c84SAndroid Build Coastguard Worker 
212*cf5a6c84SAndroid Build Coastguard Worker   // Load uevent data, look up names in database
213*cf5a6c84SAndroid Build Coastguard Worker   if (6>scan_uevent(new, 3, (struct scanloop[]){{"DRIVER=", &driver, 0},
214*cf5a6c84SAndroid Build Coastguard Worker     {"PCI_CLASS=%x", cvd, 0}, {"PCI_ID=%x:%x", cvd+1, cvd+2}})) return 0;
215*cf5a6c84SAndroid Build Coastguard Worker   get_names(TT.class, 255&(cvd[0]>>16), 255&(cvd[0]>>8), names, names);
216*cf5a6c84SAndroid Build Coastguard Worker   get_names(TT.ids, cvd[1], cvd[2], names+1, names+2);
217*cf5a6c84SAndroid Build Coastguard Worker   if (!FLAG(e)) cvd[0] >>= 8;
218*cf5a6c84SAndroid Build Coastguard Worker 
219*cf5a6c84SAndroid Build Coastguard Worker   // Output line according to flags
220*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(D) || strncmp(new->name, "0000:", bus-new->name)) bus = new->name;
221*cf5a6c84SAndroid Build Coastguard Worker   printf("%s", bus);
222*cf5a6c84SAndroid Build Coastguard Worker   for (ii = 0; ii<3; ii++) {
223*cf5a6c84SAndroid Build Coastguard Worker     sprintf(buf, "%0*x", 6-2*(ii||!FLAG(e)), cvd[ii]);
224*cf5a6c84SAndroid Build Coastguard Worker     if (!TT.n) printf(FLAG(m) ? " \"%s\"" : ": %s"+(ii!=1), names[ii] ? : buf);
225*cf5a6c84SAndroid Build Coastguard Worker     else if (TT.n==1) printf(FLAG(m) ? " \"%s\"" : (ii==2)?"%s ":" %s:", buf);
226*cf5a6c84SAndroid Build Coastguard Worker     else if (!FLAG(m)) {
227*cf5a6c84SAndroid Build Coastguard Worker       // This one permutes the order, so do it all first time and abort loop
228*cf5a6c84SAndroid Build Coastguard Worker       printf(" %s [%s]: %s %s [%04x:%04x]", names[0], buf, names[1], names[2],
229*cf5a6c84SAndroid Build Coastguard Worker         cvd[1], cvd[2]);
230*cf5a6c84SAndroid Build Coastguard Worker       break;
231*cf5a6c84SAndroid Build Coastguard Worker     } else printf(" \"%s [%s]\"", names[ii], buf);
232*cf5a6c84SAndroid Build Coastguard Worker   }
233*cf5a6c84SAndroid Build Coastguard Worker   if (revision) printf(FLAG(m) ? " -r%02x" : " (rev %02x)", revision);
234*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(k) && driver) printf(FLAG(m) ? " \"%s\"" : " %s", driver);
235*cf5a6c84SAndroid Build Coastguard Worker   xputc('\n');
236*cf5a6c84SAndroid Build Coastguard Worker 
237*cf5a6c84SAndroid Build Coastguard Worker   if (TT.x) {
238*cf5a6c84SAndroid Build Coastguard Worker     FILE *fp;
239*cf5a6c84SAndroid Build Coastguard Worker     int b, col = 0, max = (TT.x >= 4) ? 4096 : ((TT.x >= 3) ? 256 : 64);
240*cf5a6c84SAndroid Build Coastguard Worker 
241*cf5a6c84SAndroid Build Coastguard Worker     snprintf(toybuf, sizeof(toybuf), "/sys/bus/pci/devices/%s/config", new->name);
242*cf5a6c84SAndroid Build Coastguard Worker     fp = xfopen(toybuf, "r");
243*cf5a6c84SAndroid Build Coastguard Worker     while ((b = fgetc(fp)) != EOF) {
244*cf5a6c84SAndroid Build Coastguard Worker       if ((col % 16) == 0) printf("%02x: ", col & 0xf0);
245*cf5a6c84SAndroid Build Coastguard Worker       printf("%02x ", (b & 0xff));
246*cf5a6c84SAndroid Build Coastguard Worker       if ((++col % 16) == 0) xputc('\n');
247*cf5a6c84SAndroid Build Coastguard Worker       if (col == max) break;
248*cf5a6c84SAndroid Build Coastguard Worker     }
249*cf5a6c84SAndroid Build Coastguard Worker     xputc('\n');
250*cf5a6c84SAndroid Build Coastguard Worker     fclose(fp);
251*cf5a6c84SAndroid Build Coastguard Worker   }
252*cf5a6c84SAndroid Build Coastguard Worker 
253*cf5a6c84SAndroid Build Coastguard Worker   return 0;
254*cf5a6c84SAndroid Build Coastguard Worker }
255*cf5a6c84SAndroid Build Coastguard Worker 
lspci_main(void)256*cf5a6c84SAndroid Build Coastguard Worker void lspci_main(void)
257*cf5a6c84SAndroid Build Coastguard Worker {
258*cf5a6c84SAndroid Build Coastguard Worker   // Parse https://pci-ids.ucw.cz/v2.2/pci.ids (if available)
259*cf5a6c84SAndroid Build Coastguard Worker   if (TT.n != 1) TT.class = parse_dev_ids("pci.ids", (void *)&TT.ids);
260*cf5a6c84SAndroid Build Coastguard Worker   dirtree_read("/sys/bus/pci/devices/", list_pci);
261*cf5a6c84SAndroid Build Coastguard Worker }
262