/* * XXX: a bug still exists here. we have a thread polling on this * XXX: device in the kernel, we need to get rid of this also. * XXX: since we're going to move the waiter thread up to the * XXX: user level, it'll be easier to kill off as part of the * XXX: cleanup of the device private data. */ static void rmscsi_close(char *path, dev_t rdev) { char namebuf[MAXNAMELEN]; struct stat sb; struct devs *dp; struct rmscsi_priv *rsp; int i; debug(1, "rmscsi_close %s\n", path); (void) sprintf(namebuf, RMSCSI_NAMEPROTO, path, RMSCSI_BASEPART); if (stat(namebuf, &sb) < 0) { if (rdev == NODEV) { warning(gettext("rmscsi_close: %s; %m\n"), namebuf); return; } } else { rdev = sb.st_rdev; } if ((dp = dev_getdp(rdev)) == NULL) { debug(1, "rmscsi_close: %s not in use\n", path); return; } /* get our private data */ rsp = (struct rmscsi_priv *)dp->dp_priv; /* * take care of the listner thread */ (void) mutex_lock(&rsp->rs_killmutex); (void) thr_kill(rsp->rs_tid, SIGUSR1); (void) mutex_unlock(&rsp->rs_killmutex); (void) thr_join(rsp->rs_tid, 0, 0); debug(1, "rmscsi_close: thread id %d reaped (killed/joined)\n", rsp->rs_tid); /* * if there is a volume inserted in this device ... */ if (dp->dp_vol) { /* * clean up the name space and the device maps * to remove references to any volume that might * be in the device right now * * this crap with the flags is to keep the * "poll" from being relaunched by this function * * yes, its a hack and there should be a better way */ if (dp->dp_dsw->d_flags & D_POLL) { dp->dp_dsw->d_flags &= ~D_POLL; dev_eject(dp->dp_vol, TRUE); dp->dp_dsw->d_flags |= D_POLL; } else { dev_eject(dp->dp_vol, TRUE); } if (dp->dp_vol != NULL) { return; } /* do the eject work */ (void) ioctl(rsp->rs_fd[RMSCSI_BASEPART], DKIOCEJECT, 0); } /* * clean up the names in the name space */ node_unlink(dp->dp_bvn); node_unlink(dp->dp_rvn); /* * free the private data we've allocated */ for (i = 0; i < V_NUMPAR; i++) { if (rsp->rs_rawpath[i]) { free(rsp->rs_rawpath[i]); } if (rsp->rs_fd[i] != -1) { (void) close(rsp->rs_fd[i]); } } #if defined(_FIRMWARE_NEEDS_FDISK) for (i = 0; i < (FD_NUMPART+1); i++) { if (rsp->rs_raw_pfd[i] >= 0) { (void) close(rsp->rs_raw_pfd[i]); } } #endif free(rsp); /* * free the dp, so no one points at us anymore */ dev_freedp(dp); }
int main(int argc, char **argv) { #define IOCTL_ERROR(__str) \ do { \ msg(MSG_ERR, "%s: Error during ioctl call\n", __str);\ dev_close();\ cd_device = NULL;\ is_error = TRUE;\ } while (0) int opt; int opt_index; int tracklist = -1; static struct option options[] = { {"help", 0, 0, 'h'}, {"version", 0, 0, 'V'}, {"device", 1, 0, 'd'}, {"noscan", 0, 0, 'n'}, {"slave", 0, 0, 's'}, {0, 0, 0, 0} }; char *cmd_str = NULL; size_t line_len; char *cmd_ptr = NULL; command_t cmd; char *cd_device = NULL; char *tmp_device = NULL; char **device_list = NULL; int num_devices = 0; unsigned short slave = 0; int arg_val; int noscan = 0; int i; int is_error = FALSE; dev_status_t status; while ((opt = getopt_long(argc, argv, "hvVd:ns", options, &opt_index)) != -1) { switch (opt) { case 'h': msg(MSG_STD, "help not implemented yet... sorry\n"); exit(0); break; case 'V': msg(MSG_STD, "Maja's CD player, version " VERSION "\n"); exit(0); break; case 'd': cd_device = optarg; break; case 'n': noscan = 1; break; case 's': slave = 1; break; default: break; } } if ((!cd_device) && (noscan) && (!slave)) { msg(MSG_ERR, "No device specified and scanning prohibited. " "Don't know what to do.\nExiting.\n\n"); return EXIT_FAILURE; } if (cd_device) { if (dev_open(cd_device) < 0) { msg(MSG_ERR, "Error opening device %s\n", cd_device); return EXIT_FAILURE; } dev_prepare(); if (!dev_isaudio()) { msg(MSG_STD, "%s: no audio disc\n", cd_device); dev_close(); cd_device = NULL; is_error = TRUE; } } num_devices = get_cd_devices(&device_list); if (!cd_device && !noscan && !is_error) { msg(MSG_STD, "Scanning devices...\n"); for (i = 0; i < num_devices; i++) { cd_device = device_list[i]; if (dev_open(cd_device) < 0) msg(MSG_STD, "%s: could not open", cd_device); dev_prepare(); if (dev_isaudio()) { msg(MSG_STD, "%s: OK\n", cd_device); break; } else msg(MSG_STD, "%s: no audio disc\n", cd_device); dev_close(); cd_device = NULL; } } if ((!cd_device) && (!slave)) { msg(MSG_ERR, "No usable CD device found.\n"); free_list(&device_list, num_devices); return EXIT_FAILURE; } if (slave) { msg(MSG_STD, is_error ? "ERROR\n" : "OK\n"); } if (optind == argc) { if (!slave) { msg(MSG_STD, "No command given\n"); free_list(&device_list, num_devices); return EXIT_FAILURE; } } else if (argv[optind]) cmd_str = strdup(argv[optind]); do { is_error = FALSE; if ((!cmd_str) && (slave)) { if (getline(&cmd_str, &line_len, stdin) < 0) { free(cmd_str); cmd_str = strdup("quit"); } if ((cmd_ptr = strrchr(cmd_str, '\n'))) *cmd_ptr = '\0'; } if ((!cd_device) && (strncmp(cmd_str, "device", 6) != 0) && (strcmp(cmd_str, "scan") != 0) && (strcmp(cmd_str, "quit") != 0)) { msg(MSG_STD, "No device opened. " "Only 'scan', 'device' and 'quit' commands are allowed\n"); msg(MSG_STD, "ERROR\n"); free(cmd_str); cmd_str = NULL; continue; } switch (cmd = get_cmd_num(cmd_str)) { case CMD_PLAY: arg_val = -1; if (++optind < argc) arg_val = atoi(argv[optind]); cmd_ptr = &(cmd_str[4]); while (*cmd_ptr == ' ') cmd_ptr++; if ((arg_val < 0) && (*cmd_ptr != '\0')) arg_val = atoi(cmd_ptr); if (arg_val <= 0) arg_val = 1; if (dev_query_status(&status, &tracklist, NULL, NULL) < 0) IOCTL_ERROR("Play"); else { if ((status != ST_PLAYING) || (arg_val != tracklist)) { STATUS_OUT(cd_device, arg_val, "Playing", 0U, 0U); if (dev_play(arg_val) < 0) IOCTL_ERROR("Play"); } else if (print_status(cd_device) < 0) IOCTL_ERROR("Play"); tracklist = -1; } break; case CMD_STOP: if (dev_stop() < 0) IOCTL_ERROR("Stop"); break; case CMD_PAUSE: if (dev_pause() < 0) IOCTL_ERROR("Pause"); break; case CMD_NEXT: if ((dev_query_status(NULL, &tracklist, NULL, NULL) < 0) || (dev_stop < 0) || (dev_play(tracklist + 1) < 0)) IOCTL_ERROR("Next"); break; case CMD_PREV: if ((dev_query_status(NULL, &tracklist, NULL, NULL) < 0) || (dev_stop < 0) || (dev_play(tracklist - 1) < 0)) IOCTL_ERROR("Prev"); break; case CMD_TOGGLE: if ((dev_query_status(&status, NULL, NULL, NULL) < 0) || ((status == ST_PLAYING) && (dev_pause() < 0)) || ((status == ST_PAUSED) && (dev_resume() < 0))) IOCTL_ERROR("Toggle"); break; case CMD_EJECT: if (dev_eject() < 0) IOCTL_ERROR("Eject"); break; case CMD_CLOSE: if (dev_close_tray() < 0) IOCTL_ERROR("Close"); break; case CMD_STATUS: if (print_status(cd_device) < 0) IOCTL_ERROR("Status"); break; case CMD_INFO: if (print_info(cd_device) < 0) is_error = TRUE; break; case CMD_SCAN: dev_close(); for (i = 0; i < num_devices; i++) { tmp_device = device_list[i]; if (dev_open(tmp_device) < 0) { msg(MSG_STD, "%s: could not open\n", tmp_device); msg(MSG_STD, "ERROR\n"); is_error = TRUE; continue; } dev_prepare(); if (dev_isaudio()) msg(MSG_STD, "%s: OK\n", tmp_device); else msg(MSG_STD, "%s: no audio disc\n", tmp_device); dev_close(); } if (cd_device) { if (dev_open(cd_device) < 0) { msg(MSG_STD, "%s: error reopening\n", cd_device); is_error = TRUE; } else dev_prepare(); } break; case CMD_DEVICE: cmd_ptr = &(cmd_str[6]); while (*cmd_ptr == ' ') ++cmd_ptr; is_error = TRUE; if (*cmd_ptr == '\0') { for(i = 0; i < num_devices; i++) msg(MSG_STD, "%s\n", device_list[i]); is_error = FALSE; } else { dev_close(); for (i = 0; i < num_devices; i++) { if(strcmp(cmd_ptr, device_list[i]) != 0) continue; tmp_device = device_list[i]; if (dev_open(tmp_device) < 0) { msg(MSG_STD, "%s: could not open\n", tmp_device); msg(MSG_STD, "ERROR\n"); } else { dev_prepare(); if (!dev_isaudio()) msg(MSG_STD, "%s: no audio disc\n", tmp_device); else { msg(MSG_STD, "%s: OK\n", tmp_device); cd_device = device_list[i]; is_error = FALSE; } } break; } if ((is_error) && (cd_device)) { if (dev_open(cd_device) < 0) msg(MSG_STD, "%s: error reopening\n", tmp_device); else dev_prepare(); } } break; case CMD_VOLUME: cmd_ptr = &(cmd_str[6]); while (*cmd_ptr == ' ') cmd_ptr++; switch (*cmd_ptr) { case '+': arg_val = dev_get_volume(); cmd_ptr++; arg_val = CLAMP(arg_val + atoi(cmd_ptr), VOL_MIN, VOL_MAX); break; case '-': arg_val = dev_get_volume(); cmd_ptr++; arg_val = CLAMP(arg_val - atoi(cmd_ptr), VOL_MIN, VOL_MAX); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': arg_val = CLAMP(atoi(cmd_ptr), VOL_MIN, VOL_MAX); break; default: arg_val = -1; break; } if ((arg_val >= 0) && (dev_set_volume(arg_val) < 0)) IOCTL_ERROR("Volume"); else { arg_val = dev_get_volume(); msg(MSG_STD, "Volume %d\n", arg_val); } break; case CMD_SEEK: { unsigned min, sec, st_min, st_sec; int trk; is_error = (dev_query_status(NULL, &trk, &min, &sec) < 0); if (!is_error) is_error = (dev_get_track_time(trk, &st_min, &st_sec, NULL, NULL) < 0); if (is_error) { msg(MSG_ERR, "Error querying current position\n"); break; } if (!slave && ++optind < argc) cmd_ptr = argv[optind]; else { cmd_ptr = &(cmd_str[4]); while (*cmd_ptr == ' ') cmd_ptr++; } /* Current position from beginning of the CD in seconds */ arg_val = (int)((min + st_min) * 60 + st_sec + sec); switch (*cmd_ptr) { case '+': cmd_ptr++; arg_val += atoi(cmd_ptr); break; case '-': cmd_ptr++; arg_val -= atoi(cmd_ptr); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': arg_val = atoi(cmd_ptr); break; default: arg_val = -1; break; } msg(MSG_STD, "Seeking to: %d\n", arg_val); if (dev_seek(arg_val) < 0) { msg(MSG_ERR, "Error seeking to %d sec\n", arg_val); is_error = TRUE; } break; } case CMD_QUIT: noscan = 1; slave = 0; if ((cd_device) && (dev_close() < 0)) { msg(MSG_ERR, "Error closing device %s\n", cd_device); is_error = TRUE; } break; default: if (cmd_str) { msg(MSG_ERR, "Unknown command: %s\n", cmd_str); is_error = TRUE; } else { msg(MSG_ERR, "Nothing to do\n"); is_error = TRUE; } } /* switch */ msg(MSG_STD, is_error ? "ERROR\n" : "OK\n"); fflush(stderr); free(cmd_str); cmd_str = NULL; } while (slave); free_list(&device_list, num_devices); return EXIT_SUCCESS; }