]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dev.h
b37c48d1955da500c8cffb57adfa1cedaaa08d1e
[bacula/bacula] / bacula / src / stored / dev.h
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Definitions for using the Device functions in Bacula
30  *  Tape and File storage access
31  *
32  * Kern Sibbald, MM
33  *
34  *   Version $Id$
35  *
36  */
37
38
39 #ifndef __DEV_H
40 #define __DEV_H 1
41
42 #undef DCR                            /* used by Bacula */
43
44 #define lock_device(d) _lock_device(__FILE__, __LINE__, (d))
45 #define unlock_device(d) _unlock_device(__FILE__, __LINE__, (d))
46 #define block_device(d, s) _block_device(__FILE__, __LINE__, (d), s)
47 #define unblock_device(d) _unblock_device(__FILE__, __LINE__, (d))
48 #define steal_device_lock(d, p, s) _steal_device_lock(__FILE__, __LINE__, (d), (p), s)
49 #define give_back_device_lock(d, p) _give_back_device_lock(__FILE__, __LINE__, (d), (p))
50
51 /* Return values from wait_for_sysop() */
52 enum {
53    W_ERROR = 1,
54    W_TIMEOUT,
55    W_POLL,
56    W_MOUNT,
57    W_WAKE
58 };
59
60 /* Arguments to open_dev() */
61 enum {
62    CREATE_READ_WRITE = 1,
63    OPEN_READ_WRITE,
64    OPEN_READ_ONLY,
65    OPEN_WRITE_ONLY
66 };
67
68 /* Device types */
69 enum {
70    B_FILE_DEV = 1,
71    B_TAPE_DEV,
72    B_DVD_DEV,
73    B_FIFO_DEV,
74    B_PROG_DEV
75 };
76
77 /* Generic status bits returned from status_dev() */
78 #define BMT_TAPE           (1<<0)     /* is tape device */
79 #define BMT_EOF            (1<<1)     /* just read EOF */
80 #define BMT_BOT            (1<<2)     /* at beginning of tape */
81 #define BMT_EOT            (1<<3)     /* end of tape reached */
82 #define BMT_SM             (1<<4)     /* DDS setmark */
83 #define BMT_EOD            (1<<5)     /* DDS at end of data */
84 #define BMT_WR_PROT        (1<<6)     /* tape write protected */
85 #define BMT_ONLINE         (1<<7)     /* tape online */
86 #define BMT_DR_OPEN        (1<<8)     /* tape door open */
87 #define BMT_IM_REP_EN      (1<<9)     /* immediate report enabled */
88
89
90 /* Bits for device capabilities */
91 #define CAP_EOF            (1<<0)     /* has MTWEOF */
92 #define CAP_BSR            (1<<1)     /* has MTBSR */
93 #define CAP_BSF            (1<<2)     /* has MTBSF */
94 #define CAP_FSR            (1<<3)     /* has MTFSR */
95 #define CAP_FSF            (1<<4)     /* has MTFSF */
96 #define CAP_EOM            (1<<5)     /* has MTEOM */
97 #define CAP_REM            (1<<6)     /* is removable media */
98 #define CAP_RACCESS        (1<<7)     /* is random access device */
99 #define CAP_AUTOMOUNT      (1<<8)     /* Read device at start to see what is there */
100 #define CAP_LABEL          (1<<9)     /* Label blank tapes */
101 #define CAP_ANONVOLS       (1<<10)    /* Mount without knowing volume name */
102 #define CAP_ALWAYSOPEN     (1<<11)    /* always keep device open */
103 #define CAP_AUTOCHANGER    (1<<12)    /* AutoChanger */
104 #define CAP_OFFLINEUNMOUNT (1<<13)    /* Offline before unmount */
105 #define CAP_STREAM         (1<<14)    /* Stream device */
106 #define CAP_BSFATEOM       (1<<15)    /* Backspace file at EOM */
107 #define CAP_FASTFSF        (1<<16)    /* Fast forward space file */
108 #define CAP_TWOEOF         (1<<17)    /* Write two eofs for EOM */
109 #define CAP_CLOSEONPOLL    (1<<18)    /* Close device on polling */
110 #define CAP_POSITIONBLOCKS (1<<19)    /* Use block positioning */
111 #define CAP_MTIOCGET       (1<<20)    /* Basic support for fileno and blkno */
112 #define CAP_REQMOUNT       (1<<21)    /* Require mount to read files back (typically: DVD) */
113 #define CAP_CHECKLABELS    (1<<22)    /* Check for ANSI/IBM labels */
114
115 /* Test state */
116 #define dev_state(dev, st_state) ((dev)->state & (st_state))
117
118 /* Device state bits */
119 #define ST_XXXXXX          (1<<0)     /* was ST_OPENED */
120 #define ST_XXXXX           (1<<1)     /* was ST_TAPE */
121 #define ST_XXXX            (1<<2)     /* was ST_FILE */
122 #define ST_XXX             (1<<3)     /* was ST_FIFO */
123 #define ST_XX              (1<<4)     /* was ST_DVD */
124 #define ST_X               (1<<5)     /* was ST_PROG */
125
126 #define ST_LABEL           (1<<6)     /* label found */
127 #define ST_MALLOC          (1<<7)     /* dev packet malloc'ed in init_dev() */
128 #define ST_APPEND          (1<<8)     /* ready for Bacula append */
129 #define ST_READ            (1<<9)     /* ready for Bacula read */
130 #define ST_EOT             (1<<10)    /* at end of tape */
131 #define ST_WEOT            (1<<11)    /* Got EOT on write */
132 #define ST_EOF             (1<<12)    /* Read EOF i.e. zero bytes */
133 #define ST_NEXTVOL         (1<<13)    /* Start writing on next volume */
134 #define ST_SHORT           (1<<14)    /* Short block read */
135 #define ST_MOUNTED         (1<<15)    /* the device is mounted to the mount point */
136 #define ST_MEDIA           (1<<16)    /* Media found in mounted device */
137 #define ST_OFFLINE         (1<<17)    /* set offline by operator */
138 #define ST_PART_SPOOLED    (1<<18)    /* spooling part */
139 #define ST_FREESPACE_OK    (1<<19)    /* Have valid freespace for DVD */
140
141 /* m_blocked states (mutually exclusive) */
142 enum {
143    BST_NOT_BLOCKED = 0,               /* not blocked */
144    BST_UNMOUNTED,                     /* User unmounted device */
145    BST_WAITING_FOR_SYSOP,             /* Waiting for operator to mount tape */
146    BST_DOING_ACQUIRE,                 /* Opening/validating/moving tape */
147    BST_WRITING_LABEL,                 /* Labeling a tape */
148    BST_UNMOUNTED_WAITING_FOR_SYSOP,   /* User unmounted during wait for op */
149    BST_MOUNT                          /* Mount request */
150 };
151
152 /* Volume Catalog Information structure definition */
153 struct VOLUME_CAT_INFO {
154    /* Media info for the current Volume */
155    uint32_t VolCatJobs;               /* number of jobs on this Volume */
156    uint32_t VolCatFiles;              /* Number of files */
157    uint32_t VolCatBlocks;             /* Number of blocks */
158    uint64_t VolCatBytes;              /* Number of bytes written */
159    uint32_t VolCatParts;              /* Number of parts written */
160    uint32_t VolCatMounts;             /* Number of mounts this volume */
161    uint32_t VolCatErrors;             /* Number of errors this volume */
162    uint32_t VolCatWrites;             /* Number of writes this volume */
163    uint32_t VolCatReads;              /* Number of reads this volume */
164    uint64_t VolCatRBytes;             /* Number of bytes read */
165    uint32_t VolCatRecycles;           /* Number of recycles this volume */
166    uint32_t EndFile;                  /* Last file number */
167    uint32_t EndBlock;                 /* Last block number */
168    int32_t  LabelType;                /* Bacula/ANSI/IBM */
169    int32_t  Slot;                     /* >0=Slot loaded, 0=nothing, -1=unknown */
170    uint32_t VolCatMaxJobs;            /* Maximum Jobs to write to volume */
171    uint32_t VolCatMaxFiles;           /* Maximum files to write to volume */
172    uint64_t VolCatMaxBytes;           /* Max bytes to write to volume */
173    uint64_t VolCatCapacityBytes;      /* capacity estimate */
174    btime_t  VolReadTime;              /* time spent reading */
175    btime_t  VolWriteTime;             /* time spent writing this Volume */
176    int64_t  VolMediaId;               /* MediaId */
177    utime_t  VolFirstWritten;          /* Time of first write */
178    bool     InChanger;                /* Set if vol in current magazine */
179    char VolCatStatus[20];             /* Volume status */
180    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
181 };
182
183
184 typedef struct s_steal_lock {
185    pthread_t  no_wait_id;             /* id of no wait thread */
186    int        dev_blocked;            /* state */
187    int        dev_prev_blocked;       /* previous blocked state */
188 } bsteal_lock_t;
189
190 class DEVRES;                        /* Device resource defined in stored_conf.h */
191
192 class DCR; /* forward reference */
193 /*
194  * Device structure definition. There is one of these for
195  *  each physical device. Everything here is "global" to
196  *  that device and effects all jobs using the device.
197  */
198 class DEVICE {
199 private:
200    int m_fd;                          /* file descriptor */
201    int m_blocked;                     /* set if we must wait (i.e. change tape) */
202 public:
203    dlist *attached_dcrs;              /* attached DCR list */
204    pthread_mutex_t m_mutex;           /* access control */
205    pthread_mutex_t spool_mutex;       /* mutex for updating spool_size */
206    pthread_cond_t wait;               /* thread wait variable */
207    pthread_cond_t wait_next_vol;      /* wait for tape to be mounted */
208    pthread_t no_wait_id;              /* this thread must not wait */
209    int dev_prev_blocked;              /* previous blocked state */
210    int num_waiting;                   /* number of threads waiting */
211    int num_writers;                   /* number of writing threads */
212    int reserved_device;               /* number of device reservations */
213
214    /* New access control in process of being implemented */
215 // brwlock_t xlock;                   /* New mutual exclusion lock */
216
217    int capabilities;                  /* capabilities mask */
218    int state;                         /* state mask */
219    int dev_errno;                     /* Our own errno */
220    int mode;                          /* read/write modes */
221    int openmode;                      /* parameter passed to open_dev (useful to reopen the device) */
222    int dev_type;                      /* device type */
223    bool autoselect;                   /* Autoselect in autochanger */
224    int label_type;                    /* Bacula/ANSI/IBM label types */
225    uint32_t drive_index;              /* Autochanger drive index (base 0) */
226    int32_t  Slot;                     /* Slot currently in drive (base 1) */
227    POOLMEM *dev_name;                 /* Physical device name */
228    POOLMEM *prt_name;                 /* Name used for display purposes */
229    char *errmsg;                      /* nicely edited error message */
230    uint32_t block_num;                /* current block number base 0 */
231    uint32_t file;                     /* current file number base 0 */
232    uint64_t file_addr;                /* Current file read/write address */
233    uint64_t file_size;                /* Current file size */
234    uint32_t EndBlock;                 /* last block written */
235    uint32_t EndFile;                  /* last file written */
236    uint32_t min_block_size;           /* min block size */
237    uint32_t max_block_size;           /* max block size */
238    uint64_t max_volume_size;          /* max bytes to put on one volume */
239    uint64_t max_file_size;            /* max file size to put in one file on volume */
240    uint64_t volume_capacity;          /* advisory capacity */
241    uint64_t max_spool_size;           /* maximum spool file size */
242    uint64_t spool_size;               /* current spool size for this device */
243    uint32_t max_rewind_wait;          /* max secs to allow for rewind */
244    uint32_t max_open_wait;            /* max secs to allow for open */
245    uint32_t max_open_vols;            /* max simultaneous open volumes */
246    
247    uint64_t max_part_size;            /* max part size */
248    uint64_t part_size;                /* current part size */
249    uint32_t part;                     /* current part number (starts at 0) */
250    uint64_t part_start;               /* current part start address (relative to the whole volume) */
251    uint32_t num_dvd_parts;            /* number of parts WRITTEN on the DVD */
252    /* state ST_FREESPACE_OK is set if free_space is valid */
253    uint64_t free_space;               /* current free space on medium (without the current part) */
254    int free_space_errno;              /* indicates errno getting freespace */
255    bool truncating;                   /* if set, we are currently truncating the DVD */
256    bool blank_dvd;                    /* if set, we have a blank DVD in the drive */
257    
258    
259    utime_t  vol_poll_interval;        /* interval between polling Vol mount */
260    DEVRES *device;                    /* pointer to Device Resource */
261    btimer_t *tid;                     /* timer id */
262
263    VOLUME_CAT_INFO VolCatInfo;        /* Volume Catalog Information */
264    VOLUME_LABEL VolHdr;               /* Actual volume label */
265    char pool_name[MAX_NAME_LENGTH];   /* pool name */
266    char pool_type[MAX_NAME_LENGTH];   /* pool type */
267
268    /* Device wait times ***FIXME*** look at durations */
269    char BadVolName[MAX_NAME_LENGTH];  /* Last wrong Volume mounted */
270    bool poll;                         /* set to poll Volume */
271    int min_wait;
272    int max_wait;
273    int max_num_wait;
274    int wait_sec;
275    int rem_wait_sec;
276    int num_wait;
277
278    btime_t last_timer;        /* used by read/write/seek to get stats (usec) */
279    btime_t last_tick;         /* contains last read/write time (usec) */
280
281    btime_t  DevReadTime;
282    btime_t  DevWriteTime;
283    uint64_t DevWriteBytes;
284    uint64_t DevReadBytes;
285
286    /* Methods */
287    btime_t get_timer_count();         /* return the last timer interval (ms) */
288
289    int has_cap(int cap) const { return capabilities & cap; }
290    void clear_cap(int cap) { capabilities &= ~cap; }
291    void set_cap(int cap) { capabilities |= cap; }
292    int is_autochanger() const { return capabilities & CAP_AUTOCHANGER; }
293    int requires_mount() const { return capabilities & CAP_REQMOUNT; }
294    int is_removable() const { return capabilities & CAP_REM; }
295    int is_tape() const { return dev_type == B_TAPE_DEV; }
296    int is_file() const { return dev_type == B_FILE_DEV; }
297    int is_fifo() const { return dev_type == B_FIFO_DEV; }
298    int is_dvd() const  { return dev_type == B_DVD_DEV; }
299    int is_prog() const  { return dev_type == B_PROG_DEV; }
300    int is_open() const { return m_fd >= 0; }
301    int is_offline() const { return state & ST_OFFLINE; }
302    int is_labeled() const { return state & ST_LABEL; }
303    int is_mounted() const { return state & ST_MOUNTED; }
304    int is_part_spooled() const { return state & ST_PART_SPOOLED; }
305    int have_media() const { return state & ST_MEDIA; }
306    int is_short_block() const { return state & ST_SHORT; }
307    int is_busy() const { return (state & ST_READ) || num_writers || reserved_device; }
308    int at_eof() const { return state & ST_EOF; }
309    int at_eot() const { return state & ST_EOT; }
310    int at_weot() const { return state & ST_WEOT; }
311    int can_append() const { return state & ST_APPEND; }
312    int is_freespace_ok() const { return state & ST_FREESPACE_OK; }
313    /*
314     * can_write() is meant for checking at the end of a job to see
315     * if we still have a tape (perhaps not if at end of tape
316     * and the job is canceled).
317     */
318    int can_write() const { return is_open() && can_append() &&
319                             is_labeled() && !at_weot(); }
320    int can_read() const   { return state & ST_READ; }
321    bool can_steal_lock() const { return m_blocked &&
322                     (m_blocked == BST_UNMOUNTED ||
323                      m_blocked == BST_WAITING_FOR_SYSOP ||
324                      m_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); };
325    bool waiting_for_mount() const { return 
326                     (m_blocked == BST_UNMOUNTED ||
327                      m_blocked == BST_WAITING_FOR_SYSOP ||
328                      m_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); };
329    const char *strerror() const;
330    const char *archive_name() const;
331    const char *name() const;
332    const char *print_name() const;    /* Name for display purposes */
333    void set_ateof(); /* in dev.c */
334    void set_ateot(); /* in dev.c */
335    void set_eot() { state |= ST_EOT; };
336    void set_eof() { state |= ST_EOF; };
337    void set_append() { state |= ST_APPEND; };
338    void set_labeled() { state |= ST_LABEL; };
339    inline void set_read() { state |= ST_READ; };
340    void set_offline() { state |= ST_OFFLINE; };
341    void set_mounted() { state |= ST_MOUNTED; };
342    void set_media() { state |= ST_MEDIA; };
343    void set_short_block() { state |= ST_SHORT; };
344    void set_freespace_ok() { state |= ST_FREESPACE_OK; }
345    void set_part_spooled(int val) { if (val) state |= ST_PART_SPOOLED; \
346           else state &= ~ST_PART_SPOOLED;
347    };
348    void set_mounted(int val) { if (val) state |= ST_MOUNTED; \
349           else state &= ~ST_MOUNTED; };
350    void clear_append() { state &= ~ST_APPEND; };
351    void clear_read() { state &= ~ST_READ; };
352    void clear_labeled() { state &= ~ST_LABEL; };
353    void clear_offline() { state &= ~ST_OFFLINE; };
354    void clear_eot() { state &= ~ST_EOT; };
355    void clear_eof() { state &= ~ST_EOF; };
356    void clear_opened() { m_fd = -1; };
357    void clear_mounted() { state &= ~ST_MOUNTED; };
358    void clear_media() { state &= ~ST_MEDIA; };
359    void clear_short_block() { state &= ~ST_SHORT; };
360    void clear_freespace_ok() { state &= ~ST_FREESPACE_OK; };
361    char *bstrerror(void) { return errmsg; };
362    char *print_errmsg() { return errmsg; };
363    void lock() { P(m_mutex); } 
364    void unlock() { V(m_mutex); } 
365
366    void clear_volhdr();          /* in dev.c */
367    void block(int why);          /* in dev.c */
368    void unblock();               /* in dev.c */
369    void close();                 /* in dev.c */
370    void close_part(DCR *dcr);    /* in dev.c */
371    bool truncate(DCR *dcr);      /* in dev.c */
372    int open(DCR *dcr, int mode); /* in dev.c */
373    void term(void);              /* in dev.c */
374    ssize_t read(void *buf, size_t len); /* in dev.c */
375    ssize_t write(const void *buf, size_t len);  /* in dev.c */
376    bool rewind(DCR *dcr);        /* in dev.c */
377    bool mount(int timeout);      /* in dev.c */
378    bool unmount(int timeout);    /* in dev.c */
379    void edit_mount_codes(POOL_MEM &omsg, const char *imsg); /* in dev.c */
380    bool offline_or_rewind();     /* in dev.c */
381    bool offline();               /* in dev.c */
382    bool bsf(int count);          /* in dev.c */
383    bool eod(DCR *dcr);           /* in dev.c */
384    bool fsr(int num);            /* in dev.c */
385    bool fsf(int num);            /* in dev.c */
386    bool bsr(int num);            /* in dev.c */
387    bool weof(int num);           /* in dev.c */
388    void lock_door();             /* in dev.c */
389    void unlock_door();           /* in dev.c */
390    int32_t get_os_tape_file();   /* in dev.c */
391    bool scan_dir_for_volume(DCR *dcr); /* in scan.c */
392    bool reposition(DCR *dcr, uint32_t rfile, uint32_t rblock); /* in dev.c */
393    void clrerror(int func);      /* in dev.c */
394    boffset_t lseek(DCR *dcr, boffset_t offset, int whence); /* in dev.c */
395    bool update_pos(DCR *dcr);    /* in dev.c */
396    bool update_freespace();      /* in dvd.c */
397
398    void set_blocked(int block) { m_blocked = block; };
399    int  blocked() const { return m_blocked; };
400    uint32_t get_file() const { return file; };
401    uint32_t get_block() const { return block_num; };
402    const char *print_blocked() const; /* in dev.c */
403    bool is_blocked() const { return m_blocked != BST_NOT_BLOCKED; };
404    int fd() const { return m_fd; };
405
406 private:
407    bool do_mount(int mount, int timeout);      /* in dev.c */
408    void set_mode(int omode);                   /* in dev.c */
409    void open_tape_device(DCR *dcr, int omode); /* in dev.c */
410    void open_file_device(DCR *dcr, int omode); /* in dev.c */
411    void open_dvd_device(DCR *dcr, int omode);  /* in dev.c */
412 };
413
414 /* Note, these return int not bool! */
415 inline const char *DEVICE::strerror() const { return errmsg; }
416 inline const char *DEVICE::archive_name() const { return dev_name; }
417 inline const char *DEVICE::print_name() const { return prt_name; }
418
419 /*
420  * Device Context (or Control) Record.
421  *  There is one of these records for each Job that is using
422  *  the device. Items in this record are "local" to the Job and
423  *  do not affect other Jobs. Note, a job can have multiple
424  *  DCRs open, each pointing to a different device. 
425  */
426 class DCR {
427 public:
428    dlink dev_link;                    /* link to attach to dev */
429    JCR *jcr;                          /* pointer to JCR */
430    DEVICE *dev;                       /* pointer to device */
431    DEVRES *device;                    /* pointer to device resource */
432    DEV_BLOCK *block;                  /* pointer to block */
433    DEV_RECORD *rec;                   /* pointer to record */
434    int spool_fd;                      /* fd if spooling */
435    bool spool_data;                   /* set to spool data */
436    bool spooling;                     /* set when actually spooling */
437    bool despooling;                   /* set when despooling */
438    bool despool_wait;                 /* waiting for despooling */
439    bool dev_locked;                   /* set if dev already locked */
440    bool NewVol;                       /* set if new Volume mounted */
441    bool WroteVol;                     /* set if Volume written */
442    bool NewFile;                      /* set when EOF written */
443    bool reserved_device;              /* set if reserve done */
444    bool any_volume;                   /* Any OK for dir_find_next... */
445    bool attached_to_dev;              /* set when attached to dev */
446    uint32_t VolFirstIndex;            /* First file index this Volume */
447    uint32_t VolLastIndex;             /* Last file index this Volume */
448    uint32_t FileIndex;                /* Current File Index */
449    uint32_t EndFile;                  /* End file written */
450    uint32_t StartFile;                /* Start write file */
451    uint32_t StartBlock;               /* Start write block */
452    uint32_t EndBlock;                 /* Ending block written */
453    int64_t job_spool_size;            /* Current job spool size */
454    int64_t max_job_spool_size;        /* Max job spool size */
455    char VolumeName[MAX_NAME_LENGTH];  /* Volume name */
456    char pool_name[MAX_NAME_LENGTH];   /* pool name */
457    char pool_type[MAX_NAME_LENGTH];   /* pool type */
458    char media_type[MAX_NAME_LENGTH];  /* media type */
459    char dev_name[MAX_NAME_LENGTH];    /* dev name */
460    int Copy;                          /* identical copy number */
461    int Stripe;                        /* RAIT stripe */
462    VOLUME_CAT_INFO VolCatInfo;        /* Catalog info for desired volume */
463 };
464
465 /*
466  * Volume reservation class -- see reserve.c
467  */
468 class VOLRES { 
469 public:
470    dlink link;
471    char *vol_name;
472    DEVICE *dev;
473    DCR *dcr;
474 };
475
476
477 /* Get some definition of function to position
478  *  to the end of the medium in MTEOM. System
479  *  dependent. Arrgggg!
480  */
481 #ifndef MTEOM
482 #ifdef  MTSEOD
483 #define MTEOM MTSEOD
484 #endif
485 #ifdef MTEOD
486 #undef MTEOM
487 #define MTEOM MTEOD
488 #endif
489 #endif
490
491 #endif