Annotation of nono/lib/mainapp.cpp, revision 1.1.1.16

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.12  root        7: //
                      8: // CLI/GUI 共通のメイン部分
                      9: //
                     10: 
1.1       root       11: #include "mainapp.h"
1.1.1.16! root       12: #include "accel_avx2.h"
1.1.1.12  root       13: #include "config.h"
                     14: #include "hostnet.h"
                     15: #include "logger.h"
                     16: #include "monitor.h"
1.1.1.2   root       17: #include "mystring.h"
1.1.1.12  root       18: #include "mythread.h"
1.1.1.14  root       19: #include "sram.h"
1.1.1.12  root       20: #include "vm_luna.h"
1.1.1.14  root       21: #include "vm_news.h"
1.1.1.16! root       22: #include "vm_virt68k.h"
1.1.1.12  root       23: #include "vm_x68k.h"
1.1.1.14  root       24: #include <fcntl.h>
1.1.1.2   root       25: #include <getopt.h>
1.1.1.14  root       26: #include <pwd.h>
1.1.1.16! root       27: #include <sys/param.h>
1.1.1.2   root       28: #include <sys/stat.h>
1.1.1.8   root       29: #include <algorithm>
1.1.1.12  root       30: #if defined(__linux__)
                     31: #include <sys/prctl.h>
                     32: #endif
1.1.1.2   root       33: 
                     34: // グローバルインスタンス
                     35: MainApp gMainApp;
                     36: 
1.1.1.12  root       37: // コンストラクタ
                     38: MainApp::MainApp()
                     39: {
                     40: }
                     41: 
                     42: // デストラクタ
                     43: MainApp::~MainApp()
                     44: {
                     45:        // 逆順に解放
                     46: 
                     47:        pVM.reset();
1.1.1.14  root       48: 
                     49:        pConfig.reset();
                     50:        gConfig = NULL;
                     51: 
                     52:        pMonitorManager.reset();
                     53:        gMonitorManager = NULL;
                     54: 
1.1.1.12  root       55: #if 0  // 確認用
                     56:        if (objects.empty() == false) {
                     57:                printf("~MainApp: undead objects are:");
                     58:                for (const auto *obj : objects) {
1.1.1.14  root       59:                        printf(" %s", obj->GetIdStr());
1.1.1.12  root       60:                }
                     61:                printf("\n");
                     62:        }
                     63: #endif
                     64: 
                     65:        logger.reset();
                     66: }
                     67: 
1.1.1.16! root       68: // VM を解放。
        !            69: void
        !            70: MainApp::Dispose()
        !            71: {
        !            72:        if ((bool)pVM) {
        !            73:                pVM->Dispose();
        !            74:        }
        !            75: }
        !            76: 
1.1.1.2   root       77: // ヘルプメッセージ
                     78: void
                     79: MainApp::ShowHelp(bool all) const
                     80: {
                     81:        ShowVersion();
                     82: 
                     83: #define p(msg) printf(" " msg "\n")
                     84: 
                     85:        printf("usage: %s [<options>]\n", getprogname());
1.1.1.6   root       86:        p("-c <path>           vm directory or configuration file");
1.1.1.14  root       87:        p("-f                  fast mode (same as '-V fast-mode=1')");
1.1.1.2   root       88:        if (IsGUI())
1.1.1.14  root       89:                p("--fontsize <height> fontsize (same as '-V monitor-fontsize=<height>')");
1.1.1.2   root       90:        p("-h                  show brief help message");
                     91:        p("--help              show all help message including for developers");
                     92:        if (IsGUI())
1.1.1.14  root       93:                p("-s <scale>          mainview scale (same as '-V mainview-scale=<scale>')");
1.1.1.2   root       94:        p("--show-config       show configuration variables");
1.1.1.8   root       95:        p("--show-hostnet      show list of hostnet drivers");
1.1.1.2   root       96:        p("-v                  show version");
                     97:        p("-V <key>=<val>      overwrite config option");
1.1.1.16! root       98:        p("-X <file>           load and execute host binary (a.out or ELF)");
        !            99:        p("--initrd <img>      initial ramdisk (only for virt68k)");
1.1.1.2   root      100: 
                    101:        if (all) {
                    102:                printf("\n(options for developers)\n");
1.1.1.14  root      103:                p("-b [<cpu>,]<addr>[,<skip>]");
                    104:                p("                    set breakpoint. <cpu> is either 'main'(default) or 'xp'");
1.1.1.16! root      105:                p("--bi-exg            set instruction breakpoint on 'exg sp,sp'");
1.1.1.2   root      106:                p("-B <rom#>           benchmark mode");
                    107:                p("-C                  output log to console");
                    108:                p("-d                  debugger prompt on startup");
1.1.1.12  root      109:                p("-D                  same as '-V debugger-driver=stdio'");
1.1.1.10  root      110:                p("-H                  human68k console emulation");
1.1.1.2   root      111:                p("-L <name>=<lv>[,..] set loglevel (-Lhelp displays names)");
                    112:                p("-M <name>[,..]      monitors to display at startup (-Mhelp displays names)");
1.1.1.14  root      113:                p("   memdump<N>[=<hex-addr>[.<fmt>]]  fmt := B/W/L/M(MMU)/I(Disasm)/Z(XPDisasm)");
                    114:                p("-S                  MSX-DOS console emulation");
1.1.1.12  root      115:                p("--perf              performance measure mode");
1.1.1.2   root      116:        }
                    117: }
                    118: 
                    119: // long option は enum と struct option をアルファベット順に並べる。
                    120: // enum は getopt() の1文字のオプションと衝突しなければいいので適当に
                    121: // 0x80 から始めておく。
                    122: enum {
1.1.1.14  root      123:        OPTstart = 0x80 - 1,
1.1.1.16! root      124:        OPT_bi_exg,
1.1.1.14  root      125:        OPT_create_sram,
                    126:        OPT_fontsize,
1.1.1.2   root      127:        OPT_help,
1.1.1.16! root      128:        OPT_initrd,
1.1.1.12  root      129:        OPT_perf,
1.1.1.2   root      130:        OPT_show_config,
1.1.1.3   root      131:        OPT_show_config_all,
1.1.1.8   root      132:        OPT_show_hostnet,
1.1.1.2   root      133: };
                    134: static struct option longopts[] = {
1.1.1.16! root      135:        { "bi-exg",                     no_argument,            NULL,   OPT_bi_exg },
1.1.1.14  root      136:        { "create-sram",        no_argument,            NULL,   OPT_create_sram },
1.1.1.2   root      137:        { "fontsize",           required_argument,      NULL,   OPT_fontsize },
                    138:        { "help",                       no_argument,            NULL,   OPT_help },
1.1.1.16! root      139:        { "initrd",                     required_argument,      NULL,   OPT_initrd },
1.1.1.12  root      140:        { "perf",                       no_argument,            NULL,   OPT_perf },
1.1.1.2   root      141:        { "show-config",        no_argument,            NULL,   OPT_show_config },
1.1.1.3   root      142:        // --show-config-all は開発用なのでヘルプには載せない
                    143:        { "show-config-all",no_argument,                NULL,   OPT_show_config_all },
1.1.1.8   root      144:        { "show-hostnet",       no_argument,            NULL,   OPT_show_hostnet },
1.1.1.2   root      145:        { NULL,                         0,                                      NULL,   0 },
                    146: };
                    147: 
1.1.1.7   root      148: // VM の初期化、ステージ1。
                    149: // VM 作成と設定確定あたりまで。スレッド生成を伴わないもの。
1.1.1.2   root      150: // 所々 CLI と GUI で処理が違う。
1.1.1.5   root      151: // 戻り値は以下のいずれか。
                    152: //  MainApp::PASS .. 実行を継続(通常パス)
                    153: //  EXIT_SUCCESS / EXIT_FAILURE .. この終了コードでアプリケーションを終了
                    154: int
1.1.1.7   root      155: MainApp::Init1(bool is_cli_, int ac, char *av[])
1.1.1.2   root      156: {
1.1.1.14  root      157:        int rv;
                    158: 
1.1.1.2   root      159:        is_cli = is_cli_;
                    160: 
1.1.1.16! root      161:        rv = Init1a(ac, av);
        !           162:        if (rv != MainApp::PASS) {
        !           163:                return rv;
        !           164:        }
        !           165: 
        !           166:        rv = Init1b();
        !           167:        return rv;
        !           168: }
        !           169: 
        !           170: // VM の初期化、ステージ1 の前半。
        !           171: // Config.Fix まで。
        !           172: int
        !           173: MainApp::Init1a(int ac, char *av[])
        !           174: {
        !           175:        int rv;
        !           176: 
1.1.1.12  root      177: #if defined(__linux__)
                    178:        // Linux ではケーパビリティが設定されていると coredump しないので
                    179:        // 明示的に許可する必要がある
                    180:        prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
                    181: #endif
                    182: 
1.1.1.14  root      183:        rv = ParseOpt(ac, av);
                    184:        if (rv != MainApp::PASS) {
                    185:                return rv;
1.1.1.2   root      186:        }
1.1       root      187: 
1.1.1.2   root      188:        // ログ機構は引数処理後なるはや
                    189:        // CLI ならログは常に標準出力へ(も)出力。
                    190:        // GUI なら -C で指定。
1.1.1.12  root      191:        logger.reset(new Logger());
                    192:        logger->UseStdout(IsCLI() ? true : log_to_console);
                    193: 
                    194:        // モニタマネージャ (VM 作成より前、もしかしたら Config より前?)
                    195:        pMonitorManager.reset(new MonitorManager());
                    196:        gMonitorManager = pMonitorManager.get();
1.1.1.2   root      197: 
1.1.1.14  root      198:        // 設定を作成。
                    199:        // c0. コンストラクタで初期値を用意。
1.1.1.12  root      200:        pConfig.reset(new Config());
                    201:        gConfig = pConfig.get();
1.1.1.2   root      202: 
1.1.1.14  root      203:        // c1. ホームディレクトリに設定ファイルがあれば読み込んで設定を更新。
                    204:        struct passwd *passwd = getpwuid(getuid());
                    205:        // 見付からないことはないはずだが、一応。
                    206:        if (passwd != NULL) {
                    207:                std::string filename = std::string(passwd->pw_dir) + "/.nono.cfg";
1.1.1.16! root      208:                ConfigFile dotfile(filename, ConfigItem::FromHome);
1.1.1.14  root      209:                if (dotfile.Load()) {
                    210:                        if (gConfig->Update(dotfile) == false) {
                    211:                                return EXIT_FAILURE;
                    212:                        }
                    213:                }
1.1.1.2   root      214:        }
1.1.1.14  root      215: 
                    216:        // c2. VM ディレクトリに設定ファイルがあれば読み込んで設定を更新。
                    217:        // vmfile が存在するかどうかはここで調べるまで分からない。
1.1.1.16! root      218:        ConfigFile cfgfile(vmfile, ConfigItem::FromConfig);
1.1.1.14  root      219:        if (cfgfile.Load()) {
                    220:                if (gConfig->Update(cfgfile) == false) {
                    221:                        return EXIT_FAILURE;
                    222:                }
1.1.1.2   root      223:        }
1.1.1.14  root      224: 
                    225:        // c3. 最後にコマンドライン引数で更新
                    226:        for (const auto& pair : config_options) {
                    227:                if (gConfig->Update(pair.first, pair.second) == false) {
                    228:                        return EXIT_FAILURE;
                    229:                }
                    230:        }
                    231: 
1.1.1.16! root      232:        // c4. exec-file, exec-arg をここでメンバ変数 exec_file, exec_arg に代入。
        !           233:        // (c3 までに確定していて、1. VM コンストラクト時には必要)
        !           234:        const ConfigItem& itemexec = gConfig->Find("exec-file");
        !           235:        const std::string& execstr = itemexec.AsString();
        !           236:        if (execstr.empty() == false) {
        !           237:                // 歴史的経緯で exec_file は const char *。
        !           238:                exec_file = strdup(NormalizePath(execstr).c_str());
        !           239:        }
        !           240:        const ConfigItem& itemarg = gConfig->Find("exec-arg");
        !           241:        exec_arg = itemarg.AsString();
        !           242: 
1.1.1.14  root      243:        // MSX-DOS モードならここでいくつかパラメータを強制的に変更。
                    244:        if (msxdos_mode) {
                    245:                // LUNA-I 最小構成でいい
                    246:                gConfig->Update("vmtype=luna", "-S");
                    247:                gConfig->Update("ram-size=16", "-S");
                    248:                gConfig->Update("luna-video-plane=1", "-S");
                    249:                // ホスト側には干渉しない。
                    250:                gConfig->Update("hostcom-driver=none", "-S");
                    251:                gConfig->Update("hostnet-driver=none", "-S");
1.1.1.2   root      252:        }
1.1       root      253: 
1.1.1.16! root      254:        // ホスト CPU の機能チェック。
        !           255:        if (CheckCPU() == false) {
        !           256:                return EXIT_FAILURE;
        !           257:        }
        !           258: 
1.1.1.12  root      259:        // 0. VM 種別を決定
1.1.1.9   root      260:        // VM 種別文字列から vmtype を決定
                    261:        const ConfigItem& item = gConfig->Find("vmtype");
1.1.1.14  root      262:        vmstr = string_tolower(item.AsString());
1.1.1.9   root      263:        if (vmstr == "x68030") {
1.1.1.13  root      264:                vmtype = VMType::X68030;
1.1.1.9   root      265:        } else if (vmstr == "luna") {
1.1.1.13  root      266:                vmtype = VMType::LUNA1;
1.1.1.9   root      267:        } else if (vmstr == "luna88k") {
1.1.1.13  root      268:                vmtype = VMType::LUNA88K;
1.1.1.14  root      269:        } else if (vmstr == "news") {
                    270:                vmtype = VMType::NEWS;
1.1.1.16! root      271:        } else if (vmstr == "virt68k") {
        !           272:                vmtype = VMType::VIRT68K;
1.1.1.2   root      273:        } else {
1.1.1.9   root      274:                if (item.GetFrom() == ConfigItem::FromInitial) {
                    275:                        // 未指定の時
                    276:                        warnx("vmtype must be specified");
1.1.1.2   root      277:                } else {
1.1.1.9   root      278:                        // ユーザ由来の時
1.1.1.14  root      279:                        item.Err("Invalid vmtype");
1.1.1.2   root      280:                }
1.1.1.9   root      281:                return EXIT_FAILURE;
1.1.1.2   root      282:        }
1.1       root      283: 
1.1.1.14  root      284:        // 0.5. VM が確定したところで SRAM 作成。
                    285:        if (create_sram) {
                    286:                if (vmtype == VMType::X68030) {
                    287:                        return CreateSRAM();
                    288:                } else {
                    289:                        warnx("--create-sram is only for X68030 mode");
                    290:                        return EXIT_FAILURE;
                    291:                }
                    292:        }
                    293: 
1.1.1.12  root      294:        // 1. VM 作成
1.1.1.2   root      295:        switch (vmtype) {
1.1.1.13  root      296:         case VMType::X68030:
1.1.1.12  root      297:                pVM.reset(new VM_X68030());
1.1.1.2   root      298:                break;
                    299: 
1.1.1.13  root      300:         case VMType::LUNA1:
1.1.1.12  root      301:                pVM.reset(new VM_LUNA1());
1.1.1.2   root      302:                break;
                    303: 
1.1.1.13  root      304:         case VMType::LUNA88K:
1.1.1.12  root      305:                pVM.reset(new VM_LUNA88K());
1.1.1.2   root      306:                break;
1.1       root      307: 
1.1.1.14  root      308:         case VMType::NEWS:
                    309:                pVM.reset(new VM_NEWS());
                    310:                break;
                    311: 
1.1.1.16! root      312:         case VMType::VIRT68K:
        !           313:                pVM.reset(new VM_Virt68k());
        !           314:                break;
        !           315: 
1.1.1.2   root      316:         default:
1.1.1.16! root      317:                PANIC("vmtype=%s not configured", vmstr.c_str());
1.1.1.2   root      318:        }
                    319: 
1.1.1.12  root      320:        // 2. 動的なコンストラクション
1.1.1.16! root      321:        if (!pVM->Create()) {
1.1.1.12  root      322:                pVM.reset();
1.1.1.5   root      323:                return EXIT_FAILURE;
                    324:        }
                    325: 
1.1.1.16! root      326:        // 3. 設定を確定。
1.1.1.5   root      327:        // (VM コンストラクタで変数の増減があるのでそれより後、
                    328:        // Create() でも SCSI パラメータを減らすので、それより後)
1.1.1.14  root      329:        if (gConfig->Fix() == false) {
                    330:                pVM.reset();
                    331:                return EXIT_SUCCESS;
                    332:        }
1.1.1.16! root      333: 
        !           334:        // Fix() は配列から削除を行うため、これより前に取得していた ConfigItem
        !           335:        // のポインタや参照は無効になっている可能性がある。Fix() をまたいで
        !           336:        // ポインタや参照を使ってしまわないようここで一旦フォーカスを抜ける。
        !           337:        // なお Fix() 後は要素の削除は出来ないため、以降はこの問題は発生しない。
        !           338: 
        !           339:        return PASS;
        !           340: }
        !           341: 
        !           342: // VM の初期化、ステージ1 の後半。
        !           343: // Config.Fix 以降。
        !           344: int
        !           345: MainApp::Init1b()
        !           346: {
        !           347:        // 3.1 設定が確定したので --show-config なら設定内容を表示して終了。
1.1.1.2   root      348:        if (show_config) {
1.1.1.3   root      349:                gConfig->Show(show_config - 1);
1.1.1.12  root      350:                pVM.reset();
1.1.1.5   root      351:                return EXIT_SUCCESS;
1.1.1.2   root      352:        }
                    353: 
1.1.1.16! root      354:        // 3.2 ログレベルを設定。コンストラクト後すぐに行う。
1.1.1.2   root      355:        // -L help もここで処理。
                    356:        if (!ParseLogopt()) {
1.1.1.12  root      357:                pVM.reset();
1.1.1.5   root      358:                return EXIT_FAILURE;
1.1.1.2   root      359:        }
                    360: 
1.1.1.16! root      361:        // 3.3 -X のチェック。
        !           362:        // -L help より後にしないとヘルプが表示できない。
        !           363:        const ConfigItem& itemexec = gConfig->Find("exec-file");
        !           364:        if (exec_file == NULL) {
        !           365:                // -X が必要なケースで指定されてなければエラー。
        !           366: 
        !           367:                // 実行ファイル指定が必須の VM。
        !           368:                if (vmtype == VMType::NEWS || vmtype == VMType::VIRT68K) {
        !           369:                        if (itemexec.GetFrom() == ConfigItem::FromInitial) {
        !           370:                                warnx("vmtype=%s requires -X option (or exec-file).",
        !           371:                                        vmstr.c_str());
        !           372:                        } else {
        !           373:                                itemexec.Err("filename must be specified.");
        !           374:                        }
        !           375:                        return EXIT_FAILURE;
        !           376:                }
        !           377: 
        !           378:                // Human モード、MSX-DOS モードでも実行ファイル名が必要。
        !           379:                if (human_mode) {
        !           380:                        warnx("-H option needs -X");
        !           381:                        return EXIT_FAILURE;
        !           382:                }
        !           383:                if (msxdos_mode) {
        !           384:                        warnx("-S option needs -X");
        !           385:                        return EXIT_FAILURE;
        !           386:                }
        !           387:        } else {
        !           388:                // 実行ファイルのファイル名を間違えたくらいならここでエラーに出来る。
        !           389:                int r = access(exec_file, R_OK);
        !           390:                if (r != 0) {
        !           391:                        itemexec.Err("%s", strerror(errno));
        !           392:                        return EXIT_FAILURE;
        !           393:                }
        !           394:        }
        !           395: 
1.1.1.5   root      396:        return PASS;
1.1.1.2   root      397: }
                    398: 
1.1.1.7   root      399: // VM の初期化、ステージ2。スレッド生成を伴う。
                    400: // Init1() で引数を受け付けてから Init2() でデバッガスレッドなどを起動するが、
1.1.1.2   root      401: // -Mhelp とかが指定された場合はここでスレッド開始する前にプロセスを終了する
1.1.1.7   root      402: // 必要があるので分けてある。wxapp.cpp も参照。
1.1.1.2   root      403: bool
1.1.1.7   root      404: MainApp::Init2()
1.1.1.2   root      405: {
1.1.1.12  root      406:        // 5. VM 初期化。
1.1.1.16! root      407:        if (!pVM->Init()) {
1.1.1.2   root      408:                return false;
                    409:        }
                    410: 
1.1.1.12  root      411:        // メインスレッド名を設定
                    412:        PTHREAD_SETNAME("Main");
                    413: 
                    414:        // 6. スレッド開始
1.1.1.16! root      415:        if (!pVM->StartThread()) {
1.1.1.12  root      416:                return false;
                    417:        }
                    418: 
                    419:        // 7. 起動時設定の適用
1.1.1.16! root      420:        if (!pVM->Apply()) {
1.1.1.2   root      421:                return false;
                    422:        }
                    423: 
                    424:        return true;
                    425: }
                    426: 
                    427: // コマンドライン引数を処理する。
                    428: // 知らない引数とかがあればこちらで usage を表示して false を返す。
1.1.1.14  root      429: // 戻り値は、MainApp::PASS なら実行を継続、
                    430: // EXIT_SUCCESS/EXIT_FAILURE ならこのコードで終了。
                    431: int
1.1.1.2   root      432: MainApp::ParseOpt(int ac, char *av[])
                    433: {
1.1.1.6   root      434:        struct stat st;
                    435:        const char *cpath;
1.1.1.2   root      436:        int b;
                    437:        int c;
                    438: 
1.1.1.6   root      439:        cpath = ".";
1.1.1.2   root      440: 
1.1.1.14  root      441:        while ((c = getopt_long(ac, av, "b:B:c:CdDfhHL:M:s:SvV:X:",
1.1.1.2   root      442:                                longopts, NULL)) != -1) {
                    443:                switch (c) {
                    444:                 case 'b':
1.1.1.4   root      445:                        debug_breakaddr.push_back(optarg);
1.1.1.2   root      446:                        break;
                    447: 
                    448:                 case 'B':
                    449:                        b = atoi(optarg);
                    450:                        if (b < 2 || b > 6) {
                    451:                                fprintf(stderr, "-B <benchmark_mode>: 2..6\n");
1.1.1.14  root      452:                                return EXIT_FAILURE;
1.1.1.2   root      453:                        }
                    454:                        benchmark_mode = b;
                    455:                        break;
                    456: 
                    457:                 case 'c':
1.1.1.6   root      458:                        cpath = optarg;
                    459:                        // 空文字列なら再び初期値に
                    460:                        if (cpath[0] == '\0') {
                    461:                                cpath = ".";
                    462:                        }
1.1.1.2   root      463:                        break;
                    464: 
                    465:                 case 'C':
                    466:                        log_to_console = true;
                    467:                        break;
                    468: 
                    469:                 case 'd':
                    470:                        debug_on_start = true;
                    471:                        break;
                    472: 
                    473:                 case 'D':
1.1.1.12  root      474:                        // -D は -V debugger-driver=stdio と等価。
1.1.1.14  root      475:                        config_options.emplace_back("debugger-driver=stdio", "-D");
1.1.1.2   root      476:                        break;
                    477: 
                    478:                 case 'f':
1.1.1.14  root      479:                        // -f は -V fast-mode=1 と等価。
                    480:                        config_options.emplace_back("fast-mode=1", "-f");
1.1.1.2   root      481:                        break;
                    482: 
1.1.1.9   root      483:                 case 'H':
                    484:                        human_mode = true;
                    485:                        break;
                    486: 
1.1.1.2   root      487:                 case 'L':
1.1.1.12  root      488:                        AddLogopt(optarg);
1.1.1.2   root      489:                        break;
                    490: 
                    491:                 case 'M':
                    492:                        if (!monitor_opt.empty()) {
                    493:                                monitor_opt += ",";
                    494:                        }
                    495:                        monitor_opt += optarg;
                    496:                        break;
                    497: 
                    498:                 case 's':
1.1.1.14  root      499:                 {
                    500:                        auto line = string_format("mainview-scale=%s", optarg);
                    501:                        config_options.emplace_back(line, "-s");
                    502:                        break;
                    503:                 }
                    504: 
                    505:                 case 'S':
                    506:                        msxdos_mode = true;
1.1.1.2   root      507:                        break;
                    508: 
                    509:                 case 'X':
1.1.1.16! root      510:                 {
        !           511:                        // 相対パスはカレントディレクトリ起点とする。
        !           512:                        char cwd[PATH_MAX];
        !           513:                        getcwd(cwd, sizeof(cwd));
        !           514:                        std::string path = NormalizePath(optarg, std::string(cwd));
        !           515:                        std::string line = "exec-file=" + path;
        !           516:                        config_options.emplace_back(line, "-X");
        !           517: 
        !           518:                        // Human68k モードなら後続を引数にする。
        !           519:                        // UNIX モードでは親和性が悪いのでしない。
        !           520:                        if (human_mode) {
        !           521:                                std::string arg;
        !           522:                                arg = "exec-arg=";
        !           523:                                for (int i = optind; i < ac; i++) {
        !           524:                                        if (i != optind) {
        !           525:                                                arg += " ";
        !           526:                                        }
        !           527:                                        arg += av[i];
1.1.1.2   root      528:                                }
1.1.1.16! root      529:                                optind = ac;
        !           530:                                config_options.emplace_back(arg, "-X");
1.1.1.2   root      531:                        }
                    532:                        break;
1.1.1.16! root      533:                 }
1.1.1.2   root      534: 
                    535:                 case 'v':
                    536:                        ShowVersion();
                    537:                        exit(0);
                    538: 
                    539:                 case 'V':
1.1.1.14  root      540:                        config_options.emplace_back(optarg, "-V");
                    541:                        break;
                    542: 
1.1.1.16! root      543:                 case OPT_bi_exg:
        !           544:                        debug_breakinst_exg = true;
        !           545:                        break;
        !           546: 
1.1.1.14  root      547:                 case OPT_create_sram:
                    548:                        create_sram = true;
1.1.1.2   root      549:                        break;
                    550: 
                    551:                 case OPT_fontsize:
1.1.1.14  root      552:                 {
                    553:                        auto line = string_format("monitor-fontsize=%s", optarg);
                    554:                        config_options.emplace_back(line, "--fontsize");
1.1.1.2   root      555:                        break;
1.1.1.14  root      556:                 }
1.1.1.2   root      557: 
                    558:                 case OPT_help:
                    559:                        ShowHelp(true);
1.1.1.14  root      560:                        return EXIT_SUCCESS;
1.1.1.2   root      561: 
1.1.1.16! root      562:                 case OPT_initrd:
        !           563:                 {
        !           564:                        // 相対パスはカレントディレクトリを起点とする。
        !           565:                        char cwd[PATH_MAX];
        !           566:                        getcwd(cwd, sizeof(cwd));
        !           567:                        std::string path = NormalizePath(optarg, std::string(cwd));
        !           568:                        std::string line = "exec-initrd=" + path;
        !           569:                        config_options.emplace_back(line, "--initrd");
        !           570:                        break;
        !           571:                 }
        !           572: 
1.1.1.12  root      573:                 case OPT_perf:
1.1.1.16! root      574:                 {
1.1.1.12  root      575:                        // パフォーマンス確認用。
                    576:                        // -Vprom-image=PROM.DAT はパスの問題があるので各自で追加指定
                    577:                        // する必要がある。
1.1.1.16! root      578:                        std::string where = "--perf -V";
        !           579:                        config_options.emplace_back(".rtc-force-fixed=1", where);
        !           580:                        config_options.emplace_back("clock-sync=virtual", where);
1.1.1.14  root      581:                        config_options.emplace_back("ethernet-macaddr=02:00:00:00:00:01",
1.1.1.16! root      582:                                where);
        !           583:                        config_options.emplace_back("hostcom-driver=none", where);
        !           584:                        config_options.emplace_back("hostnet-driver=none", where);
        !           585:                        config_options.emplace_back("luna-dipsw1=11110111", where);
        !           586:                        config_options.emplace_back("spc0-id0-writeignore=1", where);
        !           587:                        config_options.emplace_back("spc0-id1-writeignore=1", where);
        !           588:                        config_options.emplace_back("spc0-id2-writeignore=1", where);
        !           589:                        config_options.emplace_back("spc0-id3-writeignore=1", where);
        !           590:                        config_options.emplace_back("spc0-id4-writeignore=1", where);
        !           591:                        config_options.emplace_back("spc0-id5-writeignore=1", where);
        !           592:                        config_options.emplace_back("spc0-id6-writeignore=1", where);
        !           593:                        config_options.emplace_back("fast-mode=1", where);
1.1.1.14  root      594:                        // -C
1.1.1.12  root      595:                        log_to_console = true;
                    596:                        break;
1.1.1.16! root      597:                 }
1.1.1.12  root      598: 
1.1.1.2   root      599:                 case OPT_show_config:
1.1.1.3   root      600:                        show_config = 1;
                    601:                        break;
                    602: 
                    603:                 case OPT_show_config_all:
                    604:                        show_config = 2;
1.1.1.2   root      605:                        break;
                    606: 
1.1.1.8   root      607:                 case OPT_show_hostnet:
                    608:                        ShowHostnet();
1.1.1.14  root      609:                        return EXIT_SUCCESS;
1.1.1.8   root      610: 
1.1.1.2   root      611:                 case 'h':
1.1.1.14  root      612:                        ShowHelp(false);
                    613:                        return EXIT_SUCCESS;
                    614: 
1.1.1.2   root      615:                 default:
                    616:                        ShowHelp(false);
1.1.1.14  root      617:                        return EXIT_FAILURE;
1.1.1.2   root      618:                }
                    619:        }
                    620: 
1.1.1.6   root      621:        // 引数がディレクトリなら、それを VM ディレクトリとし、その中の
                    622:        // nono.cfg を設定ファイルとする。
                    623:        // 引数がファイルなら、それを設定ファイルとし、そのファイルがある
                    624:        // ディレクトリを VM ディレクトリとする。
                    625:        // -c DIR       => vmdir = DIR, vmfile = DIR/nono.cfg
                    626:        // -c DIR/FILE  => vmdir = DIR, vmfile = FILE
                    627:        if (stat(cpath, &st) < 0) {
                    628:                warn("stat %s", cpath);
1.1.1.14  root      629:                return EXIT_FAILURE;
1.1.1.2   root      630:        }
1.1.1.6   root      631:        if (S_ISDIR(st.st_mode)) {
                    632:                vmdir = std::string(cpath);
                    633:                if (vmdir.back() != '/') {
                    634:                        vmdir += '/';
                    635:                }
                    636:                vmfile = vmdir + "nono.cfg";
                    637:        } else if (S_ISREG(st.st_mode)) {
                    638:                vmfile = std::string(cpath);
                    639:                auto pos = vmfile.rfind('/');
                    640:                if (pos != std::string::npos) {
                    641:                        vmdir = vmfile.substr(0, pos + 1);
                    642:                } else {
                    643:                        vmdir = "./";
                    644:                }
                    645:        } else {
                    646:                warnx("-c %s: path must be file or directory", cpath);
1.1.1.14  root      647:                return EXIT_FAILURE;
1.1.1.2   root      648:        }
                    649: 
                    650:        // CLI 版で -Mhelp つけても黙って起動するのはさすがにどうかと思う。
                    651:        // とは言え GUI 版のコマンドラインを CLI 版用に書き換えた時に -M を
                    652:        // 消して回らないと起動できないのも面倒なので -M オプション自体は
                    653:        // 無意味だけど許容する。うーん。
                    654:        if (IsCLI()) {
                    655:                if (monitor_opt == "help") {
                    656:                        warnx("-Mhelp is not available on CLI");
1.1.1.14  root      657:                        return EXIT_FAILURE;
1.1.1.2   root      658:                }
                    659:                if (!monitor_opt.empty()) {
                    660:                        warnx("-M option is ignored on CLI");
1.1.1.14  root      661:                        return EXIT_FAILURE;
1.1.1.2   root      662:                }
                    663:        }
                    664: 
1.1.1.16! root      665:        return MainApp::PASS;
        !           666: }
1.1.1.9   root      667: 
1.1.1.16! root      668: // CPU の機能とかをチェック。
        !           669: bool
        !           670: MainApp::CheckCPU()
        !           671: {
        !           672: #if defined(HAVE_AVX2)
        !           673:        // AVX2
        !           674:        detect_avx2 = ::DetectAVX2();
        !           675: 
        !           676:        const ConfigItem& item_avx2 = gConfig->Find("host-avx2");
        !           677:        std::string cfg_avx2 = item_avx2.AsString();
        !           678: 
        !           679:        if (cfg_avx2 == "auto") {
        !           680:                enable_avx2 = detect_avx2;
        !           681:        } else if (cfg_avx2 == "no") {
        !           682:                enable_avx2 = false;
        !           683:        } else {
        !           684:                item_avx2.Err("must be either \"auto\" or \"no\".");
        !           685:                return false;
1.1.1.14  root      686:        }
1.1.1.16! root      687: #endif
        !           688:        // AVX2 以外は何もしない。設定のチェックもしないほうがいい。
        !           689:        return true;
1.1.1.2   root      690: }
                    691: 
                    692: // バージョンを表示
                    693: void
                    694: MainApp::ShowVersion() const
                    695: {
                    696:        // ここは実行ファイル名によらず nono にする
                    697:        fprintf(stderr, "nono version %d.%d.%d (%s)\n",
                    698:                NONO_MAJOR_VER, NONO_MINOR_VER, NONO_PATCH_VER, NONO_DATE);
                    699: }
                    700: 
1.1.1.12  root      701: // ログレベル指定文字列を logopt に追加する。
                    702: void
                    703: MainApp::AddLogopt(const char *opt)
                    704: {
                    705:        if (logopt.empty() == false) {
                    706:                logopt += ',';
                    707:        }
                    708:        logopt += opt;
                    709: }
                    710: 
1.1.1.8   root      711: // ログレベル指定文字列を処理する。
                    712: // str はログレベル指定文字列を ',' で連結した "foo=1,bar=2" 形式の文字列で、
                    713: // これを分解してそれぞれ担当するオブジェクトのログレベルにセットする。
                    714: // "help" があれば設定は行わず一覧を表示。
1.1       root      715: bool
1.1.1.2   root      716: MainApp::ParseLogopt()
1.1       root      717: {
1.1.1.8   root      718:        std::vector<std::string> items;
                    719: 
                    720:        // 分解して..
1.1.1.12  root      721:        items = string_split(logopt.c_str(), ',');
1.1.1.8   root      722: 
                    723:        // "help" があればヘルプを表示して終了
                    724:        for (const auto& item : items) {
                    725:                if (item == "help") {
                    726:                        std::vector<std::string> list = GetLogNames();
                    727:                        // less したいだろうから stderr ではなく stdout に出力する
                    728:                        for (const auto& name : list) {
                    729:                                printf(" %s\n", name.c_str());
                    730:                        }
                    731:                        return false;
1.1       root      732:                }
1.1.1.8   root      733:        }
                    734: 
                    735:        // ログレベルを設定
                    736:        std::string errmsg;
                    737:        if (SetLogopt(items, &errmsg) == false) {
                    738:                warnx("%s", errmsg.c_str());
1.1       root      739:                return false;
                    740:        }
                    741: 
1.1.1.8   root      742:        return true;
                    743: }
1.1       root      744: 
1.1.1.8   root      745: // ログレベルを設定する。
                    746: // ログレベル指定文字列を 1つずつに分解したリスト items を処理する。
                    747: // "help" があるケースはここに来るまでに処理してあるので、ここには来ない。
                    748: // 成功なら何も表示せず true を返す。失敗なら *errmsg にエラーメッセージを
                    749: // 格納して false を返す。
                    750: // MainApp 内と Debugger からも呼ばれる。
                    751: /*static*/ bool
                    752: MainApp::SetLogopt(const std::vector<std::string>& items, std::string *errmsg)
                    753: {
                    754:        for (const auto& item : items) {
                    755:                if (SetLogopt1(item.c_str(), errmsg) == false) {
                    756:                        return false;
                    757:                }
                    758:        }
                    759:        if (0) {        // デバッグ用
1.1.1.12  root      760:                for (const auto o : gMainApp.GetObjects()) {
1.1.1.8   root      761:                        printf("%-16s %d\n", o->GetName().c_str(), o->loglevel);
1.1       root      762:                }
1.1.1.8   root      763:        }
                    764:        return true;
                    765: }
                    766: 
                    767: // "logname[=loglevel]" 形式をパースしてオブジェクトにログレベルを設定する。
                    768: // loglevel は省略なら 1 とする。
                    769: // logname が "all" なら全オブジェクトにセットする。
                    770: // そうでない場合は case ignore で完全一致するか前方一致で1つに確定すれば、
                    771: // そのオブジェクトにログレベルを設定して true を返す。
                    772: // 見付からないか候補が複数ある場合はエラーメッセージを *errmsg に出力して
                    773: // false を返す。
                    774: // この関数は (このすぐ上の SetLogopt() を経由して)
                    775: // MainApp と Debugger から呼ばれることに注意。
                    776: /*static*/ bool
                    777: MainApp::SetLogopt1(const std::string& item, std::string *errmsg)
                    778: {
                    779:        std::string name;
                    780:        const char *v;
                    781:        int level;
                    782: 
                    783:        v = strchr(item.c_str(), '=');
                    784:        if (v) {
                    785:                name = std::string(item.c_str(), v - item.c_str());
                    786:                level = atoi(++v);
                    787:        } else {
                    788:                name = item;
                    789:                level = 1;
                    790:        }
                    791:        // ここで name は変数名、level は値(省略されたら1)
                    792: 
                    793:        if (name.empty()) {
                    794:                *errmsg = "logname must be specified";
                    795:                return false;
                    796:        }
1.1       root      797: 
1.1.1.12  root      798:        // 今の所、値域は -1 〜 9 ということにしておく。
                    799:        if (level < -1) {
                    800:                level = -1;
                    801:        } else if (level > 9) {
                    802:                level = 9;
                    803:        }
                    804: 
1.1.1.8   root      805:        // "all" なら全部にセット
                    806:        if (name == "all") {
1.1.1.12  root      807:                for (auto obj : gMainApp.GetObjects()) {
1.1.1.8   root      808:                        if (obj->GetName().empty() == false) {
1.1.1.12  root      809:                                obj->SetLogLevel(level);
1.1.1.8   root      810:                        }
1.1       root      811:                }
1.1.1.8   root      812:                return true;
                    813:        }
1.1.1.13  root      814:        // "fdd" なら "fdd*" 全部にする
                    815:        if (name == "fdd") {
                    816:                for (auto obj : gMainApp.GetObjects()) {
                    817:                        if (strncasecmp(obj->GetName().c_str(), "fdd", 3) == 0) {
                    818:                                obj->SetLogLevel(level);
                    819:                        }
                    820:                }
                    821:                return true;
                    822:        }
1.1.1.15  root      823:        // "bankram" も "bankram[01]" 両方にする
                    824:        if (name == "bankram") {
                    825:                for (auto obj : gMainApp.GetObjects()) {
                    826:                        if (strncasecmp(obj->GetName().c_str(), "bankram", 7) == 0) {
                    827:                                obj->SetLogLevel(level);
                    828:                        }
                    829:                }
                    830:                return true;
                    831:        }
1.1.1.16! root      832:        // "gfpic" も "gfpic*" 全部にする
        !           833:        if (name == "gfpic") {
        !           834:                for (auto obj : gMainApp.GetObjects()) {
        !           835:                        if (strncasecmp(obj->GetName().c_str(), "gfpic", 5) == 0) {
        !           836:                                obj->SetLogLevel(level);
        !           837:                        }
        !           838:                }
        !           839:                return true;
        !           840:        }
1.1.1.8   root      841: 
1.1.1.12  root      842:        // エイリアスリストを作る
                    843:        using aliaslist_t = std::vector<std::pair<std::string, Object *>>;
                    844:        aliaslist_t alias_list;
                    845:        for (const auto& obj : gMainApp.GetObjects()) {
1.1.1.8   root      846:                const std::vector<std::string>& aliases = obj->GetAliases();
                    847: 
                    848:                for (const auto& a : aliases) {
1.1.1.12  root      849:                        alias_list.emplace_back(a, obj);
                    850:                }
                    851:        }
1.1.1.8   root      852: 
1.1.1.12  root      853:        // エイリアスを完全一致のみのものと部分一致も許容するものに分ける
                    854:        aliaslist_t exact_alias;
                    855:        aliaslist_t partial_alias;
                    856:        for (const auto& a0 : alias_list) {
                    857:                bool exact = false;
                    858:                for (const auto& a1 : alias_list) {
                    859:                        if (a0.first == a1.first) {
                    860:                                continue;
                    861:                        }
                    862:                        if (starts_with_ignorecase(a0.first, a1.first)) {
                    863:                                exact = true;
                    864:                                break;
1.1       root      865:                        }
1.1.1.8   root      866:                }
1.1.1.12  root      867:                if (exact) {
                    868:                        exact_alias.push_back(a0);
                    869:                } else {
                    870:                        partial_alias.push_back(a0);
                    871:                }
                    872:        }
                    873: 
                    874:        // 完全一致をまず調べる
                    875:        for (const auto& a : exact_alias) {
                    876:                if (strcasecmp(a.first.c_str(), name.c_str()) == 0) {
                    877:                        a.second->SetLogLevel(level);
                    878:                        return true;
                    879:                }
                    880:        }
                    881: 
                    882:        aliaslist_t found;
                    883:        for (const auto& a : partial_alias) {
                    884:                // 前方一致したら覚えておく
                    885:                if (starts_with_ignorecase(a.first, name)) {
                    886:                        found.push_back(a);
                    887:                }
1.1.1.8   root      888:        }
                    889: 
                    890:        // 見付からない場合はエラー
                    891:        if (found.empty()) {
                    892:                *errmsg = string_format("Unknown logname \"%s\"", name.c_str());
                    893:                return false;
                    894:        }
                    895: 
                    896:        // 1つだけなら確定
                    897:        if (found.size() == 1) {
1.1.1.12  root      898:                found[0].second->SetLogLevel(level);
1.1.1.8   root      899:                return true;
                    900:        }
                    901: 
                    902:        // 複数あれば候補文字列を作成
                    903:        *errmsg = string_format("Ambiguous logname \"%s\": candidates are",
                    904:                name.c_str());
1.1.1.12  root      905:        for (const auto& cand : found) {
                    906:                *errmsg += string_format(" \"%s\"", cand.first.c_str());
1.1.1.8   root      907:        }
                    908:        return false;
                    909: }
                    910: 
                    911: // ログ名の一覧を取得する。
                    912: // MainApp と Debugger から呼ばれる。
                    913: /*static*/ std::vector<std::string>
                    914: MainApp::GetLogNames()
                    915: {
                    916:        std::vector<Object *> sortobj;
                    917: 
                    918:        // エイリアスを持つオブジェクトだけ抜き出す
1.1.1.12  root      919:        for (const auto& obj : gMainApp.GetObjects()) {
1.1.1.8   root      920:                if (obj->GetAliases().empty() == false) {
                    921:                        sortobj.emplace_back(obj);
                    922:                }
                    923:        }
                    924: 
                    925:        // aliases の一語目で sortobj をソートする
                    926:        std::sort(sortobj.begin(), sortobj.end(),
1.1.1.12  root      927:                [](const auto a, const auto b) {
1.1.1.8   root      928:                        const auto& sa = a->GetAliases()[0];
                    929:                        const auto& sb = b->GetAliases()[0];
1.1.1.12  root      930:                        return sa < sb;
1.1.1.8   root      931:                }
                    932:        );
                    933: 
                    934:        std::vector<std::string> list;
                    935:        for (const auto *obj : sortobj) {
                    936:                const auto& aliases = obj->GetAliases();
                    937:                std::string str;
                    938: 
1.1.1.12  root      939:                str = aliases[0];
1.1.1.8   root      940:                if (aliases.size() > 1) {
                    941:                        str += " (alias:";
                    942:                        for (int i = 1, sz = aliases.size(); i < sz; i++) {
                    943:                                str += ' ';
                    944:                                str += aliases[i];
1.1       root      945:                        }
1.1.1.8   root      946:                        str += ')';
1.1.1.6   root      947:                }
1.1.1.8   root      948:                list.emplace_back(str);
1.1       root      949:        }
1.1.1.8   root      950:        list.emplace_back("all");
1.1       root      951: 
1.1.1.8   root      952:        return list;
1.1       root      953: }
1.1.1.2   root      954: 
                    955: // 関連するファイルのパスを取得。
1.1.1.3   root      956: // 1. name がファイル名のみなら、VM ディレクトリとその親ディレクトリを検索。
                    957: //    ファイルが存在すればその時点で戻り値とする。ファイルが存在したけど
                    958: //    何らか不都合があったとしても (例えばファイルサイズが 0 だとか
                    959: //    パーミッションが足りないとか) 次を試すとかはしない。
1.1.1.16! root      960: // 2. 通常手順(相対パスは VM ディレクトリ起点) でパスを展開。
        !           961: //    ファイルの有無は不問。
1.1.1.2   root      962: std::string
                    963: MainApp::SearchFile(const std::string& name) const
                    964: {
1.1.1.3   root      965:        // 1. パス区切りを含んでなければ、ファイル名のみ
                    966:        if (name.find('/') == std::string::npos) {
1.1.1.16! root      967:                std::string path;
        !           968:                struct stat st;
        !           969: 
1.1.1.3   root      970:                // 1a. VM ディレクトリ
                    971:                path = GetVMDir() + name;
                    972:                if (stat(path.c_str(), &st) == 0) {
                    973:                        return path;
                    974:                }
                    975: 
1.1.1.16! root      976:                // 1b. 親ディレクトリ
1.1.1.3   root      977:                path = GetVMDir() + "../" + name;
                    978:                if (stat(path.c_str(), &st) == 0) {
                    979:                        return path;
                    980:                }
                    981: 
                    982:                // どちらもなければエラー
                    983:                return "";
                    984:        }
1.1.1.2   root      985: 
1.1.1.16! root      986:        // 2. 通常手順でパスを展開。
        !           987:        return NormalizePath(name);
        !           988: }
        !           989: 
        !           990: // path を必要なら絶対パスに展開して返す。
        !           991: // 相対パスは VM ディレクトリを起点とする。
        !           992: std::string
        !           993: MainApp::NormalizePath(const std::string& path) const
        !           994: {
        !           995:        return NormalizePath(path, GetVMDir());
        !           996: }
        !           997: 
        !           998: // path を必要なら絶対パスに展開して返す。
        !           999: // 相対パスは basedir を起点とする。
        !          1000: std::string
        !          1001: MainApp::NormalizePath(const std::string& path,
        !          1002:        const std::string& basedir) const
        !          1003: {
        !          1004:        // 絶対パスならそのまま返す。
        !          1005:        if (path[0] == '/') {
        !          1006:                return path;
1.1.1.2   root     1007:        }
                   1008: 
1.1.1.16! root     1009:        std::string newpath;
        !          1010: 
        !          1011:        if (path[0] == '~') {
        !          1012:                // 先頭が '~' ならホームディレクトリに展開。
        !          1013: 
        !          1014:                struct passwd *passwd = getpwuid(getuid());
        !          1015:                // 見付からないことはないはずだが、一応。
        !          1016:                if (passwd != NULL) {
        !          1017:                        newpath = std::string(passwd->pw_dir);
        !          1018:                }
        !          1019:                newpath += &path[1];
        !          1020:        } else {
        !          1021:                // basedir からの相対パスとして展開。
        !          1022: 
        !          1023:                newpath = basedir;
        !          1024:                if (newpath.empty() || newpath.back() != '/') {
        !          1025:                        newpath += '/';
        !          1026:                }
        !          1027:                newpath += path;
1.1.1.2   root     1028:        }
                   1029: 
1.1.1.16! root     1030:        return newpath;
1.1.1.3   root     1031: }
                   1032: 
1.1.1.14  root     1033: // 初回起動時用に SRAM.DAT を作成する。
                   1034: // 戻り値は EXIT_SUCCESS / EXIT_FAILURE。
                   1035: int
                   1036: MainApp::CreateSRAM()
                   1037: {
                   1038:        char buf[16 * 1024];
                   1039:        std::string filename;
                   1040:        autofd fd;
                   1041:        int r;
                   1042: 
                   1043:        filename = GetVMDir() + "SRAM.DAT";
                   1044: 
                   1045:        // 存在確認のため一旦読み込み専用で開いてみる。
                   1046:        // オープン出来たら何もしない。
                   1047:        fd = open(filename.c_str(), O_RDONLY);
                   1048:        if (fd >= 0) {
                   1049:                warnx("%s: Already exists", filename.c_str());
                   1050:                return EXIT_FAILURE;
                   1051:        }
                   1052: 
                   1053:        fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
                   1054:        if (fd < 0) {
                   1055:                warn("%s: open failed", filename.c_str());
                   1056:                return EXIT_FAILURE;
                   1057:        }
                   1058: 
                   1059:        memset(&buf[0], 0, sizeof(buf));
                   1060:        for (int i = 0; i < SRAMDevice::InitialData.size(); i++) {
                   1061:                buf[i] = SRAMDevice::InitialData[i];
                   1062:        }
                   1063: 
                   1064:        r = write(fd, buf, sizeof(buf));
                   1065:        if (r < 0) {
                   1066:                warn("%s: write failed", filename.c_str());
                   1067:                return EXIT_FAILURE;
                   1068:        }
                   1069: 
                   1070:        fd.Close();
                   1071:        warnx("created %s", filename.c_str());
                   1072:        return EXIT_SUCCESS;
                   1073: }
                   1074: 
1.1.1.13  root     1075: // 現在の VM が指定のケーパビリティを持っているか?
1.1.1.3   root     1076: bool
1.1.1.13  root     1077: MainApp::Has(VMCap cap) const
1.1.1.3   root     1078: {
1.1.1.13  root     1079:        uint32 vmcap = 1U << (int)GetVMType();
                   1080:        return (vmcap & (uint32)cap) != 0;
1.1.1.2   root     1081: }
1.1.1.8   root     1082: 
1.1.1.16! root     1083: // VM 機種名を返す。
        !          1084: const char *
        !          1085: MainApp::GetVMName() const
        !          1086: {
        !          1087:        if ((bool)pVM) {
        !          1088:                return pVM->GetVMName();
        !          1089:        } else {
        !          1090:                return NULL; // not configured
        !          1091:        }
        !          1092: }
        !          1093: 
1.1.1.8   root     1094: // コンパイルされている host netdriver の一覧を表示。
                   1095: void
                   1096: MainApp::ShowHostnet() const
                   1097: {
1.1.1.12  root     1098:        auto list = HostNetDevice::GetDrivers();
1.1.1.8   root     1099:        for (const auto& name : list) {
                   1100:                printf(" %s\n", name.c_str());
                   1101:        }
                   1102: }
1.1.1.12  root     1103: 
1.1.1.14  root     1104: // オブジェクト登録
1.1.1.12  root     1105: void
1.1.1.14  root     1106: MainApp::RegistObject(Object *obj)
1.1.1.12  root     1107: {
1.1.1.14  root     1108:        // ID が重複していないかチェック (NONE なら重複可)
                   1109:        auto id = obj->GetId();
                   1110:        if (id != OBJ_NONE) {
                   1111:                if (FindObject(id)) {
                   1112:                        PANIC("%s already exists", Object::GetIdStr(id));
                   1113:                }
                   1114:        }
                   1115: 
                   1116:        obj->logger = gMainApp.GetLogger();
1.1.1.12  root     1117: 
                   1118:        objects.push_back(obj);
                   1119: }
                   1120: 
1.1.1.14  root     1121: // オブジェクト削除
1.1.1.12  root     1122: void
1.1.1.14  root     1123: MainApp::UnregistObject(Object *obj)
1.1.1.12  root     1124: {
1.1.1.14  root     1125:        // 最初に見付かった一つを削除するだけでいい
1.1.1.12  root     1126:        for (auto it = objects.begin(); it != objects.end(); ++it) {
                   1127:                if (*it == obj) {
                   1128:                        objects.erase(it);
                   1129:                        break;
                   1130:                }
                   1131:        }
                   1132: }
1.1.1.14  root     1133: 
                   1134: // 指定された id を持つオブジェクトを返す。なければ NULL を返す。
                   1135: Object *
                   1136: MainApp::FindObject(int id) const
                   1137: {
                   1138:        // NONE はここで検索しない (SCSI デバイスなど、そっちで検索する)
                   1139:        if (id == OBJ_NONE) {
                   1140:                return NULL;
                   1141:        }
                   1142:        for (auto obj : objects) {
                   1143:                if (obj->GetId() == id) {
                   1144:                        return obj;
                   1145:                }
                   1146:        }
                   1147:        return NULL;
                   1148: }
                   1149: 
                   1150: // 指定された id を持つオブジェクトを探す。なければ assert する。
                   1151: Object *
                   1152: MainApp::GetObject(int id) const
                   1153: {
                   1154:        Object *obj = FindObject(id);
                   1155:        if (__predict_false(obj == NULL)) {
                   1156:                PANIC("objid=%s not found", Object::GetIdStr(id));
                   1157:        }
                   1158:        return obj;
                   1159: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.