| 1648 | } |
| 1649 | |
| 1650 | static const char *parse_interpreter(const char *cmd) |
| 1651 | { |
| 1652 | static char buf[100]; |
| 1653 | char *p, *opt; |
| 1654 | ssize_t n; /* read() can return negative values */ |
| 1655 | int fd; |
| 1656 | |
| 1657 | /* don't even try a .exe */ |
| 1658 | n = strlen(cmd); |
| 1659 | if (n >= 4 && !strcasecmp(cmd+n-4, ".exe")) |
| 1660 | return NULL; |
| 1661 | |
| 1662 | fd = open(cmd, O_RDONLY); |
| 1663 | if (fd < 0) |
| 1664 | return NULL; |
| 1665 | n = read(fd, buf, sizeof(buf)-1); |
| 1666 | close(fd); |
| 1667 | if (n < 4) /* at least '#!/x' and not error */ |
| 1668 | return NULL; |
| 1669 | |
| 1670 | if (buf[0] != '#' || buf[1] != '!') |
| 1671 | return NULL; |
| 1672 | buf[n] = '\0'; |
| 1673 | p = buf + strcspn(buf, "\r\n"); |
| 1674 | if (!*p) |
| 1675 | return NULL; |
| 1676 | |
| 1677 | *p = '\0'; |
| 1678 | if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\'))) |
| 1679 | return NULL; |
| 1680 | /* strip options */ |
| 1681 | if ((opt = strchr(p+1, ' '))) |
| 1682 | *opt = '\0'; |
| 1683 | return p+1; |
| 1684 | } |
| 1685 | |
| 1686 | /* |
| 1687 | * exe_only means that we only want to detect .exe files, but not scripts |
no outgoing calls
no test coverage detected