Unix v7 Y2k patch

Posted by Unik on 13.01.2018

В Unix v7 как и во многих других ОС для PDP-11 есть проблема Y2k. Решение было найдено в японском блоге. Попробуем это повторить.

В первую очередь нужно исправить часовой пояс т.к. по умолчанию стоит cевероамериканское восточное время EST (GMT–05). А мне нужно UTC+3. Для того чтобы изменить часовой пояс нужно изменить файл /usr/sys/h/param.h и пересобрать ядро.

# cat /usr/sys/h/param.h
/*
 * tunable variables
 */

#define NBUF    29              /* size of buffer cache */
#define NINODE  200             /* number of in core inodes */
#define NFILE   175             /* number of in core file structures */
#define NMOUNT  8               /* number of mountable file systems */
#define MAXMEM  (64*32)         /* max core per process - first # is Kw */
#define MAXUPRC 25              /* max processes per user */
#define SSIZE   20              /* initial stack size (*64 bytes) */
#define SINCR   20              /* increment of stack (*64 bytes) */
#define NOFILE  20              /* max open files per process */
#define CANBSIZ 256             /* max size of typewriter line */
#define CMAPSIZ 50              /* size of core allocation area */
#define SMAPSIZ 50              /* size of swap allocation area */
#define NCALL   20              /* max simultaneous time callouts */
#define NPROC   150             /* max number of processes */
#define NTEXT   40              /* max number of pure texts */
#define NCLIST  100             /* max total clist size */
#define HZ      60              /* Ticks/second of the clock */
#define TIMEZONE (5*60)         /* Minutes westward from Greenwich */
#define DSTFLAG 1               /* Daylight Saving Time applies in this locality */
#define MSGBUFS 128             /* Characters saved from error messages */
#define NCARGS  5120            /* # characters in exec arglist */ 

В этом файле нужно поменять значение TIMEZONE и DSTFLAG(0 - отключить летнее время) для UTC+3 это будет выглядеть так:

# ed /usr/sys/h/param.h
4411
22p
#define TIMEZONE (5*60)         /* Minutes westward from Greenwich */
22c
#define TIMEZONE (-3*60)         /* Minutes westward from Greenwich */
.<cr>
23c
#define DSTFLAG 0               /* Daylight Saving Time applies in this locality */
.<cr>
22,23p
#define TIMEZONE (-3*60)         /* Minutes westward from Greenwich */
#define DSTFLAG 0               /* Daylight Saving Time applies in this locality */
w
4431
q
#

Затем нужно пересобрать ядро, выполнив сначала make all

# cd /usr/sys/conf
# make all
cd ../sys; cc -c -O *.c; mklib; rm *.o
acct.c:
...
# make
ld -o unix -X -i l.o mch.o c.o ../sys/LIB1 ../dev/LIB2
#

Часовой пояс будет установлен правильно, но не будет отображаться в системе, чтобы и это исправить придется добавить его в файл /usr/src/libc/gen/timezone.c

# cd /usr/src/libc/gen
# cat timezone.c
/*
 * The arguments are the number of minutes of time
 * you are westward from Greenwich and whether DST is in effect.
 * It returns a string
 * giving the name of the local timezone.
 *
 * Sorry, I don't know all the names.
 */

static struct zone {
        int     offset;
        char    *stdzone;
        char    *dlzone;
} zonetab[] = {
        4*60, "AST", "ADT",             /* Atlantic */
        5*60, "EST", "EDT",             /* Eastern */
        6*60, "CST", "CDT",             /* Central */
        7*60, "MST", "MDT",             /* Mountain */
        8*60, "PST", "PDT",             /* Pacific */
        0, "GMT", 0,                    /* Greenwich */
        -1
};

Отредактируем в этом файле часовой пояс

} zonetab[] = {
        -3*60, "MSK", 0,             /* Russia */
        4*60, "AST", "ADT",             /* Atlantic */
        5*60, "EST", "EDT",             /* Eastern */
        6*60, "CST", "CDT",             /* Central */
        7*60, "MST", "MDT",             /* Mountain */
        8*60, "PST", "PDT",             /* Pacific */
        0, "GMT", 0,                    /* Greenwich */
        -1
};

И скомпилируем исходник

# cc -c -O timezone.c

Поскольку часовой пояс является частью libc.a, замените содержимое libc.a на новый файл.

# cd /lib
# cp libc.a libc.a.org
# ar r libc.a /usr/src/libc/gen/timezone.o

С часовым поясом всё, но осталось решить проблему с годами больше 1999 и для этого нужно подправить команду date, исходник которой находится в /usr/src/cmd/date.c Подправим функцию gtime(), где укажем что если значение года меньше или равно 50, то это 2000-е годы.

gtime()
{
...
        if (hour==24) {
                hour=0; day++;
        }
        if (hour<0 hour="">23)
                return(1);
        timbuf = 0;
        /* fix y2k */
        /*year += 1900;*/ оригинальная строка
        if (year > 50){
                year += 1900;
        }
        else{
                year += 2000;
        }
        /* fix y2k end */
        for(i=1970; i<year; i++)
                timbuf += dysize(i);
        /* Leap year */
        if (dysize(year)==366 && month >= 3)
                timbuf++;
        while(--month)
                timbuf += dmsize[month-1];
        timbuf += day-1;
        timbuf = 24*timbuf + hour;
        timbuf = 60*timbuf + mins;
        timbuf = 60*timbuf + secs;
        return(0);

}

# cd /usr/src/cmd
# ed date.c

Скомпилируем файл и заменим им /bin/date

# cc -o date date.c
# mv /bin/date /bin/date.org
# cp ./date /bin/

Заменим ядро на только что собранное и перезагрузим систему

# mv /unix /oldunix
# cp /usr/sys/conf/unix /unix
# sync;sync;sync;
# (Ctrl-E)

После загрузки проверяем что получилось.

# date 1801131607
Sat Jan 13 16:07:00 MSK 2018
# date -u
Sat Jan 13 13:07:05 GMT 2018

UPD. После каждого изменения timezone.c нужно заново компилировать date.c иначе изменения не применяться.