1 /* command-line utility to enqueue tracks for mmq-player */
3 #define _XOPEN_SOURCE 600
18 #include <sys/resource.h>
20 extern NORETURN
void die(const char *tmp
, ...) PRINTF
;
21 extern void emit(const char *fmt
, ...) PRINTF
;
22 extern void warn(const char *fmt
, ...) PRINTF
;
24 static const char *usage
= "Usage: %s [-p PRIO] [-n] [-s] [-c] [-P] FILE...\n";
26 # define MMQ_MQUEUE "/mmq"
28 static char path
[PATH_MAX
+2];
29 static int peek
, clear
, verbose
;
31 static void * xmalloc(size_t size
)
33 void *rv
= malloc(size
);
36 die("malloc: %s\n", strerror(errno
));
41 struct peek_tmp
*next
;
47 static void set_mq_nonblock(mqd_t mq
, int nb
)
51 attr
.mq_flags
= nb
? O_NONBLOCK
: 0;
53 if (mq_setattr(mq
, &attr
, NULL
) < 0)
54 die("mq_setattr(nonblock=%d): %s\n", nb
, strerror(errno
));
57 static void clear_or_peek(mqd_t mq
, struct mq_attr
*attr
)
61 char *tmp
= xmalloc(attr
->mq_msgsize
+ 2);
62 struct peek_tmp
*peekhead
= NULL
;
63 struct peek_tmp
*peektail
= NULL
;
64 struct peek_tmp
*peektmp
;
67 if (!(attr
->mq_flags
& O_NONBLOCK
))
68 set_mq_nonblock(mq
, 1);
70 for (i
= 0; i
< 30; i
++) {
71 while ((r
= mq_receive(mq
, tmp
, attr
->mq_msgsize
, &pr
)) >= 0) {
73 * successful receive, ensure we try again after
74 * we've sched_yield()-ed, below
88 peektmp
= xmalloc(sizeof(struct peek_tmp
) + r
);
94 memcpy(peektmp
->buf
, tmp
, r
);
96 peektail
->next
= peektmp
;
105 * in case another process is blocking on mq_send(),
106 * let that process run so we can try mq_receive()
107 * what was just sent...
109 if (errno
== EAGAIN
) {
110 setpriority(PRIO_PROCESS
, 0, 19);
119 set_mq_nonblock(mq
, 0);
125 die("mq_send: %s\n", strerror(errno
));
126 peektmp
= peekhead
->next
;
131 set_mq_nonblock(mq
, 1);
133 if (!(attr
->mq_flags
& O_NONBLOCK
))
134 set_mq_nonblock(mq
, 0);
138 int main(int argc
, char * const argv
[])
143 char *mqueue
= getenv("MQUEUE");
151 while ((opt
= getopt(argc
, argv
, "p:nvscPh")) != -1) {
174 xprio
= strtoul(optarg
, &err
, 10);
175 if (*err
|| xprio
< 0 || xprio
> UINT_MAX
)
176 die("prio must be an unsigned int\n");
177 prio
= (unsigned)xprio
;
184 emit(usage
, argv
[0]);
191 if (argi
>= argc
&& ! clear
&& ! peek
)
194 if ((mq
= mq_open(mqueue
, oflag
)) < 0)
195 die("mq_open: %s\n", strerror(errno
));
196 if (mq_getattr(mq
, &attr
) < 0)
197 die("mq_getattr: %s\n", strerror(errno
));
199 emit("MQUEUE=%s\n", mqueue
);
202 clear_or_peek(mq
, &attr
);
204 for (; argi
< argc
; ++argi
) {
208 if (realpath(argv
[argi
], path
+ 1) == NULL
) {
209 warn("realpath: %s\n", strerror(errno
));
210 write(2, argv
[argi
], strlen(argv
[argi
]));
214 len
= strlen(argv
[argi
]);
215 if (len
> PATH_MAX
) {
216 warn("longer than PATH_MAX: %d\n", PATH_MAX
);
217 write(2, argv
[argi
], len
);
220 memcpy(path
+ 1, argv
[argi
], len
);
226 assert(path
[len
] == 0);
228 write(1, path
, len
+ 1);
231 if (mq_send(mq
, path
, len
, prio
) < 0) {
232 warn("mq_send: %s\n", strerror(errno
));