1 /*
2 * Copyright (c) 2002, 2003 MATPOCKuH. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include <sys/types.h>
26 #include <sys/cdio.h>
27 #include <sys/ioctl.h>
28 #include <sys/stat.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <sys/wait.h>
32 #include <sys/param.h>
33 #include <sys/ucred.h>
34 #include <sys/mount.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <fcntl.h>
40 #include <fstab.h>
41 #include <unistd.h>
42 #include <pwd.h>
43 #include <grp.h>
44 #include <signal.h>
45 #include <stdarg.h>
46 #include <ctype.h>
47 #include <sysexits.h>
48
49 #ifdef HAVE_CONFIG_H
50 #include <config.h>
51 #endif
52
53 #ifdef HAVE_SYS_CDRIO_H
54 #include <sys/cdrio.h>
55 #endif
56
57 #include "settings.h"
58 #include "mqueue.h"
59 #include "logger.h"
60 #include "acd.h"
61 #include "version.h"
62
63 #define autocd_opendev(_dev) (_dev->dev = _dev->dev == -1 ?\
64 open(_dev->device, O_RDONLY) : _dev->dev)
65
66 typedef struct {
67 void *next;
68 void *prev;
69 char *device, *mnt_point, *mnt_fstype, *mnt_opts;
70 int dev, ejected, disabled;
71 #ifdef HAVE_SYS_CDRIO_H
72 int locked_speed;
73 #endif
74 int first_audio_track, last_audio_track;
75 u_int cdid;
76 struct cd_sub_channel_info sub_channel_info;
77 struct ioc_toc_header toc_header;
78 struct cd_toc_entry toc_entry[MAXTRACKS];
79 struct ioc_read_subchannel read_subchannel;
80 struct ioc_read_toc_entry read_toc_entry;
81 struct ioc_play_msf play_msf;
82 } device_t;
83
84 typedef struct {
85 void *next;
86 void *prev;
87 int fd;
88 device_t *device;
89 } client_t;
90
91 typedef struct {
92 void *next;
93 void *prev;
94 u_int cdid;
95 struct ioc_play_msf play_msf;
96 } saved_msf_t;
97
98 typedef int handler_t(client_t *);
99 typedef int handler_wp_t(client_t *, char *);
100
101 int autocd_close(client_t *);
102 int autocd_cdid(client_t *);
103 int autocd_disable(client_t *);
104 int autocd_die(client_t *);
105 int autocd_eject(client_t *);
106 int autocd_enable(client_t *);
107 int autocd_help(client_t *);
108 int autocd_info(client_t *);
109 int autocd_listdevices(client_t *);
110 int autocd_listsaved(client_t *);
111 int autocd_load(client_t *);
112 int autocd_next(client_t *);
113 int autocd_play(client_t *);
114 int autocd_pause(client_t *);
115 int autocd_previous(client_t *);
116 int autocd_closeclient(client_t *);
117 int autocd_stat(client_t *);
118 int autocd_save(client_t *);
119 int autocd_stop(client_t *);
120 int autocd_version(client_t *);
121 int autocd_volume(client_t *);
122 int autocd_changedevice(client_t *, char *);
123 int autocd_play_with_params(client_t *, char *);
124 #ifdef HAVE_SYS_CDRIO_H
125 int autocd_speed(client_t *, char *);
126 int autocd_lockspeed(client_t *, char *);
127 #endif
128 int autocd_changevolume(client_t *, char *);
129
130 struct {
131 char *cmd, *params;
132 handler_t *handler;
133 int need_opendev;
134 int need_disc;
135 int need_play;
136 } cmds[] = {
137 {"Close", NULL, &autocd_close, 1, 0, 0},
138 {"CDid", NULL, &autocd_cdid, 0, 1, 0},
139 {"Disable", NULL, &autocd_disable, 0, 0, 0},
140 {"DIE", NULL, &autocd_die, 0, 0, 0},
141 {"Eject", NULL, &autocd_eject, 0, 0, 0},
142 {"Enable", NULL, &autocd_enable, 0, 0, 0},
143 {"Help", NULL, &autocd_help, 0, 0, 0},
144 {"Info", NULL, &autocd_info, 0, 1, 0},
145 {"List", NULL, &autocd_listdevices, 0, 0, 0},
146 {"LISTSaved", NULL, &autocd_listsaved, 0, 0, 0},
147 {"LOad", NULL, &autocd_load, 1, 1, 0},
148 {"Next", NULL, &autocd_next, 1, 1, 1},
149 {"Play", NULL, &autocd_play, 1, 1, 0},
150 {"PAuse", NULL, &autocd_pause, 1, 1, 1},
151 {"PRevious", NULL, &autocd_previous, 1, 1, 1},
152 {"Quit", NULL, &autocd_closeclient, 0, 0, 0},
153 {"Status", NULL, &autocd_stat, 0, 0, 0},
154 {"SAve", NULL, &autocd_save, 0, 1, 1},
155 {"STOp", NULL, &autocd_stop, 1, 1, 1},
156 {"Version", NULL, &autocd_version, 0, 0, 0},
157 {"VOlume", NULL, &autocd_volume, 1, 0, 0},
158 {"Device", "device", (handler_t *) &autocd_changedevice, 0, 0, 0},
159 #ifdef HAVE_SYS_CDRIO_H
160 {"Lockspeed", "speed", (handler_t *) &autocd_lockspeed, 0, 0, 0},
161 #endif
162 {"Play", "first_track [last_track]",
163 (handler_t *) &autocd_play_with_params, 1, 1, 0},
164 #ifdef HAVE_SYS_CDRIO_H
165 {"Speed", "speed", (handler_t *) &autocd_speed, 1, 0, 0},
166 #endif
167 {"Volume", "[+|-]volume", (handler_t *) &autocd_changevolume, 1, 0, 0},
168 {NULL, NULL, NULL, 0, 0, 0}
169 };
170
171 mq_queue_t *devices, *clients, *saved_msfs;
172 fd_set read_fds;
173
174 uid_t socket_owner = SOCKET_OWNER;
175 gid_t socket_group = SOCKET_GROUP;
176 mode_t socket_mode = SOCKET_MODE;
177 int socket_fd, dont_close_while_playing = 0;
178
179 char *audio_status[] =
180 {"invalid",
181 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
182 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
183 "playing", "paused", "completed",
184 "error", "no status"};
185
186 static volatile sig_atomic_t nobreak = 1;
187
188 /*
189 * dbprog_sum
190 * Convert an integer to its text string representation, and
191 * compute its checksum. Used by dbprog_discid to derive the
192 * disc ID.
193 *
194 * Args:
195 * n - The integer value.
196 *
197 * Return:
198 * The integer checksum.
199 */
200 int
dbprog_sum(int n)201 dbprog_sum(int n)
202 {
203 char buf[12], *p;
204 int ret = 0;
205
206 /* For backward compatibility this algorithm must not change */
207 sprintf(buf, "%u", n);
208 for (p = buf; *p != '\0'; p++)
209 ret += (*p - '0');
210
211 return(ret);
212 }
213
214 /*
215 * dbprog_discid
216 * Compute a magic disc ID based on the number of tracks,
217 * the length of each track, and a checksum of the string
218 * that represents the offset of each track.
219 *
220 * Args:
221 * s - Pointer to the curstat_t structure.
222 *
223 * Return:
224 * The integer disc ID.
225 */
226 u_int
dbprog_discid(device_t * device)227 dbprog_discid(device_t *device)
228 {
229 int i, ntr, t = 0, n = 0;
230
231 ntr = device->toc_header.ending_track -
232 device->toc_header.starting_track + 1;
233
234 /* For backward compatibility this algorithm must not change */
235 for (i = 0; i < ntr; i++) {
236 #define TC_MM(a) device->toc_entry[a].addr.msf.minute
237 #define TC_SS(a) device->toc_entry[a].addr.msf.second
238 n += dbprog_sum((TC_MM(i) * 60) + TC_SS(i));
239
240 t += ((TC_MM(i+1) * 60) + TC_SS(i+1)) - ((TC_MM(i) * 60) + TC_SS(i));
241 }
242
243 return((n % 0xff) << 24 | t << 8 | ntr);
244 }
245
246 void
autocd_init()247 autocd_init()
248 {
249 devices = mq_makequeue(sizeof(device_t));
250 clients = mq_makequeue(sizeof(client_t));
251 saved_msfs = mq_makequeue(sizeof(saved_msf_t));
252 FD_ZERO(&read_fds);
253 }
254
255 void
autocd_setsocketpath(const char * spath)256 autocd_setsocketpath(const char *spath)
257 {
258 if(socket_path != SOCKET_PATH)
259 free(socket_path);
260
261 socket_path = strdup(spath);
262 }
263
264 int
autocd_setsocketowner(const char * owner)265 autocd_setsocketowner(const char *owner)
266 {
267 if(sscanf(owner, "%i", &socket_owner) == 0) {
268 struct passwd *passwd;
269
270 if(!(passwd = getpwnam(owner))) {
271 logger("Failed to get uid for %s: %s\n", owner, strerror(errno));
272 return -1;
273 }
274
275 socket_owner = passwd->pw_uid;
276
277 endpwent();
278 }
279
280 return 0;
281 }
282
283 int
autocd_setsocketgroup(const char * group)284 autocd_setsocketgroup(const char *group)
285 {
286 if(sscanf(group, "%i", &socket_group) == 0) {
287 struct group *gr;
288
289 if(!(gr = getgrnam(group))) {
290 logger("Failed to get gid for %s: %s\n", group, strerror(errno));
291 return -1;
292 }
293
294 socket_group = gr->gr_gid;
295
296 endgrent();
297 }
298
299 return 0;
300 }
301
302 int
autocd_setsocketmode(const char * mode)303 autocd_setsocketmode(const char *mode)
304 {
305 unsigned int tmp;
306
307 sscanf(mode, "%o", &tmp);
308 socket_mode = tmp;
309
310 return 0;
311 }
312
313 int
autocd_initdevice(char * device)314 autocd_initdevice(char *device)
315 {
316 device_t *tmp;
317 struct stat st;
318 char *dev;
319
320 if(device[0] != '/')
321 asprintf(&dev, "/dev/%s", device);
322 else
323 dev = strdup(device);
324
325 if(stat(dev, &st) == -1) {
326 logger("Failed to use device %s: %s\n", dev, strerror(errno));
327 free(dev);
328 return -1;
329 }
330
331 if(!(st.st_mode & S_IFBLK) && !(st.st_mode & S_IFCHR)) {
332 logger("%s is not a character or block special file\n", dev);
333 free(dev);
334 return -1;
335 }
336
337 tmp = malloc(sizeof(device_t));
338 bzero(tmp, sizeof(*tmp));
339
340 tmp->read_subchannel.address_format = CD_MSF_FORMAT;
341 tmp->read_subchannel.data_format = CD_CURRENT_POSITION;
342 tmp->read_subchannel.data_len = sizeof(struct cd_sub_channel_info);
343 tmp->read_subchannel.data = &tmp->sub_channel_info;
344
345 tmp->read_toc_entry.address_format = CD_MSF_FORMAT;
346 tmp->read_toc_entry.starting_track = 1;
347 tmp->read_toc_entry.data_len = sizeof(tmp->toc_entry);
348 tmp->read_toc_entry.data = tmp->toc_entry;
349
350 if((tmp->dev = open(dev, O_RDONLY)) == -1) {
351 if((errno != ENXIO) && (errno != EIO) && (errno != ENODEV)) {
352 logger("Failed to open device %s: %s\n", dev, strerror(errno));
353 free(dev);
354 free(tmp);
355 return -1;
356 }
357 } else {
358 if(ioctl(tmp->dev, CDIOCREADSUBCHANNEL, &tmp->read_subchannel) == -1) {
359 if((errno != EBUSY) && (errno != EIO) && (errno != ENXIO)) {
360 logger("Failed to use device %s: %s\n", dev, strerror(errno));
361 free(dev);
362 free(tmp);
363 return -1;
364 }
365 }
366
367 close(tmp->dev);
368 tmp->dev = -1;
369 }
370
371 if(geteuid()) {
372 logger("Not running from root. Automount disabled for %s.\n", dev);
373 tmp->mnt_point = NULL;
374 } else {
375 struct fstab *fstab;
376
377 if(!(fstab = getfsspec(dev))) {
378 tmp->mnt_point = NULL;
379 tmp->mnt_fstype = FSTYPE;
380 tmp->mnt_opts = MNTOPTS;
381 } else {
382 tmp->mnt_point = strdup(fstab->fs_file);
383 tmp->mnt_fstype = strdup(fstab->fs_vfstype);
384 tmp->mnt_opts = strdup(fstab->fs_mntops);
385 }
386
387 endfsent();
388 }
389
390 tmp->device = dev;
391 tmp->ejected = 1;
392 tmp->disabled = 0;
393
394 #ifdef HAVE_SYS_CDRIO_H
395 tmp->locked_speed = 0;
396 #endif
397
398 mq_addrecord(devices, (mq_record_t *) tmp);
399
400 return 0;
401 }
402
403 int
autocd_noclose()404 autocd_noclose()
405 {
406 dont_close_while_playing = 1;
407
408 return 0;
409 }
410
411 int
autocd_set_mnt_point(const char * mnt_point)412 autocd_set_mnt_point(const char *mnt_point)
413 {
414 device_t *d;
415
416 if(geteuid()) {
417 logger("Not running from root. Mount is not avaible.\n");
418 return -1;
419 }
420
421 if(!(d = (device_t *) mq_gettail(devices))) {
422 logger("Strange call autocd_set_mnt_point()\n");
423 return -1;
424 }
425
426 if(d->mnt_point)
427 free(d->mnt_point);
428
429 d->mnt_point = strdup(mnt_point);
430
431 return 0;
432 }
433
434 int
autocd_set_mnt_fstype(const char * mnt_fstype)435 autocd_set_mnt_fstype(const char *mnt_fstype)
436 {
437 device_t *d;
438
439 if(!(d = (device_t *) mq_gettail(devices))) {
440 logger("Strange call autocd_set_mnt_fstype()\n");
441 return -1;
442 }
443
444 if(!d->mnt_point) {
445 logger("No mount point for %s. fstype ignored.\n", d->device);
446 return -1;
447 }
448
449 if(d->mnt_fstype != FSTYPE)
450 free(d->mnt_fstype);
451
452 d->mnt_fstype = strdup(mnt_fstype);
453
454 return 0;
455 }
456
457 int
autocd_set_mnt_opts(const char * mnt_opts)458 autocd_set_mnt_opts(const char *mnt_opts)
459 {
460 device_t *d;
461
462 if(!(d = (device_t *) mq_gettail(devices))) {
463 logger("Strange call autocd_set_mnt_opts()\n");
464 return -1;
465 }
466
467 if(!d->mnt_point) {
468 logger("No mount point for %s. Mount options ignored.\n", d->device);
469 return -1;
470 }
471
472 if(d->mnt_opts != MNTOPTS)
473 free(d->mnt_opts);
474
475 d->mnt_opts = strdup(mnt_opts);
476
477 return 0;
478 }
479
480 int
autocd_initsocket()481 autocd_initsocket()
482 {
483 struct sockaddr_un unix_addr;
484 struct stat st;
485 int fd;
486
487 if(stat(socket_path, &st)) {
488 if(errno != ENOENT) {
489 logger("Failed to create socket: %s\n", strerror(errno));
490 return -1;
491 }
492 } else {
493 if((st.st_mode & S_IFSOCK) != S_IFSOCK) {
494 logger("Failed to create socket: %s is not socket\n", socket_path);
495 return -1;
496 }
497
498 if((fd = acd_connect()) == -1) {
499 if(errno != ECONNREFUSED) {
500 logger("Failed to connect to another daemon: %s\n",
501 strerror(errno));
502 return -1;
503 }
504 } else {
505 logger("Found running copy of daemon\n");
506 close(fd);
507 return -1;
508 }
509
510 if(unlink(socket_path) == -1) {
511 logger("Failed to remove stale socket: %s\n", strerror(errno));
512 return -1;
513 }
514
515 logger("Removed stale socket.\n");
516 }
517
518 if((socket_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
519 return -1;
520
521 memset(&unix_addr, 0, sizeof(unix_addr));
522 unix_addr.sun_family = AF_UNIX;
523 strncpy(unix_addr.sun_path, socket_path, sizeof(unix_addr.sun_path));
524 unix_addr.sun_len = sizeof(unix_addr.sun_len) +
525 sizeof(unix_addr.sun_family) + strlen(unix_addr.sun_path) + 1;
526
527 if(bind(socket_fd, (struct sockaddr *) &unix_addr, unix_addr.sun_len) < 0) {
528 logger("Failed to create socket: %s\n", strerror(errno));
529 close(socket_fd);
530 unlink(socket_path);
531 return -1;
532 }
533
534 if(listen(socket_fd, 5) < 0) {
535 logger("Failed to create socket: %s\n", strerror(errno));
536 close(socket_fd);
537 unlink(socket_path);
538 return -1;
539 }
540
541 if(!geteuid()) {
542 chown(socket_path, socket_owner, socket_group);
543 }
544
545 chmod(socket_path, socket_mode);
546
547 FD_SET(socket_fd, &read_fds);
548
549 return 0;
550 }
551
552 void
autocd_accept()553 autocd_accept()
554 {
555 int fd;
556 client_t *client;
557 struct sockaddr_un unix_addr;
558 size_t len;
559
560 len = sizeof(unix_addr);
561 if ((fd = accept(socket_fd, (struct sockaddr *) &unix_addr, &len)) < 0) {
562 logger("accept() failed: %s\n", strerror(errno));
563 return;
564 }
565
566 client = (client_t *) mq_addnewrecord(clients);
567 client->fd = fd;
568 client->device = (device_t *) mq_gethead(devices);
569
570 FD_SET(fd, &read_fds);
571 }
572
573 int
autocd_play_msf(device_t * device)574 autocd_play_msf(device_t *device)
575 {
576 if(ioctl(device->dev, CDIOCPLAYMSF, &device->play_msf) == -1) {
577 logger("CDIOCPLAYMSF failed: %s\n", strerror(errno));
578 return -1;
579 }
580
581 device->sub_channel_info.header.audio_status = CD_AS_PLAY_IN_PROGRESS;
582
583 return 0;
584 }
585
586 int
autocd_playtracks(device_t * device,int ftrack,int ltrack)587 autocd_playtracks(device_t *device, int ftrack, int ltrack)
588 {
589 union msf_lba *msf_lba;
590
591 msf_lba = &device->toc_entry[ftrack - 1].addr;
592 device->play_msf.start_m = msf_lba->msf.minute;
593 device->play_msf.start_s = msf_lba->msf.second;
594 device->play_msf.start_f = msf_lba->msf.frame;
595
596 msf_lba = &device->toc_entry[ltrack].addr;
597 device->play_msf.end_m = msf_lba->msf.minute;
598 device->play_msf.end_s = msf_lba->msf.second;
599 device->play_msf.end_f = msf_lba->msf.frame;
600
601 return autocd_play_msf(device);
602 }
603
604 void
autocd_closedev(device_t * device)605 autocd_closedev(device_t *device)
606 {
607 if(device->dev == -1)
608 return;
609
610 if(dont_close_while_playing &&
611 ((device->sub_channel_info.header.audio_status ==
612 CD_AS_PLAY_IN_PROGRESS) ||
613 (device->sub_channel_info.header.audio_status == CD_AS_PLAY_PAUSED)))
614 return;
615
616 close(device->dev);
617 device->dev = -1;
618 }
619
620 void
autocd_doinsert(device_t * device)621 autocd_doinsert(device_t *device)
622 {
623 device->read_toc_entry.data_len =
624 (device->toc_header.ending_track + 1) * sizeof(struct cd_toc_entry);
625
626 if(ioctl(device->dev, CDIOREADTOCENTRYS, &device->read_toc_entry) == -1) {
627 logger("CDIOREADTOCENTRYS failed: %s\n", strerror(errno));
628 return;
629 }
630
631 for(device->first_audio_track = 1;
632 (device->toc_entry[device->first_audio_track - 1].control & 4) &&
633 (device->first_audio_track < device->toc_header.ending_track);
634 device->first_audio_track++);
635
636 for(device->last_audio_track = device->toc_header.ending_track;
637 (device->toc_entry[device->last_audio_track - 1].control & 4) &&
638 (device->first_audio_track < device->last_audio_track);
639 device->last_audio_track--);
640
641 if(device->toc_entry[device->first_audio_track - 1].control & 4) {
642 if(device->mnt_point) {
643 int status;
644
645 autocd_closedev(device);
646
647 switch(fork()) {
648 case 0:
649 execl(MOUNT, MOUNT, "-o", device->mnt_opts,
650 "-t", device->mnt_fstype,
651 device->device, device->mnt_point, NULL);
652
653
654 logger("Can't run "MOUNT": %s\n", strerror(errno));
655
656 exit(EX_OSERR);
657
658 case -1:
659 logger("fork() failed: %s\n", strerror(errno));
660 break;
661
662 default:
663 wait(&status);
664 }
665
666 autocd_opendev(device);
667 }
668 } else {
669 if(device->sub_channel_info.header.audio_status !=
670 CD_AS_PLAY_IN_PROGRESS) {
671 autocd_playtracks(device,
672 device->first_audio_track, device->last_audio_track);
673 }
674 }
675
676 device->cdid = dbprog_discid(device);
677
678 #ifdef HAVE_SYS_CDRIO_H
679 if(device->locked_speed != 0)
680 if(ioctl(device->dev, CDRIOCREADSPEED, &device->locked_speed) == -1)
681 device->locked_speed = 0;
682 #endif
683
684 }
685
686 void
autocd_checkdevice(device_t * dev)687 autocd_checkdevice(device_t *dev)
688 {
689 if(dev->disabled)
690 return;
691
692 if(autocd_opendev(dev) == -1) {
693 dev->ejected = 1;
694 return;
695 }
696
697 if(ioctl(dev->dev, CDIOCREADSUBCHANNEL, &dev->read_subchannel) == -1) {
698 dev->ejected = 1;
699 } else {
700 if(ioctl(dev->dev, CDIOREADTOCHEADER, &dev->toc_header) == -1) {
701 dev->ejected = 1;
702 } else {
703 if(dev->ejected) {
704 dev->ejected = 0;
705 bzero(&dev->play_msf, sizeof(dev->play_msf));
706 autocd_doinsert(dev);
707 }
708 }
709 }
710
711 autocd_closedev(dev);
712 }
713
714 void
autocd_vcprintf(client_t * client,char * fmt,va_list ap)715 autocd_vcprintf(client_t *client, char *fmt, va_list ap)
716 {
717 char *buf;
718
719 vasprintf(&buf, fmt, ap);
720 write(client->fd, buf, strlen(buf));
721 free(buf);
722 }
723
724 void
autocd_cprintf(client_t * client,char * fmt,...)725 autocd_cprintf(client_t *client, char *fmt, ...)
726 {
727 va_list ap;
728
729 va_start(ap, fmt);
730 autocd_vcprintf(client, fmt, ap);
731 va_end(ap);
732 }
733
734 void
autocd_ERROR(client_t * client,char * fmt,...)735 autocd_ERROR(client_t *client, char *fmt, ...)
736 {
737 va_list ap;
738
739 va_start(ap, fmt);
740 vlogger(fmt, ap);
741 autocd_vcprintf(client, fmt, ap);
742 va_end(ap);
743 }
744
745 int
autocd_eject(client_t * client)746 autocd_eject(client_t *client)
747 {
748 device_t *device = client->device;
749 int rc = 0;
750
751 if(!geteuid()) {
752 int i, size;
753 struct statfs *fs;
754
755 size = sizeof(struct statfs) * (i = getfsstat(NULL, 0, MNT_NOWAIT));
756 fs = malloc(size);
757 getfsstat(fs, size, MNT_NOWAIT);
758
759 for(; i; i--) {
760 if(!strcmp(device->device, fs[i - 1].f_mntfromname)) {
761 if(unmount(fs[i - 1].f_mntonname, 0) == -1) {
762 autocd_ERROR(client, "ERROR: unmount() failed: %s\n",
763 strerror(errno));
764 return -2;
765 }
766 break;
767 }
768 }
769
770 free(fs);
771 }
772
773 if(autocd_opendev(client->device) == -1)
774 return -1;
775
776 if(ioctl(device->dev, CDIOCALLOW) == -1)
777 logger("ioctl(CDIOCALLOW) failed: %s\n", strerror(errno));
778
779 if(ioctl(device->dev, CDIOCEJECT) == -1) {
780 autocd_ERROR(client, "ERROR: ioctl(CDIOCEJECT) failed: %s\n",
781 strerror(errno));
782 rc = -2;
783 }
784
785 autocd_closedev(client->device);
786
787 return rc;
788 }
789
790 int
autocd_pause(client_t * client)791 autocd_pause(client_t *client)
792 {
793 device_t *device = client->device;
794 int rcode = 0;
795
796 switch(device->sub_channel_info.header.audio_status) {
797 case CD_AS_PLAY_IN_PROGRESS:
798 rcode = ioctl(device->dev, CDIOCPAUSE);
799 break;
800
801 case CD_AS_PLAY_PAUSED:
802 rcode = ioctl(device->dev, CDIOCRESUME);
803 break;
804 }
805
806 if(rcode == -1)
807 return -1;
808
809 return 0;
810 }
811
812 int
autocd_stop(client_t * client)813 autocd_stop(client_t *client)
814 {
815 device_t *device = client->device;
816
817 if(ioctl(device->dev, CDIOCSTOP) == -1)
818 return -1;
819
820 return 0;
821 }
822
823 int
autocd_close(client_t * client)824 autocd_close(client_t *client)
825 {
826 device_t *device = client->device;
827
828 if(ioctl(device->dev, CDIOCALLOW) == -1)
829 logger("ioctl(CDIOCALLOW) failed: %s\n", strerror(errno));
830
831 if(ioctl(device->dev, CDIOCCLOSE) == -1)
832 return -1;
833
834 return 0;
835 }
836
837 int
autocd_stat(client_t * client)838 autocd_stat(client_t *client)
839 {
840 struct cd_sub_channel_info *s_ch_info = &client->device->sub_channel_info;
841 u_char audiostatus = s_ch_info->header.audio_status;
842
843 if(client->device->disabled) {
844 autocd_cprintf(client, "Device disabled\n");
845 return 0;
846 }
847
848 if(client->device->ejected) {
849 autocd_cprintf(client, "No current status info available\n");
850 return 0;
851 }
852
853 autocd_cprintf(client,
854 "Audio status = %i<%s>, current track = %i,\
855 current position = %i:%02i.%02i\n",
856 audiostatus,
857 audiostatus <= CD_AS_NO_STATUS ? audio_status[audiostatus] : NULL,
858 s_ch_info->what.position.track_number,
859 s_ch_info->what.position.reladdr.msf.minute,
860 s_ch_info->what.position.reladdr.msf.second,
861 s_ch_info->what.position.reladdr.msf.frame);
862
863 return 0;
864 }
865
866 int
autocd_info(client_t * client)867 autocd_info(client_t *client)
868 {
869 device_t *dev = client->device;
870 int i, ftrack, ltrack;
871 int trackb, tracke, len;
872 char slen[11], blen[9], stype[8];
873
874 autocd_cprintf(client,
875 "Starting track = %i, ending track = %i, TOC size = %i bytes\n\
876 track start duration block length type\n\
877 -------------------------------------------------\n",
878 ftrack = dev->toc_header.starting_track,
879 ltrack = dev->toc_header.ending_track, dev->toc_header.len);
880
881 trackb = tracke = 75 * (60 * dev->toc_entry[0].addr.msf.minute +
882 dev->toc_entry[0].addr.msf.second) +
883 dev->toc_entry[0].addr.msf.frame;
884
885 for(i = 0; i <= ltrack; i++) {
886 if(dev->toc_entry[i].track != MAXTRACKS) {
887 len = (tracke = 75 * (60 * dev->toc_entry[i + 1].addr.msf.minute +
888 dev->toc_entry[i + 1].addr.msf.second) +
889 dev->toc_entry[i + 1].addr.msf.frame) - trackb;
890 snprintf(slen, sizeof(slen), "%4i:%02i.%02i",
891 len / (75 * 60), (len / 75) % 60, len % 75);
892 snprintf(blen, sizeof(blen), "%8i", len);
893 snprintf(stype, sizeof(stype), "%7s",
894 (dev->toc_entry[i].control & 4) ? "data" : "audio");
895 } else {
896 snprintf(slen, sizeof(slen), "%10s", "-");
897 snprintf(blen, sizeof(blen), "%8s", "-");
898 snprintf(stype, sizeof(stype), "%7s", "-");
899 }
900
901 autocd_cprintf(client,
902 "%5i%4i:%02i.%02i%s%8i%s%s\n",
903 dev->toc_entry[i].track,
904 dev->toc_entry[i].addr.msf.minute,
905 dev->toc_entry[i].addr.msf.second,
906 dev->toc_entry[i].addr.msf.frame,
907 slen, trackb - 2 * 75, blen, stype);
908
909 trackb = tracke;
910 }
911
912 return 0;
913 }
914
915 int
autocd_play(client_t * client)916 autocd_play(client_t *client)
917 {
918 device_t *device = client->device;
919
920 if(autocd_playtracks(device,
921 device->first_audio_track, device->last_audio_track) == -1)
922 return -1;
923
924 return 0;
925 }
926
927 int
autocd_next(client_t * client)928 autocd_next(client_t *client)
929 {
930 device_t *device = client->device;
931 u_char track;
932
933 if((track = device->sub_channel_info.what.position.track_number) >=
934 device->last_audio_track) {
935 autocd_cprintf(client, "ERROR: this is last track\n");
936 return -2;
937 }
938
939 device->play_msf.start_m = device->toc_entry[track].addr.msf.minute;
940 device->play_msf.start_s = device->toc_entry[track].addr.msf.second;
941 device->play_msf.start_f = device->toc_entry[track].addr.msf.frame;
942
943 if(autocd_play_msf(device) == -1)
944 return -1;
945
946 return 0;
947 }
948
949 int
autocd_previous(client_t * client)950 autocd_previous(client_t *client)
951 {
952 device_t *device = client->device;
953 int track;
954
955 if((track = device->sub_channel_info.what.position.track_number - 2) <
956 (device->first_audio_track - 1)) {
957 autocd_cprintf(client, "ERROR: this is first track\n");
958 return -2;
959 }
960
961 device->play_msf.start_m = device->toc_entry[track].addr.msf.minute;
962 device->play_msf.start_s = device->toc_entry[track].addr.msf.second;
963 device->play_msf.start_f = device->toc_entry[track].addr.msf.frame;
964
965 if(autocd_play_msf(device) == -1)
966 return -1;
967
968 return 0;
969 }
970
971 int
autocd_play_with_params(client_t * client,char * params)972 autocd_play_with_params(client_t *client, char *params)
973 {
974 device_t *device = client->device;
975 int ftrack, ltrack;
976 char *param2;
977
978 if(!isdigit(params[0])) {
979 autocd_cprintf(client, "ERROR: invalid parameters for play\n");
980 return -2;
981 }
982
983 if((param2 = strchr(params, ' '))) {
984 param2++[0] = 0;
985 sscanf(param2, "%i", <rack);
986 } else
987 ltrack = device->last_audio_track;
988
989 sscanf(params, "%i", &ftrack);
990
991 if(autocd_playtracks(device, ftrack, ltrack) == -1)
992 return -1;
993
994 return 0;
995 }
996
997 int
autocd_volume(client_t * client)998 autocd_volume(client_t *client)
999 {
1000 device_t *device = client->device;
1001 struct ioc_vol volume;
1002
1003 if(ioctl(device->dev, CDIOCGETVOL, &volume) == -1)
1004 return -1;
1005
1006 autocd_cprintf(client, "Left volume = %i, right volume = %i\n",
1007 volume.vol[0], volume.vol[1]);
1008
1009 return 0;
1010 }
1011
1012 int
autocd_changevolume(client_t * client,char * params)1013 autocd_changevolume(client_t *client, char *params)
1014 {
1015 device_t *device = client->device;
1016 struct ioc_vol volume;
1017 char *s;
1018
1019 if(params[0] != '+' && params[0] != '-') {
1020 if((s = strchr(params, ':')) == NULL) {
1021 volume.vol[0] = volume.vol[1] = atoi(params);
1022 } else {
1023 s[0] = 0;
1024 volume.vol[0] = atoi(params);
1025 volume.vol[1] = atoi(++s);
1026 }
1027 } else {
1028 int offset[2];
1029
1030 if(ioctl(device->dev, CDIOCGETVOL, &volume) == -1)
1031 return -1;
1032
1033 if((s = strchr(params, ':')) == NULL) {
1034 offset[0] = offset[1] = atoi(params);
1035 } else {
1036 s[0] = 0;
1037 offset[0] = atoi(params);
1038 offset[1] = atoi(++s);
1039 }
1040
1041 if((offset[0] + (int)volume.vol[0]) > 255)
1042 offset[0] = 255 - volume.vol[0];
1043
1044 if((offset[0] + (int)volume.vol[0]) < 0)
1045 offset[0] = - (int)volume.vol[0];
1046
1047 if((offset[1] + (int)volume.vol[1]) > 255)
1048 offset[1] = 255 - volume.vol[1];
1049
1050 if((offset[1] + (int)volume.vol[1]) < 0)
1051 offset[1] = - (int)volume.vol[1];
1052
1053 volume.vol[0] += offset[0];
1054 volume.vol[1] += offset[1];
1055 }
1056
1057 if(ioctl(device->dev, CDIOCSETVOL, &volume) == -1)
1058 return -1;
1059
1060 return 0;
1061 }
1062
1063 #ifdef HAVE_SYS_CDRIO_H
1064 int
autocd_speed(client_t * client,char * params)1065 autocd_speed(client_t *client, char *params)
1066 {
1067 device_t *device = client->device;
1068 int speed;
1069
1070 speed = atoi(params);
1071
1072 if(speed <= 0)
1073 speed = CDR_MAX_SPEED;
1074
1075 if(ioctl(device->dev, CDRIOCREADSPEED, &speed) == -1)
1076 return -1;
1077
1078 return 0;
1079 }
1080
1081 int
autocd_lockspeed(client_t * client,char * params)1082 autocd_lockspeed(client_t *client, char *params)
1083 {
1084 device_t *device = client->device;
1085 int speed;
1086
1087 speed = atoi(params);
1088
1089 if(speed <= 0 || speed > CDR_MAX_SPEED)
1090 speed = CDR_MAX_SPEED;
1091
1092 device->locked_speed = speed == CDR_MAX_SPEED ? 0 : speed;
1093
1094 if(!device->ejected)
1095 if(autocd_opendev(device) != -1) {
1096 if(ioctl(device->dev, CDRIOCREADSPEED, &speed) == -1) {
1097 autocd_closedev(device);
1098 device->locked_speed = 0;
1099 return -1;
1100 }
1101 autocd_closedev(device);
1102 }
1103
1104 return 0;
1105 }
1106 #endif
1107
1108 int
autocd_listdevices(client_t * client)1109 autocd_listdevices(client_t *client)
1110 {
1111 device_t *device;
1112 int i;
1113
1114 for(device = (device_t *)mq_gethead(devices), i = 0; device;
1115 device = device->next, i++) {
1116 autocd_cprintf(client, "%i %s\n", i, device->device);
1117 }
1118
1119 return 0;
1120 }
1121
1122 int
autocd_listsaved(client_t * client)1123 autocd_listsaved(client_t *client)
1124 {
1125 saved_msf_t *msf;
1126
1127 autocd_cprintf(client, "cdid\t\tposition\n");
1128
1129 for(mq_resetcurrent(saved_msfs);
1130 (msf = (saved_msf_t *) mq_nextrecord(saved_msfs));) {
1131 autocd_cprintf(client, "%08x\t%2i:%02i.%02i - %2i:%02i.%02i\n",
1132 msf->cdid, msf->play_msf.start_m, msf->play_msf.start_s,
1133 msf->play_msf.start_f, msf->play_msf.end_m, msf->play_msf.end_s,
1134 msf->play_msf.end_f);
1135 }
1136
1137 return 0;
1138 }
1139
1140 int
autocd_changedevice(client_t * client,char * dev)1141 autocd_changedevice(client_t *client, char *dev)
1142 {
1143 int i;
1144 device_t *device = NULL;
1145
1146 if(sscanf(dev, "%i", &i) == 0) {
1147 for(device = (device_t *)mq_gethead(devices);
1148 device; device = device->next)
1149 if(!strcmp(device->device, dev))
1150 break;
1151 } else {
1152 for(device = (device_t *)mq_gethead(devices);
1153 device && i; i--, device = device->next);
1154 }
1155
1156 if(!device) {
1157 autocd_ERROR(client, "ERROR: no such device: %s\n", dev);
1158 return -2;
1159 }
1160
1161 client->device = device;
1162
1163 return 0;
1164 }
1165
1166 int
autocd_cdid(client_t * client)1167 autocd_cdid(client_t *client)
1168 {
1169 autocd_cprintf(client, "%08x\n", client->device->cdid);
1170
1171 return 0;
1172 }
1173
1174 int
autocd_disable(client_t * client)1175 autocd_disable(client_t *client)
1176 {
1177 client->device->disabled = 1;
1178
1179 return 0;
1180 }
1181
1182 int
autocd_enable(client_t * client)1183 autocd_enable(client_t *client)
1184 {
1185 client->device->disabled = 0;
1186
1187 return 0;
1188 }
1189
1190 int
autocd_die(client_t * client)1191 autocd_die(client_t *client)
1192 {
1193 uid_t my_euid, client_euid;
1194 gid_t client_egid;
1195
1196 if(getpeereid(client->fd, &client_euid, &client_egid) < 0)
1197 return -1;
1198
1199 my_euid = geteuid();
1200
1201 if((client_euid != 0) && (client_euid != my_euid)) {
1202 autocd_ERROR(client, "ERROR: permission denied\n");
1203 return -2;
1204 }
1205
1206 nobreak = 0;
1207
1208 return 0;
1209 }
1210
1211 int
autocd_help(client_t * client)1212 autocd_help(client_t *client)
1213 {
1214 int i;
1215
1216 for(i = 0; cmds[i].cmd; i++) {
1217 if(cmds[i].params)
1218 autocd_cprintf(client, "%s %s\n", cmds[i].cmd, cmds[i].params);
1219 else
1220 autocd_cprintf(client, "%s\n", cmds[i].cmd);
1221 }
1222
1223 return 0;
1224 }
1225
1226 int
autocd_version(client_t * client)1227 autocd_version(client_t *client)
1228 {
1229 autocd_cprintf(client, "%s\n", ver_getversionstring());
1230
1231 return 0;
1232 }
1233
1234 int
autocd_save(client_t * client)1235 autocd_save(client_t *client)
1236 {
1237 device_t *device = client->device;
1238 saved_msf_t *msf;
1239
1240 for(mq_resetcurrent(saved_msfs);
1241 (msf = (saved_msf_t *) mq_nextrecord(saved_msfs));) {
1242 if(device->cdid == msf->cdid)
1243 break;
1244 }
1245
1246 if(!msf)
1247 msf = (saved_msf_t *)mq_addnewrecord(saved_msfs);
1248
1249 msf->play_msf.start_m =
1250 device->sub_channel_info.what.position.absaddr.msf.minute;
1251 msf->play_msf.start_s =
1252 device->sub_channel_info.what.position.absaddr.msf.second;
1253 msf->play_msf.start_f =
1254 device->sub_channel_info.what.position.absaddr.msf.frame;
1255 msf->cdid = device->cdid;
1256
1257 msf->play_msf.end_m = device->play_msf.end_m;
1258 msf->play_msf.end_s = device->play_msf.end_s;
1259 msf->play_msf.end_f = device->play_msf.end_f;
1260
1261 return 0;
1262 }
1263
1264 int
autocd_load(client_t * client)1265 autocd_load(client_t *client)
1266 {
1267 device_t *device = client->device;
1268 saved_msf_t *msf;
1269
1270 for(mq_resetcurrent(saved_msfs);
1271 (msf = (saved_msf_t *) mq_nextrecord(saved_msfs));) {
1272 if(device->cdid == msf->cdid) {
1273 device->play_msf = msf->play_msf;
1274
1275 mq_removecurrent(saved_msfs);
1276
1277 if(autocd_play_msf(device) == -1)
1278 return -1;
1279
1280 return 0;
1281 }
1282 }
1283
1284 autocd_ERROR(client, "ERROR: no saved position for cdid = %u\n",
1285 device->cdid);
1286 return -2;
1287 }
1288
1289 int
autocd_closeclient(client_t * client)1290 autocd_closeclient(client_t *client)
1291 {
1292 int fd;
1293
1294 if(((client_t *) mq_getcurrent(clients)) != client) {
1295 logger("Strange autocd_closeclient() call\n");
1296 return -1;
1297 }
1298
1299 fd = client->fd;
1300 FD_CLR(fd, &read_fds);
1301 close(fd);
1302
1303 mq_removecurrent(clients);
1304
1305 return -2;
1306 }
1307
1308 void
autocd_execmd(char * cmd)1309 autocd_execmd(char *cmd)
1310 {
1311 client_t *client;
1312 char *params;
1313 int slen, i;
1314
1315 client = (client_t *)mq_getcurrent(clients);
1316
1317 slen = strlen(cmd);
1318
1319 if((params = strchr(cmd, ' '))) {
1320 params[0] = 0;
1321 slen = params++ - cmd;
1322 }
1323
1324 for(i = 0; cmds[i].cmd; i++) {
1325 if(!strncasecmp(cmd, cmds[i].cmd, slen)) {
1326 int rcode;
1327
1328 if((params == NULL) != (cmds[i].params == NULL))
1329 continue;
1330
1331 if(cmds[i].need_disc) {
1332 if(client->device->ejected) {
1333 autocd_cprintf(client, "ERROR: no disc in drive\n");
1334 return;
1335 }
1336
1337 if(cmds[i].need_play) {
1338 u_char audio_status =
1339 client->device->sub_channel_info.header.audio_status;
1340
1341 if(audio_status != CD_AS_PLAY_IN_PROGRESS &&
1342 audio_status != CD_AS_PLAY_PAUSED) {
1343 autocd_cprintf(client,
1344 "ERROR: no playing in progress\n");
1345 return;
1346 }
1347 }
1348 }
1349
1350 if(cmds[i].need_opendev) {
1351 if(autocd_opendev(client->device) == -1) {
1352 autocd_cprintf(client, "ERROR: %s\n", strerror(errno));
1353 return;
1354 }
1355 }
1356
1357 if(params) {
1358 handler_wp_t *handler = (handler_wp_t *)(*cmds[i].handler);
1359 rcode = (*handler)(client, params);
1360 } else {
1361 rcode = (*cmds[i].handler)(client);
1362 }
1363
1364 switch(rcode) {
1365 case -1:
1366 autocd_cprintf(client, "ERROR: %s\n", strerror(errno));
1367 break;
1368
1369 case 0:
1370 autocd_cprintf(client, "OK\n");
1371 break;
1372 }
1373
1374 if(cmds[i].need_opendev)
1375 autocd_closedev(client->device);
1376
1377 return;
1378 }
1379 }
1380
1381 autocd_ERROR(client, "ERROR: unknown command: %s\n", cmd);
1382 }
1383
1384 void
autocd_serveclient()1385 autocd_serveclient()
1386 {
1387 client_t *client;
1388 int i, begin, len, fd;
1389 char buf[BUFSIZE];
1390
1391 fd = (client = (client_t *) mq_getcurrent(clients))->fd;
1392
1393 if(!(len = read(fd, buf, sizeof(buf) - sizeof(char)))) {
1394 autocd_closeclient(client);
1395 return;
1396 }
1397
1398 while((len > 0) && ((buf[len - 1] == 13) || (buf[len - 1] == 10)))
1399 len--;
1400 buf[len] = 0;
1401
1402 if(!len)
1403 return;
1404
1405 for(begin = i = 0; i < len; i++) {
1406 if((buf[i] == 13) || (buf[i] == 10)) {
1407 buf[i] = 0;
1408 autocd_execmd(buf + begin);
1409
1410 for(i++; (i < len) && ((buf[i] == 13) || (buf[i] == 10)); i++);
1411
1412 begin = i;
1413 }
1414 }
1415
1416 if(begin != i)
1417 autocd_execmd(buf + begin);
1418 }
1419
1420 void
autocd_loop()1421 autocd_loop()
1422 {
1423 device_t *dev;
1424 fd_set fds;
1425 struct timeval tv = {1, 0};
1426 client_t *client;
1427
1428 for(mq_resetcurrent(devices);
1429 (dev = (device_t *) mq_nextrecord(devices));) {
1430 autocd_checkdevice(dev);
1431
1432 if(dev->sub_channel_info.header.audio_status ==
1433 CD_AS_PLAY_IN_PROGRESS) {
1434 union msf_lba *msf_lba;
1435
1436 msf_lba = &dev->toc_entry[dev->first_audio_track].addr;
1437 dev->play_msf.start_m = msf_lba->msf.minute;
1438 dev->play_msf.start_s = msf_lba->msf.second;
1439 dev->play_msf.start_f = msf_lba->msf.frame;
1440
1441 msf_lba = &dev->toc_entry[dev->last_audio_track].addr;
1442 dev->play_msf.end_m = msf_lba->msf.minute;
1443 dev->play_msf.end_s = msf_lba->msf.second;
1444 dev->play_msf.end_f = msf_lba->msf.frame;
1445 }
1446 }
1447
1448 while(nobreak) {
1449 int rcode;
1450
1451 fds = read_fds;
1452
1453 if((rcode = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 0) {
1454 if(errno != EINTR) {
1455 logger("select() failed: %s\n", strerror(errno));
1456 break;
1457 }
1458 rcode = 0;
1459 }
1460
1461 for(mq_resetcurrent(devices);
1462 (dev = (device_t *) mq_nextrecord(devices));)
1463 autocd_checkdevice(dev);
1464
1465 if(rcode == 0)
1466 continue;
1467
1468 if(FD_ISSET(socket_fd, &fds)) {
1469 autocd_accept();
1470 }
1471
1472 for(mq_resetcurrent(clients);
1473 (client = (client_t *) mq_nextrecord(clients));) {
1474 if(FD_ISSET(client->fd, &fds)) {
1475 autocd_serveclient();
1476 }
1477 }
1478 }
1479
1480 close(socket_fd);
1481 unlink(socket_path);
1482
1483 for(mq_resetcurrent(clients);
1484 (client = (client_t *) mq_nextrecord(clients));)
1485 autocd_closeclient(client);
1486
1487 exit(EX_OK);
1488 }
1489
1490 void
sigterm_handler()1491 sigterm_handler()
1492 {
1493 nobreak = 0;
1494 }
1495
1496 int
autocd_daemon()1497 autocd_daemon()
1498 {
1499 if(daemon(0, 1) == -1) {
1500 logger("daemon() failed: %s\n", strerror(errno));
1501 return -1;
1502 }
1503
1504 set_daemon_mode("autocd");
1505
1506 signal(SIGHUP, SIG_IGN);
1507 signal(SIGTERM, &sigterm_handler);
1508 signal(SIGINT, &sigterm_handler);
1509
1510 autocd_loop();
1511
1512 return 0;
1513 }
1514