Bug Summary

File:player/mplayer/mplayer.c
Location:line 92, column 34
Description:Function call argument is an uninitialized value

Annotated Source Code

1/*
2 * Copyright (c) 2010, 2011, 2012 Ryan Flannery <ryan.flannery@gmail.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "mplayer.h"
18#include "mplayer_conf.h"
19
20/* callback functions */
21void (*mplayer_callback_playnext)(void) = NULL((void *)0);
22void (*mplayer_callback_notice)(char *, ...) = NULL((void *)0);
23void (*mplayer_callback_error)(char *, ...) = NULL((void *)0);
24void (*mplayer_callback_fatal)(char *, ...) = NULL((void *)0);
25
26
27/* record keeping */
28static struct {
29 /* exported to player interface */
30 float position;
31 float volume;
32 bool_Bool playing;
33 bool_Bool paused;
34
35 /* specific to this backend */
36 pid_t pid;
37 int pipe_read;
38 int pipe_write;
39 const char *current_song;
40} mplayer_state;
41
42bool_Bool restarting = false0;
43
44
45void mplayer_volume_set(float);
46void mplayer_volume_query();
47
48static void
49mplayer_send_cmd(const char *cmd)
50{
51 write(mplayer_state.pipe_write, cmd, strlen(cmd));
52}
53
54void
55mplayer_start()
56{
57 int pwrite[2];
58 int pread[2];
59 int flags;
60
61 if (!exe_in_path(MPLAYER_PATH))
5
Taking false branch
62 errx(1, "it appears '%s' does not exist in your $PATH", MPLAYER_PATH);
63
64 if (pipe(pwrite) == -1 || pipe(pread) == -1)
65 err(1, "%s: pipe() failed", __FUNCTION__);
66
67 switch (mplayer_state.pid = fork()) {
6
'Default' branch taken. Execution continues on line 92
68 case -1:
69 err(1, "%s: fork() failed", __FUNCTION__);
70 break;
71
72 case 0: /* child process */
73 if (close(0) == -1 || close(1) == -1 || close(2) == -1)
74 err(1, "%s: child close()'s failed(1)", __FUNCTION__);
75
76 if (close(pwrite[1]) == -1 || close(pread[0]) == -1)
77 err(1, "%s: child close()'s failed(2)", __FUNCTION__);
78
79 if (dup(pwrite[0]) == -1 || dup(pread[1]) == -1)
80 err(1, "%s: child dup()'s failed", __FUNCTION__);
81
82 if (execvp(MPLAYER_PATH, MPLAYER_ARGS) == -1)
83 kill(getppid(), SIGCHLD20); /* send signal NOW! */
84
85 exit(1);
86 break;
87 }
88
89 /* Back to the parent... */
90
91 /* close unnecessary pipe ends */
92 if (close(pwrite[0]) == -1 || close(pread[1]) == -1)
7
Function call argument is an uninitialized value
93 err(1, "%s: parent close()'s failed", __FUNCTION__);
94
95 /* setup player pipes */
96 mplayer_state.pipe_read = pread[0];
97 mplayer_state.pipe_write = pwrite[1];
98
99 /* setup read pipe to media player as non-blocking */
100 if ((flags = fcntl(mplayer_state.pipe_read, F_GETFL3, 0)) == -1)
101 err(1, "%s: fcntl() failed to get current flags", __FUNCTION__);
102
103 if (fcntl(mplayer_state.pipe_read, F_SETFL4, flags | O_NONBLOCK0x0004) == -1)
104 err(1, "%s: fcntl() failed to set pipe non-blocking", __FUNCTION__);
105
106 if (!restarting) {
107 mplayer_state.playing = false0;
108 mplayer_state.paused = false0;
109 mplayer_state.volume = -1;
110 mplayer_state.position = 0;
111 mplayer_state.current_song = NULL((void *)0);
112 }
113 restarting = true1;
114}
115
116void
117mplayer_finish()
118{
119 mplayer_send_cmd("\nquit\n");
120
121 close(mplayer_state.pipe_read);
122 close(mplayer_state.pipe_write);
123
124 waitpid(mplayer_state.pid, NULL((void *)0), 0);
125}
126
127void
128mplayer_restart()
129{
130 int status;
131
132 close(mplayer_state.pipe_read);
133 close(mplayer_state.pipe_write);
134 wait(&status);
135
136 restarting = true1;
137 mplayer_start();
4
Calling 'mplayer_start'
138
139 if (mplayer_state.playing && !mplayer_state.paused) {
140 int previous_position = mplayer_state.position;
141 mplayer_play(mplayer_state.current_song);
142 mplayer_seek(previous_position);
143 }
144}
145
146void
147mplayer_sigchld_message()
148{
149 /* TODO find a way to check if mplayer is in $PATH in start() */
150 mplayer_callback_fatal("%s is crashing too often. Possible causes are:\n\
151 1. %s is not in your $PATH\n\
152 2. The installed %s is older, and not supported by vitunes\n",
153 MPLAYER_PATH, MPLAYER_PATH, MPLAYER_PATH);
154}
155
156void
157mplayer_sigchld()
158{
159 static time_t last_sigchld = -1;
160
161 if (kill(mplayer_state.pid, 0) != 0) {
1
Taking true branch
162 if (time(0) - last_sigchld <= 1) {
2
Taking false branch
163 if (mplayer_callback_fatal != NULL((void *)0))
164 mplayer_sigchld_message();
165 } else {
166 mplayer_restart();
3
Calling 'mplayer_restart'
167 if (mplayer_callback_error != NULL((void *)0))
168 mplayer_callback_error("%s died. Restarting it.", MPLAYER_PATH);
169 }
170 }
171
172 last_sigchld = time(0);
173}
174
175void
176mplayer_play(const char *file)
177{
178 static const char *cmd_fmt = "\nloadfile \"%s\" 0\nget_property time_pos\n";
179 char *cmd;
180
181 if (asprintf(&cmd, cmd_fmt, file) == -1)
182 err(1, "%s: asprintf failed", __FUNCTION__);
183
184 mplayer_send_cmd(cmd);
185 free(cmd);
186
187 mplayer_state.position = 0;
188 mplayer_state.playing = true1;
189 mplayer_state.paused = false0;
190 mplayer_state.current_song = file;
191
192 /* if we have a volume, reset it */
193 if (mplayer_state.volume > -1)
194 mplayer_volume_set(mplayer_state.volume);
195}
196
197void
198mplayer_stop()
199{
200 mplayer_send_cmd("\nstop\n");
201
202 mplayer_state.playing = false0;
203 mplayer_state.paused = false0;
204}
205
206void
207mplayer_pause()
208{
209 if (!mplayer_state.playing)
210 return;
211
212 mplayer_send_cmd("\npause\n");
213 mplayer_state.paused = !mplayer_state.paused;
214}
215
216void
217mplayer_seek(int seconds)
218{
219 static const char *cmd_fmt = "\nseek %i 0\nget_property time_pos\n";
220 char *cmd;
221
222 if (!mplayer_state.playing)
223 return;
224
225 if (asprintf(&cmd, cmd_fmt, seconds) == -1)
226 err(1, "%s: asprintf failed", __FUNCTION__);
227
228 mplayer_send_cmd(cmd);
229 free(cmd);
230
231 if (mplayer_state.paused)
232 mplayer_state.paused = false0;
233}
234
235void
236mplayer_volume_step(float percent)
237{
238 static const char *cmd_fmt = "\npausing_keep volume %f\n";
239 char *cmd;
240
241 if (!mplayer_state.playing)
242 return;
243
244 /* this is a hack, since mplayer's volume command doesn't seem to work
245 * as documented.
246 */
247 if (mplayer_state.volume > -1) {
248 percent += mplayer_state.volume;
249 mplayer_volume_set(percent);
250 return;
251 }
252
253 if (asprintf(&cmd, cmd_fmt, percent) == -1)
254 err(1, "%s: asprintf failed", __FUNCTION__);
255
256 mplayer_send_cmd(cmd);
257 free(cmd);
258
259 mplayer_volume_query();
260}
261
262void
263mplayer_volume_set(float percent)
264{
265 static const char *cmd_fmt = "\npausing_keep set_property volume %f\n";
266 char *cmd;
267
268 if (!mplayer_state.playing)
269 return;
270
271 if (percent > 100) percent = 100;
272 if (percent < 0) percent = 0;
273
274 if (asprintf(&cmd, cmd_fmt, percent) == -1)
275 err(1, "%s: asprintf failed", __FUNCTION__);
276
277
278 mplayer_send_cmd(cmd);
279 free(cmd);
280
281 mplayer_volume_query();
282}
283
284void
285mplayer_volume_query()
286{
287 static const char *cmd = "\npausing_keep get_property volume\n";
288
289 if (!mplayer_state.playing)
290 return;
291
292 mplayer_send_cmd(cmd);
293}
294
295/* query functions */
296float mplayer_get_position() { return mplayer_state.position; }
297float mplayer_get_volume() { return mplayer_state.volume; }
298bool_Bool mplayer_is_playing() { return mplayer_state.playing; }
299bool_Bool mplayer_is_paused() { return mplayer_state.paused; }
300
301/* set-callback functions */
302void
303mplayer_set_callback_playnext(void (*f)(void))
304{
305 mplayer_callback_playnext = f;
306}
307
308void
309mplayer_set_callback_notice(void (*f)(char *, ...))
310{
311 mplayer_callback_notice = f;
312}
313
314void
315mplayer_set_callback_error(void (*f)(char *, ...))
316{
317 mplayer_callback_error = f;
318}
319
320void
321mplayer_set_callback_fatal(void (*f)(char *, ...))
322{
323 mplayer_callback_fatal = f;
324}
325
326
327/*****************************************************************************
328 * Player monitor function, called repeatedly via the signal handler in the
329 * vitunes main loop.
330 *
331 * This communicates with the child process periodically to accomplish the
332 * following:
333 * 1. If the player is currently playing a song, determine the position
334 * (in seconds) into the playback
335 * 2. When the player finishes playing a song, it starts playing the next
336 * song, according to the current playmode.
337 ****************************************************************************/
338void
339mplayer_monitor()
340{
341 static const char *query_cmd = "\nget_property time_pos\n";
342 static const char *answer_fail = "ANS_ERROR=PROPERTY_UNAVAILABLE";
343 static const char *answer_good = "ANS_time_pos";
344 static char response[1000]; /* mplayer can be noisy */
345 char *s;
346 int nbytes;
347
348 /* in this case, nothing to monitor */
349 if (!mplayer_state.playing || mplayer_state.paused)
350 return;
351
352 /* read any output from the player */
353 bzero(response, sizeof(response));
354 nbytes = read(mplayer_state.pipe_read, &response, sizeof(response));
355
356 if (nbytes == -1 && errno(*__errno()) == EAGAIN35)
357 return;
358
359 response[nbytes + 1] = '\0';
360
361 /* case: reached end of playback for a given file */
362 if (strstr(response, answer_fail) != NULL((void *)0)) {
363 if (mplayer_callback_playnext != NULL((void *)0)) mplayer_callback_playnext();
364 return;
365 }
366
367 /* case: continue in playing current file. update position */
368 if ((s = strstr(response, answer_good)) != NULL((void *)0)) {
369 while (strstr(s + 1, answer_good) != NULL((void *)0))
370 s = strstr(s + 1, answer_good);
371
372 if (sscanf(s, "ANS_time_pos=%20f", &mplayer_state.position) != 1)
373 errx(1, "player_monitor: player child is misbehaving.");
374 }
375
376 mplayer_send_cmd(query_cmd);
377
378 /* check for recent volume */
379 static const char *volume_good = "ANS_volume";
380 if ((s = strstr(response, volume_good)) != NULL((void *)0)) {
381 while (strstr(s + 1, volume_good) != NULL((void *)0))
382 s = strstr(s + 1, volume_good);
383
384 if (sscanf(s, "ANS_volume=%20f", &mplayer_state.volume) != 1)
385 errx(1, "player_monitor: player child is misbehaving.");
386 }
387}
388