Merge with lastest private git
[framework/connectivity/bluez.git] / tools / avinfo.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2006-2010  Nokia Corporation
6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <getopt.h>
37 #include <stdint.h>
38 #include <sys/param.h>
39 #include <sys/ioctl.h>
40 #include <sys/socket.h>
41
42 #include <bluetooth/bluetooth.h>
43 #include <bluetooth/hci.h>
44 #include <bluetooth/hci_lib.h>
45 #include <bluetooth/l2cap.h>
46
47 #define AVDTP_PSM                       25
48
49 /* Commands */
50 #define AVDTP_DISCOVER                  0x01
51 #define AVDTP_GET_CAPABILITIES          0x02
52
53 #define AVDTP_PKT_TYPE_SINGLE           0x00
54
55 #define AVDTP_MSG_TYPE_COMMAND          0x00
56
57 /* SEP capability categories */
58 #define AVDTP_MEDIA_TRANSPORT           0x01
59 #define AVDTP_REPORTING                 0x02
60 #define AVDTP_RECOVERY                  0x03
61 #define AVDTP_CONTENT_PROTECTION        0x04
62 #define AVDTP_HEADER_COMPRESSION        0x05
63 #define AVDTP_MULTIPLEXING              0x06
64 #define AVDTP_MEDIA_CODEC               0x07
65
66 /* SEP types definitions */
67 #define AVDTP_SEP_TYPE_SOURCE           0x00
68 #define AVDTP_SEP_TYPE_SINK             0x01
69
70 /* Media types definitions */
71 #define AVDTP_MEDIA_TYPE_AUDIO          0x00
72 #define AVDTP_MEDIA_TYPE_VIDEO          0x01
73 #define AVDTP_MEDIA_TYPE_MULTIMEDIA     0x02
74
75 #define A2DP_CODEC_SBC                  0x00
76 #define A2DP_CODEC_MPEG12               0x01
77 #define A2DP_CODEC_MPEG24               0x02
78 #define A2DP_CODEC_ATRAC                0x03
79
80 #define SBC_SAMPLING_FREQ_16000         (1 << 3)
81 #define SBC_SAMPLING_FREQ_32000         (1 << 2)
82 #define SBC_SAMPLING_FREQ_44100         (1 << 1)
83 #define SBC_SAMPLING_FREQ_48000         (1 << 0)
84
85 #define SBC_CHANNEL_MODE_MONO           (1 << 3)
86 #define SBC_CHANNEL_MODE_DUAL_CHANNEL   (1 << 2)
87 #define SBC_CHANNEL_MODE_STEREO         (1 << 1)
88 #define SBC_CHANNEL_MODE_JOINT_STEREO   (1 << 0)
89
90 #define SBC_BLOCK_LENGTH_4              (1 << 3)
91 #define SBC_BLOCK_LENGTH_8              (1 << 2)
92 #define SBC_BLOCK_LENGTH_12             (1 << 1)
93 #define SBC_BLOCK_LENGTH_16             (1 << 0)
94
95 #define SBC_SUBBANDS_4                  (1 << 1)
96 #define SBC_SUBBANDS_8                  (1 << 0)
97
98 #define SBC_ALLOCATION_SNR              (1 << 1)
99 #define SBC_ALLOCATION_LOUDNESS         (1 << 0)
100
101 #define MPEG_CHANNEL_MODE_MONO          (1 << 3)
102 #define MPEG_CHANNEL_MODE_DUAL_CHANNEL  (1 << 2)
103 #define MPEG_CHANNEL_MODE_STEREO        (1 << 1)
104 #define MPEG_CHANNEL_MODE_JOINT_STEREO  (1 << 0)
105
106 #define MPEG_LAYER_MP1                  (1 << 2)
107 #define MPEG_LAYER_MP2                  (1 << 1)
108 #define MPEG_LAYER_MP3                  (1 << 0)
109
110 #define MPEG_SAMPLING_FREQ_16000        (1 << 5)
111 #define MPEG_SAMPLING_FREQ_22050        (1 << 4)
112 #define MPEG_SAMPLING_FREQ_24000        (1 << 3)
113 #define MPEG_SAMPLING_FREQ_32000        (1 << 2)
114 #define MPEG_SAMPLING_FREQ_44100        (1 << 1)
115 #define MPEG_SAMPLING_FREQ_48000        (1 << 0)
116
117 #define MPEG_BIT_RATE_VBR               0x8000
118 #define MPEG_BIT_RATE_320000            0x4000
119 #define MPEG_BIT_RATE_256000            0x2000
120 #define MPEG_BIT_RATE_224000            0x1000
121 #define MPEG_BIT_RATE_192000            0x0800
122 #define MPEG_BIT_RATE_160000            0x0400
123 #define MPEG_BIT_RATE_128000            0x0200
124 #define MPEG_BIT_RATE_112000            0x0100
125 #define MPEG_BIT_RATE_96000             0x0080
126 #define MPEG_BIT_RATE_80000             0x0040
127 #define MPEG_BIT_RATE_64000             0x0020
128 #define MPEG_BIT_RATE_56000             0x0010
129 #define MPEG_BIT_RATE_48000             0x0008
130 #define MPEG_BIT_RATE_40000             0x0004
131 #define MPEG_BIT_RATE_32000             0x0002
132 #define MPEG_BIT_RATE_FREE              0x0001
133
134 struct avdtp_service_capability {
135         uint8_t category;
136         uint8_t length;
137         uint8_t data[0];
138 } __attribute__ ((packed));
139
140 #if __BYTE_ORDER == __LITTLE_ENDIAN
141
142 struct avdtp_header {
143         uint8_t message_type:2;
144         uint8_t packet_type:2;
145         uint8_t transaction:4;
146         uint8_t signal_id:6;
147         uint8_t rfa0:2;
148 } __attribute__ ((packed));
149
150 struct seid_info {
151         uint8_t rfa0:1;
152         uint8_t inuse:1;
153         uint8_t seid:6;
154         uint8_t rfa2:3;
155         uint8_t type:1;
156         uint8_t media_type:4;
157 } __attribute__ ((packed));
158
159 struct seid_req {
160         struct avdtp_header header;
161         uint8_t rfa0:2;
162         uint8_t acp_seid:6;
163 } __attribute__ ((packed));
164
165 struct avdtp_media_codec_capability {
166         uint8_t rfa0:4;
167         uint8_t media_type:4;
168         uint8_t media_codec_type;
169         uint8_t data[0];
170 } __attribute__ ((packed));
171
172 struct sbc_codec_cap {
173         struct avdtp_media_codec_capability cap;
174         uint8_t channel_mode:4;
175         uint8_t frequency:4;
176         uint8_t allocation_method:2;
177         uint8_t subbands:2;
178         uint8_t block_length:4;
179         uint8_t min_bitpool;
180         uint8_t max_bitpool;
181 } __attribute__ ((packed));
182
183 struct mpeg_codec_cap {
184         struct avdtp_media_codec_capability cap;
185         uint8_t channel_mode:4;
186         uint8_t crc:1;
187         uint8_t layer:3;
188         uint8_t frequency:6;
189         uint8_t mpf:1;
190         uint8_t rfa:1;
191         uint16_t bitrate;
192 } __attribute__ ((packed));
193
194 #elif __BYTE_ORDER == __BIG_ENDIAN
195
196 struct avdtp_header {
197         uint8_t transaction:4;
198         uint8_t packet_type:2;
199         uint8_t message_type:2;
200         uint8_t rfa0:2;
201         uint8_t signal_id:6;
202 } __attribute__ ((packed));
203
204 struct seid_info {
205         uint8_t seid:6;
206         uint8_t inuse:1;
207         uint8_t rfa0:1;
208         uint8_t media_type:4;
209         uint8_t type:1;
210         uint8_t rfa2:3;
211 } __attribute__ ((packed));
212
213 struct seid_req {
214         struct avdtp_header header;
215         uint8_t acp_seid:6;
216         uint8_t rfa0:2;
217 } __attribute__ ((packed));
218
219 struct avdtp_media_codec_capability {
220         uint8_t media_type:4;
221         uint8_t rfa0:4;
222         uint8_t media_codec_type;
223         uint8_t data[0];
224 } __attribute__ ((packed));
225
226 struct sbc_codec_cap {
227         struct avdtp_media_codec_capability cap;
228         uint8_t frequency:4;
229         uint8_t channel_mode:4;
230         uint8_t block_length:4;
231         uint8_t subbands:2;
232         uint8_t allocation_method:2;
233         uint8_t min_bitpool;
234         uint8_t max_bitpool;
235 } __attribute__ ((packed));
236
237 struct mpeg_codec_cap {
238         struct avdtp_media_codec_capability cap;
239         uint8_t layer:3;
240         uint8_t crc:1;
241         uint8_t channel_mode:4;
242         uint8_t rfa:1;
243         uint8_t mpf:1;
244         uint8_t frequency:6;
245         uint16_t bitrate;
246 } __attribute__ ((packed));
247
248 #else
249 #error "Unknown byte order"
250 #endif
251
252 struct discover_resp {
253         struct avdtp_header header;
254         struct seid_info seps[0];
255 } __attribute__ ((packed));
256
257 struct getcap_resp {
258         struct avdtp_header header;
259         uint8_t caps[0];
260 } __attribute__ ((packed));
261
262
263 static void print_mpeg12(struct mpeg_codec_cap *mpeg)
264 {
265         printf("\tMedia Codec: MPEG12\n\t\tChannel Modes: ");
266
267         if (mpeg->channel_mode & MPEG_CHANNEL_MODE_MONO)
268                 printf("Mono ");
269         if (mpeg->channel_mode & MPEG_CHANNEL_MODE_DUAL_CHANNEL)
270                 printf("DualChannel ");
271         if (mpeg->channel_mode & MPEG_CHANNEL_MODE_STEREO)
272                 printf("Stereo ");
273         if (mpeg->channel_mode & MPEG_CHANNEL_MODE_JOINT_STEREO)
274                 printf("JointStereo");
275
276         printf("\n\t\tFrequencies: ");
277         if (mpeg->frequency & MPEG_SAMPLING_FREQ_16000)
278                 printf("16Khz ");
279         if (mpeg->frequency & MPEG_SAMPLING_FREQ_22050)
280                 printf("22.05Khz ");
281         if (mpeg->frequency & MPEG_SAMPLING_FREQ_24000)
282                 printf("24Khz ");
283         if (mpeg->frequency & MPEG_SAMPLING_FREQ_32000)
284                 printf("32Khz ");
285         if (mpeg->frequency & MPEG_SAMPLING_FREQ_44100)
286                 printf("44.1Khz ");
287         if (mpeg->frequency & MPEG_SAMPLING_FREQ_48000)
288                 printf("48Khz ");
289
290         printf("\n\t\tCRC: %s", mpeg->crc ? "Yes" : "No");
291
292         printf("\n\t\tLayer: ");
293         if (mpeg->layer & MPEG_LAYER_MP1)
294                 printf("1 ");
295         if (mpeg->layer & MPEG_LAYER_MP2)
296                 printf("2 ");
297         if (mpeg->layer & MPEG_LAYER_MP3)
298                 printf("3 ");
299
300         printf("\n\t\tBit Rate: ");
301         if (mpeg->bitrate & MPEG_BIT_RATE_FREE)
302                 printf("Free format");
303         else {
304                 if (mpeg->bitrate & MPEG_BIT_RATE_32000)
305                         printf("32kbps ");
306                 if (mpeg->bitrate & MPEG_BIT_RATE_40000)
307                         printf("40kbps ");
308                 if (mpeg->bitrate & MPEG_BIT_RATE_48000)
309                         printf("48kbps ");
310                 if (mpeg->bitrate & MPEG_BIT_RATE_56000)
311                         printf("56kbps ");
312                 if (mpeg->bitrate & MPEG_BIT_RATE_64000)
313                         printf("64kbps ");
314                 if (mpeg->bitrate & MPEG_BIT_RATE_80000)
315                         printf("80kbps ");
316                 if (mpeg->bitrate & MPEG_BIT_RATE_96000)
317                         printf("96kbps ");
318                 if (mpeg->bitrate & MPEG_BIT_RATE_112000)
319                         printf("112kbps ");
320                 if (mpeg->bitrate & MPEG_BIT_RATE_128000)
321                         printf("128kbps ");
322                 if (mpeg->bitrate & MPEG_BIT_RATE_160000)
323                         printf("160kbps ");
324                 if (mpeg->bitrate & MPEG_BIT_RATE_192000)
325                         printf("192kbps ");
326                 if (mpeg->bitrate & MPEG_BIT_RATE_224000)
327                         printf("224kbps ");
328                 if (mpeg->bitrate & MPEG_BIT_RATE_256000)
329                         printf("256kbps ");
330                 if (mpeg->bitrate & MPEG_BIT_RATE_320000)
331                         printf("320kbps ");
332         }
333
334         printf("\n\t\tVBR: %s", mpeg->bitrate & MPEG_BIT_RATE_VBR ? "Yes" :
335                 "No");
336
337         printf("\n\t\tPayload Format: ");
338         if (mpeg->mpf)
339                 printf("RFC-2250 RFC-3119\n");
340         else
341                 printf("RFC-2250\n");
342 }
343
344 static void print_sbc(struct sbc_codec_cap *sbc)
345 {
346         printf("\tMedia Codec: SBC\n\t\tChannel Modes: ");
347
348         if (sbc->channel_mode & SBC_CHANNEL_MODE_MONO)
349                 printf("Mono ");
350         if (sbc->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
351                 printf("DualChannel ");
352         if (sbc->channel_mode & SBC_CHANNEL_MODE_STEREO)
353                 printf("Stereo ");
354         if (sbc->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
355                 printf("JointStereo");
356
357         printf("\n\t\tFrequencies: ");
358         if (sbc->frequency & SBC_SAMPLING_FREQ_16000)
359                 printf("16Khz ");
360         if (sbc->frequency & SBC_SAMPLING_FREQ_32000)
361                 printf("32Khz ");
362         if (sbc->frequency & SBC_SAMPLING_FREQ_44100)
363                 printf("44.1Khz ");
364         if (sbc->frequency & SBC_SAMPLING_FREQ_48000)
365                 printf("48Khz ");
366
367         printf("\n\t\tSubbands: ");
368         if (sbc->allocation_method & SBC_SUBBANDS_4)
369                 printf("4 ");
370         if (sbc->allocation_method & SBC_SUBBANDS_8)
371                 printf("8");
372
373         printf("\n\t\tBlocks: ");
374         if (sbc->block_length & SBC_BLOCK_LENGTH_4)
375                 printf("4 ");
376         if (sbc->block_length & SBC_BLOCK_LENGTH_8)
377                 printf("8 ");
378         if (sbc->block_length & SBC_BLOCK_LENGTH_12)
379                 printf("12 ");
380         if (sbc->block_length & SBC_BLOCK_LENGTH_16)
381                 printf("16 ");
382
383         printf("\n\t\tBitpool Range: %d-%d\n",
384                                 sbc->min_bitpool, sbc->max_bitpool);
385 }
386
387 static void print_media_codec(struct avdtp_media_codec_capability *cap)
388 {
389         switch (cap->media_codec_type) {
390         case A2DP_CODEC_SBC:
391                 print_sbc((void *) cap);
392                 break;
393         case A2DP_CODEC_MPEG12:
394                 print_mpeg12((void *) cap);
395                 break;
396         default:
397                 printf("\tMedia Codec: Unknown\n");
398         }
399 }
400
401 static void print_caps(void *data, int size)
402 {
403         int processed;
404
405         for (processed = 0; processed + 2 < size;) {
406                 struct avdtp_service_capability *cap;
407
408                 cap = data;
409
410                 if (processed + 2 + cap->length > size) {
411                         printf("Invalid capability data in getcap resp\n");
412                         break;
413                 }
414
415                 switch (cap->category) {
416                 case AVDTP_MEDIA_TRANSPORT:
417                 case AVDTP_REPORTING:
418                 case AVDTP_RECOVERY:
419                 case AVDTP_CONTENT_PROTECTION:
420                 case AVDTP_MULTIPLEXING:
421                         /* FIXME: Add proper functions */
422                         break;
423                 case AVDTP_MEDIA_CODEC:
424                         print_media_codec((void *) cap->data);
425                         break;
426                 }
427
428                 processed += 2 + cap->length;
429                 data += 2 + cap->length;
430         }
431 }
432
433 static void init_request(struct avdtp_header *header, int request_id)
434 {
435         static int transaction = 0;
436
437         header->packet_type = AVDTP_PKT_TYPE_SINGLE;
438         header->message_type = AVDTP_MSG_TYPE_COMMAND;
439         header->transaction = transaction;
440         header->signal_id = request_id;
441
442         /* clear rfa bits */
443         header->rfa0 = 0;
444
445         transaction = (transaction + 1) % 16;
446 }
447
448 static ssize_t avdtp_send(int sk, void *data, int len)
449 {
450         ssize_t ret;
451
452         ret = send(sk, data, len, 0);
453
454         if (ret < 0)
455                 ret = -errno;
456         else if (ret != len)
457                 ret = -EIO;
458
459         if (ret < 0) {
460                 printf("Unable to send message: %s (%zd)\n",
461                                                 strerror(-ret), -ret);
462                 return ret;
463         }
464
465         return ret;
466 }
467
468 static ssize_t avdtp_receive(int sk, void *data, int len)
469 {
470         ssize_t ret;
471
472         ret = recv(sk, data, len, 0);
473
474         if (ret < 0) {
475                 printf("Unable to receive message: %s (%d)\n",
476                                                 strerror(errno), errno);
477                 return -errno;
478         }
479
480         return ret;
481 }
482
483 static ssize_t avdtp_get_caps(int sk, int seid)
484 {
485         struct seid_req req;
486         char buffer[1024];
487         struct getcap_resp *caps = (void *) buffer;
488         ssize_t ret;
489
490         memset(&req, 0, sizeof(req));
491         init_request(&req.header, AVDTP_GET_CAPABILITIES);
492         req.acp_seid = seid;
493
494         ret = avdtp_send(sk, &req, sizeof(req));
495         if (ret < 0)
496                 return ret;
497
498         memset(&buffer, 0, sizeof(buffer));
499         ret = avdtp_receive(sk, caps, sizeof(buffer));
500         if (ret < 0)
501                 return ret;
502
503         if ((size_t) ret < (sizeof(struct getcap_resp) + 4 +
504                         sizeof(struct avdtp_media_codec_capability))) {
505                 printf("Invalid capabilities\n");
506                 return -1;
507         }
508
509         print_caps(caps, ret);
510
511         return 0;
512 }
513
514 static ssize_t avdtp_discover(int sk)
515 {
516         struct avdtp_header req;
517         char buffer[256];
518         struct discover_resp *discover = (void *) buffer;
519         int seps, i;
520         ssize_t ret;
521
522         memset(&req, 0, sizeof(req));
523         init_request(&req, AVDTP_DISCOVER);
524
525         ret = avdtp_send(sk, &req, sizeof(req));
526         if (ret < 0)
527                 return ret;
528
529         memset(&buffer, 0, sizeof(buffer));
530         ret = avdtp_receive(sk, discover, sizeof(buffer));
531         if (ret < 0)
532                 return ret;
533
534         seps = (ret - sizeof(struct avdtp_header)) / sizeof(struct seid_info);
535         for (i = 0; i < seps; i++) {
536                 const char *type, *media;
537
538                 switch (discover->seps[i].type) {
539                 case AVDTP_SEP_TYPE_SOURCE:
540                         type = "Source";
541                         break;
542                 case AVDTP_SEP_TYPE_SINK:
543                         type = "Sink";
544                         break;
545                 default:
546                         type = "Invalid";
547                 }
548
549                 switch (discover->seps[i].media_type) {
550                 case AVDTP_MEDIA_TYPE_AUDIO:
551                         media = "Audio";
552                         break;
553                 case AVDTP_MEDIA_TYPE_VIDEO:
554                         media = "Video";
555                         break;
556                 case AVDTP_MEDIA_TYPE_MULTIMEDIA:
557                         media = "Multimedia";
558                         break;
559                 default:
560                         media = "Invalid";
561                 }
562
563                 printf("Stream End-Point #%d: %s %s %s\n",
564                                         discover->seps[i].seid, media, type,
565                                         discover->seps[i].inuse ? "*" : "");
566
567                 avdtp_get_caps(sk, discover->seps[i].seid);
568         }
569
570         return 0;
571 }
572
573 static int l2cap_connect(bdaddr_t *src, bdaddr_t *dst)
574 {
575         struct sockaddr_l2 l2a;
576         int sk;
577
578         memset(&l2a, 0, sizeof(l2a));
579         l2a.l2_family = AF_BLUETOOTH;
580         bacpy(&l2a.l2_bdaddr, src);
581
582         sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
583         if (sk < 0) {
584                 printf("Cannot create L2CAP socket. %s(%d)\n", strerror(errno),
585                                 errno);
586                 return -errno;
587         }
588
589         if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a)) < 0) {
590                 printf("Bind failed. %s (%d)\n", strerror(errno), errno);
591                 return -errno;
592         }
593
594         memset(&l2a, 0, sizeof(l2a));
595         l2a.l2_family = AF_BLUETOOTH;
596         bacpy(&l2a.l2_bdaddr, dst);
597         l2a.l2_psm = htobs(AVDTP_PSM);
598
599         if (connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) < 0) {
600                 printf("Connect failed. %s(%d)\n", strerror(errno), errno);
601                 return -errno;
602         }
603
604         return sk;
605 }
606
607 static void usage(void)
608 {
609         printf("avinfo - Audio/Video Info Tool ver %s\n", VERSION);
610         printf("Usage:\n"
611                 "\tavinfo [options] <remote address>\n");
612         printf("Options:\n"
613                 "\t-h\t\tDisplay help\n"
614                 "\t-i\t\tSpecify source interface\n");
615 }
616
617 static struct option main_options[] = {
618         { "help",       0, 0, 'h' },
619         { "device",     1, 0, 'i' },
620         { 0, 0, 0, 0 }
621 };
622
623 int main(int argc, char *argv[])
624 {
625         bdaddr_t src, dst;
626         int opt, sk, dev_id;
627
628         if (argc < 2) {
629                 usage();
630                 exit(0);
631         }
632
633         bacpy(&src, BDADDR_ANY);
634         dev_id = hci_get_route(&src);
635         if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0)) {
636                 printf("Cannot find any local adapter\n");
637                 exit(-1);
638         }
639
640         while ((opt = getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
641                 switch (opt) {
642                 case 'i':
643                         if (!strncmp(optarg, "hci", 3))
644                                 hci_devba(atoi(optarg + 3), &src);
645                         else
646                                 str2ba(optarg, &src);
647                         break;
648
649                 case 'h':
650                 default:
651                         usage();
652                         exit(0);
653                 }
654         }
655
656         printf("Connecting ... \n");
657
658         if (bachk(argv[optind]) < 0) {
659                 printf("Invalid argument\n");
660                 exit(1);
661         }
662
663         str2ba(argv[optind], &dst);
664         sk = l2cap_connect(&src, &dst);
665         if (sk < 0)
666                 exit(1);
667
668         if (avdtp_discover(sk) < 0)
669                 exit(1);
670
671         return 0;
672 }