strace.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. int debug = 0;
  13. int outf = 2;
  14. void
  15. usage(void)
  16. {
  17. fprint(2, "Usage: ratrace [-o file] [-d] [-c cmd [arg...]] | [pid]\n");
  18. exits("usage");
  19. }
  20. void
  21. hang(void)
  22. {
  23. int me, amt;
  24. char *myctl;
  25. static char hang[] = "hang";
  26. myctl = smprint("/proc/%d/ctl", getpid());
  27. me = open(myctl, OWRITE);
  28. if (me < 0)
  29. sysfatal("can't open %s: %r", myctl);
  30. amt = write(me, hang, sizeof hang - 1);
  31. if (amt < (sizeof(hang) - 1))
  32. sysfatal("Write 'hang' to %s: %r", myctl);
  33. close(me);
  34. free(myctl);
  35. }
  36. void
  37. main(int argc, char **argv)
  38. {
  39. int pid, fd, amt;
  40. char *cmd = nil;
  41. char **args = nil;
  42. static char p[512], buf[16384];
  43. /*
  44. * don't bother with fancy arg processing, because it picks up options
  45. * for the command you are starting. Just check for -c as argv[1]
  46. * and then take it from there.
  47. */
  48. ++argv;
  49. --argc;
  50. while (argv[0][0] == '-') {
  51. switch(argv[0][1]) {
  52. case 'c':
  53. if (argc < 2)
  54. usage();
  55. cmd = strdup(argv[1]);
  56. args = &argv[1];
  57. break;
  58. case 'd':
  59. debug = 1;
  60. break;
  61. case 'o':
  62. if (argc < 2)
  63. usage();
  64. outf = create(argv[1], OWRITE, 0666);
  65. if (outf < 0)
  66. sysfatal(smprint("%s: %r", argv[1]));
  67. ++argv;
  68. --argc;
  69. break;
  70. default:
  71. usage();
  72. }
  73. ++argv;
  74. --argc;
  75. }
  76. /* run a command? */
  77. if(cmd) {
  78. pid = fork();
  79. if (pid < 0)
  80. sysfatal("fork failed: %r");
  81. if(pid == 0) {
  82. hang();
  83. exec(cmd, args);
  84. if(cmd[0] != '/')
  85. exec(smprint("/bin/%s", cmd), args);
  86. sysfatal("exec %s failed: %r", cmd);
  87. }
  88. } else {
  89. if(argc != 1)
  90. usage();
  91. pid = atoi(argv[0]);
  92. }
  93. /* the child is hanging, now we can start it up and collect the output. */
  94. snprint(p, sizeof(p), "/proc/%d/ctl", pid);
  95. fd = open(p, OWRITE);
  96. if (fd < 0) {
  97. sysfatal("open %s: %r\n", p);
  98. }
  99. snprint(p, sizeof(p), "straceall");
  100. if (write(fd, p, strlen(p)) < strlen(p)) {
  101. sysfatal("write to ctl %s %d: %r\n", p, fd);
  102. }
  103. // This kind of sucks. We have to wait just a bit or we get
  104. // an error when we send the start command. FIXME.
  105. sleep(1000);
  106. // unset hang. We only need it initially.
  107. snprint(p, sizeof(p), "nohang");
  108. if (write(fd, p, strlen(p)) < strlen(p)) {
  109. sysfatal("write to ctl %s %d: %r\n", p, fd);
  110. }
  111. snprint(p, sizeof(p), "start");
  112. if (write(fd, p, strlen(p)) < strlen(p)) {
  113. sysfatal("write to ctl %s %d: %r\n", p, fd);
  114. }
  115. close(fd);
  116. snprint(p, sizeof(p), "/proc/%d/strace", pid);
  117. fd = open(p, OREAD);
  118. if (fd < 0) {
  119. sysfatal("open %s: %r\n", p);
  120. }
  121. while ((amt = read(fd, buf, sizeof(buf))) > 0) {
  122. if (write(outf, buf, amt) < amt) {
  123. sysfatal("Write to stdout: %r\n");
  124. }
  125. }
  126. if (amt < 0)
  127. fprint(2, "Read fd %d for %s: %r\n", fd, p);
  128. }