1 /*
2 * libdi - CD Audio Device Interface Library
3 *
4 * Copyright (C) 1993-2004 Ti Kan
5 * E-mail: xmcd@amb.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 #ifndef lint
22 static char *_libdi_c_ident_ = "@(#)libdi.c 7.170 04/04/20";
23 #endif
24
25 #include "common_d/appenv.h"
26 #include "common_d/version.h"
27 #include "common_d/util.h"
28 #include "libdi_d/libdi.h"
29 #include "libdi_d/scsipt.h"
30 #include "libdi_d/slioc.h"
31 #include "libdi_d/fbioc.h"
32 #include "libdi_d/aixioc.h"
33 #include "cdda_d/cdda.h"
34
35
36 #define PARM_BUF_SZ (STR_BUF_SZ * 16) /* Temporary buffer size */
37
38
39 extern appdata_t app_data;
40 extern FILE *errfp;
41
42
43 /* libdi module init routines */
44 diinit_tbl_t diinit[] = {
45 { scsipt_init }, /* SCSI pass-through method */
46 { slioc_init }, /* SunOS/Solaris/Linux ioctl method */
47 { fbioc_init }, /* FreeBSD ioctl method */
48 { aixioc_init }, /* AIX IDE ioctl method */
49 { NULL } /* List terminator */
50 };
51
52
53 /* libdi interface calling table */
54 di_tbl_t ditbl[MAX_METHODS];
55
56 /* Application callbacks */
57 di_client_t *di_clinfo;
58
59 /* Device list table */
60 char **di_devlist;
61
62 /* Clip frames */
63 sword32_t di_clip_frames;
64
65 /* Flag to indicate whether CD information has been loaded */
66 STATIC bool_t di_cdinfo_loaded = FALSE;
67
68 /* Device lock file */
69 STATIC char lockfile[FILE_PATH_SZ] = { '\0' };
70
71
72 /***********************
73 * internal routines *
74 ***********************/
75
76
77 /*
78 * di_boolstr
79 * Return the string "False" or "True" depending upon the
80 * passed in boolean parameter.
81 *
82 * Args:
83 * parm - boolean parameter
84 *
85 * Return:
86 * "False" if parm is FALSE.
87 * "True" is parm is TRUE.
88 */
89 STATIC char *
di_boolstr(bool_t parm)90 di_boolstr(bool_t parm)
91 {
92 return ((parm == FALSE) ? "False" : "True");
93 }
94
95
96 /*
97 * di_prncfg
98 * Display configuration information
99 *
100 * Args:
101 * None.
102 *
103 * Return:
104 * Nothing.
105 */
106 STATIC void
di_prncfg(void)107 di_prncfg(void)
108 {
109 (void) fprintf(errfp, "\nBasic parameters:\n");
110
111 (void) fprintf(errfp, "\tlibdir:\t\t\t\t%s\n",
112 app_data.libdir);
113
114 (void) fprintf(errfp, "\nX resources:\n");
115
116 (void) fprintf(errfp, "\tversion:\t\t\t%s\n",
117 app_data.version == NULL ?
118 "(undef)" : app_data.version);
119 (void) fprintf(errfp, "\tmainWindowMode:\t\t\t%d\n",
120 app_data.main_mode);
121 (void) fprintf(errfp, "\tmodeChangeGravity:\t\t%d\n",
122 app_data.modechg_grav);
123 (void) fprintf(errfp, "\tnormalMainWidth:\t\t%d\n",
124 app_data.normal_width);
125 (void) fprintf(errfp, "\tnormalMainHeight:\t\t%d\n",
126 app_data.normal_height);
127 (void) fprintf(errfp, "\tbasicMainWidth:\t\t\t%d\n",
128 app_data.basic_width);
129 (void) fprintf(errfp, "\tbasicMainHeight:\t\t%d\n",
130 app_data.basic_height);
131 (void) fprintf(errfp, "\tdisplayBlinkOnInterval:\t\t%d\n",
132 app_data.blinkon_interval);
133 (void) fprintf(errfp, "\tdisplayBlinkOffInterval:\t%d\n",
134 app_data.blinkoff_interval);
135 (void) fprintf(errfp, "\tmainShowFocus:\t\t\t%s\n",
136 di_boolstr(app_data.main_showfocus));
137 (void) fprintf(errfp, "\tinstallColormap:\t\t%s\n",
138 di_boolstr(app_data.instcmap));
139
140 (void) fprintf(errfp, "\nCommon parameters:\n");
141
142 (void) fprintf(errfp, "\tdevice:\t\t\t\t%s\n",
143 app_data.device);
144 (void) fprintf(errfp, "\toutputPort:\t\t\t0x%x\n",
145 (int) app_data.outport);
146 (void) fprintf(errfp, "\tcdinfoPath:\t\t\t%s\n",
147 app_data.cdinfo_path);
148 (void) fprintf(errfp, "\tcharsetConvMode:\t\t%d\n",
149 app_data.chset_xlat);
150 (void) fprintf(errfp, "\tlangUtf8:\t\t\t%s\n",
151 app_data.lang_utf8);
152 (void) fprintf(errfp, "\tacceptFuzzyDefault:\t\t%s\n",
153 di_boolstr(app_data.single_fuzzy));
154 (void) fprintf(errfp, "\tcdinfoFileMode:\t\t\t%s\n",
155 app_data.cdinfo_filemode);
156 (void) fprintf(errfp, "\tproxyServer:\t\t\t%s\n",
157 app_data.proxy_server == NULL ?
158 "(undef)" : app_data.proxy_server);
159 (void) fprintf(errfp, "\thistoryFileMode:\t\t%s\n",
160 app_data.hist_filemode);
161 (void) fprintf(errfp, "\thistoryFileDisable:\t\t%s\n",
162 di_boolstr(app_data.histfile_dsbl));
163 (void) fprintf(errfp, "\tcddbCacheTimeout:\t\t%d\n",
164 app_data.cache_timeout);
165 (void) fprintf(errfp, "\tserviceTimeout:\t\t\t%d\n",
166 app_data.srv_timeout);
167 (void) fprintf(errfp, "\tlocalDiscographyMode:\t\t%d\n",
168 app_data.discog_mode);
169 (void) fprintf(errfp, "\tmaximumHistory:\t\t\t%d\n",
170 app_data.cdinfo_maxhist);
171 (void) fprintf(errfp, "\tstatusPollInterval:\t\t%d\n",
172 app_data.stat_interval);
173 (void) fprintf(errfp, "\tinsertPollInterval:\t\t%d\n",
174 app_data.ins_interval);
175 (void) fprintf(errfp, "\ttimeDisplayMode:\t\t%d\n",
176 app_data.timedpy_mode);
177 (void) fprintf(errfp, "\ttooltipDelayInterval:\t\t%d\n",
178 app_data.tooltip_delay);
179 (void) fprintf(errfp, "\ttooltipActiveInterval:\t\t%d\n",
180 app_data.tooltip_time);
181 (void) fprintf(errfp, "\tinsertPollDisable:\t\t%s\n",
182 di_boolstr(app_data.ins_disable));
183 (void) fprintf(errfp, "\tpreviousThreshold:\t\t%d\n",
184 app_data.prev_threshold);
185 (void) fprintf(errfp, "\tsearchSkipBlocks:\t\t%d\n",
186 app_data.skip_blks);
187 (void) fprintf(errfp, "\tsearchPauseInterval:\t\t%d\n",
188 app_data.skip_pause);
189 (void) fprintf(errfp, "\tsearchSpeedUpCount:\t\t%d\n",
190 app_data.skip_spdup);
191 (void) fprintf(errfp, "\tsearchVolumePercent:\t\t%d\n",
192 app_data.skip_vol);
193 (void) fprintf(errfp, "\tsearchMinVolume:\t\t%d\n",
194 app_data.skip_minvol);
195 (void) fprintf(errfp, "\tsampleBlocks:\t\t\t%d\n",
196 app_data.sample_blks);
197 (void) fprintf(errfp, "\tinternetOffline:\t\t%s\n",
198 di_boolstr(app_data.cdinfo_inetoffln));
199 (void) fprintf(errfp, "\tcddbUseProxy:\t\t\t%s\n",
200 di_boolstr(app_data.use_proxy));
201 (void) fprintf(errfp, "\tproxyAuthorization:\t\t%s\n",
202 di_boolstr(app_data.proxy_auth));
203 (void) fprintf(errfp, "\tautoMusicBrowser:\t\t%s\n",
204 di_boolstr(app_data.auto_musicbrowser));
205 (void) fprintf(errfp, "\tshowScsiErrMsg:\t\t\t%s\n",
206 di_boolstr(app_data.scsierr_msg));
207 (void) fprintf(errfp, "\tsolaris2VolumeManager:\t\t%s\n",
208 di_boolstr(app_data.sol2_volmgt));
209 (void) fprintf(errfp, "\ttooltipEnable:\t\t\t%s\n",
210 di_boolstr(app_data.tooltip_enable));
211 (void) fprintf(errfp, "\tremoteControlEnable:\t\t%s\n",
212 di_boolstr(app_data.remote_enb));
213 (void) fprintf(errfp, "\tremoteControlLog:\t\t%s\n",
214 di_boolstr(app_data.remote_log));
215 (void) fprintf(errfp, "\tcddaFilePerTrack:\t\t%s\n",
216 di_boolstr(app_data.cdda_trkfile));
217 (void) fprintf(errfp, "\tcddaSpaceToUnderscore:\t\t%s\n",
218 di_boolstr(app_data.subst_underscore));
219 (void) fprintf(errfp, "\tcddaFileFormat:\t\t\t%d\n",
220 app_data.cdda_filefmt);
221 (void) fprintf(errfp, "\tcddaFileTemplate:\t\t%s\n",
222 app_data.cdda_tmpl == NULL ? "-" : app_data.cdda_tmpl);
223 (void) fprintf(errfp, "\tcddaPipeProgram:\t\t%s\n",
224 app_data.pipeprog == NULL ? "-" : app_data.pipeprog);
225 (void) fprintf(errfp, "\tcddaSchedOptions:\t\t%d\n",
226 app_data.cdda_sched);
227 (void) fprintf(errfp, "\tcddaHeartbeatTimeout:\t\t%d\n",
228 app_data.hb_timeout);
229 (void) fprintf(errfp, "\tcompressionMode:\t\t%d\n",
230 app_data.comp_mode);
231 (void) fprintf(errfp, "\tcompressionBitrate:\t\t%d\n",
232 app_data.bitrate);
233 (void) fprintf(errfp, "\tminimumBitrate:\t\t\t%d\n",
234 app_data.bitrate_min);
235 (void) fprintf(errfp, "\tmaximumBitrate:\t\t\t%d\n",
236 app_data.bitrate_max);
237 (void) fprintf(errfp, "\tcompressionQuality:\t\t%d\n",
238 app_data.qual_factor);
239 (void) fprintf(errfp, "\tchannelMode:\t\t\t%d\n",
240 app_data.chan_mode);
241 (void) fprintf(errfp, "\tcompressionAlgorithm:\t\t%d\n",
242 app_data.comp_algo);
243 (void) fprintf(errfp, "\tlowpassMode:\t\t\t%d\n",
244 app_data.lowpass_mode);
245 (void) fprintf(errfp, "\tlowpassFrequency:\t\t%d\n",
246 app_data.lowpass_freq);
247 (void) fprintf(errfp, "\tlowpassWidth:\t\t\t%d\n",
248 app_data.lowpass_width);
249 (void) fprintf(errfp, "\thighpassMode:\t\t\t%d\n",
250 app_data.highpass_mode);
251 (void) fprintf(errfp, "\thighpassFrequency:\t\t%d\n",
252 app_data.highpass_freq);
253 (void) fprintf(errfp, "\thighpassWidth:\t\t\t%d\n",
254 app_data.highpass_width);
255 (void) fprintf(errfp, "\tcopyrightFlag:\t\t\t%s\n",
256 di_boolstr(app_data.copyright));
257 (void) fprintf(errfp, "\toriginalFlag:\t\t\t%s\n",
258 di_boolstr(app_data.original));
259 (void) fprintf(errfp, "\tnoBitReservoirFlag:\t\t%s\n",
260 di_boolstr(app_data.nores));
261 (void) fprintf(errfp, "\tchecksumFlag:\t\t\t%s\n",
262 di_boolstr(app_data.checksum));
263 (void) fprintf(errfp, "\tstrictISO:\t\t\t%s\n",
264 di_boolstr(app_data.strict_iso));
265 (void) fprintf(errfp, "\taddInfoTag:\t\t\t%s\n",
266 di_boolstr(app_data.add_tag));
267 (void) fprintf(errfp, "\tlameOptionsMode:\t\t%d\n",
268 app_data.lameopts_mode);
269 (void) fprintf(errfp, "\tlameOptions:\t\t\t%s\n",
270 app_data.lame_opts == NULL ? "-" : app_data.lame_opts);
271 (void) fprintf(errfp, "\tid3TagMode:\t\t\t%d\n",
272 app_data.id3tag_mode);
273 (void) fprintf(errfp, "\tspinDownOnLoad:\t\t\t%s\n",
274 di_boolstr(app_data.load_spindown));
275 (void) fprintf(errfp, "\tplayOnLoad:\t\t\t%s\n",
276 di_boolstr(app_data.load_play));
277 (void) fprintf(errfp, "\tejectOnDone:\t\t\t%s\n",
278 di_boolstr(app_data.done_eject));
279 (void) fprintf(errfp, "\texitOnExit:\t\t\t%s\n",
280 di_boolstr(app_data.done_exit));
281 (void) fprintf(errfp, "\tejectOnExit:\t\t\t%s\n",
282 di_boolstr(app_data.exit_eject));
283 (void) fprintf(errfp, "\tstopOnExit:\t\t\t%s\n",
284 di_boolstr(app_data.exit_stop));
285 (void) fprintf(errfp, "\texitOnEject:\t\t\t%s\n",
286 di_boolstr(app_data.eject_exit));
287 (void) fprintf(errfp, "\trepeatMode:\t\t\t%s\n",
288 di_boolstr(app_data.repeat_mode));
289 (void) fprintf(errfp, "\tshuffleMode:\t\t\t%s\n",
290 di_boolstr(app_data.shuffle_mode));
291 (void) fprintf(errfp, "\tdiscogURLPrefix:\t\t%s\n",
292 app_data.discog_url_pfx == NULL ?
293 "-" : app_data.discog_url_pfx);
294 (void) fprintf(errfp, "\tautoMotdDisable:\t\t%s\n",
295 di_boolstr(app_data.automotd_dsbl));
296 (void) fprintf(errfp, "\tdebugLevel:\t\t\t0x%x\n",
297 (int) app_data.debug);
298 (void) fprintf(errfp, "\texcludeWords:\t\t\t%s\n",
299 app_data.exclude_words == NULL ?
300 "(undef)" : app_data.exclude_words);
301
302 (void) fprintf(errfp, "\nDevice-specific (privileged) parameters:\n");
303
304 (void) fprintf(errfp, "\tdevnum:\t\t\t\t%d\n",
305 app_data.devnum);
306 (void) fprintf(errfp, "\tdeviceList:\t\t\t%s\n",
307 app_data.devlist);
308 (void) fprintf(errfp, "\tdeviceInterfaceMethod:\t\t%d\n",
309 app_data.di_method);
310 (void) fprintf(errfp, "\tcddaMethod:\t\t\t%d\n",
311 app_data.cdda_method);
312 (void) fprintf(errfp, "\tcddaReadMethod:\t\t\t%d\n",
313 app_data.cdda_rdmethod);
314 (void) fprintf(errfp, "\tcddaWriteMethod:\t\t%d\n",
315 app_data.cdda_wrmethod);
316 (void) fprintf(errfp, "\tcddaScsiModeSelect:\t\t%s\n",
317 di_boolstr(app_data.cdda_modesel));
318 (void) fprintf(errfp, "\tcddaScsiDensity:\t\t%d\n",
319 app_data.cdda_scsidensity);
320 (void) fprintf(errfp, "\tcddaScsiReadCommand:\t\t%d\n",
321 app_data.cdda_scsireadcmd);
322 (void) fprintf(errfp, "\tcddaReadChunkBlocks:\t\t%d\n",
323 app_data.cdda_readchkblks);
324 (void) fprintf(errfp, "\tcddaDataBigEndian:\t\t%s\n",
325 di_boolstr(app_data.cdda_bigendian));
326 (void) fprintf(errfp, "\tdriveVendorCode:\t\t%d\n",
327 app_data.vendor_code);
328 (void) fprintf(errfp, "\tscsiVersionCheck:\t\t%s\n",
329 di_boolstr(app_data.scsiverck));
330 (void) fprintf(errfp, "\tnumDiscs:\t\t\t%d\n",
331 app_data.numdiscs);
332 (void) fprintf(errfp, "\tmediumChangeMethod:\t\t%d\n",
333 app_data.chg_method);
334 (void) fprintf(errfp, "\tscsiAudioVolumeBase:\t\t%d\n",
335 app_data.base_scsivol);
336 (void) fprintf(errfp, "\tminimumPlayBlocks:\t\t%d\n",
337 app_data.min_playblks);
338 (void) fprintf(errfp, "\tplayAudio10Support:\t\t%s\n",
339 di_boolstr(app_data.play10_supp));
340 (void) fprintf(errfp, "\tplayAudio12Support:\t\t%s\n",
341 di_boolstr(app_data.play12_supp));
342 (void) fprintf(errfp, "\tplayAudioMSFSupport:\t\t%s\n",
343 di_boolstr(app_data.playmsf_supp));
344 (void) fprintf(errfp, "\tplayAudioTISupport:\t\t%s\n",
345 di_boolstr(app_data.playti_supp));
346 (void) fprintf(errfp, "\tloadSupport:\t\t\t%s\n",
347 di_boolstr(app_data.load_supp));
348 (void) fprintf(errfp, "\tejectSupport:\t\t\t%s\n",
349 di_boolstr(app_data.eject_supp));
350 (void) fprintf(errfp, "\tmodeSenseSetDBD:\t\t%s\n",
351 di_boolstr(app_data.msen_dbd));
352 (void) fprintf(errfp, "\tmodeSenseUse10Byte:\t\t%s\n",
353 di_boolstr(app_data.msen_10));
354 (void) fprintf(errfp, "\tvolumeControlSupport:\t\t%s\n",
355 di_boolstr(app_data.mselvol_supp));
356 (void) fprintf(errfp, "\tbalanceControlSupport:\t\t%s\n",
357 di_boolstr(app_data.balance_supp));
358 (void) fprintf(errfp, "\tchannelRouteSupport:\t\t%s\n",
359 di_boolstr(app_data.chroute_supp));
360 (void) fprintf(errfp, "\tpauseResumeSupport:\t\t%s\n",
361 di_boolstr(app_data.pause_supp));
362 (void) fprintf(errfp, "\tstrictPauseResume:\t\t%s\n",
363 di_boolstr(app_data.strict_pause_resume));
364 (void) fprintf(errfp, "\tplayPausePlay:\t\t\t%s\n",
365 di_boolstr(app_data.play_pause_play));
366 (void) fprintf(errfp, "\tcaddyLockSupport:\t\t%s\n",
367 di_boolstr(app_data.caddylock_supp));
368 (void) fprintf(errfp, "\tcurposFormat:\t\t\t%s\n",
369 di_boolstr(app_data.curpos_fmt));
370 (void) fprintf(errfp, "\tnoTURWhenPlaying:\t\t%s\n",
371 di_boolstr(app_data.play_notur));
372 (void) fprintf(errfp, "\ttocLBA:\t\t\t\t%s\n",
373 di_boolstr(app_data.toc_lba));
374 (void) fprintf(errfp, "\tsubChannelLBA:\t\t\t%s\n",
375 di_boolstr(app_data.subq_lba));
376 (void) fprintf(errfp, "\tdriveBlockSize:\t\t\t%d\n",
377 app_data.drv_blksz);
378 (void) fprintf(errfp, "\tspinUpInterval:\t\t\t%d\n",
379 app_data.spinup_interval);
380 (void) fprintf(errfp, "\tmcnDisable:\t\t\t%s\n",
381 di_boolstr(app_data.mcn_dsbl));
382 (void) fprintf(errfp, "\tisrcDisable:\t\t\t%s\n",
383 di_boolstr(app_data.isrc_dsbl));
384 (void) fprintf(errfp, "\tcdTextDisable:\t\t\t%s\n",
385 di_boolstr(app_data.cdtext_dsbl));
386
387 (void) fprintf(errfp,
388 "\nDevice-specific (user-modifiable) parameters:\n");
389
390 (void) fprintf(errfp, "\tplayMode:\t\t\t%d\n",
391 app_data.play_mode);
392 (void) fprintf(errfp, "\tvolumeControlTaper:\t\t%d\n",
393 app_data.vol_taper);
394 (void) fprintf(errfp, "\tstartupVolume:\t\t\t%d\n",
395 app_data.startup_vol);
396 (void) fprintf(errfp, "\tchannelRoute:\t\t\t%d\n",
397 app_data.ch_route);
398 (void) fprintf(errfp, "\tcloseOnEject:\t\t\t%s\n",
399 di_boolstr(app_data.eject_close));
400 (void) fprintf(errfp, "\tcaddyLock:\t\t\t%s\n",
401 di_boolstr(app_data.caddy_lock));
402 (void) fprintf(errfp, "\tmultiPlay:\t\t\t%s\n",
403 di_boolstr(app_data.multi_play));
404 (void) fprintf(errfp, "\treversePlay:\t\t\t%s\n",
405 di_boolstr(app_data.reverse));
406 (void) fprintf(errfp, "\tcddaJitterCorrection:\t\t%s\n",
407 di_boolstr(app_data.cdda_jitter_corr));
408
409 (void) fprintf(errfp, "\n");
410 }
411
412
413 /*
414 * di_parse_devlist
415 * Parse the app_data.devlist string and create the di_devlist array.
416 *
417 * Args:
418 * None.
419 *
420 * Return:
421 * Nothing.
422 */
423 STATIC void
di_parse_devlist(void)424 di_parse_devlist(void)
425 {
426 char *p,
427 *q;
428 int i,
429 n,
430 listsz;
431 curstat_t *s = di_clinfo->curstat_addr();
432
433 if (app_data.chg_method < 0 || app_data.chg_method >= MAX_CHG_METHODS)
434 /* Fix-up in case of mis-configuration */
435 app_data.chg_method = CHG_NONE;
436
437 n = app_data.numdiscs;
438
439 switch (app_data.chg_method) {
440 case CHG_SCSI_MEDCHG:
441 n = 2;
442 /*FALLTHROUGH*/
443
444 case CHG_SCSI_LUN:
445 /* SCSI LUN addressing method */
446 listsz = n * sizeof(char *);
447
448 di_devlist = (char **) MEM_ALLOC("di_devlist", listsz);
449 if (di_devlist == NULL) {
450 DI_FATAL(app_data.str_nomemory);
451 return;
452 }
453 (void) memset(di_devlist, 0, listsz);
454
455 p = q = app_data.devlist;
456 if (p == NULL || *p == '\0') {
457 DI_FATAL(app_data.str_devlist_undef);
458 return;
459 }
460
461 for (i = 0; i < n; i++) {
462 q = strchr(p, ';');
463
464 if (q == NULL && i < (n - 1)) {
465 DI_FATAL(app_data.str_devlist_count);
466 return;
467 }
468
469 if (q != NULL)
470 *q = '\0';
471
472 if (!util_newstr(&di_devlist[i], p)) {
473 DI_FATAL(app_data.str_nomemory);
474 return;
475 }
476
477 if (q != NULL)
478 *q = ';';
479
480 p = q + 1;
481 }
482
483 /* In this mode, closeOnEject must be True */
484 app_data.eject_close = TRUE;
485 break;
486
487 case CHG_OS_IOCTL:
488 case CHG_NONE:
489 default:
490 if (app_data.chg_method == CHG_OS_IOCTL) {
491 /* In this mode, closeOnEject must be True */
492 app_data.eject_close = TRUE;
493 }
494 else {
495 /* Some fix-ups in case of mis-configuration */
496 app_data.numdiscs = 1;
497 }
498
499 if (app_data.devlist == NULL) {
500 if (!util_newstr(&app_data.devlist, app_data.device)) {
501 DI_FATAL(app_data.str_nomemory);
502 return;
503 }
504 }
505 else if (strcmp(app_data.devlist, app_data.device) != 0) {
506 MEM_FREE(app_data.devlist);
507 app_data.devlist = NULL;
508 if (!util_newstr(&app_data.devlist, app_data.device)) {
509 DI_FATAL(app_data.str_nomemory);
510 return;
511 }
512 }
513
514 di_devlist = (char **) MEM_ALLOC("di_devlist", sizeof(char *));
515 if (di_devlist == NULL) {
516 DI_FATAL(app_data.str_nomemory);
517 return;
518 }
519 di_devlist[0] = NULL;
520 if (!util_newstr(&di_devlist[0], app_data.devlist)) {
521 DI_FATAL(app_data.str_nomemory);
522 return;
523 }
524 break;
525 }
526
527 /* Initialize to the first device */
528 s->curdev = di_devlist[0];
529 }
530
531
532 /*
533 * di_chktmpl
534 * Check the CDDA save-to-file path template for the specified token.
535 *
536 * Args:
537 * s - Pointer to the curstat_t structure
538 * tok - The token string to look for
539 *
540 * Return:
541 * TRUE - Token is found
542 * FALSE - Token not found
543 */
544 STATIC bool_t
di_chktmpl(curstat_t * s,char * tok)545 di_chktmpl(curstat_t *s, char *tok)
546 {
547 char *p;
548
549 if ((p = util_strstr(s->outf_tmpl, tok)) != NULL) {
550 if (p == s->outf_tmpl) {
551 /* The token is found at the beginning
552 * of the template string.
553 */
554 return TRUE;
555 }
556 else if (p == (s->outf_tmpl + 1)) {
557 if (*(p-1) != '%') {
558 /* The token is found and is not a character
559 * after a "%%" token. This is a special
560 * case check for cases where the token
561 * is 1 character offset into the template
562 * string.
563 */
564 return TRUE;
565 }
566 }
567 else if (*(p-1) != '%' || *(p-2) == '%') {
568 /* The token is found and is not a character after
569 * a "%%" token. This is a "general" check for
570 * tokens that appear at 2 character offset into
571 * the template string or more.
572 */
573 return TRUE;
574 }
575 }
576
577 /* The token is not found in the template string */
578 return FALSE;
579 }
580
581
582 /***********************
583 * public routines *
584 ***********************/
585
586
587 /*
588 * di_init
589 * Top-level function to initialize the libdi modules.
590 *
591 * Args:
592 * s - Pointer to the curstat_t structure
593 *
594 * Return:
595 * Nothing.
596 */
597 void
di_init(di_client_t * clp)598 di_init(di_client_t *clp)
599 {
600 int i;
601 curstat_t *s = clp->curstat_addr();
602
603 di_clinfo = (di_client_t *)(void *) MEM_ALLOC(
604 "di_client_t",
605 sizeof(di_client_t)
606 );
607 if (di_clinfo == NULL) {
608 DI_FATAL(app_data.str_nomemory);
609 return;
610 }
611 (void) memcpy(di_clinfo, clp, sizeof(di_client_t));
612
613 #if defined(DI_SCSIPT) && defined(DEMO_ONLY)
614 /* Hardwire some params for demo mode. This overrides the
615 * parameters from the config files.
616 */
617 app_data.di_method = DI_SCSIPT;
618 app_data.vendor_code = VENDOR_SCSI2;
619 app_data.play10_supp = TRUE;
620 app_data.play12_supp = TRUE;
621 app_data.playmsf_supp = TRUE;
622 app_data.playti_supp = TRUE;
623 app_data.load_supp = TRUE;
624 app_data.eject_supp = TRUE;
625 app_data.msen_dbd = FALSE;
626 app_data.mselvol_supp = TRUE;
627 app_data.balance_supp = TRUE;
628 app_data.chroute_supp = TRUE;
629 app_data.pause_supp = TRUE;
630 app_data.caddylock_supp = TRUE;
631 app_data.curpos_fmt = TRUE;
632 app_data.cdda_scsidensity = 0;
633 app_data.cdda_scsireadcmd = 0; /* MMC Read CD */
634 app_data.cdda_readchkblks = 4; /* Max xfer length of cdsim */
635 app_data.cdda_method = 0; /* None */
636 app_data.cdda_rdmethod = 1; /* SCSI pass-through */
637 app_data.cdda_wrmethod = 8; /* File and pipe only */
638 app_data.cdda_jitter_corr = FALSE;
639 #else
640 /* Sanity check */
641 if (app_data.di_method < 0 || app_data.di_method >= MAX_METHODS) {
642 DI_FATAL(app_data.str_nomethod);
643 return;
644 }
645 #endif
646
647 /* Parse the device list and set up structure */
648 di_parse_devlist();
649
650 /* Check string lengths. This is to avoid subsequent
651 * string buffer overflows.
652 */
653 if (((int) (strlen(app_data.str_notrom) +
654 strlen(app_data.device)) >= ERR_BUF_SZ) ||
655 ((int) (strlen(app_data.str_notscsi2) +
656 strlen(app_data.device)) >= ERR_BUF_SZ) ||
657 ((int) (strlen(app_data.str_staterr) +
658 strlen(app_data.device)) >= ERR_BUF_SZ) ||
659 ((int) (strlen(app_data.str_noderr) +
660 strlen(app_data.device)) >= ERR_BUF_SZ) ||
661 ((int) (strlen(app_data.str_nocfg) + 12 +
662 strlen(app_data.libdir)) >= ERR_BUF_SZ)) {
663 DI_FATAL(app_data.str_longpatherr);
664 return;
665 }
666
667 lockfile[0] = '\0';
668
669 /* Initialize the libdi modules */
670 for (i = 0; i < MAX_METHODS; i++) {
671 if (diinit[i].init != NULL)
672 diinit[i].init(s, &ditbl[i]);
673 }
674
675 /* Sanity check again */
676 if (ditbl[app_data.di_method].methodstr == NULL) {
677 DI_FATAL(app_data.str_nomethod);
678 return;
679 }
680
681 /* Fill in device capabilities bitmask return */
682 clp->capab = (cdda_capab() | CAPAB_PLAYAUDIO);
683 }
684
685
686 /*
687 * di_bitrate_valid
688 * Check if a bitrate is valid.
689 *
690 * Args:
691 * bitrate - The bitrate in kb/s to check
692 *
693 * Returns:
694 * TRUE - valid
695 * FALSE - invalid
696 */
697 bool_t
di_bitrate_valid(int bitrate)698 di_bitrate_valid(int bitrate)
699 {
700 int i,
701 n = cdda_bitrates();
702
703 if (bitrate == 0)
704 return TRUE; /* Special case for "default" bitrate */
705
706 /* Check against list of valid bitrates */
707 for (i = 0; i < n; i++) {
708 int br = cdda_bitrate_val(i);
709
710 if (br >= 32 && br == bitrate)
711 break;
712 }
713 if (i == n)
714 return FALSE;
715
716 return TRUE;
717 }
718
719
720 /*
721 * di_load_cdtext
722 * Read CD-TEXT information from the CD if available, parse the raw
723 * data and fill the di_cdtext_t structure.
724 *
725 * Args:
726 * s - Pointer to the curstat_t structure
727 * t - Pointer to the di_cdtext_t structure
728 *
729 * Return:
730 * Nothing.
731 */
732 void
di_load_cdtext(curstat_t * s,di_cdtext_t * t)733 di_load_cdtext(curstat_t *s, di_cdtext_t *t)
734 {
735 if (ditbl[app_data.di_method].load_cdtext != NULL)
736 ditbl[app_data.di_method].load_cdtext(s, t);
737 else
738 t->cdtext_valid = FALSE;
739 }
740
741
742 /*
743 * di_clear_cdtext
744 * Clear the contents of the CD-TEXT information structure.
745 *
746 * Args:
747 * t - Pointer to the di_cdtext_t structure
748 *
749 * Return:
750 * Nothing.
751 */
752 void
di_clear_cdtext(di_cdtext_t * t)753 di_clear_cdtext(di_cdtext_t *t)
754 {
755 int i;
756
757 t->cdtext_valid = FALSE;
758 if (t->disc.title != NULL) {
759 MEM_FREE(t->disc.title);
760 t->disc.title = NULL;
761 }
762 if (t->disc.performer != NULL) {
763 MEM_FREE(t->disc.performer);
764 t->disc.performer = NULL;
765 }
766 if (t->disc.songwriter != NULL) {
767 MEM_FREE(t->disc.songwriter);
768 t->disc.songwriter = NULL;
769 }
770 if (t->disc.composer != NULL) {
771 MEM_FREE(t->disc.composer);
772 t->disc.composer = NULL;
773 }
774 if (t->disc.arranger != NULL) {
775 MEM_FREE(t->disc.arranger);
776 t->disc.arranger = NULL;
777 }
778 if (t->disc.message != NULL) {
779 MEM_FREE(t->disc.message);
780 t->disc.message = NULL;
781 }
782 if (t->disc.catno != NULL) {
783 MEM_FREE(t->disc.catno);
784 t->disc.catno = NULL;
785 }
786 for (i = 0; i < MAXTRACK; i++) {
787 if (t->track[i].title != NULL) {
788 MEM_FREE(t->track[i].title);
789 t->track[i].title = NULL;
790 }
791 if (t->track[i].performer != NULL) {
792 MEM_FREE(t->track[i].performer);
793 t->track[i].performer = NULL;
794 }
795 if (t->track[i].songwriter != NULL) {
796 MEM_FREE(t->track[i].songwriter);
797 t->track[i].songwriter = NULL;
798 }
799 if (t->track[i].composer != NULL) {
800 MEM_FREE(t->track[i].composer);
801 t->track[i].composer = NULL;
802 }
803 if (t->track[i].arranger != NULL) {
804 MEM_FREE(t->track[i].arranger);
805 t->track[i].arranger = NULL;
806 }
807 if (t->track[i].message != NULL) {
808 MEM_FREE(t->track[i].message);
809 t->track[i].message = NULL;
810 }
811 if (t->track[i].catno != NULL) {
812 MEM_FREE(t->track[i].catno);
813 t->track[i].catno = NULL;
814 }
815 }
816 }
817
818
819 /*
820 * di_playmode
821 * Init/halt the CDDA mode
822 *
823 * Args:
824 * s - Pointer to the curstat_t structure
825 *
826 * Return:
827 * TRUE - success
828 * FALSE - failure
829 */
830 bool_t
di_playmode(curstat_t * s)831 di_playmode(curstat_t *s)
832 {
833 switch (s->mode) {
834 case MOD_STOP:
835 case MOD_NODISC:
836 case MOD_BUSY:
837 break;
838 default:
839 /* Stop playback first before changing mode */
840 di_stop(s, TRUE);
841 break;
842 }
843
844 /* Set clip frames */
845 if (PLAYMODE_IS_STD(app_data.play_mode))
846 di_clip_frames = CLIP_FRAMES;
847 else
848 di_clip_frames = 0;
849
850 if (ditbl[app_data.di_method].playmode != NULL)
851 return (ditbl[app_data.di_method].playmode(s));
852
853 return FALSE;
854 }
855
856
857 /*
858 * di_check_disc
859 * Check if disc is ready for use
860 *
861 * Args:
862 * s - Pointer to the curstat_t structure
863 *
864 * Return:
865 * TRUE - success
866 * FALSE - failure
867 */
868 bool_t
di_check_disc(curstat_t * s)869 di_check_disc(curstat_t *s)
870 {
871 if (ditbl[app_data.di_method].check_disc != NULL)
872 return (ditbl[app_data.di_method].check_disc(s));
873
874 return FALSE;
875 }
876
877
878 /*
879 * di_status_upd
880 * Force update of playback status
881 *
882 * Args:
883 * s - Pointer to the curstat_t structure
884 *
885 * Return:
886 * Nothing.
887 */
888 void
di_status_upd(curstat_t * s)889 di_status_upd(curstat_t *s)
890 {
891 if (ditbl[app_data.di_method].status_upd != NULL)
892 ditbl[app_data.di_method].status_upd(s);
893 }
894
895
896 /*
897 * di_lock
898 * Caddy lock function
899 *
900 * Args:
901 * s - Pointer to the curstat_t structure
902 * enable - whether to enable/disable caddy lock
903 *
904 * Return:
905 * Nothing.
906 */
907 void
di_lock(curstat_t * s,bool_t enable)908 di_lock(curstat_t *s, bool_t enable)
909 {
910 if (ditbl[app_data.di_method].lock != NULL)
911 ditbl[app_data.di_method].lock(s, enable);
912 }
913
914
915 /*
916 * di_repeat
917 * Repeat mode function
918 *
919 * Args:
920 * s - Pointer to the curstat_t structure
921 * enable - whether to enable/disable repeat mode
922 *
923 * Return:
924 * Nothing.
925 */
926 void
di_repeat(curstat_t * s,bool_t enable)927 di_repeat(curstat_t *s, bool_t enable)
928 {
929 if (ditbl[app_data.di_method].repeat != NULL)
930 ditbl[app_data.di_method].repeat(s, enable);
931 }
932
933
934 /*
935 * di_shuffle
936 * Shuffle mode function
937 *
938 * Args:
939 * s - Pointer to the curstat_t structure
940 * enable - whether to enable/disable shuffle mode
941 *
942 * Return:
943 * Nothing.
944 */
945 void
di_shuffle(curstat_t * s,bool_t enable)946 di_shuffle(curstat_t *s, bool_t enable)
947 {
948 if (ditbl[app_data.di_method].shuffle != NULL)
949 ditbl[app_data.di_method].shuffle(s, enable);
950 }
951
952
953 /*
954 * di_load_eject
955 * CD caddy load and eject function. If disc caddy is not
956 * loaded, it will attempt to load it. Otherwise, it will be
957 * ejected.
958 *
959 * Args:
960 * s - Pointer to the curstat_t structure
961 *
962 * Return:
963 * Nothing.
964 */
965 void
di_load_eject(curstat_t * s)966 di_load_eject(curstat_t *s)
967 {
968 if (ditbl[app_data.di_method].load_eject != NULL)
969 ditbl[app_data.di_method].load_eject(s);
970 }
971
972
973 /*
974 * di_ab
975 * A->B segment play mode function
976 *
977 * Args:
978 * s - Pointer to the curstat_t structure
979 *
980 * Return:
981 * Nothing.
982 */
983 void
di_ab(curstat_t * s)984 di_ab(curstat_t *s)
985 {
986 if (ditbl[app_data.di_method].ab != NULL)
987 ditbl[app_data.di_method].ab(s);
988 }
989
990
991 /*
992 * di_sample
993 * Sample play mode function
994 *
995 * Args:
996 * s - Pointer to the curstat_t structure
997 *
998 * Return:
999 * Nothing.
1000 */
1001 void
di_sample(curstat_t * s)1002 di_sample(curstat_t *s)
1003 {
1004 if (ditbl[app_data.di_method].sample != NULL)
1005 ditbl[app_data.di_method].sample(s);
1006 }
1007
1008
1009 /*
1010 * di_level
1011 * Audio volume control function
1012 *
1013 * Args:
1014 * s - Pointer to the curstat_t structure
1015 * level - The volume level to set to
1016 * drag - Whether this is an update due to the user dragging the
1017 * volume control slider thumb. If this is FALSE, then
1018 * a final volume setting has been found.
1019 *
1020 * Return:
1021 * Nothing.
1022 */
1023 void
di_level(curstat_t * s,byte_t level,bool_t drag)1024 di_level(curstat_t *s, byte_t level, bool_t drag)
1025 {
1026 if (ditbl[app_data.di_method].level != NULL)
1027 ditbl[app_data.di_method].level(s, level, drag);
1028 }
1029
1030
1031 /*
1032 * di_play_pause
1033 * Audio playback and pause function
1034 *
1035 * Args:
1036 * s - Pointer to the curstat_t structure
1037 *
1038 * Return:
1039 * Nothing.
1040 */
1041 void
di_play_pause(curstat_t * s)1042 di_play_pause(curstat_t *s)
1043 {
1044 if (ditbl[app_data.di_method].play_pause != NULL)
1045 ditbl[app_data.di_method].play_pause(s);
1046 }
1047
1048
1049 /*
1050 * di_stop
1051 * Stop function
1052 *
1053 * Args:
1054 * s - Pointer to the curstat_t structure
1055 * stop_disc - Whether to actually spin down the disc or just
1056 * update status.
1057 *
1058 * Return:
1059 * Nothing.
1060 */
1061 void
di_stop(curstat_t * s,bool_t stop_disc)1062 di_stop(curstat_t *s, bool_t stop_disc)
1063 {
1064 if (ditbl[app_data.di_method].stop != NULL)
1065 ditbl[app_data.di_method].stop(s, stop_disc);
1066 }
1067
1068
1069 /*
1070 * di_chgdisc
1071 * Change disc function
1072 *
1073 * Args:
1074 * s - Pointer to the curstat_t structure
1075 *
1076 * Return:
1077 * Nothing.
1078 */
1079 void
di_chgdisc(curstat_t * s)1080 di_chgdisc(curstat_t *s)
1081 {
1082 if (ditbl[app_data.di_method].chgdisc != NULL)
1083 ditbl[app_data.di_method].chgdisc(s);
1084 }
1085
1086
1087 /*
1088 * di_prevtrk
1089 * Previous track function
1090 *
1091 * Args:
1092 * s - Pointer to the curstat_t structure
1093 *
1094 * Return:
1095 * Nothing.
1096 */
1097 void
di_prevtrk(curstat_t * s)1098 di_prevtrk(curstat_t *s)
1099 {
1100 if (ditbl[app_data.di_method].prevtrk != NULL)
1101 ditbl[app_data.di_method].prevtrk(s);
1102 }
1103
1104
1105 /*
1106 * di_nexttrk
1107 * Next track function
1108 *
1109 * Args:
1110 * s - Pointer to the curstat_t structure
1111 *
1112 * Return:
1113 * Nothing.
1114 */
1115 void
di_nexttrk(curstat_t * s)1116 di_nexttrk(curstat_t *s)
1117 {
1118 if (ditbl[app_data.di_method].nexttrk != NULL)
1119 ditbl[app_data.di_method].nexttrk(s);
1120 }
1121
1122
1123 /*
1124 * di_previdx
1125 * Previous index function
1126 *
1127 * Args:
1128 * s - Pointer to the curstat_t structure
1129 *
1130 * Return:
1131 * Nothing.
1132 */
1133 void
di_previdx(curstat_t * s)1134 di_previdx(curstat_t *s)
1135 {
1136 if (ditbl[app_data.di_method].previdx != NULL)
1137 ditbl[app_data.di_method].previdx(s);
1138 }
1139
1140
1141 /*
1142 * di_nextidx
1143 * Next index function
1144 *
1145 * Args:
1146 * s - Pointer to the curstat_t structure
1147 *
1148 * Return:
1149 * Nothing.
1150 */
1151 void
di_nextidx(curstat_t * s)1152 di_nextidx(curstat_t *s)
1153 {
1154 if (ditbl[app_data.di_method].nextidx != NULL)
1155 ditbl[app_data.di_method].nextidx(s);
1156 }
1157
1158
1159 /*
1160 * di_rew
1161 * Search-rewind function
1162 *
1163 * Args:
1164 * s - Pointer to the curstat_t structure
1165 *
1166 * Return:
1167 * Nothing.
1168 */
1169 void
di_rew(curstat_t * s,bool_t start)1170 di_rew(curstat_t *s, bool_t start)
1171 {
1172 if (ditbl[app_data.di_method].rew != NULL)
1173 ditbl[app_data.di_method].rew(s, start);
1174 }
1175
1176
1177 /*
1178 * di_ff
1179 * Search-fast-forward function
1180 *
1181 * Args:
1182 * s - Pointer to the curstat_t structure
1183 *
1184 * Return:
1185 * Nothing.
1186 */
1187 void
di_ff(curstat_t * s,bool_t start)1188 di_ff(curstat_t *s, bool_t start)
1189 {
1190 if (ditbl[app_data.di_method].ff != NULL)
1191 ditbl[app_data.di_method].ff(s, start);
1192 }
1193
1194
1195 /*
1196 * di_warp
1197 * Track warp function
1198 *
1199 * Args:
1200 * s - Pointer to the curstat_t structure
1201 *
1202 * Return:
1203 * Nothing.
1204 */
1205 void
di_warp(curstat_t * s)1206 di_warp(curstat_t *s)
1207 {
1208 if (ditbl[app_data.di_method].warp != NULL)
1209 ditbl[app_data.di_method].warp(s);
1210 }
1211
1212
1213 /*
1214 * di_route
1215 * Channel routing function
1216 *
1217 * Args:
1218 * s - Pointer to the curstat_t structure
1219 *
1220 * Return:
1221 * Nothing.
1222 */
1223 void
di_route(curstat_t * s)1224 di_route(curstat_t *s)
1225 {
1226 if (ditbl[app_data.di_method].route != NULL)
1227 ditbl[app_data.di_method].route(s);
1228 }
1229
1230
1231 /*
1232 * di_mute_on
1233 * Mute audio function
1234 *
1235 * Args:
1236 * s - Pointer to the curstat_t structure
1237 *
1238 * Return:
1239 * Nothing.
1240 */
1241 void
di_mute_on(curstat_t * s)1242 di_mute_on(curstat_t *s)
1243 {
1244 if (ditbl[app_data.di_method].mute_on != NULL)
1245 ditbl[app_data.di_method].mute_on(s);
1246 }
1247
1248
1249 /*
1250 * di_mute_off
1251 * Un-mute audio function
1252 *
1253 * Args:
1254 * s - Pointer to the curstat_t structure
1255 *
1256 * Return:
1257 * Nothing.
1258 */
1259 void
di_mute_off(curstat_t * s)1260 di_mute_off(curstat_t *s)
1261 {
1262 if (ditbl[app_data.di_method].mute_off != NULL)
1263 ditbl[app_data.di_method].mute_off(s);
1264 }
1265
1266
1267 /*
1268 * di_cddajitter
1269 * CDDA jitter correction setting change notification function
1270 *
1271 * Args:
1272 * s - Pointer to the curstat_t structure
1273 *
1274 * Return:
1275 * Nothing.
1276 */
1277 void
di_cddajitter(curstat_t * s)1278 di_cddajitter(curstat_t *s)
1279 {
1280 if (ditbl[app_data.di_method].cddajitter != NULL)
1281 ditbl[app_data.di_method].cddajitter(s);
1282 }
1283
1284
1285 /*
1286 * di_debug
1287 * Debug level change notification function
1288 *
1289 * Args:
1290 * None.
1291 *
1292 * Return:
1293 * Nothing.
1294 */
1295 void
di_debug(void)1296 di_debug(void)
1297 {
1298 if (ditbl[app_data.di_method].debug != NULL)
1299 ditbl[app_data.di_method].debug();
1300 }
1301
1302
1303 /*
1304 * di_start
1305 * Start the SCSI pass-through module.
1306 *
1307 * Args:
1308 * s - Pointer to the curstat_t structure
1309 *
1310 * Return:
1311 * Nothing.
1312 */
1313 void
di_start(curstat_t * s)1314 di_start(curstat_t *s)
1315 {
1316 if (app_data.debug & DBG_ALL)
1317 di_prncfg(); /* Print debug information */
1318
1319 if (ditbl[app_data.di_method].start != NULL)
1320 ditbl[app_data.di_method].start(s);
1321 }
1322
1323
1324 /*
1325 * di_icon
1326 * Handler for main window iconification/de-iconification
1327 *
1328 * Args:
1329 * s - Pointer to the curstat_t structure
1330 * iconified - Whether the main window is iconified
1331 *
1332 * Return:
1333 * Nothing.
1334 */
1335 void
di_icon(curstat_t * s,bool_t iconified)1336 di_icon(curstat_t *s, bool_t iconified)
1337 {
1338 if (ditbl[app_data.di_method].icon != NULL)
1339 ditbl[app_data.di_method].icon(s, iconified);
1340 }
1341
1342
1343 /*
1344 * di_halt
1345 * Shut down the SCSI pass-through and vendor-unique modules.
1346 *
1347 * Args:
1348 * s - Pointer to the curstat_t structure
1349 *
1350 * Return:
1351 * Nothing.
1352 */
1353 void
di_halt(curstat_t * s)1354 di_halt(curstat_t *s)
1355 {
1356 if (ditbl[app_data.di_method].halt != NULL)
1357 ditbl[app_data.di_method].halt(s);
1358
1359 di_devunlock(s);
1360 }
1361
1362
1363 /*
1364 * di_dump_curstat
1365 * Display contents of the the curstat_t structure.
1366 *
1367 * Args:
1368 * s - Pointer to the curstat_t structure.
1369 *
1370 * Return:
1371 * Nothing.
1372 */
1373 void
di_dump_curstat(curstat_t * s)1374 di_dump_curstat(curstat_t *s)
1375 {
1376 int i;
1377
1378 (void) fprintf(errfp,
1379 "\nDumping contents of curstat_t structure at 0x%lx:\n",
1380 (unsigned long) s);
1381 (void) fprintf(errfp,
1382 "curdev=%s\nfirst_disc=%d last_disc=%d\n",
1383 s->curdev, s->first_disc, s->last_disc);
1384 (void) fprintf(errfp,
1385 "cur_disc=%d prev_disc=%d\n",
1386 s->cur_disc, s->prev_disc);
1387 (void) fprintf(errfp,
1388 "mode=%d time_dpy=%d flags=0x%x\n",
1389 s->mode, s->time_dpy, s->flags);
1390 (void) fprintf(errfp,
1391 "first_trk=%d last_trk=%d tot_trks=%d mcn=\"%s\"\n",
1392 s->first_trk, s->last_trk, s->tot_trks, s->mcn);
1393 (void) fprintf(errfp, "cur_trk=%d cur_idx=%d\n",
1394 s->cur_trk, s->cur_idx);
1395 (void) fprintf(errfp,
1396 "discpos_tot.msf=%02u:%02u:%02u discpos_tot.addr=0x%x\n",
1397 s->discpos_tot.min, s->discpos_tot.sec,
1398 s->discpos_tot.frame, s->discpos_tot.addr);
1399 (void) fprintf(errfp,
1400 "curpos_tot.msf=%02u:%02u:%02u curpos_tot.addr=0x%x\n",
1401 s->curpos_tot.min, s->curpos_tot.sec,
1402 s->curpos_tot.frame, s->curpos_tot.addr);
1403 (void) fprintf(errfp,
1404 "curpos_trk.msf=%02u:%02u:%02u curpos_trk.addr=0x%x\n",
1405 s->curpos_tot.min, s->curpos_tot.sec,
1406 s->curpos_tot.frame, s->curpos_tot.addr);
1407
1408 for (i = 0; i < MAXTRACK; i++) {
1409 (void) fprintf(errfp,
1410 "[%2d] trkno=%03d addr=%06d (0x%05x) "
1411 "msf=%02d:%02d:%02d type=%d isrc=\"%s\"\n",
1412 i, s->trkinfo[i].trkno,
1413 s->trkinfo[i].addr, s->trkinfo[i].addr,
1414 s->trkinfo[i].min, s->trkinfo[i].sec,
1415 s->trkinfo[i].frame, s->trkinfo[i].type,
1416 s->trkinfo[i].isrc);
1417 if (s->trkinfo[i].trkno == LEAD_OUT_TRACK)
1418 break;
1419 }
1420
1421 (void) fprintf(errfp, "playorder=");
1422 for (i = 0; i < (int) s->prog_tot; i++)
1423 (void) fprintf(errfp, "%d ",
1424 s->trkinfo[s->trkinfo[i].playorder].trkno);
1425 (void) fprintf(errfp, "\n");
1426
1427 (void) fprintf(errfp,
1428 "sav_iaddr=0x%x rptcnt=%d repeat=%d shuffle=%d program=%d\n",
1429 s->sav_iaddr, s->rptcnt, s->repeat, s->shuffle, s->program);
1430 (void) fprintf(errfp,
1431 "onetrk_prog=%d caddy_lk=%d prog_tot=%d prog_cnt=%d\n",
1432 s->onetrk_prog, s->caddy_lock,
1433 s->prog_tot, s->prog_cnt);
1434 (void) fprintf(errfp,
1435 "chgrscan=%d level=%d "
1436 "level_left=%d level_right=%d cdda_att=%d\n",
1437 s->chgrscan, s->level, s->level_left, s->level_right,
1438 s->cdda_att);
1439 (void) fprintf(errfp,
1440 "vendor=\"%-8s\" prod=\"%-16s\" revnum=\"%-4s\"\n",
1441 s->vendor, s->prod, s->revnum);
1442 (void) fprintf(errfp, "outf_tmpl=%s\n",
1443 s->outf_tmpl == NULL ? "NULL" : s->outf_tmpl);
1444 }
1445
1446
1447 /*
1448 * di_common_parmload
1449 * Load the common configuration file and initialize parameters.
1450 *
1451 * Args:
1452 * path - Path name to the file to load.
1453 * priv - Whether the privileged keywords are to be recognized.
1454 * reload - This is a reload operation
1455 *
1456 * Return:
1457 * Nothing.
1458 */
1459 void
di_common_parmload(char * path,bool_t priv,bool_t reload)1460 di_common_parmload(char *path, bool_t priv, bool_t reload)
1461 {
1462 FILE *fp;
1463 char *buf,
1464 *parm,
1465 errstr[ERR_BUF_SZ],
1466 trypath[FILE_PATH_SZ];
1467 struct utsname *un;
1468 bool_t notry2;
1469 static bool_t force_debug;
1470 #ifndef __VMS
1471 pid_t cpid;
1472 waitret_t wstat;
1473 int ret,
1474 pfd[2];
1475
1476 un = util_get_uname();
1477
1478 if (priv && di_isdemo())
1479 app_data.device = "(sim1)";
1480
1481 if (PIPE(pfd) < 0) {
1482 DBGPRN(DBG_GEN)(errfp,
1483 "di_common_parmload: pipe failed (errno=%d)\n",
1484 errno);
1485 if (priv && !di_isdemo()) {
1486 (void) sprintf(errstr, app_data.str_nocfg, path);
1487 DI_FATAL(errstr);
1488 }
1489 return;
1490 }
1491
1492 switch (cpid = FORK()) {
1493 case 0:
1494 /* Child */
1495
1496 /* Close un-needed pipe descriptor */
1497 (void) close(pfd[0]);
1498
1499 /* Force uid and gid to original setting */
1500 if (!util_set_ougid()) {
1501 (void) close(pfd[1]);
1502 _exit(1);
1503 }
1504
1505 notry2 = FALSE;
1506 if (((int) strlen(path) + (int) strlen(un->nodename) + 2)
1507 > FILE_PATH_SZ) {
1508 DBGPRN(DBG_GEN)(errfp, "NOTICE: %s: %s\n",
1509 "Host-specific config files not used",
1510 "Name too long");
1511 (void) strcpy(trypath, path);
1512 notry2 = TRUE;
1513 }
1514 else
1515 /* Try host-specific config file first */
1516 (void) sprintf(trypath, "%s-%s", path, un->nodename);
1517
1518 DBGPRN(DBG_GEN)(errfp,
1519 "Loading common parameters: %s\n", trypath);
1520 fp = fopen(trypath, "r");
1521
1522 if (fp == NULL && !notry2) {
1523 DBGPRN(DBG_GEN)(errfp, " Cannot open %s\n",
1524 trypath);
1525
1526 /* Try generic config file */
1527 (void) strcpy(trypath, path);
1528
1529 DBGPRN(DBG_GEN)(errfp,
1530 "Loading common parameters: %s\n",
1531 trypath);
1532 fp = fopen(trypath, "r");
1533 }
1534
1535 if (fp == NULL) {
1536 DBGPRN(DBG_GEN)(errfp, " Cannot open %s\n",
1537 trypath);
1538 (void) close(pfd[1]);
1539
1540 if (priv && !di_isdemo())
1541 _exit(3);
1542 _exit(0);
1543 }
1544
1545 /* Allocate temporary buffer */
1546 if ((buf = (char *) MEM_ALLOC("buf", PARM_BUF_SZ)) == NULL) {
1547 (void) close(pfd[1]);
1548 (void) fclose(fp);
1549 _exit(2);
1550 }
1551
1552 while (fgets(buf, PARM_BUF_SZ, fp) != NULL) {
1553 /* Skip comments and blank lines */
1554 if (buf[0] == '#' || buf[0] == '!' || buf[0] == '\n')
1555 continue;
1556 (void) write(pfd[1], buf, strlen(buf));
1557 }
1558 (void) write(pfd[1], ".\n", 2);
1559
1560 (void) close(pfd[1]);
1561 (void) fclose(fp);
1562
1563 MEM_FREE(buf);
1564 _exit(0);
1565 /*NOTREACHED*/
1566
1567 case -1:
1568 DBGPRN(DBG_GEN)(errfp,
1569 "di_common_parmload: fork failed (errno=%d)\n",
1570 errno);
1571 (void) close(pfd[0]);
1572 (void) close(pfd[1]);
1573
1574 if (priv && !di_isdemo()) {
1575 (void) sprintf(errstr, app_data.str_nocfg, path);
1576 DI_FATAL(errstr);
1577 }
1578 return;
1579
1580 default:
1581 /* Parent */
1582
1583 /* Close un-needed pipe descriptor */
1584 (void) close(pfd[1]);
1585
1586 if ((fp = fdopen(pfd[0], "r")) == NULL) {
1587 DBGPRN(DBG_GEN)(errfp,
1588 "di_common_parmload: read pipe fdopen failed\n");
1589 if (priv && !di_isdemo()) {
1590 /* Cannot open pipe */
1591 (void) sprintf(errstr, app_data.str_nocfg,
1592 path);
1593 DI_FATAL(errstr);
1594 }
1595 return;
1596 }
1597 break;
1598 }
1599 #else
1600 un = util_get_uname();
1601
1602 notry2 = FALSE;
1603 if (((int) strlen(path) + (int) strlen(un->nodename) + 2)
1604 > FILE_PATH_SZ) {
1605 DBGPRN(DBG_GEN)(errfp, "NOTICE: %s: %s\n",
1606 "Host-specific config files not used",
1607 "Name too long");
1608 (void) strcpy(trypath, path);
1609 notry2 = TRUE;
1610 }
1611 else
1612 /* Try host-specific config file first */
1613 (void) sprintf(trypath, "%s-%s", path, un->nodename);
1614
1615 DBGPRN(DBG_GEN)(errfp, "Loading common parameters: %s\n", trypath);
1616 fp = fopen(trypath, "r");
1617
1618 if (fp == NULL && !notry2) {
1619 DBGPRN(DBG_GEN)(errfp, " Cannot open %s\n", trypath);
1620
1621 /* Try generic config file */
1622 (void) strcpy(trypath, path);
1623
1624 DBGPRN(DBG_GEN)(errfp,
1625 "Loading common parameters: %s\n", trypath);
1626 fp = fopen(trypath, "r");
1627 }
1628
1629 if (fp == NULL) {
1630 DBGPRN(DBG_GEN)(errfp, " Cannot open %s\n", trypath);
1631 if (priv && !di_isdemo()) {
1632 /* Cannot open system config file. */
1633 (void) sprintf(errstr, app_data.str_nocfg, path);
1634 DI_FATAL(errstr);
1635 }
1636 return;
1637 }
1638 #endif /* __VMS */
1639
1640 /* Allocate temporary buffer */
1641 buf = (char *) MEM_ALLOC("buf", PARM_BUF_SZ);
1642 parm = (char *) MEM_ALLOC("parmbuf", PARM_BUF_SZ);
1643 if (buf == NULL || parm == NULL) {
1644 DI_FATAL(app_data.str_nomemory);
1645 return;
1646 }
1647
1648 if ((priv && (app_data.debug & DBG_ALL) != 0) || reload)
1649 force_debug = TRUE;
1650 else
1651 force_debug = FALSE;
1652
1653 /* Read in common parameters */
1654 while (fgets(buf, PARM_BUF_SZ, fp) != NULL) {
1655 /* Skip comments and blank lines */
1656 if (buf[0] == '#' || buf[0] == '!' || buf[0] == '\n')
1657 continue;
1658
1659 /* Done */
1660 if (buf[0] == '.' && buf[1] == '\n')
1661 break;
1662
1663 if (priv && sscanf(buf, "device: %[^\n]\n", parm) > 0) {
1664 if (di_isdemo())
1665 continue;
1666
1667 /* If app_data.device is not NULL, then it means
1668 * the user had specified a device on the command
1669 * line, and that should take precedence.
1670 */
1671 if (app_data.device == NULL &&
1672 !util_newstr(&app_data.device, parm)) {
1673 DI_FATAL(app_data.str_nomemory);
1674 return;
1675 }
1676 continue;
1677 }
1678 if (sscanf(buf, "outputPort: %s\n", parm) > 0) {
1679 app_data.outport = (word32_t) atoi(parm);
1680 continue;
1681 }
1682 if (sscanf(buf, "cdinfoPath: %[^\n]\n", parm) > 0) {
1683 if (strcmp(parm, "-") == 0)
1684 parm[0] = '\0';
1685 if (!util_newstr(&app_data.cdinfo_path, parm)) {
1686 DI_FATAL(app_data.str_nomemory);
1687 return;
1688 }
1689 continue;
1690 }
1691 if (sscanf(buf, "charsetConvMode: %s\n", parm) > 0) {
1692 app_data.chset_xlat = atoi(parm);
1693 continue;
1694 }
1695 if (sscanf(buf, "langUtf8: %[^\n]\n", parm) > 0) {
1696 if (strcmp(parm, "-") == 0)
1697 parm[0] = '\0';
1698 if (!util_newstr(&app_data.lang_utf8, parm)) {
1699 DI_FATAL(app_data.str_nomemory);
1700 return;
1701 }
1702 continue;
1703 }
1704 if (sscanf(buf, "acceptFuzzyDefault: %s\n", parm) > 0) {
1705 app_data.single_fuzzy = util_stob(parm);
1706 continue;
1707 }
1708 if (sscanf(buf, "proxyServer: %[^\n]\n", parm) > 0) {
1709 if (strcmp(parm, "-") == 0)
1710 parm[0] = '\0';
1711 if (!util_newstr(&app_data.proxy_server, parm)) {
1712 DI_FATAL(app_data.str_nomemory);
1713 return;
1714 }
1715 continue;
1716 }
1717 if (sscanf(buf, "cddbCacheTimeout: %s\n", parm) > 0) {
1718 app_data.cache_timeout = atoi(parm);
1719 continue;
1720 }
1721 if (sscanf(buf, "serviceTimeout: %s\n", parm) > 0) {
1722 app_data.srv_timeout = atoi(parm);
1723 continue;
1724 }
1725 if (sscanf(buf, "localDiscographyMode: %s\n", parm) > 0) {
1726 app_data.discog_mode = atoi(parm);
1727 continue;
1728 }
1729 if (sscanf(buf, "maximumHistory: %s\n", parm) > 0) {
1730 app_data.cdinfo_maxhist = atoi(parm);
1731 continue;
1732 }
1733 if (sscanf(buf, "internetOffline: %s\n", parm) > 0) {
1734 app_data.cdinfo_inetoffln = util_stob(parm);
1735 continue;
1736 }
1737 if (sscanf(buf, "cddbUseProxy: %s\n", parm) > 0) {
1738 app_data.use_proxy = util_stob(parm);
1739 continue;
1740 }
1741 if (sscanf(buf, "proxyAuthorization: %s\n", parm) > 0) {
1742 app_data.proxy_auth = util_stob(parm);
1743 continue;
1744 }
1745 if (sscanf(buf, "autoMusicBrowser: %s\n", parm) > 0) {
1746 app_data.auto_musicbrowser = util_stob(parm);
1747 continue;
1748 }
1749 if (sscanf(buf, "cdinfoFileMode: %s\n", parm) > 0) {
1750 if (!util_newstr(&app_data.cdinfo_filemode, parm)) {
1751 DI_FATAL(app_data.str_nomemory);
1752 return;
1753 }
1754 continue;
1755 }
1756 if (sscanf(buf, "historyFileMode: %s\n", parm) > 0) {
1757 if (!util_newstr(&app_data.hist_filemode, parm)) {
1758 DI_FATAL(app_data.str_nomemory);
1759 return;
1760 }
1761 continue;
1762 }
1763 if (sscanf(buf, "statusPollInterval: %s\n", parm) > 0) {
1764 app_data.stat_interval = atoi(parm);
1765 continue;
1766 }
1767 if (sscanf(buf, "insertPollInterval: %s\n", parm) > 0) {
1768 app_data.ins_interval = atoi(parm);
1769 continue;
1770 }
1771 if (sscanf(buf, "insertPollDisable: %s\n", parm) > 0) {
1772 app_data.ins_disable = util_stob(parm);
1773 continue;
1774 }
1775 if (sscanf(buf, "previousThreshold: %s\n", parm) > 0) {
1776 app_data.prev_threshold = atoi(parm);
1777 continue;
1778 }
1779 if (sscanf(buf, "sampleBlocks: %s\n", parm) > 0) {
1780 app_data.sample_blks = atoi(parm);
1781 continue;
1782 }
1783 if (sscanf(buf, "timeDisplayMode: %s\n", parm) > 0) {
1784 app_data.timedpy_mode = atoi(parm);
1785 continue;
1786 }
1787 if (sscanf(buf, "solaris2VolumeManager: %s\n", parm) > 0) {
1788 app_data.sol2_volmgt = util_stob(parm);
1789 continue;
1790 }
1791 if (sscanf(buf, "showScsiErrMsg: %s\n", parm) > 0) {
1792 app_data.scsierr_msg = util_stob(parm);
1793 continue;
1794 }
1795 if (sscanf(buf, "curfileEnable: %s\n", parm) > 0) {
1796 app_data.write_curfile = util_stob(parm);
1797 continue;
1798 }
1799 if (sscanf(buf, "tooltipEnable: %s\n", parm) > 0) {
1800 app_data.tooltip_enable = util_stob(parm);
1801 continue;
1802 }
1803 if (sscanf(buf, "tooltipDelayInterval: %s\n", parm) > 0) {
1804 app_data.tooltip_delay = atoi(parm);
1805 continue;
1806 }
1807 if (sscanf(buf, "tooltipActiveInterval: %s\n", parm) > 0) {
1808 app_data.tooltip_time = atoi(parm);
1809 continue;
1810 }
1811 if (sscanf(buf, "historyFileDisable: %s\n", parm) > 0) {
1812 app_data.histfile_dsbl = util_stob(parm);
1813 continue;
1814 }
1815 if (sscanf(buf, "remoteControlEnable: %s\n", parm) > 0) {
1816 app_data.remote_enb = util_stob(parm);
1817 continue;
1818 }
1819 if (sscanf(buf, "remoteControlLog: %s\n", parm) > 0) {
1820 app_data.remote_log = util_stob(parm);
1821 continue;
1822 }
1823 if (sscanf(buf, "cddaFilePerTrack: %s\n", parm) > 0) {
1824 app_data.cdda_trkfile = util_stob(parm);
1825 continue;
1826 }
1827 if (sscanf(buf, "cddaSpaceToUnderscore: %s\n", parm) > 0) {
1828 app_data.subst_underscore = util_stob(parm);
1829 continue;
1830 }
1831 if (sscanf(buf, "cddaFileFormat: %s\n", parm) > 0) {
1832 app_data.cdda_filefmt = atoi(parm);
1833 continue;
1834 }
1835 if (sscanf(buf, "cddaFileTemplate: %[^\n]\n", parm) > 0) {
1836 if (strcmp(parm, "-") == 0)
1837 parm[0] = '\0';
1838 if (!util_newstr(&app_data.cdda_tmpl, parm)) {
1839 DI_FATAL(app_data.str_nomemory);
1840 return;
1841 }
1842 continue;
1843 }
1844 if (sscanf(buf, "cddaPipeProgram: %[^\n]\n", parm) > 0) {
1845 if (strcmp(parm, "-") == 0)
1846 parm[0] = '\0';
1847 if (!util_newstr(&app_data.pipeprog, parm)) {
1848 DI_FATAL(app_data.str_nomemory);
1849 return;
1850 }
1851 continue;
1852 }
1853 if (sscanf(buf, "cddaSchedOptions: %s\n", parm) > 0) {
1854 app_data.cdda_sched = atoi(parm);
1855 continue;
1856 }
1857 if (sscanf(buf, "cddaHeartbeatTimeout: %s\n", parm) > 0) {
1858 app_data.hb_timeout = atoi(parm);
1859 continue;
1860 }
1861 if (sscanf(buf, "compressionMode: %s\n", parm) > 0) {
1862 app_data.comp_mode = atoi(parm);
1863 continue;
1864 }
1865 if (sscanf(buf, "compressionBitrate: %s\n", parm) > 0) {
1866 app_data.bitrate = atoi(parm);
1867 continue;
1868 }
1869 if (sscanf(buf, "minimumBitrate: %s\n", parm) > 0) {
1870 app_data.bitrate_min = atoi(parm);
1871 continue;
1872 }
1873 if (sscanf(buf, "maximumBitrate: %s\n", parm) > 0) {
1874 app_data.bitrate_max = atoi(parm);
1875 continue;
1876 }
1877 if (sscanf(buf, "compressionQuality: %s\n", parm) > 0) {
1878 app_data.qual_factor = atoi(parm);
1879 continue;
1880 }
1881 if (sscanf(buf, "channelMode: %s\n", parm) > 0) {
1882 app_data.chan_mode = atoi(parm);
1883 continue;
1884 }
1885 if (sscanf(buf, "compressionAlgorithm: %s\n", parm) > 0) {
1886 app_data.comp_algo = atoi(parm);
1887 continue;
1888 }
1889 if (sscanf(buf, "lowpassMode: %s\n", parm) > 0) {
1890 app_data.lowpass_mode = atoi(parm);
1891 continue;
1892 }
1893 if (sscanf(buf, "lowpassFrequency: %s\n", parm) > 0) {
1894 app_data.lowpass_freq = atoi(parm);
1895 continue;
1896 }
1897 if (sscanf(buf, "lowpassWidth: %s\n", parm) > 0) {
1898 app_data.lowpass_width = atoi(parm);
1899 continue;
1900 }
1901 if (sscanf(buf, "highpassMode: %s\n", parm) > 0) {
1902 app_data.highpass_mode = atoi(parm);
1903 continue;
1904 }
1905 if (sscanf(buf, "highpassFrequency: %s\n", parm) > 0) {
1906 app_data.highpass_freq = atoi(parm);
1907 continue;
1908 }
1909 if (sscanf(buf, "highpassWidth: %s\n", parm) > 0) {
1910 app_data.highpass_width = atoi(parm);
1911 continue;
1912 }
1913 if (sscanf(buf, "copyrightFlag: %s\n", parm) > 0) {
1914 app_data.copyright = util_stob(parm);
1915 continue;
1916 }
1917 if (sscanf(buf, "originalFlag: %s\n", parm) > 0) {
1918 app_data.original = util_stob(parm);
1919 continue;
1920 }
1921 if (sscanf(buf, "noBitReservoirFlag: %s\n", parm) > 0) {
1922 app_data.nores = util_stob(parm);
1923 continue;
1924 }
1925 if (sscanf(buf, "checksumFlag: %s\n", parm) > 0) {
1926 app_data.checksum = util_stob(parm);
1927 continue;
1928 }
1929 if (sscanf(buf, "strictISO: %s\n", parm) > 0) {
1930 app_data.strict_iso = util_stob(parm);
1931 continue;
1932 }
1933 if (sscanf(buf, "lameOptionsMode: %s\n", parm) > 0) {
1934 app_data.lameopts_mode = atoi(parm);
1935 continue;
1936 }
1937 if (sscanf(buf, "lameOptions: %[^\n]\n", parm) > 0) {
1938 if (strcmp(parm, "-") == 0)
1939 parm[0] = '\0';
1940 if (!util_newstr(&app_data.lame_opts, parm)) {
1941 DI_FATAL(app_data.str_nomemory);
1942 return;
1943 }
1944 continue;
1945 }
1946 if (sscanf(buf, "addInfoTag: %s\n", parm) > 0) {
1947 app_data.add_tag = util_stob(parm);
1948 continue;
1949 }
1950 if (sscanf(buf, "id3TagMode: %s\n", parm) > 0) {
1951 app_data.id3tag_mode = atoi(parm);
1952 continue;
1953 }
1954 if (sscanf(buf, "spinDownOnLoad: %s\n", parm) > 0) {
1955 app_data.load_spindown = util_stob(parm);
1956 continue;
1957 }
1958 if (sscanf(buf, "playOnLoad: %s\n", parm) > 0) {
1959 app_data.load_play = util_stob(parm);
1960 continue;
1961 }
1962 if (sscanf(buf, "ejectOnDone: %s\n", parm) > 0) {
1963 app_data.done_eject = util_stob(parm);
1964 continue;
1965 }
1966 if (sscanf(buf, "exitOnDone: %s\n", parm) > 0) {
1967 app_data.done_exit = util_stob(parm);
1968 continue;
1969 }
1970 if (sscanf(buf, "ejectOnExit: %s\n", parm) > 0) {
1971 app_data.exit_eject = util_stob(parm);
1972 continue;
1973 }
1974 if (sscanf(buf, "stopOnExit: %s\n", parm) > 0) {
1975 app_data.exit_stop = util_stob(parm);
1976 continue;
1977 }
1978 if (sscanf(buf, "exitOnEject: %s\n", parm) > 0) {
1979 app_data.eject_exit = util_stob(parm);
1980 continue;
1981 }
1982 if (sscanf(buf, "repeatMode: %s\n", parm) > 0) {
1983 app_data.repeat_mode = util_stob(parm);
1984 continue;
1985 }
1986 if (sscanf(buf, "shuffleMode: %s\n", parm) > 0) {
1987 app_data.shuffle_mode = util_stob(parm);
1988 continue;
1989 }
1990 if (sscanf(buf, "discogURLPrefix: %[^\n]\n", parm) > 0) {
1991 if (strcmp(parm, "-") == 0)
1992 parm[0] = '\0';
1993 if (!util_newstr(&app_data.discog_url_pfx, parm)) {
1994 DI_FATAL(app_data.str_nomemory);
1995 return;
1996 }
1997 continue;
1998 }
1999 if (sscanf(buf, "autoMotdDisable: %s\n", parm) > 0) {
2000 app_data.automotd_dsbl = util_stob(parm);
2001 continue;
2002 }
2003 if (sscanf(buf, "debugLevel: %s\n", parm) > 0) {
2004 if (!force_debug)
2005 app_data.debug = (word32_t) atoi(parm);
2006 continue;
2007 }
2008 if (sscanf(buf, "excludeWords: %[^\n]\n", parm) > 0) {
2009 if (strcmp(parm, "-") == 0)
2010 parm[0] = '\0';
2011 if (!util_newstr(&app_data.exclude_words, parm)) {
2012 DI_FATAL(app_data.str_nomemory);
2013 return;
2014 }
2015 continue;
2016 }
2017 }
2018
2019 MEM_FREE(buf);
2020 MEM_FREE(parm);
2021
2022 (void) fclose(fp);
2023
2024 /* In case of error */
2025 if (app_data.device == NULL || app_data.device[0] == '\0')
2026 app_data.device = "/dev/cdrom";
2027 if (app_data.lang_utf8 == NULL || app_data.lang_utf8[0] == '\0')
2028 app_data.lang_utf8 = "UTF-8";
2029 if (app_data.timedpy_mode < 0 ||
2030 app_data.timedpy_mode >= TIMEDPY_MAX_MODES)
2031 app_data.timedpy_mode = 0;
2032 if (app_data.tooltip_delay < 0)
2033 app_data.tooltip_delay = 1000;
2034 if (app_data.tooltip_time < 0)
2035 app_data.tooltip_delay = 3000;
2036 if (app_data.stat_interval <= 0)
2037 app_data.stat_interval = 260;
2038 if (app_data.cdinfo_maxhist < 0)
2039 app_data.cdinfo_maxhist = 0;
2040 if (app_data.cache_timeout <= 0)
2041 app_data.cache_timeout = DEF_CACHE_TIMEOUT;
2042 if (app_data.srv_timeout <= 0)
2043 app_data.srv_timeout = DEF_SRV_TIMEOUT;
2044 if (app_data.cdda_filefmt < 0 || app_data.cdda_filefmt >= MAX_FILEFMTS)
2045 app_data.cdda_filefmt = FILEFMT_RAW;
2046 if (app_data.comp_mode < 0 || app_data.comp_mode > 3)
2047 app_data.comp_mode = 0;
2048 if (app_data.qual_factor < 1 || app_data.qual_factor > 10)
2049 app_data.qual_factor = 3;
2050 if (app_data.chan_mode < 0 || app_data.chan_mode > 3)
2051 app_data.chan_mode = 0;
2052 if (app_data.comp_algo < 1 || app_data.comp_algo > 10)
2053 app_data.comp_algo = 4;
2054 if (app_data.lowpass_mode < 0 || app_data.lowpass_mode > 2)
2055 app_data.lowpass_mode = 0;
2056 if (app_data.highpass_mode < 0 || app_data.highpass_mode > 2)
2057 app_data.highpass_mode = 0;
2058 if (app_data.lowpass_freq < MIN_LOWPASS_FREQ ||
2059 app_data.lowpass_freq > MAX_LOWPASS_FREQ)
2060 app_data.lowpass_freq = MAX_LOWPASS_FREQ;
2061 if (app_data.lowpass_width < 0)
2062 app_data.lowpass_width = 0;
2063 if (app_data.highpass_freq < MIN_HIGHPASS_FREQ ||
2064 app_data.highpass_freq > MAX_HIGHPASS_FREQ)
2065 app_data.highpass_freq = MIN_HIGHPASS_FREQ;
2066 if (app_data.highpass_width < 0)
2067 app_data.highpass_width = 0;
2068 if (app_data.lameopts_mode < 0 || app_data.lameopts_mode > 3)
2069 app_data.lameopts_mode = 0;
2070 if (app_data.id3tag_mode < 1 || app_data.id3tag_mode > 3)
2071 app_data.id3tag_mode = 3;
2072
2073 if (app_data.cdda_sched < 0 || app_data.cdda_sched > 3)
2074 app_data.cdda_sched = 0;
2075 if (app_data.hb_timeout < MIN_HB_TIMEOUT)
2076 app_data.hb_timeout = DEF_HB_TIMEOUT;
2077
2078 /* playOnLoad overrides spinDownOnLoad */
2079 if (app_data.load_play)
2080 app_data.load_spindown = FALSE;
2081
2082 /* Check validity of bitrates */
2083 if (!di_bitrate_valid(app_data.bitrate))
2084 app_data.bitrate = 0;
2085 if (!di_bitrate_valid(app_data.bitrate_min))
2086 app_data.bitrate_min = 0;
2087 if (!di_bitrate_valid(app_data.bitrate_max))
2088 app_data.bitrate_min = 0;
2089 if (app_data.bitrate_min > 0 && app_data.bitrate > 0 &&
2090 (app_data.bitrate_min > app_data.bitrate ||
2091 app_data.bitrate_min > app_data.bitrate_max))
2092 app_data.bitrate_min = 0;
2093 if (app_data.bitrate_max > 0 && app_data.bitrate > 0 &&
2094 (app_data.bitrate_max < app_data.bitrate ||
2095 app_data.bitrate_max < app_data.bitrate_min))
2096 app_data.bitrate_min = 0;
2097
2098 #ifdef __VMS
2099 /* Force space/tab substitution to underscores on VMS */
2100 app_data.subst_underscore = TRUE;
2101 #else
2102 /* Wait for child to exit */
2103 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
2104 NULL, 0, FALSE, &wstat);
2105 if (ret < 0) {
2106 DBGPRN(DBG_GEN)(errfp, "di_common_parmload: "
2107 "waitpid failed (errno=%d)\n", errno);
2108 }
2109 else if (WIFEXITED(wstat)) {
2110 if (WEXITSTATUS(wstat) != 0) {
2111 DBGPRN(DBG_GEN)(errfp, "di_common_parmload: "
2112 "child exited (status=%d)\n",
2113 WEXITSTATUS(wstat));
2114 (void) sprintf(errstr, app_data.str_nocfg, path);
2115 if (priv && !di_isdemo()) {
2116 DI_FATAL(errstr);
2117 }
2118 else {
2119 DI_WARNING(errstr);
2120 }
2121 }
2122 }
2123 else if (WIFSIGNALED(wstat)) {
2124 DBGPRN(DBG_GEN)(errfp, "di_common_parmload: "
2125 "child killed (signal=%d)\n",
2126 WTERMSIG(wstat));
2127 (void) sprintf(errstr, app_data.str_nocfg, path);
2128 if (priv && !di_isdemo()) {
2129 DI_FATAL(errstr);
2130 }
2131 else {
2132 DI_WARNING(errstr);
2133 }
2134 }
2135 #endif
2136 }
2137
2138
2139 /*
2140 * di_devspec_parmload
2141 * Load the specified device-specific configuration file and
2142 * initialize parameters.
2143 *
2144 * Args:
2145 * path - Path name to the file to load.
2146 * priv - Whether the privileged keywords are to be recognized.
2147 * reload - This is a reload operation.
2148 *
2149 * Return:
2150 * Nothing.
2151 */
2152 /*ARGSUSED*/
2153 void
di_devspec_parmload(char * path,bool_t priv,bool_t reload)2154 di_devspec_parmload(char *path, bool_t priv, bool_t reload)
2155 {
2156 FILE *fp;
2157 char *buf,
2158 *parm,
2159 errstr[ERR_BUF_SZ],
2160 trypath[FILE_PATH_SZ];
2161 struct utsname *un;
2162 curstat_t *s = NULL;
2163 bool_t notry2;
2164 #ifndef __VMS
2165 pid_t cpid;
2166 waitret_t wstat;
2167 int ret,
2168 pfd[2];
2169
2170 un = util_get_uname();
2171
2172 if (di_clinfo != NULL)
2173 s = di_clinfo->curstat_addr();
2174
2175 if (priv && di_isdemo()) {
2176 char *cp;
2177
2178 cp = "(sim1);(sim2);(sim3);(sim4);(sim5);(sim6);(sim7);(sim8)";
2179 if (!util_newstr(&app_data.devlist, cp)) {
2180 DI_FATAL(app_data.str_nomemory);
2181 return;
2182 }
2183 app_data.numdiscs = 8;
2184 app_data.chg_method = CHG_SCSI_LUN;
2185 app_data.multi_play = TRUE;
2186 }
2187
2188 if (PIPE(pfd) < 0) {
2189 DBGPRN(DBG_GEN)(errfp,
2190 "di_devspec_parmload: pipe failed (errno=%d)\n",
2191 errno);
2192 if (priv && !di_isdemo()) {
2193 (void) sprintf(errstr, app_data.str_nocfg, path);
2194 DI_FATAL(errstr);
2195 }
2196 return;
2197 }
2198
2199 switch (cpid = FORK()) {
2200 case 0:
2201 /* Child */
2202
2203 /* Close un-needed pipe descriptor */
2204 (void) close(pfd[0]);
2205
2206 /* Force uid and gid to original setting */
2207 if (!util_set_ougid()) {
2208 (void) close(pfd[1]);
2209 _exit(1);
2210 }
2211
2212 notry2 = FALSE;
2213 if (((int) strlen(path) + (int) strlen(un->nodename) + 2)
2214 > FILE_PATH_SZ) {
2215 DBGPRN(DBG_GEN)(errfp, "NOTICE: %s: %s\n",
2216 "Host-specific config files not used",
2217 "Name too long");
2218 (void) strcpy(trypath, path);
2219 notry2 = TRUE;
2220 }
2221 else
2222 /* Try host-specific config file first */
2223 (void) sprintf(trypath, "%s-%s", path, un->nodename);
2224
2225 DBGPRN(DBG_GEN)(errfp,
2226 "Loading device-specific parameters: %s\n", trypath);
2227
2228 fp = fopen(trypath, "r");
2229
2230 if (fp == NULL && !notry2) {
2231 DBGPRN(DBG_GEN)(errfp, " Cannot open %s\n",
2232 trypath);
2233
2234 /* Try generic config file */
2235 (void) strcpy(trypath, path);
2236
2237 DBGPRN(DBG_GEN)(errfp,
2238 "Loading device-specific parameters: %s\n",
2239 trypath);
2240 fp = fopen(trypath, "r");
2241 }
2242
2243 if (fp == NULL) {
2244 DBGPRN(DBG_GEN)(errfp, " Cannot open %s\n",
2245 trypath);
2246 (void) close(pfd[1]);
2247
2248 if (priv && !di_isdemo())
2249 _exit(3);
2250 _exit(0);
2251 }
2252
2253 /* Allocate temporary buffer */
2254 if ((buf = (char *) MEM_ALLOC("buf", PARM_BUF_SZ)) == NULL) {
2255 (void) close(pfd[1]);
2256 (void) fclose(fp);
2257 _exit(2);
2258 }
2259
2260 while (fgets(buf, PARM_BUF_SZ, fp) != NULL) {
2261 /* Skip comments and blank lines */
2262 if (buf[0] == '#' || buf[0] == '!' || buf[0] == '\n')
2263 continue;
2264 (void) write(pfd[1], buf, strlen(buf));
2265 }
2266 (void) write(pfd[1], ".\n", 2);
2267
2268 (void) close(pfd[1]);
2269 (void) fclose(fp);
2270
2271 MEM_FREE(buf);
2272 _exit(0);
2273 /*NOTREACHED*/
2274
2275 case -1:
2276 DBGPRN(DBG_GEN)(errfp,
2277 "di_devspec_parmload: fork failed (errno=%d)\n",
2278 errno);
2279 (void) close(pfd[0]);
2280 (void) close(pfd[1]);
2281
2282 if (priv && !di_isdemo()) {
2283 (void) sprintf(errstr, app_data.str_nocfg, path);
2284 DI_FATAL(errstr);
2285 }
2286 return;
2287
2288 default:
2289 /* Parent */
2290
2291 /* Close un-needed pipe descriptor */
2292 (void) close(pfd[1]);
2293
2294 if ((fp = fdopen(pfd[0], "r")) == NULL) {
2295 DBGPRN(DBG_GEN)(errfp,
2296 "di_devspec_parmload: read pipe fdopen failed\n");
2297 if (priv && !di_isdemo()) {
2298 /* Cannot open pipe */
2299 (void) sprintf(errstr, app_data.str_nocfg,
2300 path);
2301 DI_FATAL(errstr);
2302 }
2303 return;
2304 }
2305 break;
2306 }
2307 #else
2308 un = util_get_uname();
2309
2310 notry2 = FALSE;
2311 if (((int) strlen(path) + (int) strlen(un->nodename) + 2)
2312 > FILE_PATH_SZ) {
2313 DBGPRN(DBG_GEN)(errfp, "NOTICE: %s: %s\n",
2314 "Host-specific config files not used",
2315 "Name too long");
2316 (void) strcpy(trypath, path);
2317 notry2 = TRUE;
2318 }
2319 else
2320 /* Try host-specific config file first */
2321 (void) sprintf(trypath, "%s-%s", path, un->nodename);
2322
2323 DBGPRN(DBG_GEN)(errfp,
2324 "Loading device-specific parameters: %s\n", trypath);
2325 fp = fopen(trypath, "r");
2326
2327 if (fp == NULL && !notry2) {
2328 DBGPRN(DBG_GEN)(errfp, " Cannot open %s\n", trypath);
2329
2330 /* Try generic config file */
2331 (void) strcpy(trypath, path);
2332
2333 DBGPRN(DBG_GEN)(errfp,
2334 "Loading device-specific parameters: %s\n", trypath);
2335 fp = fopen(trypath, "r");
2336 }
2337
2338 if (fp == NULL) {
2339 DBGPRN(DBG_GEN)(errfp, " Cannot open %s\n", trypath);
2340 if (priv && !di_isdemo()) {
2341 /* Cannot open master device-specific
2342 * config file.
2343 */
2344 (void) sprintf(errstr, app_data.str_nocfg, path);
2345 DI_FATAL(errstr);
2346 }
2347 return;
2348 }
2349 #endif /* __VMS */
2350
2351 /* Allocate temporary buffer */
2352 buf = (char *) MEM_ALLOC("buf", PARM_BUF_SZ);
2353 parm = (char *) MEM_ALLOC("parmbuf", PARM_BUF_SZ);
2354 if (buf == NULL || parm == NULL) {
2355 DI_FATAL(app_data.str_nomemory);
2356 return;
2357 }
2358
2359 /* Read in device-specific parameters */
2360 while (fgets(buf, PARM_BUF_SZ, fp) != NULL) {
2361 /* Skip comments and blank lines */
2362 if (buf[0] == '#' || buf[0] == '!' || buf[0] == '\n')
2363 continue;
2364
2365 /* Done */
2366 if (buf[0] == '.' && buf[1] == '\n')
2367 break;
2368
2369 /* These are privileged parameters and users
2370 * cannot overide them in their .xmcdcfg file.
2371 */
2372 if (priv) {
2373 if (sscanf(buf, "logicalDriveNumber: %s\n",
2374 parm) > 0) {
2375 app_data.devnum = atoi(parm);
2376 continue;
2377 }
2378 if (sscanf(buf, "deviceList: %[^\n]\n", parm) > 0) {
2379 if (!util_newstr(&app_data.devlist, parm)) {
2380 DI_FATAL(app_data.str_nomemory);
2381 return;
2382 }
2383 continue;
2384 }
2385 if (sscanf(buf, "deviceInterfaceMethod: %s\n",
2386 parm) > 0) {
2387 app_data.di_method = atoi(parm);
2388 continue;
2389 }
2390 if (sscanf(buf, "cddaMethod: %s\n", parm) > 0) {
2391 app_data.cdda_method = atoi(parm);
2392 continue;
2393 }
2394 if (sscanf(buf, "cddaReadMethod: %s\n", parm) > 0) {
2395 app_data.cdda_rdmethod = atoi(parm);
2396 continue;
2397 }
2398 if (sscanf(buf, "cddaWriteMethod: %s\n", parm) > 0) {
2399 app_data.cdda_wrmethod = atoi(parm);
2400 continue;
2401 }
2402 if (sscanf(buf, "cddaScsiModeSelect: %s\n",
2403 parm) > 0) {
2404 app_data.cdda_modesel = util_stob(parm);
2405 continue;
2406 }
2407 if (sscanf(buf, "cddaScsiDensity: %s\n", parm) > 0) {
2408 app_data.cdda_scsidensity = atoi(parm);
2409 continue;
2410 }
2411 if (sscanf(buf, "cddaScsiReadCommand: %s\n",
2412 parm) > 0) {
2413 app_data.cdda_scsireadcmd = atoi(parm);
2414 continue;
2415 }
2416 if (sscanf(buf, "cddaReadChunkBlocks: %s\n",
2417 parm) > 0) {
2418 app_data.cdda_readchkblks = atoi(parm);
2419 continue;
2420 }
2421 if (sscanf(buf, "cddaDataBigEndian: %s\n", parm) > 0) {
2422 app_data.cdda_bigendian = util_stob(parm);
2423 continue;
2424 }
2425 if (sscanf(buf, "driveVendorCode: %s\n",
2426 parm) > 0) {
2427 app_data.vendor_code = atoi(parm);
2428 continue;
2429 }
2430 if (sscanf(buf, "scsiVersionCheck: %s\n",
2431 parm) > 0) {
2432 app_data.scsiverck = util_stob(parm);
2433 continue;
2434 }
2435 if (sscanf(buf, "numDiscs: %s\n", parm) > 0) {
2436 app_data.numdiscs = atoi(parm);
2437 continue;
2438 }
2439 if (sscanf(buf, "mediumChangeMethod: %s\n",
2440 parm) > 0) {
2441 app_data.chg_method = atoi(parm);
2442 continue;
2443 }
2444 if (sscanf(buf, "scsiAudioVolumeBase: %s\n",
2445 parm) > 0) {
2446 app_data.base_scsivol = atoi(parm);
2447 continue;
2448 }
2449 if (sscanf(buf, "minimumPlayBlocks: %s\n", parm) > 0) {
2450 app_data.min_playblks = atoi(parm);
2451 continue;
2452 }
2453 if (sscanf(buf, "playAudio10Support: %s\n",
2454 parm) > 0) {
2455 app_data.play10_supp = util_stob(parm);
2456 continue;
2457 }
2458 if (sscanf(buf, "playAudio12Support: %s\n",
2459 parm) > 0) {
2460 app_data.play12_supp = util_stob(parm);
2461 continue;
2462 }
2463 if (sscanf(buf, "playAudioMSFSupport: %s\n",
2464 parm) > 0) {
2465 app_data.playmsf_supp = util_stob(parm);
2466 continue;
2467 }
2468 if (sscanf(buf, "playAudioTISupport: %s\n",
2469 parm) > 0) {
2470 app_data.playti_supp = util_stob(parm);
2471 continue;
2472 }
2473 if (sscanf(buf, "loadSupport: %s\n", parm) > 0) {
2474 app_data.load_supp = util_stob(parm);
2475 continue;
2476 }
2477 if (sscanf(buf, "ejectSupport: %s\n", parm) > 0) {
2478 app_data.eject_supp = util_stob(parm);
2479 continue;
2480 }
2481 if (sscanf(buf, "modeSenseSetDBD: %s\n", parm) > 0) {
2482 app_data.msen_dbd = util_stob(parm);
2483 continue;
2484 }
2485 if (sscanf(buf, "modeSenseUse10Byte: %s\n",
2486 parm) > 0) {
2487 app_data.msen_10 = util_stob(parm);
2488 continue;
2489 }
2490 if (sscanf(buf, "volumeControlSupport: %s\n",
2491 parm) > 0) {
2492 app_data.mselvol_supp = util_stob(parm);
2493 continue;
2494 }
2495 if (sscanf(buf, "balanceControlSupport: %s\n",
2496 parm) > 0) {
2497 app_data.balance_supp = util_stob(parm);
2498 continue;
2499 }
2500 if (sscanf(buf, "channelRouteSupport: %s\n",
2501 parm) > 0) {
2502 app_data.chroute_supp = util_stob(parm);
2503 continue;
2504 }
2505 if (sscanf(buf, "pauseResumeSupport: %s\n",
2506 parm) > 0) {
2507 app_data.pause_supp = util_stob(parm);
2508 continue;
2509 }
2510 if (sscanf(buf, "strictPauseResume: %s\n", parm) > 0) {
2511 app_data.strict_pause_resume = util_stob(parm);
2512 continue;
2513 }
2514 if (sscanf(buf, "playPausePlay: %s\n", parm) > 0) {
2515 app_data.play_pause_play = util_stob(parm);
2516 continue;
2517 }
2518 if (sscanf(buf, "caddyLockSupport: %s\n", parm) > 0) {
2519 app_data.caddylock_supp = util_stob(parm);
2520 continue;
2521 }
2522 if (sscanf(buf, "curposFormat: %s\n", parm) > 0) {
2523 app_data.curpos_fmt = util_stob(parm);
2524 continue;
2525 }
2526 if (sscanf(buf, "noTURWhenPlaying: %s\n", parm) > 0) {
2527 app_data.play_notur = util_stob(parm);
2528 continue;
2529 }
2530 if (sscanf(buf, "tocLBA: %s\n", parm) > 0) {
2531 app_data.toc_lba = util_stob(parm);
2532 continue;
2533 }
2534 if (sscanf(buf, "subChannelLBA: %s\n", parm) > 0) {
2535 app_data.subq_lba = util_stob(parm);
2536 continue;
2537 }
2538 if (sscanf(buf, "driveBlockSize: %s\n", parm) > 0) {
2539 app_data.drv_blksz = atoi(parm);
2540 continue;
2541 }
2542 if (sscanf(buf, "spinUpInterval: %s\n", parm) > 0) {
2543 app_data.spinup_interval = atoi(parm);
2544 continue;
2545 }
2546 if (sscanf(buf, "mcnDisable: %s\n", parm) > 0) {
2547 app_data.mcn_dsbl = util_stob(parm);
2548 continue;
2549 }
2550 if (sscanf(buf, "isrcDisable: %s\n", parm) > 0) {
2551 app_data.isrc_dsbl = util_stob(parm);
2552 continue;
2553 }
2554 if (sscanf(buf, "cdTextDisable: %s\n", parm) > 0) {
2555 app_data.cdtext_dsbl = util_stob(parm);
2556 continue;
2557 }
2558 }
2559
2560 /* These are general parameters that can be
2561 * changed by the user.
2562 */
2563 if (sscanf(buf, "playMode: %s\n", parm) > 0) {
2564 /* Only allow playmode to change while not playing */
2565 if (s == NULL ||
2566 (s->mode != MOD_PLAY && s->mode != MOD_PAUSE &&
2567 s->mode != MOD_SAMPLE)) {
2568 app_data.play_mode = atoi(parm);
2569 }
2570 continue;
2571 }
2572 if (sscanf(buf, "volumeControlTaper: %s\n", parm) > 0) {
2573 app_data.vol_taper = atoi(parm);
2574 continue;
2575 }
2576 if (sscanf(buf, "startupVolume: %s\n", parm) > 0) {
2577 app_data.startup_vol = atoi(parm);
2578 continue;
2579 }
2580 if (sscanf(buf, "channelRoute: %s\n", parm) > 0) {
2581 app_data.ch_route = atoi(parm);
2582 continue;
2583 }
2584 if (sscanf(buf, "searchSkipBlocks: %s\n", parm) > 0) {
2585 app_data.skip_blks = atoi(parm);
2586 continue;
2587 }
2588 if (sscanf(buf, "searchPauseInterval: %s\n", parm) > 0) {
2589 app_data.skip_pause = atoi(parm);
2590 continue;
2591 }
2592 if (sscanf(buf, "searchSpeedUpCount: %s\n", parm) > 0) {
2593 app_data.skip_spdup = atoi(parm);
2594 continue;
2595 }
2596 if (sscanf(buf, "searchVolumePercent: %s\n", parm) > 0) {
2597 app_data.skip_vol = atoi(parm);
2598 continue;
2599 }
2600 if (sscanf(buf, "searchMinVolume: %s\n", parm) > 0) {
2601 app_data.skip_minvol = atoi(parm);
2602 continue;
2603 }
2604 if (sscanf(buf, "closeOnEject: %s\n", parm) > 0) {
2605 app_data.eject_close = util_stob(parm);
2606 continue;
2607 }
2608 if (sscanf(buf, "caddyLock: %s\n", parm) > 0) {
2609 app_data.caddy_lock = util_stob(parm);
2610 continue;
2611 }
2612 if (sscanf(buf, "multiPlay: %s\n", parm) > 0) {
2613 app_data.multi_play = util_stob(parm);
2614 continue;
2615 }
2616 if (sscanf(buf, "reversePlay: %s\n", parm) > 0) {
2617 app_data.reverse = util_stob(parm);
2618 continue;
2619 }
2620 if (sscanf(buf, "cddaJitterCorrection: %s\n", parm) > 0) {
2621 app_data.cdda_jitter_corr = util_stob(parm);
2622 continue;
2623 }
2624 }
2625
2626 MEM_FREE(buf);
2627 MEM_FREE(parm);
2628
2629 (void) fclose(fp);
2630
2631 #ifndef __VMS
2632 /* Wait for child to exit */
2633 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
2634 NULL, 0, FALSE, &wstat);
2635 if (ret < 0) {
2636 DBGPRN(DBG_GEN)(errfp, "di_devspec_parmload: "
2637 "waitpid failed (errno=%d)\n", errno);
2638 }
2639 else if (WIFEXITED(wstat)) {
2640 if (WEXITSTATUS(wstat) != 0) {
2641 DBGPRN(DBG_GEN)(errfp, "di_devspec_parmload: "
2642 "child exited (status=%d)\n",
2643 WEXITSTATUS(wstat));
2644 (void) sprintf(errstr, app_data.str_nocfg, path);
2645 if (priv && !di_isdemo()) {
2646 DI_FATAL(errstr);
2647 }
2648 else {
2649 DI_WARNING(errstr);
2650 }
2651 }
2652 }
2653 else if (WIFSIGNALED(wstat)) {
2654 DBGPRN(DBG_GEN)(errfp, "di_devspec_parmload: "
2655 "child killed (signal=%d)\n",
2656 WTERMSIG(wstat));
2657 (void) sprintf(errstr, app_data.str_nocfg, path);
2658 if (priv && !di_isdemo()) {
2659 DI_FATAL(errstr);
2660 }
2661 else {
2662 DI_WARNING(errstr);
2663 }
2664 }
2665 #endif
2666
2667 if (!priv) {
2668 /* If the drive does not support software eject, then we
2669 * can't lock the caddy.
2670 */
2671 if (!app_data.eject_supp) {
2672 app_data.caddylock_supp = FALSE;
2673 app_data.done_eject = FALSE;
2674 app_data.exit_eject = FALSE;
2675 }
2676
2677 /* If the drive does not support locking the caddy, don't
2678 * attempt to lock it.
2679 */
2680 if (!app_data.caddylock_supp)
2681 app_data.caddy_lock = FALSE;
2682
2683 /* If the drive does not support software volume
2684 * control, then it can't support the balance
2685 * control either. Also, force the volume control
2686 * taper selector to the linear position.
2687 */
2688 if (!app_data.mselvol_supp) {
2689 app_data.balance_supp = FALSE;
2690 app_data.vol_taper = VOLTAPER_LINEAR;
2691 }
2692
2693 /* If the drive does not support channel routing,
2694 * force the channel routing setting to normal.
2695 */
2696 if (!app_data.chroute_supp)
2697 app_data.ch_route = 0;
2698
2699 /* Other fix-ups as needed */
2700 if (app_data.numdiscs <= 0)
2701 app_data.numdiscs = 1;
2702
2703 if (app_data.numdiscs == 1) {
2704 app_data.multi_play = app_data.reverse = FALSE;
2705 }
2706
2707 if (app_data.startup_vol > 100)
2708 app_data.startup_vol = 100;
2709 else if (app_data.startup_vol < -1)
2710 app_data.startup_vol = -1;
2711
2712 if (app_data.drv_blksz == 0 ||
2713 (app_data.drv_blksz % 512) != 0)
2714 app_data.drv_blksz = STD_CDROM_BLKSZ;
2715
2716 if (app_data.cdda_readchkblks < MIN_CDDA_CHUNK_BLKS ||
2717 app_data.cdda_readchkblks > MAX_CDDA_CHUNK_BLKS)
2718 app_data.cdda_readchkblks = DEF_CDDA_CHUNK_BLKS;
2719 }
2720 }
2721
2722
2723 /*
2724 * di_common_parmsave
2725 * Save the common configuration parameters to file.
2726 *
2727 * Args:
2728 * path - Path name to the file to save to.
2729 *
2730 * Return:
2731 * Nothing.
2732 */
2733 void
di_common_parmsave(char * path)2734 di_common_parmsave(char *path)
2735 {
2736 FILE *fp;
2737 char *truestr = "True",
2738 *falsestr = "False",
2739 *cp,
2740 filetmpl[FILE_PATH_SZ * 2];
2741 bool_t user_tmpl;
2742 #ifndef __VMS
2743 int ret;
2744 pid_t cpid;
2745 waitret_t wstat;
2746 char *dirpath,
2747 errstr[ERR_BUF_SZ];
2748
2749 /* Fork child to perform actual I/O */
2750 switch (cpid = FORK()) {
2751 case 0:
2752 /* Child process */
2753 break;
2754
2755 case -1:
2756 DBGPRN(DBG_GEN)(errfp,
2757 "di_common_parmsave: fork failed (errno=%d)\n",
2758 errno);
2759 return;
2760
2761 default:
2762 /* Parent process: wait for child to exit */
2763 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
2764 NULL, 0, FALSE, &wstat);
2765 if (ret < 0) {
2766 DBGPRN(DBG_GEN)(errfp, "di_common_parmsave: "
2767 "waitpid failed (errno=%d)\n", errno);
2768 }
2769 else if (WIFEXITED(wstat)) {
2770 if (WEXITSTATUS(wstat) != 0) {
2771 DBGPRN(DBG_GEN)(errfp, "di_common_parmsave: "
2772 "child exited (status=%d)\n",
2773 WEXITSTATUS(wstat));
2774 (void) sprintf(errstr, app_data.str_nocfg,
2775 path);
2776 DI_WARNING(errstr);
2777 }
2778 }
2779 else if (WIFSIGNALED(wstat)) {
2780 DBGPRN(DBG_GEN)(errfp, "di_common_parmsave: "
2781 "child killed (signal=%d)\n",
2782 WTERMSIG(wstat));
2783 (void) sprintf(errstr, app_data.str_nocfg, path);
2784 DI_WARNING(errstr);
2785 }
2786 return;
2787 }
2788
2789 /* Force uid and gid to original setting */
2790 if (!util_set_ougid())
2791 _exit(1);
2792
2793 if ((dirpath = util_dirname(path)) == NULL) {
2794 DI_FATAL("File dirname error");
2795 return;
2796 }
2797 if (!util_mkdir(dirpath, 0755)) {
2798 DBGPRN(DBG_GEN)(errfp,
2799 "di_common_parmsave: cannot mkdir %s.\n", dirpath);
2800 MEM_FREE(dirpath);
2801 _exit(2);
2802 }
2803 MEM_FREE(dirpath);
2804 #endif /* __VMS */
2805
2806 if ((cp = strrchr(app_data.cdda_tmpl, '.')) != NULL)
2807 *cp = '\0';
2808
2809 (void) sprintf(filetmpl,
2810 #ifdef __VMS
2811 "%%S.%%C.%%I]%s",
2812 #else
2813 "%%S/%%C/%%I/%s",
2814 #endif
2815 app_data.cdda_trkfile ? FILEPATH_TRACK : FILEPATH_DISC);
2816 user_tmpl = (bool_t) (strcmp(app_data.cdda_tmpl, filetmpl) != 0);
2817
2818 if (cp != NULL)
2819 *cp = '.';
2820
2821 DBGPRN(DBG_GEN)(errfp, "Writing device-specific file %s\n", path);
2822
2823 /* Open file for writing */
2824 if ((fp = fopen(path, "w")) == NULL) {
2825 DBGPRN(DBG_GEN)(errfp,
2826 "di_common_parmsave: cannot open %s.\n", path);
2827 #ifdef __VMS
2828 return;
2829 #else
2830 _exit(2);
2831 #endif
2832 }
2833
2834 /* Write banner */
2835 (void) fprintf(fp, "# xmcd %s.%s Common Configuration File\n",
2836 VERSION_MAJ, VERSION_MIN);
2837 (void) fprintf(fp, "# %s\n# %s\n#\n# %s %s%s\n# %s\n#\n",
2838 COPYRIGHT, "Automatically generated -- DO NOT EDIT!",
2839 "See the", app_data.libdir, "/config/common.cfg",
2840 "file for details about the parameters.");
2841
2842 /* Write only parameters configurable via the user interface */
2843 (void) fprintf(fp, "outputPort:\t\t%d\n", (int) app_data.outport);
2844 (void) fprintf(fp, "cddaFilePerTrack:\t%s\n",
2845 app_data.cdda_trkfile ? truestr : falsestr);
2846 (void) fprintf(fp, "cddaSpaceToUnderscore:\t%s\n",
2847 app_data.subst_underscore ? truestr : falsestr);
2848 (void) fprintf(fp, "cddaFileFormat:\t\t%d\n", app_data.cdda_filefmt);
2849 (void) fprintf(fp, "cddaFileTemplate:\t%.1000s\n",
2850 user_tmpl ? app_data.cdda_tmpl : "-");
2851 (void) fprintf(fp, "cddaPipeProgram:\t%.1000s\n",
2852 (app_data.pipeprog != NULL) ? app_data.pipeprog : "-");
2853 (void) fprintf(fp, "cddaSchedOptions:\t%d\n", app_data.cdda_sched);
2854 (void) fprintf(fp, "cddaHeartbeatTimeout:\t%d\n", app_data.hb_timeout);
2855 (void) fprintf(fp, "compressionMode:\t%d\n", app_data.comp_mode);
2856 (void) fprintf(fp, "compressionBitrate:\t%d\n", app_data.bitrate);
2857 (void) fprintf(fp, "minimumBitrate:\t\t%d\n", app_data.bitrate_min);
2858 (void) fprintf(fp, "maximumBitrate:\t\t%d\n", app_data.bitrate_max);
2859 (void) fprintf(fp, "compressionQuality:\t%d\n", app_data.qual_factor);
2860 (void) fprintf(fp, "channelMode:\t\t%d\n", app_data.chan_mode);
2861 (void) fprintf(fp, "compressionAlgorithm:\t%d\n", app_data.comp_algo);
2862 (void) fprintf(fp, "lowpassMode:\t\t%d\n", app_data.lowpass_mode);
2863 (void) fprintf(fp, "lowpassFrequency:\t%d\n", app_data.lowpass_freq);
2864 (void) fprintf(fp, "lowpassWidth:\t\t%d\n", app_data.lowpass_width);
2865 (void) fprintf(fp, "highpassMode:\t\t%d\n", app_data.highpass_mode);
2866 (void) fprintf(fp, "highpassFrequency:\t%d\n", app_data.highpass_freq);
2867 (void) fprintf(fp, "highpassWidth:\t\t%d\n", app_data.highpass_width);
2868 (void) fprintf(fp, "copyrightFlag:\t\t%s\n",
2869 app_data.copyright ? truestr : falsestr);
2870 (void) fprintf(fp, "originalFlag:\t\t%s\n",
2871 app_data.original ? truestr : falsestr);
2872 (void) fprintf(fp, "noBitReservoirFlag:\t%s\n",
2873 app_data.nores ? truestr : falsestr);
2874 (void) fprintf(fp, "checksumFlag:\t\t%s\n",
2875 app_data.checksum ? truestr : falsestr);
2876 (void) fprintf(fp, "strictISO:\t\t%s\n",
2877 app_data.strict_iso ? truestr : falsestr);
2878 (void) fprintf(fp, "lameOptionsMode:\t%d\n", app_data.lameopts_mode);
2879 (void) fprintf(fp, "lameOptions:\t\t%.1000s\n",
2880 (app_data.lame_opts != NULL) ?
2881 app_data.lame_opts : "-");
2882 (void) fprintf(fp, "id3TagMode:\t\t%d\n", app_data.id3tag_mode);
2883 (void) fprintf(fp, "addInfoTag:\t\t%s\n",
2884 app_data.add_tag ? truestr : falsestr);
2885 (void) fprintf(fp, "spinDownOnLoad:\t\t%s\n",
2886 app_data.load_spindown ? truestr : falsestr);
2887 (void) fprintf(fp, "playOnLoad:\t\t%s\n",
2888 app_data.load_play ? truestr : falsestr);
2889 (void) fprintf(fp, "ejectOnDone:\t\t%s\n",
2890 app_data.done_eject ? truestr : falsestr);
2891 (void) fprintf(fp, "exitOnDone:\t\t%s\n",
2892 app_data.done_exit ? truestr : falsestr);
2893 (void) fprintf(fp, "ejectOnExit:\t\t%s\n",
2894 app_data.exit_eject ? truestr : falsestr);
2895 (void) fprintf(fp, "stopOnExit:\t\t%s\n",
2896 app_data.exit_stop ? truestr : falsestr);
2897 (void) fprintf(fp, "exitOnEject:\t\t%s\n",
2898 app_data.eject_exit ? truestr : falsestr);
2899 (void) fprintf(fp, "repeatMode:\t\t%s\n",
2900 app_data.repeat_mode ? truestr : falsestr);
2901 (void) fprintf(fp, "shuffleMode:\t\t%s\n",
2902 app_data.shuffle_mode ? truestr : falsestr);
2903 (void) fprintf(fp, "cdinfoPath:\t\t%s\n", app_data.cdinfo_path);
2904 (void) fprintf(fp, "charsetConvMode:\t%d\n",
2905 app_data.chset_xlat);
2906 (void) fprintf(fp, "langUtf8:\t\t%s\n", app_data.lang_utf8);
2907 (void) fprintf(fp, "acceptFuzzyDefault:\t%s\n",
2908 app_data.single_fuzzy ? truestr : falsestr);
2909 (void) fprintf(fp, "cddbUseProxy:\t\t%s\n",
2910 app_data.use_proxy ? truestr : falsestr);
2911 (void) fprintf(fp, "proxyServer:\t\t%s\n", app_data.proxy_server);
2912 (void) fprintf(fp, "proxyAuthorization:\t%s\n",
2913 app_data.proxy_auth ? truestr : falsestr);
2914 (void) fprintf(fp, "autoMusicBrowser:\t%s\n",
2915 app_data.auto_musicbrowser ? truestr : falsestr);
2916 (void) fprintf(fp, "cddbCacheTimeout:\t%d\n", app_data.cache_timeout);
2917 (void) fprintf(fp, "serviceTimeout:\t\t%d\n", app_data.srv_timeout);
2918 (void) fprintf(fp, "autoMotdDisable:\t%s\n",
2919 app_data.automotd_dsbl ? truestr : falsestr);
2920
2921 if (fclose(fp) != 0) {
2922 #ifdef __VMS
2923 return;
2924 #else
2925 _exit(1);
2926 #endif
2927 }
2928
2929 (void) chmod(path, 0644);
2930
2931 /* Child exits here */
2932 #ifndef __VMS
2933 _exit(0);
2934 #endif
2935 /*NOTREACHED*/
2936 }
2937
2938
2939 /*
2940 * di_devspec_parmsave
2941 * Save the device-specific configuration parameters to file.
2942 *
2943 * Args:
2944 * path - Path name to the file to save to.
2945 *
2946 * Return:
2947 * Nothing.
2948 */
2949 void
di_devspec_parmsave(char * path)2950 di_devspec_parmsave(char *path)
2951 {
2952 FILE *fp;
2953 char *truestr = "True",
2954 *falsestr = "False";
2955 #ifndef __VMS
2956 int ret;
2957 pid_t cpid;
2958 waitret_t wstat;
2959 char *dirpath,
2960 errstr[ERR_BUF_SZ];
2961
2962 /* Fork child to perform actual I/O */
2963 switch (cpid = FORK()) {
2964 case 0:
2965 /* Child process */
2966 break;
2967
2968 case -1:
2969 DBGPRN(DBG_GEN)(errfp,
2970 "di_devspec_parmsave: fork failed (errno=%d)\n",
2971 errno);
2972 return;
2973
2974 default:
2975 /* Parent process: wait for child to exit */
2976 ret = util_waitchild(cpid, app_data.srv_timeout + 5,
2977 NULL, 0, FALSE, &wstat);
2978 if (ret < 0) {
2979 DBGPRN(DBG_GEN)(errfp, "di_devspec_parmsave: "
2980 "waitpid failed (errno=%d)\n", errno);
2981 }
2982 else if (WIFEXITED(wstat)) {
2983 if (WEXITSTATUS(wstat) != 0) {
2984 DBGPRN(DBG_GEN)(errfp, "di_devspec_parmsave: "
2985 "child exited (status=%d)\n",
2986 WEXITSTATUS(wstat));
2987 (void) sprintf(errstr, app_data.str_nocfg,
2988 path);
2989 DI_WARNING(errstr);
2990 }
2991 }
2992 else if (WIFSIGNALED(wstat)) {
2993 DBGPRN(DBG_GEN)(errfp, "di_devspec_parmsave: "
2994 "child killed (signal=%d)\n",
2995 WTERMSIG(wstat));
2996 (void) sprintf(errstr, app_data.str_nocfg, path);
2997 DI_WARNING(errstr);
2998 }
2999 return;
3000 }
3001
3002 /* Force uid and gid to original setting */
3003 if (!util_set_ougid())
3004 _exit(1);
3005
3006 if ((dirpath = util_dirname(path)) == NULL) {
3007 DI_FATAL("File dirname error");
3008 return;
3009 }
3010 if (!util_mkdir(dirpath, 0755)) {
3011 DBGPRN(DBG_GEN)(errfp,
3012 "di_devspec_parmsave: cannot mkdir %s.\n", dirpath);
3013 MEM_FREE(dirpath);
3014 _exit(2);
3015 }
3016 MEM_FREE(dirpath);
3017 #endif /* __VMS */
3018
3019 DBGPRN(DBG_GEN)(errfp, "Writing device-specific file %s\n", path);
3020
3021 /* Open file for writing */
3022 if ((fp = fopen(path, "w")) == NULL) {
3023 DBGPRN(DBG_GEN)(errfp,
3024 "di_devspec_parmsave: cannot open %s.\n", path);
3025 #ifdef __VMS
3026 return;
3027 #else
3028 _exit(2);
3029 #endif
3030 }
3031
3032 /* Write banner */
3033 (void) fprintf(fp, "# xmcd %s.%s Device-Specific Configuration File\n",
3034 VERSION_MAJ, VERSION_MIN);
3035 (void) fprintf(fp, "# %s\n# %s\n#\n# %s %s%s\n# %s\n#\n",
3036 COPYRIGHT, "Automatically generated -- DO NOT EDIT!",
3037 "See the", app_data.libdir, "/config/device.cfg",
3038 "file for details about the parameters.");
3039
3040 /* Write only user-changeable parameters */
3041 (void) fprintf(fp, "playMode:\t\t%d\n", app_data.play_mode);
3042 (void) fprintf(fp, "cddaJitterCorrection:\t%s\n",
3043 app_data.cdda_jitter_corr ? truestr : falsestr);
3044 (void) fprintf(fp, "volumeControlTaper:\t%d\n", app_data.vol_taper);
3045 (void) fprintf(fp, "channelRoute:\t\t%d\n", app_data.ch_route);
3046 (void) fprintf(fp, "caddyLock:\t\t%s\n",
3047 app_data.caddy_lock ? truestr : falsestr);
3048 (void) fprintf(fp, "multiPlay:\t\t%s\n",
3049 app_data.multi_play ? truestr : falsestr);
3050 (void) fprintf(fp, "reversePlay:\t\t%s\n",
3051 app_data.reverse ? truestr : falsestr);
3052
3053 if (fclose(fp) != 0) {
3054 #ifdef __VMS
3055 return;
3056 #else
3057 _exit(1);
3058 #endif
3059 }
3060
3061 (void) chmod(path, 0644);
3062
3063 /* Child exits here */
3064 #ifndef __VMS
3065 _exit(0);
3066 #endif
3067 /*NOTREACHED*/
3068 }
3069
3070
3071 /*
3072 * di_devlock
3073 * Create a lock to prevent another cooperating CD audio process
3074 * from accessing the same CD-ROM device.
3075 *
3076 * Args:
3077 * s - Pointer to the curstat_t structure.
3078 * path - The CD-ROM device node path name.
3079 *
3080 * Return:
3081 * TRUE if the lock was successful. If FALSE, then it indicates
3082 * that another xmcd process currently has the lock.
3083 */
3084 /*ARGSUSED*/
3085 bool_t
di_devlock(curstat_t * s,char * path)3086 di_devlock(curstat_t *s, char *path)
3087 {
3088 #ifndef __VMS
3089 /* UNIX */
3090 int fd;
3091 pid_t pid,
3092 mypid;
3093 char buf[32];
3094 struct stat stbuf;
3095
3096 if (di_isdemo())
3097 return TRUE; /* No locking needed in demo mode */
3098
3099 if (stat(path, &stbuf) < 0) {
3100 if (errno == ENOENT)
3101 /* If the device node is missing it is probably
3102 * due to dynamic node creation/removal
3103 * on some platforms based on presence of media.
3104 * In this case, let the lock call succeed without
3105 * actually setting a lock. Otherwise the status
3106 * would erroneously become "cd busy".
3107 */
3108 return TRUE;
3109 else
3110 return FALSE;
3111 }
3112
3113 (void) sprintf(lockfile, "%s/lock.%x", TEMP_DIR, (int) stbuf.st_rdev);
3114
3115 DBGPRN(DBG_GEN)(errfp, "\nLock file: %s\n", lockfile);
3116
3117 mypid = getpid();
3118
3119 for (;;) {
3120 fd = open(lockfile, O_CREAT | O_EXCL | O_WRONLY);
3121 if (fd < 0) {
3122 if (errno == EEXIST) {
3123 fd = open(lockfile, O_RDONLY
3124 #ifdef O_NOFOLLOW
3125 | O_NOFOLLOW
3126 #endif
3127 );
3128 if (fd < 0)
3129 return FALSE;
3130
3131 if (read(fd, buf, 32) > 0) {
3132 if (strncmp(buf, "cdlk ", 5) != 0){
3133 (void) close(fd);
3134 return FALSE;
3135 }
3136 pid = (pid_t) atoi(buf + 5);
3137 }
3138 else {
3139 (void) close(fd);
3140 return FALSE;
3141 }
3142
3143 (void) close(fd);
3144
3145 if (pid == mypid)
3146 /* Our own lock */
3147 return TRUE;
3148
3149 if (pid <= 0 ||
3150 (kill(pid, 0) < 0 && errno == ESRCH)) {
3151 /* Pid died, steal its lockfile */
3152 (void) UNLINK(lockfile);
3153 }
3154 else {
3155 /* Pid still running: clash */
3156 return FALSE;
3157 }
3158 }
3159 else
3160 return FALSE;
3161 }
3162 else {
3163 (void) sprintf(buf, "cdlk %d\n", (int) mypid);
3164 (void) write(fd, buf, strlen(buf));
3165
3166 #ifdef NO_FCHMOD
3167 (void) close(fd);
3168 (void) chmod(lockfile, 0644);
3169 #else
3170 (void) fchmod(fd, 0644);
3171 (void) close(fd);
3172 #endif
3173
3174 return TRUE;
3175 }
3176 }
3177 #else
3178 /* OpenVMS */
3179 extern int SYS$GETDVIW();
3180 static char ref_cnt;
3181 int status;
3182
3183 struct {
3184 short buflen;
3185 short code;
3186 char *bufadr;
3187 int *length;
3188 int terminator;
3189 } itemlist = {
3190 4,
3191 DVI$_REFCNT,
3192 &ref_cnt,
3193 NULL,
3194 0
3195 };
3196
3197 struct dsc$descriptor dev_nam_desc;
3198
3199 if (path == NULL)
3200 return TRUE;
3201
3202 ref_cnt = 1;
3203
3204 dev_nam_desc.dsc$b_class = DSC$K_CLASS_S;
3205 dev_nam_desc.dsc$b_dtype = DSC$K_DTYPE_T;
3206 dev_nam_desc.dsc$a_pointer = path;
3207 dev_nam_desc.dsc$w_length = strlen(path);
3208
3209 status = SYS$GETDVIW(0, 0, &dev_nam_desc, &itemlist, 0, 0, 0, 0);
3210
3211 if (status != 1) {
3212 (void) fprintf(errfp,
3213 "CD audio: Cannot get information on device: %s\n",
3214 path);
3215 return FALSE;
3216 }
3217
3218 return ((bool_t) (ref_cnt == 0));
3219 #endif /* __VMS */
3220 }
3221
3222
3223 /*
3224 * di_devunlock
3225 * Unlock the lock that was created with di_devlock().
3226 *
3227 * Args:
3228 * s - Pointer to the curstat_t structure.
3229 *
3230 * Return:
3231 * Nothing.
3232 */
3233 /*ARGSUSED*/
3234 void
di_devunlock(curstat_t * s)3235 di_devunlock(curstat_t *s)
3236 {
3237 #ifndef __VMS
3238 if (lockfile[0] != '\0' && s->devlocked)
3239 (void) UNLINK(lockfile);
3240 #endif
3241 }
3242
3243
3244 /*
3245 * di_devalloc
3246 * Allocate a device descriptor structure.
3247 *
3248 * Args:
3249 * path - The device path name (required)
3250 *
3251 * Return:
3252 * Pointer to the allocated structure, or NULL on failure.
3253 */
3254 di_dev_t *
di_devalloc(char * path)3255 di_devalloc(char *path)
3256 {
3257 di_dev_t *devp;
3258
3259 if (path == NULL || *path == '\0')
3260 return FALSE;
3261
3262 devp = (di_dev_t *)(void *) MEM_ALLOC(
3263 "di_dev_t",
3264 sizeof(di_dev_t)
3265 );
3266 if (devp == NULL)
3267 return NULL;
3268
3269 (void) memset(devp, 0, sizeof(di_dev_t));
3270
3271 devp->fd = -1;
3272 devp->path = NULL;
3273 if (!util_newstr(&devp->path, path))
3274 return NULL;
3275
3276 return (devp);
3277 }
3278
3279
3280 /*
3281 * di_devfree
3282 * De-allocate a device descriptor structure.
3283 *
3284 * Args:
3285 * devp - Pointer to the device descriptor.
3286 *
3287 * Return:
3288 * Nothing.
3289 */
3290 void
di_devfree(di_dev_t * devp)3291 di_devfree(di_dev_t *devp)
3292 {
3293 MEM_FREE(devp->path);
3294 MEM_FREE(devp);
3295 }
3296
3297
3298 /*
3299 * di_methodstr
3300 * Return a text string indicating the current operating mode.
3301 *
3302 * Args:
3303 * Nothing.
3304 *
3305 * Return:
3306 * Mode text string.
3307 */
3308 char *
di_methodstr(void)3309 di_methodstr(void)
3310 {
3311 char *p;
3312 static char str[STR_BUF_SZ * 6];
3313
3314 if (ditbl[app_data.di_method].methodstr != NULL)
3315 p = (ditbl[app_data.di_method].methodstr());
3316 else
3317 p = "";
3318
3319 (void) sprintf(str, "Device interface method: %s\n%s",
3320 p, cdda_info());
3321 return (str);
3322 }
3323
3324
3325 /*
3326 * di_isdemo
3327 * Query if this is a demo-only version of the CD player.
3328 *
3329 * Args:
3330 * Nothing.
3331 *
3332 * Return:
3333 * TRUE - demo-only version.
3334 * FALSE - real version.
3335 */
3336 bool_t
di_isdemo(void)3337 di_isdemo(void)
3338 {
3339 #ifdef DEMO_ONLY
3340 return TRUE;
3341 #else
3342 return FALSE;
3343 #endif
3344 }
3345
3346
3347 /*
3348 * di_curtrk_pos
3349 * Return the trkinfo table offset location of the current playing
3350 * CD track.
3351 *
3352 * Args:
3353 * s - Pointer to the curstat_t structure.
3354 *
3355 * Return:
3356 * Integer offset into the trkinfo table, or -1 if not currently
3357 * playing audio.
3358 */
3359 int
di_curtrk_pos(curstat_t * s)3360 di_curtrk_pos(curstat_t *s)
3361 {
3362 int i;
3363
3364 if ((int) s->cur_trk <= 0)
3365 return -1;
3366
3367 i = (int) s->cur_trk - 1;
3368
3369 if (s->trkinfo[i].trkno == s->cur_trk)
3370 return (i);
3371
3372 for (i = 0; i < MAXTRACK; i++) {
3373 if (s->trkinfo[i].trkno == s->cur_trk)
3374 return (i);
3375 }
3376 return -1;
3377 }
3378
3379
3380 /*
3381 * di_curprog_pos
3382 * Return an integer representing the position of the current
3383 * program or shuffle mode playing order (0 = first, 1 = second, ...).
3384 * This routine should be used only when in program or shuffle play
3385 * mode.
3386 *
3387 * Arg:
3388 * s - Pointer to the curstat_t structure.
3389 *
3390 * Return:
3391 * An integer representing the position of the current program
3392 * or shuffle mode playing order, or -1 if not in the appropriate mode.
3393 */
3394 int
di_curprog_pos(curstat_t * s)3395 di_curprog_pos(curstat_t *s)
3396 {
3397 return ((int) s->trkinfo[s->prog_cnt].playorder);
3398 }
3399
3400
3401 /*
3402 * di_clear_cdinfo
3403 * Clear in-core CD information
3404 *
3405 * Args:
3406 * s - Pointer to the curstat_t structure
3407 * reload - Whether we're going to be reloading the CD information
3408 *
3409 * Return:
3410 * Nothing.
3411 */
3412 void
di_clear_cdinfo(curstat_t * s,bool_t reload)3413 di_clear_cdinfo(curstat_t *s, bool_t reload)
3414 {
3415 DBCLEAR(s, reload);
3416 di_cdinfo_loaded = FALSE;
3417 }
3418
3419
3420 /*
3421 * di_get_cdinfo
3422 * Look up CD information
3423 *
3424 * Args:
3425 * s - Pointer to the curstat_t structure
3426 *
3427 * Return:
3428 * CD information lookup status (QMODE_xxx from appenv.h)
3429 */
3430 byte_t
di_get_cdinfo(curstat_t * s)3431 di_get_cdinfo(curstat_t *s)
3432 {
3433 if (di_cdinfo_loaded)
3434 return TRUE;
3435
3436 /* Call into the client to do the actual lookup */
3437 DBGET(s);
3438 di_cdinfo_loaded = TRUE;
3439
3440 return (s->qmode);
3441 }
3442
3443
3444 /*
3445 * di_prepare_cdda
3446 * Prepare for CDDA operation
3447 *
3448 * Args:
3449 * s - Pointer to the curstat_t structure
3450 *
3451 * Return:
3452 * TRUE - success
3453 * FALSE - failure
3454 */
3455 bool_t
di_prepare_cdda(curstat_t * s)3456 di_prepare_cdda(curstat_t *s)
3457 {
3458 if (PLAYMODE_IS_STD(app_data.play_mode))
3459 return TRUE;
3460
3461 /* Expand CDDA output file pathnames if necessary */
3462 if ((app_data.play_mode & PLAYMODE_FILE) != 0 &&
3463 di_clinfo->mkoutpath != NULL) {
3464 if (di_chktmpl(s, "%C") ||
3465 di_chktmpl(s, "%A") || di_chktmpl(s, "%a") ||
3466 di_chktmpl(s, "%D") || di_chktmpl(s, "%d") ||
3467 di_chktmpl(s, "%R") || di_chktmpl(s, "%r") ||
3468 di_chktmpl(s, "%T") || di_chktmpl(s, "%t") ||
3469 di_chktmpl(s, "%B") || di_chktmpl(s, "%b"))
3470 (void) di_get_cdinfo(s);
3471
3472 if (!di_clinfo->mkoutpath(s))
3473 return FALSE;
3474 }
3475
3476 /* Check CDDA pipe program if necessary */
3477 if ((app_data.play_mode & PLAYMODE_PIPE) != 0 &&
3478 di_clinfo->ckpipeprog != NULL && !di_clinfo->ckpipeprog(s))
3479 return FALSE;
3480
3481 return TRUE;
3482 }
3483
3484
3485 /*
3486 * di_reset_curstat
3487 * Reset the curstat_t structure to initial defaults.
3488 *
3489 * Args:
3490 * s - Pointer to the curstat_t structure.
3491 * clear_toc - Whether the trkinfo CD table-of-contents
3492 * should be cleared.
3493 * eject - Whether the medium is being ejected
3494 *
3495 * Return:
3496 * Nothing.
3497 */
3498 void
di_reset_curstat(curstat_t * s,bool_t clear_toc,bool_t eject)3499 di_reset_curstat(curstat_t *s, bool_t clear_toc, bool_t eject)
3500 {
3501 sword32_t i;
3502 static bool_t first_time = TRUE;
3503
3504 s->cur_trk = s->cur_idx = -1;
3505 s->curpos_tot.min = s->curpos_tot.sec = s->curpos_tot.frame = 0;
3506 s->curpos_trk.min = s->curpos_trk.sec = s->curpos_trk.frame = 0;
3507 s->curpos_tot.addr = s->curpos_trk.addr = 0;
3508 s->sav_iaddr = 0;
3509 s->prog_cnt = 0;
3510 s->frm_played = s->tot_frm = 0;
3511 s->frm_per_sec = 0;
3512
3513 if (s->onetrk_prog) {
3514 s->onetrk_prog = FALSE;
3515 PROGCLEAR(s);
3516 }
3517
3518 if (clear_toc) {
3519 s->flags = 0;
3520 s->segplay = SEGP_NONE;
3521 s->first_trk = s->last_trk = -1;
3522 s->discpos_tot.min = s->discpos_tot.sec = 0;
3523 s->tot_trks = 0;
3524 s->discpos_tot.addr = 0;
3525 s->prog_tot = 0;
3526 s->program = FALSE;
3527
3528 (void) memset(s->mcn, 0, sizeof(s->mcn));
3529
3530 for (i = 0; i < MAXTRACK; i++) {
3531 s->trkinfo[i].trkno = -1;
3532 s->trkinfo[i].min = 0;
3533 s->trkinfo[i].sec = 0;
3534 s->trkinfo[i].frame = 0;
3535 s->trkinfo[i].addr = 0;
3536 s->trkinfo[i].type = TYP_AUDIO;
3537 s->trkinfo[i].playorder = -1;
3538 if (s->trkinfo[i].outfile != NULL) {
3539 MEM_FREE(s->trkinfo[i].outfile);
3540 s->trkinfo[i].outfile = NULL;
3541 }
3542
3543 (void) memset(s->trkinfo[i].isrc, 0,
3544 sizeof(s->trkinfo[i].isrc));
3545 }
3546 }
3547
3548 if (eject) {
3549 s->mode = MOD_NODISC;
3550 s->rptcnt = 0;
3551 }
3552
3553 if (first_time) {
3554 /* These are to be initialized only once */
3555 first_time = FALSE;
3556
3557 s->first_disc = 1;
3558 s->last_disc = app_data.numdiscs;
3559 s->cur_disc = app_data.reverse ? s->last_disc : s->first_disc;
3560 s->prev_disc = -1;
3561 s->time_dpy = T_ELAPSED_TRACK;
3562 s->repeat = s->shuffle = FALSE;
3563 s->rptcnt = 0;
3564 s->level = 0;
3565 s->level_left = s->level_right = 100;
3566 s->cdda_att = 100;
3567 s->caddy_lock = FALSE;
3568 s->vendor[0] = '\0';
3569 s->prod[0] = '\0';
3570 s->revnum[0] = '\0';
3571 }
3572 }
3573
3574
3575 /*
3576 * di_reset_shuffle
3577 * Recompute a new shuffle play sequence. Updates the playorder
3578 * table in the curstat_t structure.
3579 *
3580 * Args:
3581 * s - Pointer to the curstat_t structure.
3582 *
3583 * Return:
3584 * Nothing.
3585 */
3586 void
di_reset_shuffle(curstat_t * s)3587 di_reset_shuffle(curstat_t *s)
3588 {
3589 sword32_t i,
3590 j,
3591 n,
3592 x;
3593
3594 srand((unsigned) time(NULL));
3595 s->prog_cnt = 0;
3596
3597 /* Initialize the play-list with only audio tracks */
3598 n = 0;
3599 for (i = 0; i < (int) s->tot_trks; i++) {
3600 if (s->trkinfo[i].type == TYP_AUDIO)
3601 s->trkinfo[n++].playorder = i;
3602 }
3603
3604 s->prog_tot = (byte_t) n;
3605
3606 /* Initialize rest of list */
3607 for (; n < MAXTRACK; n++)
3608 s->trkinfo[n].playorder = -1;
3609
3610 /*
3611 * Now shuffle the playlist by swapping random pairs:
3612 * this is the most efficient alogorithm for a linear
3613 * distribution.
3614 */
3615 for (i = (int) s->prog_tot - 1; i > 0; i--) {
3616 j = rand() % (i + 1);
3617 if (j != i) {
3618 x = s->trkinfo[i].playorder;
3619 s->trkinfo[i].playorder = s->trkinfo[j].playorder;
3620 s->trkinfo[j].playorder = x;
3621 }
3622 }
3623
3624 if (app_data.debug & DBG_GEN) {
3625 (void) fprintf(errfp, "\nShuffle tracks: ");
3626
3627 for (i = 0; i < (int) s->prog_tot; i++)
3628 (void) fprintf(errfp, "%d ",
3629 s->trkinfo[s->trkinfo[i].playorder].trkno);
3630
3631 (void) fprintf(errfp, "\n");
3632 }
3633 }
3634
3635
3636