/usr.bin/ktrace/ktrace.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 240 lines · 176 code · 24 blank · 40 comment · 64 complexity · 119494d21d7cab6c589adee777aad120 MD5 · raw file

  1. /*-
  2. * Copyright (c) 1988, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 4. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #ifndef lint
  30. static const char copyright[] =
  31. "@(#) Copyright (c) 1988, 1993\n\
  32. The Regents of the University of California. All rights reserved.\n";
  33. #endif /* not lint */
  34. #if 0
  35. #ifndef lint
  36. static char sccsid[] = "@(#)ktrace.c 8.1 (Berkeley) 6/6/93";
  37. #endif /* not lint */
  38. #endif
  39. #include <sys/cdefs.h>
  40. __FBSDID("$FreeBSD$");
  41. #include <sys/param.h>
  42. #include <sys/file.h>
  43. #include <sys/stat.h>
  44. #include <sys/time.h>
  45. #include <sys/uio.h>
  46. #include <sys/ktrace.h>
  47. #include <err.h>
  48. #include <errno.h>
  49. #include <inttypes.h>
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <unistd.h>
  53. #include "ktrace.h"
  54. static char def_tracefile[] = DEF_TRACEFILE;
  55. static enum clear { NOTSET, CLEAR, CLEARALL } clear = NOTSET;
  56. static int pid;
  57. static void no_ktrace(int);
  58. static void set_pid_clear(const char *, enum clear);
  59. static void usage(void);
  60. int
  61. main(int argc, char *argv[])
  62. {
  63. int append, ch, fd, inherit, ops, trpoints;
  64. const char *tracefile;
  65. mode_t omask;
  66. struct stat sb;
  67. append = ops = inherit = 0;
  68. trpoints = DEF_POINTS;
  69. tracefile = def_tracefile;
  70. while ((ch = getopt(argc,argv,"aCcdf:g:ip:t:")) != -1)
  71. switch((char)ch) {
  72. case 'a':
  73. append = 1;
  74. break;
  75. case 'C':
  76. set_pid_clear("1", CLEARALL);
  77. break;
  78. case 'c':
  79. set_pid_clear(NULL, CLEAR);
  80. break;
  81. case 'd':
  82. ops |= KTRFLAG_DESCEND;
  83. break;
  84. case 'f':
  85. tracefile = optarg;
  86. break;
  87. case 'g':
  88. set_pid_clear(optarg, NOTSET);
  89. pid = -pid;
  90. break;
  91. case 'i':
  92. inherit = 1;
  93. break;
  94. case 'p':
  95. set_pid_clear(optarg, NOTSET);
  96. break;
  97. case 't':
  98. trpoints = getpoints(optarg);
  99. if (trpoints < 0) {
  100. warnx("unknown facility in %s", optarg);
  101. usage();
  102. }
  103. break;
  104. default:
  105. usage();
  106. }
  107. argv += optind;
  108. argc -= optind;
  109. /* must have either -[Cc], a pid or a command */
  110. if (clear == NOTSET && pid == 0 && argc == 0)
  111. usage();
  112. /* can't have both a pid and a command */
  113. /* (note that -C sets pid to 1) */
  114. if (pid != 0 && argc > 0) {
  115. usage();
  116. }
  117. if (inherit)
  118. trpoints |= KTRFAC_INHERIT;
  119. (void)signal(SIGSYS, no_ktrace);
  120. if (clear != NOTSET) {
  121. if (clear == CLEARALL) {
  122. ops = KTROP_CLEAR | KTRFLAG_DESCEND;
  123. trpoints = ALL_POINTS;
  124. } else {
  125. ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE;
  126. }
  127. if (ktrace(tracefile, ops, trpoints, pid) < 0)
  128. err(1, "%s", tracefile);
  129. exit(0);
  130. }
  131. omask = umask(S_IRWXG|S_IRWXO);
  132. if (append) {
  133. if ((fd = open(tracefile, O_CREAT | O_WRONLY | O_NONBLOCK,
  134. DEFFILEMODE)) < 0)
  135. err(1, "%s", tracefile);
  136. if (fstat(fd, &sb) != 0 || sb.st_uid != getuid())
  137. errx(1, "refuse to append to %s not owned by you",
  138. tracefile);
  139. if (!(S_ISREG(sb.st_mode)))
  140. errx(1, "%s not regular file", tracefile);
  141. } else {
  142. if (unlink(tracefile) == -1 && errno != ENOENT)
  143. err(1, "unlink %s", tracefile);
  144. if ((fd = open(tracefile, O_CREAT | O_EXCL | O_WRONLY,
  145. DEFFILEMODE)) < 0)
  146. err(1, "%s", tracefile);
  147. }
  148. (void)umask(omask);
  149. (void)close(fd);
  150. trpoints |= PROC_ABI_POINTS;
  151. if (argc > 0) {
  152. if (ktrace(tracefile, ops, trpoints, getpid()) < 0)
  153. err(1, "%s", tracefile);
  154. execvp(*argv, argv);
  155. err(1, "exec of '%s' failed", *argv);
  156. }
  157. if (ktrace(tracefile, ops, trpoints, pid) < 0)
  158. err(1, "%s", tracefile);
  159. exit(0);
  160. }
  161. static void
  162. set_pid_clear(const char *p, enum clear cl)
  163. {
  164. intmax_t n;
  165. char *e;
  166. if (clear != NOTSET && cl != NOTSET) {
  167. /* either -c and -C or either of them twice */
  168. warnx("only one -c or -C flag is permitted");
  169. usage();
  170. }
  171. if ((clear == CLEARALL && p != NULL) || (cl == CLEARALL && pid != 0)) {
  172. /* both -C and a pid or pgid */
  173. warnx("the -C flag may not be combined with -g or -p");
  174. usage();
  175. }
  176. if (p != NULL && pid != 0) {
  177. /* either -p and -g or either of them twice */
  178. warnx("only one -g or -p flag is permitted");
  179. usage();
  180. }
  181. if (p != NULL) {
  182. errno = 0;
  183. n = strtoimax(p, &e, 10);
  184. /*
  185. * 1) not a number, or outside the range of an intmax_t
  186. * 2) inside the range of intmax_t but outside the range
  187. * of an int, keeping in mind that the pid may be
  188. * negated if it's actually a pgid.
  189. */
  190. if (*e != '\0' || n < 1 || errno == ERANGE ||
  191. n > (intmax_t)INT_MAX || n > -(intmax_t)INT_MIN) {
  192. warnx("invalid process or group id");
  193. usage();
  194. }
  195. pid = n;
  196. }
  197. if (cl != NOTSET)
  198. if ((clear = cl) == CLEARALL)
  199. pid = 1;
  200. }
  201. static void
  202. usage(void)
  203. {
  204. fprintf(stderr, "%s\n%s\n",
  205. "usage: ktrace [-aCcdi] [-f trfile] [-g pgrp | -p pid] [-t trstr]",
  206. " ktrace [-adi] [-f trfile] [-t trstr] command");
  207. exit(1);
  208. }
  209. static void
  210. no_ktrace(int sig __unused)
  211. {
  212. fprintf(stderr, "error:\t%s\n\t%s\n",
  213. "ktrace() system call not supported in the running kernel",
  214. "re-compile kernel with 'options KTRACE'");
  215. exit(1);
  216. }