au2file.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include <assert.h>
  2. #include <errno.h>
  3. #include <inttypes.h>
  4. #include <limits.h>
  5. #include <signal.h>
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <time.h>
  12. #include <fcntl.h>
  13. #include <poll.h>
  14. #include <unistd.h>
  15. #ifdef USE_CAPSICUM
  16. #include <sys/capsicum.h>
  17. #endif
  18. #include <err.h>
  19. #include <sysexits.h>
  20. #include "au.h"
  21. #include "write/afile.h"
  22. #include "common.h"
  23. #ifndef NAMEMAX
  24. #define NAMEMAX 10
  25. #endif
  26. #ifndef BSIZE
  27. #define BSIZE 0x1000
  28. #endif
  29. #ifdef SIGINFO
  30. #define IFINFO(x) (x)
  31. #else
  32. #define IFINFO(x)
  33. #endif
  34. static sigset_t sigpend;
  35. #ifdef SIGINFO
  36. static size_t info_bytes = 0;
  37. #endif
  38. static void sighandle(int);
  39. #ifdef SIGINFO
  40. static void siginfo(int);
  41. #endif
  42. int
  43. main(int argc, char *argv[])
  44. {
  45. #ifdef USE_CAPSICUM
  46. cap_rights_t rights;
  47. #endif
  48. #ifdef USE_BITRATE
  49. uint32_t bitrate = 0;
  50. #endif
  51. #ifdef USE_MODE
  52. char *amode = NULL;
  53. #endif
  54. #ifdef USE_QUALITY
  55. double quality = 1;
  56. #endif
  57. int cpipe[2];
  58. pid_t cpid = 0;
  59. uint32_t enc;
  60. struct au au = AU_INITIALIZER;
  61. struct afile *a;
  62. ssize_t i;
  63. ssize_t r;
  64. size_t bsize = BSIZE;
  65. void *b;
  66. char *p;
  67. int c;
  68. setprogname(argv[0]);
  69. while ((c = getopt(argc, argv, "B:C:I:RWb:c:i:m:q:")) != -1)
  70. switch (c) {
  71. case 'B':
  72. #ifdef USE_BITRATE
  73. bitrate = strtou32(optarg);
  74. #endif
  75. break;
  76. case 'b':
  77. bsize = strtoul(optarg, &p, 0);
  78. if (p == optarg || *p != '\0')
  79. errx(EX_USAGE, "Invalid number '%s'",
  80. optarg);
  81. if (bsize < 0x400)
  82. errx(EX_USAGE, "The buffer size (%zu) "
  83. "is too small", bsize);
  84. break;
  85. case 'm':
  86. #ifdef USE_MODE
  87. amode = optarg;
  88. #endif
  89. break;
  90. case 'q':
  91. #ifdef USE_QUALITY
  92. quality = strtod(optarg, &p);
  93. if (p == optarg || *p != '\0')
  94. errx(EX_USAGE, "Invalid number '%s'",
  95. optarg);
  96. #endif
  97. break;
  98. default:
  99. goto usage;
  100. }
  101. if ((b = malloc(bsize)) == NULL)
  102. err(EX_OSERR, "Could not allocate the buffer");
  103. sigemptyset(&sigpend);
  104. (void)signal(SIGINT, &sighandle);
  105. IFINFO((void)signal(SIGINFO, &siginfo));
  106. #ifdef USE_PLEDGE
  107. pledge("stdio proc exec", NULL);
  108. c = 1;
  109. #endif
  110. #ifdef USE_CAPSICUM
  111. c = 1;
  112. #endif
  113. if ((a = af_fdopen(STDOUT_FILENO)) == NULL)
  114. err(EX_DATAERR, "Could not initialize audio codec");
  115. #ifdef USE_MODE
  116. if (amode != NULL && af_set(a, "mode", amode) != 1) {
  117. fprintf(stderr, "%s: Invalid mode %s\n", amode);
  118. if (af_get(a, "mode", &amode) == 1)
  119. fprintf(stderr, "Available modes: %s\n", amode);
  120. exit(EX_USAGE);
  121. }
  122. #endif
  123. #ifdef USE_BITRATE
  124. (void)af_set(a, "bitrate", bitrate);
  125. #endif
  126. #ifdef USE_QUALITY
  127. (void)af_set(a, "quality", quality);
  128. #endif
  129. while (nread(STDIN_FILENO, b, AU_SIZE) == AU_SIZE) {
  130. IFINFO(info_bytes += AU_SIZE);
  131. if (au_gethdr(&au, b) != 0)
  132. errx(EX_DATAERR, "Bad header");
  133. if (af_set(a, "rate channels", au.au_rate, au.au_chan)
  134. != 2)
  135. err(EX_DATAERR,
  136. "Could not set audio parameters");
  137. if (af_set(a, "encoding", au.au_enc) != 1) {
  138. if (cpid > 0)
  139. abort();
  140. if (af_get(a, "encoding", &enc) != 1)
  141. err(EX_SOFTWARE,
  142. "Could not get desired encoding");
  143. if (pipe(cpipe) == -1)
  144. err(EX_OSERR, "Could not create pipe");
  145. switch (cpid = fork()) {
  146. case -1:
  147. err(EX_OSERR, "Could not fork process");
  148. case 0:
  149. close(cpipe[0]);
  150. if (dup2(cpipe[1], STDOUT_FILENO) == -1)
  151. err(EX_OSERR, "Could not "
  152. "connect the pipe");
  153. auconvp(&au, enc, b, bsize);
  154. err(EX_SOFTWARE,
  155. "Could not execute auconv");
  156. default:
  157. close(cpipe[1]);
  158. if (dup2(cpipe[0], STDIN_FILENO) == -1)
  159. err(EX_OSERR, "Could not "
  160. "connect the pipe");
  161. break;
  162. }
  163. continue;
  164. }
  165. #ifdef USE_CAPSICUM
  166. if (c) {
  167. if (cap_enter() == -1 && errno != ENOSYS)
  168. err(EX_OSERR,
  169. "Could not enter capability mode");
  170. (void)cap_rights_init(&rights, CAP_READ);
  171. if (cap_rights_limit(STDIN_FILENO, &rights)
  172. != 0 && errno != ENOSYS)
  173. err(EX_OSERR, "Could not limit the "
  174. "standard input");
  175. (void)cap_rights_init(&rights, CAP_WRITE,
  176. CAP_SEEK);
  177. if (cap_rights_limit(STDOUT_FILENO, &rights)
  178. != 0 && errno != ENOSYS)
  179. err(EX_OSERR, "Could not limit the "
  180. "standard output");
  181. (void)cap_rights_init(&rights, CAP_WRITE);
  182. if (cap_rights_limit(STDERR_FILENO, &rights)
  183. != 0 && errno != ENOSYS)
  184. err(EX_OSERR, "Could not limit the "
  185. "standard error");
  186. c = 0;
  187. }
  188. #endif /* USE_CAPSICUM */
  189. #ifdef USE_PLEDGE
  190. if (c) {
  191. pledge("stdio", NULL);
  192. c = 0;
  193. }
  194. #endif
  195. for (i = AU_SIZE; i < au.au_off; i += r) {
  196. if ((r = read(STDIN_FILENO, b,
  197. MIN(bsize, au.au_off - i))) < 0) {
  198. if (errno == EINTR)
  199. goto ret;
  200. err(EX_IOERR, "read error");
  201. }
  202. if (r == 0)
  203. err(EX_DATAERR, "Unexpected EOF");
  204. IFINFO(info_bytes += r);
  205. }
  206. while ((r = read(STDIN_FILENO, b,
  207. MIN(bsize, au.au_size))) > 0) {
  208. if (af_write(a, b, r) != r) {
  209. if (errno == EINTR)
  210. goto ret;
  211. err(EX_IOERR, "write error");
  212. }
  213. if (au.au_size != UINT32_MAX)
  214. au.au_size -= r;
  215. IFINFO(info_bytes += r);
  216. }
  217. if (r < 0) {
  218. if (errno == EINTR)
  219. goto ret;
  220. err(EX_IOERR, "read error");
  221. }
  222. if (r == 0) { /* EOF */
  223. ret:
  224. if (au.au_size > 0 &&
  225. au.au_size != UINT32_MAX) {
  226. af_close(a);
  227. free(b);
  228. err(EX_DATAERR, "Unexpected EOF");
  229. }
  230. break;
  231. }
  232. }
  233. af_close(a);
  234. free(b);
  235. return (EX_OK);
  236. usage:
  237. c = strlen(getprogname()) + 8;
  238. (void)fprintf(stderr, "usage: %s"
  239. #ifdef USE_BITRATE
  240. " [-B bitrate]"
  241. #endif
  242. " [-b buffer-size]"
  243. #ifdef USE_MODE
  244. " [-m mode]"
  245. #endif
  246. #ifdef USE_QUALITY
  247. " [-q quality]"
  248. #endif
  249. "\n", getprogname());
  250. return (EX_USAGE);
  251. }
  252. void
  253. sighandle(int sig)
  254. {
  255. (void)sigaddset(&sigpend, sig);
  256. }
  257. #ifdef SIGINFO
  258. void
  259. siginfo(int sig)
  260. {
  261. /* au2XXXX: XXXXXXiB processed */
  262. char b[NAMEMAX + 2 + 8 + 11];
  263. size_t i;
  264. i = strlen(getprogname());
  265. if (i > NAMEMAX) {
  266. (void)memcpy(b, getprogname(), NAMEMAX - 3);
  267. (void)memcpy(b + NAMEMAX - 3, "...", 3);
  268. i = NAMEMAX;
  269. } else
  270. (void)memcpy(b, getprogname(), i);
  271. (void)memcpy(b + i, ": ", 2);
  272. i += 2;
  273. i += szwrite(b + i, info_bytes, "B", "iB");
  274. (void)memcpy(b + i, " processed\n", 11);
  275. i += 11;
  276. (void)write(STDERR_FILENO, b, i);
  277. }
  278. #endif