AF:
NF:0
PS:10
SRH:1
SFN:
DSR:
MID:
CFG:
PT:0
S:andy.sharp@onstor.com
RQ:
SSV:onstor-exch02.onstor.net
NSV:
SSH:
R:<larry.scheer@onstor.com>
MAID:1
X-Sylpheed-Privacy-System:
X-Sylpheed-Sign:0
SCF:#mh/Mailbox/sent
X-Sylpheed-End-Special-Headers: 1
Date: Thu, 11 Jan 2007 19:51:43 -0800
From: Andrew Sharp <andy.sharp@onstor.com>
To: Larry Scheer <larry.scheer@onstor.com>
Subject: cmd_upgrade.c attached
Message-ID: <20070111195143.50c806c9@ripper.onstor.net>
Organization: Onstor
X-Mailer: Sylpheed-Claws 2.6.0 (GTK+ 2.8.20; x86_64-pc-linux-gnu)
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary=MP_IFDMtwXLKPhRPHHeG_momek

--MP_IFDMtwXLKPhRPHHeG_momek
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

attached
--MP_IFDMtwXLKPhRPHHeG_momek
Content-Type: text/x-csrc; name=cmd_upgrade.c
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=cmd_upgrade.c


/* vi:ts=4
 *-----------------------------------------------------------------
 *
 * Name: cmd_upgrade
 *
 * RCS:  $Id$
 *
 * Copyright (C) 2001, Agile Storage, Inc.
 *
 * Description:
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created: 04/29/2002
 *
 *-----------------------------------------------------------------
 */

/* Some parts are: */
/*
 * Copyright (c) 1987, 1993
 *  The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *  This product includes software developed by the University of
 *  California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */



#include <sys/types.h>
#include <pwd.h>
#include <readline/history.h>
#include <grp.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <netinet/in.h>

#include "zebra.h"
#include "command.h"
#include "log.h"
#include "vtysh.h"
#include "memory.h"

#include "nfxsh.h"

#include "vector.h"

#include <dirent.h>

#include "nfx-defs.h"
#include "../sm-chassis/cm-api.h"
#include "../sm-anpssc/anpssc-api.h"
#include "../sm-opt/opt-api.h"
#include "../sm-elog/elog-api.h"
#include "../ssc-nfxnis/nfxnis-api.h"
#include "../ssc-nfxnis/nfxauth-api.h"
#include "../sm-ipm/ipm.h"

#include <fstab.h>

#define ALLOW_PROM_UPGRADE_FAIL 1

extern int mount_secondary(vector v);
extern vector make_secondary_fstabs(void);
extern void u_mount_secondary(vector v);
extern void free_fstab_vector(vector v);
extern void do_copy_files(char *fromdir, char *todir, char *files);
static int is_fp_addr(char *patch_location);

struct descriptor
{
    char *name;
    char *type;
    char *board;
    char *patch_name;
};


struct descriptor default_descriptor = {
    NULL,
    "app",
    "ssc",
    NULL
};


char *board_types[] = {
    "sp",
    "txrx",
    "fp",
    "ssc",
    "toshiba",
    NULL
};


char *file_types[] = {
    "prom",
    "bigprom",
    "runtime",
    "daemon",
    "app",
    "descr",
    "version",
    "kernel",
    "config",
    "services",
    NULL
};

char *fp_ports[] = {
    "fp1.0",
    "fp1.1",
    "fp1.2",
    "fp1.3",
    NULL
};

#define TIME_BUF 27
static char *mount_dir = "/mnt";
static char *patch_dir_name = NULL;
static char *local_dest = "/mnt2";
static char *descriptor_file = "/usr/local/agile/etc/descr";
static char *mtree_file_name = "/etc/mtree/4.4BSD.dist";
static char ftpprefix[] = "ftp://";
static char *patch_location;
static int upgrade_secondary;
static int compare_secondary;
static int force_upgrade;
static char *sys_upgrade_logfile = "/var/log/sys_upgrade.log";
static FILE *sys_upgrade = NULL;
static char sys_log_str[MAXPATHLEN + 1];
static char sys_log_time[TIME_BUF];

extern char *secondary_mount;
extern char *sys_config_files;

struct version
{
    int major;
    int minor;
    int maintenance;
    int patch;
    char platform;
};


static void print_vector(vector v, void (*print_fn)(void*)) __attribute((unused));
static void print_descriptor_vector(vector v) __attribute__ ((unused));
static void print_string_vector(vector v) __attribute__ ((unused));
int sleep_accurately(int secs);
static void my_print(char *str);
static char *get_time();


typedef int (*upgrade_method_t)(vector descriptors,
                                vector files, char *(*truename_func)(char *),
                                char *mtree_files);

typedef char* (*truename_func_t)(char *file);

truename_func_t cur_truename_func;

extern int noisy_make_allfs_writable(void);


/*-----------------------------------------------------------------
 * Name :   find_str()
 *
 * Description: Find a string in array of strings
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static char *
find_str(char **array, char *str)
{
    char **ptr;
    for (ptr = &array[0]; *ptr != NULL && strcmp(*ptr, str); ++ptr) {
        /* */
    }
    return *ptr;
}


/* Utility routine for current time printing. */
static char *
get_time ()
{
  int ret;
  time_t clock;
  struct tm *tm;
  time (&clock);
  tm = (struct tm*)localtime (&clock);

  ret = strftime (sys_log_time, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
  if (ret == 0) {
    sprintf(sys_log_time,"Error getting system time");
  }
   return sys_log_time;
}


/*-----------------------------------------------------------------
 * Name :   my_print()
 *
 * Description: print to stdout and file
 *
 * Created by:  Vikas Saini
 *
 * Date Created:    07/20/05
 *
 *-----------------------------------------------------------------
 */
static void
my_print(char *str)
{
    printf("%s",str); 
    fflush(stdout);
    if (sys_upgrade) {
        fprintf(sys_upgrade,"%s",str); 
        fflush(sys_upgrade);
    }
}

/*-----------------------------------------------------------------
 * Name :   vector_free_all()
 *
 * Description: Free the vector and call free() for all the elements
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
vector_free_all(vector v)
{
    int i;

    if (v != NULL) {
        for (i = 0; i < vector_max(v); ++i) {
            zfree(MTYPE_VECTOR, vector_lookup_index(v, i));
        }
        vector_free(v);
    }
}



/*-----------------------------------------------------------------
 * Name :   read_descriptor()
 *
 * Description: Read the descriptor file and return the vector of
 * struct descriptor.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static vector
read_descriptor(const char *filename)
{
    struct descriptor *descr;
    char str[300], type[100], board[100], name[100];
    int rc;
    FILE *f = fopen(filename, "r");
    vector v = NULL;

    if (f != NULL) {
        v = vector_init(200);
        while (!feof(f)) {
            if (fgets(str, 300, f) != NULL) {
                descr = zmalloc(MTYPE_VECTOR, sizeof(struct descriptor));
                rc = sscanf(str, "%s %s %s\n", type, board, name);
                if (rc != 3) {
                    rc = sscanf(str, "%s %s %s\n", type, board, name);
                    E_LOG(class_1, notice_s, eee_getApplicationId("nfxsh"), 
                          0, 0, 0, ("sscanf retry during system upgrade\n"));
                   if (sys_upgrade) {
                       fprintf(sys_upgrade,"sscanf retry during system upgrade\n");
                       fflush(sys_upgrade);
                   }
                }
                assert(rc == 3);
                descr->name = zstrdup(MTYPE_VECTOR, name);
                descr->patch_name = NULL;
                descr->type = find_str(file_types, type);
                assert(descr->type != NULL);
                descr->board = find_str(board_types, board);
                assert(descr->board != NULL);
                vector_push(v, descr);
            }
        }
        fclose(f);
    }
    return v;
}


/*-----------------------------------------------------------------
 * Name :   print-vector()
 *
 * Description: print the vector elements using function print_fn
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_vector(vector v, void (*print_fn)(void *))
{
    int i;
    char *filename;
    for (i = 0; i < vector_max(v); ++i) {
//        (*print_fn)(vector_lookup_index(v, i));
        filename = (vector_lookup_index(v, i));
        my_print(filename);
        my_print("\n");
    }
}


/*-----------------------------------------------------------------
 * Name :   print_descriptor()
 *
 * Description: print function for descriptors
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_descriptor(void *vd)
{
    struct descriptor *d = vd;
    sprintf(sys_log_str,"%s %s %s %s\n", d->type, d->board, d->name,
           d->patch_name ? d->patch_name : "(null)");
    my_print(sys_log_str);
}


/*-----------------------------------------------------------------
 * Name :   print_descriptor_vector()
 *
 * Description: print vector of struct descriptor
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_descriptor_vector(vector v) 
{
    print_vector(v, print_descriptor);
}


/*-----------------------------------------------------------------
 * Name :   print_string_vector()
 *
 * Description: print vector of strings
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_string_vector(vector v)
{
    print_vector(v, (void (*)(void *))puts);
}


/*-----------------------------------------------------------------
 * Name :   parse_version_str()
 *
 * Description: parse a string into struct version
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
parse_version_str(char *str, struct version *version)
{
    int rc = sscanf(str, "%d.%d.%d.%d%c",
                    &version->major, 
                    &version->minor, 
                    &version->maintenance, 
                    &version->patch,
                    &version->platform);
    if ((rc != 4) && (rc != 5)) {
        sprintf(sys_log_str,"invalid version string %s\n", str);
        my_print(sys_log_str);
        rc = CMD_ERR_FAILED;
    }
    else {
        if (rc == 4) {
            version->platform = '?';
        }
        rc = CMD_SUCCESS;
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   compare_versions()
 *
 * Description: compare two versions, return value is < 0 if the first is
 * lower, 0 if equal, > 0 if the first is greater
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
compare_versions(struct version *v1, struct version *v2)
{
    int major_diff, minor_diff, maintenance_diff;

    if ((major_diff = v1->major - v2->major) != 0)
        return major_diff;
    else if ((minor_diff = v1->minor - v2->minor) != 0)
        return minor_diff;
    else if ((maintenance_diff = v1->maintenance - v2->maintenance) != 0)
        return maintenance_diff;
    else return v1->patch - v2->patch;
}


/*-----------------------------------------------------------------
 * Name :   check_versions_compatible()
 *
 * Description: compare two versions to see if they are compatible and we can
 * upgrade from the first to the second.
 *
 *-----------------------------------------------------------------
 */
static int
check_versions_compatible(struct version *currVer, struct version *upgradeVer)
{
    int rc = CMD_SUCCESS;

    /* We cannot upgrade from R2.0.x to R1.3.2 or greater. */
    if ((currVer->major == 2) && (currVer->minor == 0)) {
        if ((upgradeVer->major == 1) && (upgradeVer->minor == 3) &&
            (upgradeVer->maintenance >= 2)) {
            rc = CMD_ERR_FAILED;
        }
    }

    /*
     * We cannot upgrade from R1.3.2 or greater to R2.0.  The plan is to merge
     * the release paths in R2.1, so we need to allow the upgrade path to
     * R2.1 or greater.
     */
    else if ((currVer->major == 1) && (currVer->minor == 3) &&
             (currVer->maintenance >= 2)) {
        if ((upgradeVer->major == 2) && (upgradeVer->minor == 0)) {
            rc = CMD_ERR_FAILED;
        }
    }

    return rc;
}


/*-----------------------------------------------------------------
 * Name :   valid_slot_cpu()
 *
 * Description: Return true if slot/cpu combination is valid
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/09/02
 *
 *-----------------------------------------------------------------
 */
static int
valid_slot_cpu(int slot, int cpu)
{
    switch (slot) {
    case 0 :
        return 0 <= cpu && cpu < 2;
    case 1:
        return 0 <= cpu && cpu < 4;
    case 2:
        return 0 <= cpu && cpu < 4;
    default:
        return 0;
    }
    
}


/*-----------------------------------------------------------------
 * Name :   read_version()
 *
 * Description: Read the version from the file named filename
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
read_version(const char *filename, struct version *version)
{
    FILE *f = fopen(filename, "r");
    char *s;
    int ok = CMD_ERR_FAILED;

    if (f != NULL) {
        size_t size;
        s = fgetln(f, &size);
        if (s != NULL && s[size - 1] == '\n') {
            s[size - 1] = 0;
            ok = parse_version_str(s, version);
        }
        fclose(f);
    }

    return ok;
}


/*-----------------------------------------------------------------
 * Name :   is_config()
 *
 * Description: Return true if the descriptor type is 'config'
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
is_config(struct descriptor *descr)
{
    return !strcmp(descr->type, "config");
}


/*-----------------------------------------------------------------
 * Name :   is_version()
 *
 * Description: Return true if the descriptor type is 'version'
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
is_version(struct descriptor *descr)
{
    return !strcmp(descr->type, "version");
}


/*-----------------------------------------------------------------
 * Name :   is_prom()
 *
 * Description: Return true if the descriptor type is prom
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
is_prom(struct descriptor *descr)
{
    return !strcmp(descr->type, "prom");
}


/*-----------------------------------------------------------------
 * Name :   is_bigprom()
 *
 * Description: Return true if the descriptor type is bigprom
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
is_bigprom(struct descriptor *descr)
{
    return !strcmp(descr->type, "bigprom");
}


/*-----------------------------------------------------------------
 * Name :   print_version()
 *
 * Description: 
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
print_version(struct version *version)
{
    sprintf(sys_log_str,"%d.%d.%d.%d\n", version->major, version->minor, 
           version->maintenance, version->patch);
    my_print(sys_log_str);
}


/*-----------------------------------------------------------------
 * Name :   convert_rc()
 *
 * Description: Convert unix return code to nfxsh values
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    11/01/02
 *
 *-----------------------------------------------------------------
 */
static inline int
convert_rc(int rc)
{
    return rc == 0 ? CMD_SUCCESS : CMD_ERR_FAILED;
}


/*-----------------------------------------------------------------
 * Name :   is_ftp_upgrade()
 *
 * Description: return true if upgrading using ftp
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    11/01/02
 *
 *-----------------------------------------------------------------
 */
static int
is_ftp_upgrade(char *from)
{
    return !strncmp(from, ftpprefix, strlen(ftpprefix));
}


/*-----------------------------------------------------------------
 * Name :   umount_patch()
 *
 * Description: unmount patch directory if it is mounted
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
umount_patch()
{
    do_system("/sbin/umount %s 2>/dev/null", mount_dir);
}

/*-----------------------------------------------------------------
 * Name         : upgrade_resolveName
 *
 * Description  : Resolves a name to an IP address.
 *
 * Arguments    : hostName  - Host Name.
 *                vsId      - Appropriate virtual server context.
 *                ipAddress - Returned value. 
 *
 * Return Value : NFX_OK  - Able to resolve the name to an IP address.
 *                NFX_ERR - Unable to resolve the server name .
 *
 * Created by   : Kiran Srinivasan
 *
 * Date Created : 04/23/04
 *
 *-----------------------------------------------------------------
 */
static int32
upgrade_resolveName(char *hostName,
                    vs_id_t vsId,
                    struct in_addr *hostIP)
{
    /* Check if name is already in IP address format
     */
    if(inet_aton(hostName, hostIP) != 0)
        return NFX_OK;

    /* Call the NFXNIS routine to resolve using the virtual
     * server provided (via FP). 
     */
    *(in_addr_t *)hostIP = nfxauth_resolveName(vsId,
                                              hostName);
    
    if(hostIP->s_addr == 0)
    {
        sprintf(sys_log_str,"Error : unable to resolve server : (%s).\n", hostName);
        my_print(sys_log_str);
        return NFX_ERR;
    }
 
    return NFX_OK;
}

/*-----------------------------------------------------------------
 * Name         : ftp_getServerIP
 *
 * Description  : Gets the FTP server address from the URL.
 *
 * Arguments    : ftpURL            - FTP URL
 *                vsId              - Virtual server Id.
 *                serverIP          - Pointer to in_addr structure for
 *                                    returning the IP address.
 *
 * Return Value : NFX_OK  - Able to parse the server address out of the FTP
 *                          URL.
 *                NFX_ERR - Unable to get the server address.
 *
 * Created by   : Kiran Srinivasan
 *
 * Date Created : 04/23/04
 *
 *-----------------------------------------------------------------
 */
static int32
ftp_getServerIP(const char *ftpURL,
                vs_id_t vsId,
                struct in_addr *serverIP)
{
    char *start;
    char *end;
    int32 rc;
    uint32 serverLen;
    char *serverName;

    /* Get the start of the FTP server name
     */
    if((start= strchr(ftpURL,
                      '@')) == NULL)
    {
        my_print("Error: unable to find @ in FTP URL\n");
        return NFX_ERR;
    }

    /* Get the end of the server name
     */
    if((end = strchr(start,
                     '/')) == NULL)
    {
        my_print("Error: unable to find the terminating / in the FTP URL.\n");
        return NFX_ERR;
    }

    start++;
    serverLen = (uint32) (end - start);

    if((serverName = (char *) malloc(serverLen + sizeof(char))) == NULL)
    {
        my_print("Error: unable to allocate serverName\n");
        return NFX_ERR;
    }
    strncpy(serverName,
            start,
            serverLen);
    serverName[serverLen] = '\0';

    /* Get the IP address 
     */
    rc = upgrade_resolveName(serverName,
                             vsId,
                             serverIP);  

    free(serverName);
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   mount_patch()
 *
 * Description: mount the patch directory 'from' on mount_dir
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
mount_patch(char *from)
{
	int rc;

    do_system("/sbin/umount -f %s 2>/dev/null", mount_dir);

    if (is_ftp_upgrade(from)) {
        my_print("Downloading external system software distribution.\n");
        rc = do_system("/sbin/mount_mfs -s 340000 swap %s", mount_dir);
        rc = convert_rc(rc);
        if (rc == CMD_SUCCESS) {
            if(nfxsh_vs_id != VS_ID_INVALID) {
                /* Upgrade is being done within the context of a 
                 * virtual server, pick the appropriate source IP
                 */
                struct in_addr serverIP;
                struct in_addr srcIP;
                NTSTATUS status;
                
                /* Parse the address out of the patch location
                 */
                if(ftp_getServerIP(from,
                                   nfxsh_vs_id,
                                   &serverIP) != NFX_OK)
                {
                    my_print("Error: unable to parse the destination IP address"
                           " string from the ftp URL.\n");
                    umount_patch();
                    return CMD_ERR_FAILED;
                }

                /* Get the source IP address (private)
                 */
                if((status = nfxnis_getSourceIP(nfxsh_vs_id,
                                                serverIP.s_addr,
                                                NULL,
                                                &srcIP.s_addr))
                    != STATUS_SUCCESS) {
                    if (status == STATUS_SERVER_DISABLED) {
                        sprintf(sys_log_str,
                                "Error: virtual server (ID - %d) is disabled. "
                                "FTP server %s unreachable.\n",
                                nfxsh_vs_id,
                                inet_ntoa(serverIP));
                    }
                    else if (status == STATUS_NETWORK_UNREACHABLE) {
                        sprintf(sys_log_str,
                                "Error: virtual server (ID - %d) does not have "
                                "a route to FTP server %s.\n",
                                nfxsh_vs_id,
                                inet_ntoa(serverIP));
                    }
                    else {
                        sprintf(sys_log_str,
                                "Error: Cannot reach FTP server %s from this "
                                "virtual server (ID - %d) context. status=0x%X\n",
                                inet_ntoa(serverIP),
                                nfxsh_vs_id,
                                status);
                    }
                    my_print(sys_log_str); 
                    umount_patch();
                    return CMD_ERR_FAILED;
                }

                /* Add the -s option to the ftp client to bind to the
                 * correct IP address before making the connection
                 */
                rc = do_system("/usr/bin/ftp -o - -s %s -m %s | (cd %s; tar xzpf -)",
                    inet_ntoa(srcIP), from, mount_dir);

            } else {
                rc = do_system("/usr/bin/ftp -o - -m %s | (cd %s; tar xzpf -)",
                    from, mount_dir);
			}

            rc = convert_rc(rc);
            patch_dir_name = mount_dir;
            if (rc == CMD_SUCCESS) {
                my_print("Done.\n");
            } else {
				umount_patch();
                my_print("Download failed.\n");
            }
        }
        return rc;
    } else {
        do_system("/sbin/umount %s 2>/dev/null", mount_dir);

        rc = do_system("/sbin/mount -t nfs %s %s", from, mount_dir);
        patch_dir_name = mount_dir;

        return convert_rc(rc);
    }
}


/*-----------------------------------------------------------------
 * Name :   get_upgrade_version()
 *
 * Description: determine the version of system upgrade
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
get_upgrade_version(struct version *version)
{
    char version_file[MAXPATHLEN + 1];
    strcpy(version_file, patch_dir_name);
    strcat(version_file, "/version");
    return read_version(version_file, version);
}

/*-----------------------------------------------------------------
 * Name :   zero_version()
 *
 * Description: Fill version with zeroes
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    07/03/02
 *
 *-----------------------------------------------------------------
 */
static void
zero_version(struct version *version)
{
    version->major = version->minor = version->maintenance = version->patch = 0;
}


/*-----------------------------------------------------------------
 * Name :   get_org_upgrade_version()
 *
 * Description: read original version of upgrade
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    07/03/02
 *
 *-----------------------------------------------------------------
 */
static void
get_org_upgrade_version(struct version *version)
{
    char version_file[MAXPATHLEN + 1];
    strcpy(version_file, patch_dir_name);
    strcat(version_file, "/version.org");
    if (read_version(version_file, version) != 0) {
        zero_version(version);
    }
}


/*-----------------------------------------------------------------
 * Name :   is_dotdir()
 *
 * Description: return true if the name is "." or "..".
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
is_dotdir(char *name)
{
    return (name[0] == '.' && name[1] == '\0')
        || (name[0] == '.' && name[1] == '.' && name[2] == '\0');
}


/*-----------------------------------------------------------------
 * Name :   find_files()
 *
 * Description: Find the list of the files in the directory
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
find_files(const char *dir_name, vector files)
{
    int rc = CMD_ERR_FAILED;
    DIR *dir = opendir(dir_name);
    if (dir != NULL) {
        struct dirent *dp;
        int error = 0;
        while (!error && (dp = readdir(dir)) != NULL) {
            if (!is_dotdir(dp->d_name) && strcmp(dp->d_name, ".snapshot")) {
                struct stat stbuf;
                char *fname = zmalloc(MTYPE_VECTOR,
                                      strlen(dir_name) + 2 + dp->d_reclen);
                sprintf(fname, "%s/%s", dir_name, dp->d_name);
                if (stat(fname, &stbuf) < 0) {
                    fprintf(stderr, "Error: can't stat %s: %s\n", fname,
                            strerror(errno));
					if (sys_upgrade) {
						fprintf(sys_upgrade, "Error: can't stat %s: %s\n",
							fname, strerror(errno));
						fflush(sys_upgrade);
					}
                    error = 1;
                } else {
                    if (S_ISREG(stbuf.st_mode)) {
                        vector_push(files, zstrdup(MTYPE_VECTOR, fname));
                    } else if (S_ISDIR(stbuf.st_mode)) {
                        if (find_files(fname, files) != CMD_SUCCESS) {
                            error = 1;
                        }
                    }
                    zfree(MTYPE_VECTOR, fname);
                }
            }
        }
        closedir(dir);
        rc = error ? CMD_ERR_FAILED : CMD_SUCCESS;
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   get_local_version()
 *
 * Description: determine the current system version
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
get_local_version(struct version *version)
{
    char version_file[MAXPATHLEN + 1];
    strcpy(version_file, patch_dir_name);
    strcat(version_file, "/version");
    if (read_version(cur_truename_func(version_file),
                     version) != CMD_SUCCESS) {
        zero_version(version);
    }
    return CMD_SUCCESS;
}

/*-----------------------------------------------------------------
 * Name :   get_secondary_version()
 *
 * Description: determine the system version of the secondary flash
 *
 * Created by:  Danqing Jin
 *
 * Date Created:    07/05/06
 *
 *-----------------------------------------------------------------
 */
static int
get_secondary_version(struct version *version)
{
    char version_file[MAXPATHLEN + 1];
    int rc;

    snprintf(version_file, MAXPATHLEN+1, "%s/version", secondary_mount);
    if ((rc = read_version(version_file, version)) != CMD_SUCCESS) {
        zero_version(version);
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   get_root_version()
 *
 * Description: get system version from root directory
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    01/10/03
 *
 *-----------------------------------------------------------------
 */
static int
get_root_version(struct version *version)
{
    if (read_version("/version", version) != CMD_SUCCESS) {
        zero_version(version);
    }
    return CMD_SUCCESS;
}


/*-----------------------------------------------------------------
 * Name :   compare_descr_file()
 *
 * Description: compare the descriptors using the file names
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
compare_descr_file(void *descr, void *fname)
{
    return !strcmp(((struct descriptor *)descr)->name, fname);
}


/*-----------------------------------------------------------------
 * Name :   get_file_descriptor()
 *
 * Description: find the descriptor for the file in the descriptor
 * vector dv.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static struct descriptor *
get_file_descriptor(vector dv, char *fname)
{
    struct descriptor *descr = vector_find(dv, compare_descr_file, fname);
    if (descr == NULL)
        descr = &default_descriptor;
    return descr;
}


/*-----------------------------------------------------------------
 * Name :   file_exists()
 *
 * Description: return true if the file exists
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
file_exists(char *file)
{
    struct stat statbuf;
    return stat(file, &statbuf) == 0;
}


/*-----------------------------------------------------------------
 * Name :   upgrade_truename()
 *
 * Description: return the installation name of a file in upgrade
 * directory.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static char*
upgrade_truename(char *file)
{
    return strchr(file + 1, '/');
}


static char *
secondary_upgrade_truename(char *file)
{
    static char buf[MAXPATHLEN];
    strcpy(buf, secondary_mount);
    strcat(buf, strchr(file + 1, '/'));
    return buf;
}


/*-----------------------------------------------------------------
 * Name :   shutdown_system()
 *
 * Description: tell the system daemons to shutdown
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
shutdown_system()
{
    my_print("Shutting down the system software...");
    my_print("done\n");
}


/*-----------------------------------------------------------------
 * Name :   kill_daemon()
 *
 * Description: kill the daemon, pid is in pid_file and the daemon
 * is supposed to remove the file when exiting on SIGTERM
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
void
kill_daemon(char *pid_file)
{
    FILE *f;
    int pid;
    int time_to_sleep = 10;

    f = fopen(pid_file, "r");
    if (f) {
        fscanf(f, "%d\n", &pid);
        fclose(f);
        kill(pid, SIGTERM);
        while (time_to_sleep && file_exists(pid_file)) {
            sleep(1);
            --time_to_sleep;
        }
        if (time_to_sleep == 0) {
            kill(pid, SIGKILL);
            unlink(pid_file);
        }
    }
}


/*-----------------------------------------------------------------
 * Name :   shutdown_inetd()
 *
 * Description: shutdown the inetd
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
shutdown_inetd(void)
{
    my_print("Shutting down the inetd...");
    kill_daemon("/var/run/inetd.pid");
    my_print("done\n");
}


/*-----------------------------------------------------------------
 * Name :   shutdown_pm()
 *
 * Description: shutdown the pm
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
shutdown_pm(void)
{
	/*
     * Shutdown EMRS before stopping PM because EMRS can start an executable
     * that is dependent on PM running.
	 */
	system("/usr/local/agile/bin/emrscron -r");
    my_print("Shutting down PM...");
    kill_daemon("/var/run/pm.pid");
    my_print("done\n");
}


/*-----------------------------------------------------------------
 * Name :   upgrade_files()
 *
 * Description: install the files in the vector files. 
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_files(vector files, char *(*truename_func)(char *))
{
    int i;
    int error = 0;
    if (sys_upgrade) {
        fprintf(sys_upgrade,"Upgrade files, Start time: %s\n",get_time());
        fflush(sys_upgrade);
    }
    for (i = 0; error == 0 && i < vector_max(files); ++i) {
        char *src_file = vector_lookup_index(files, i);
        char *dst_file = (*truename_func)(src_file);
        struct stat src_st;
        sprintf(sys_log_str,"Installing %s...", dst_file);
        my_print(sys_log_str);
        if (lstat(src_file, &src_st) == 0) {
            if (S_ISREG(src_st.st_mode)) {
                mode_t mode = src_st.st_mode & 07777;
                uid_t owner = src_st.st_uid;
                gid_t group = src_st.st_gid;
                fflush(stdout);
                if (sys_upgrade) {
                    fflush(sys_upgrade);
                }
                error = do_system("/usr/bin/install -S "
						"-o %d -g %d -m 0%o %s %s",
                        owner, group, mode, src_file, dst_file);
				error = convert_rc(error);
            } else if (S_ISLNK(src_st.st_mode)) {
                char link_contents[MAXPATHLEN];
                int nbytes;
                nbytes = readlink(src_file, link_contents,
                                 sizeof(link_contents));
                if (nbytes > 0) {
                    link_contents[nbytes] = '\0';
                    symlink(link_contents, dst_file);
                } else {
                    error = 1;
                }
            } else if (S_ISBLK(src_st.st_mode) || S_ISCHR(src_st.st_mode)) {
                error = mknod(dst_file, src_st.st_mode, src_st.st_dev);
            } else {
                my_print("unsupported file type\n");
                error = 1;
            }
        } else {
            error = 1;
        }
        if (error)
            my_print("failed\n");
        else
            my_print("done\n");
    }
    if (sys_upgrade) {
        fprintf(sys_upgrade,"Upgrade files, End time: %s\n",get_time());
        fflush(sys_upgrade);
    }
    return error;
}


/*-----------------------------------------------------------------
 * Name :   update_devices_if_needed()
 *
 * Description: Rerun /dev/MAKEDEV if it was modified
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 * BROKEN on upgrades of primary flash
 *
 *-----------------------------------------------------------------
 */
static int
update_devices_if_needed(vector dv, vector files_list, char *(*truename_func)(char *))
{
    int i;
    int rc = 0;
    for (i = 0; i < vector_max(files_list); ++i) {
        char *dst_file = (*truename_func)(vector_lookup_index(files_list, i));
        if (!strcmp(dst_file, "/dev/MAKEDEV")) {
            my_print("Updating devices...");
            rc = system("cd /dev && ./MAKEDEV all >/dev/null 2>/dev/null");
            my_print("done\n");
            break;
        }
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   upgrade_prom_slotcpu()
 *
 * Description: upgrade prom for the specified slot/cpu
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_prom_slotcpu(int slot, int cpu, char *file)
{
    assert(valid_slot_cpu(slot, cpu));
    return convert_rc(do_system("/usr/local/agile/bin/prom-upgrade %d %d %s",
				slot, cpu, file ? file : ""));
}

/*-----------------------------------------------------------------
 * Name :   upgrade_prom()
 *
 * Description: Upgrade the prom on the given board. Returns 0 if prom
 * upgrade successfully for all cpus.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_prom(char *board, char *file)
{
    int slot, cpu_min, cpu_max, cpu, error = 0;
    if (!strcmp(board, "toshiba")) {
        slot = 0;
        cpu_min = 1;
        cpu_max = 1;
    }
    else if (!strcmp(board, "ssc")) {
        slot = 0;
        cpu_min = 0;
        cpu_max = 0;
    }
    else if (!strcmp(board, "txrx")) {
        slot = 1;
        cpu_min = 0;
        cpu_max = 0;
    }
    else if (!strcmp(board, "fp")) {
        slot = 1;
        cpu_min = 3;
        cpu_max = 3;
    }
    else if (!strcmp(board, "sp")) {
        slot = 2;
        cpu_min = 0;
#ifdef BOBCAT
        cpu_max = 0;
#else
        cpu_max = 3;
#endif
    }
    else {
        return 1;
    }
    for (cpu = cpu_min; cpu <= cpu_max; ++cpu) {
        if (upgrade_prom_slotcpu(slot, cpu, file) != 0) {
#if ALLOW_PROM_UPGRADE_FAIL
            error = 0;
#else
            sprintf(sys_log_str,"Failed to upgrade the prom for slot %d cpu %d\n",
                   slot, cpu);
            my_print(sys_log_str);
            my_print("After the system comes up after reboot, verify that the slot/cpu\n");
            my_print("is in UP state and execute the following command:\n");
            sprintf(sys_log_str,"system promupgrade %d %d\n", slot, cpu);
            my_print(sys_log_str);
            error = 1;
#endif          
        }
    }
    return error;
}


/*-----------------------------------------------------------------
 * Name :   upgrade_proms_if_needed()
 *
 * Description: Upgrade the proms for the boards which had their
 * PROMs modified.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_proms_if_needed(vector dv, vector files_list, char *(*truename_func)(char *))
{
    int rc = 0;
    int i;

    for (i = 0; i < vector_max(files_list); ++i) {
        char *dst_file = (*truename_func)(vector_lookup_index(files_list, i));
        char *root_dst_file = upgrade_truename(
            vector_lookup_index(files_list, i));
        struct descriptor *descr = get_file_descriptor(dv, root_dst_file);
        if (is_prom(descr) || is_bigprom(descr)) {
            int j;
            for (j = 0; j < vector_max(dv); ++j) {
                struct descriptor *descr = vector_lookup_index(dv, j);
                if (!strcmp(descr->name, root_dst_file) && is_bigprom(descr)) {
#ifdef BOBCAT
                    /* Don't upgrade big flash through SSC
                     * It will be done through FC
                     */
                    if (strcmp(descr->board, "ssc"))
#endif
                    rc |= upgrade_prom(descr->board, dst_file);
                }
            }
            for (j = 0; j < vector_max(dv); ++j) {
                struct descriptor *descr = vector_lookup_index(dv, j);
                if (!strcmp(descr->name, root_dst_file) && is_prom(descr)) {
#ifdef BOBCAT
                    /* Don't upgrade small prom through SP
                     * because it would be redundant (same as SSC prom)
                     */
                    if (strcmp(descr->board, "sp"))
#endif
                    rc |= upgrade_prom(descr->board, dst_file);
                }
            }
        }
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   reboot_boards()
 *
 * Description: reboot slots 1 and 2
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
reboot_boards(vector files_list, char *(*truname_func)(char *))
{
    chassisdMsgRebootReq_t msg;
    my_print("Rebooting boards...");
    msg.hdr.mid = CHASSISD_REBOOT_REQ;
    msg.reboot_type = CM_REBOOT_TYPE_SLOT;
    msg.slot = 1;
    msg.slice = 0;
    nfxsh_send(&msg, sizeof(msg), "cm", 1, 0, 1, NULL, NULL, 0,
        NFXSH_SEND_AGILE);
    msg.slot = 2;
    nfxsh_send(&msg, sizeof(msg), "cm", 1, 0, 1, NULL, NULL, 0,
        NFXSH_SEND_AGILE);
    my_print("done\n");
    return 0;
}


/*-----------------------------------------------------------------
 * Name :   reboot_cold()
 *
 * Description: Do a cold reboot of the system
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static void
reboot_cold()
{
    my_print("Rebooting the system...\n");
    /* if upgrading to secondary, tell reboot to switch the disks */
    do_system("/sbin/reboot -c %s\n", upgrade_secondary ? "-s" : "");
}


/*-----------------------------------------------------------------
 * Name :   upgrade_directories()
 *
 * Description: Update directories according to new dist file.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
static int
upgrade_directories(char *mtree_file)
{
    int rc;

    my_print("Updating directories...");
    rc = do_system("/usr/sbin/mtree -qdUef %s -p %s", mtree_file,
            upgrade_secondary ? secondary_mount : "/");
    my_print("done\n");
    return convert_rc(rc);
}


/*-----------------------------------------------------------------
 * Name :   shutdown_all()
 *
 * Description: Shutdown the system software and kill the daemons so
 * we can proceed with upgrade in peace.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
void
shutdown_all(void)
{
    char buf[20];

    /* Stop the hostidd
     */
    strcpy(buf, "suspend");
    nfxsh_send(buf, strlen(buf), "hostid",
               NFX_SSC_UNIX, SSC_SLOT, MGMTPLANE, _4sec, 0, 0,
               NFXSH_SEND_AGILE);
    shutdown_system();
    shutdown_pm();
    shutdown_inetd();
}


/*-----------------------------------------------------------------
 * Name :   reboot_all()
 *
 * Description: reset FP and SP and reboot SSC.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
void
reboot_all(void)
{
    reboot_boards(NULL, NULL);
    reboot_cold();
}


/*-----------------------------------------------------------------
 * Name :   noisy_make_allfs_writable
 *
 * Description: Remount local filesystems writable making some noise
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    08/15/02
 *
 *-----------------------------------------------------------------
 */
int
noisy_make_allfs_writable(void)
{
    int rv;
    my_print("Remounting the local filesystem read-write...");
    rv = make_allfs_writable();
    if (rv == 0)
        my_print("done\n");
    else
        my_print("failed\n");
    return rv;
}



/*-----------------------------------------------------------------
 * Name :   complete_upgrade()
 *
 * Description: The worst-case upgrade - shutdown and restart everything
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
complete_upgrade(vector dv, vector files_list, char *(*truename_func)(char *),
                 char *mtree_file)
{
    int rc = 0;
    cmMsgHeartbeatControlReq_t req;
#ifdef BOBCAT
    int i;
    ipm_link_change_status_t   ipm_req, ipm_rsp;
#else
    char buf[20];
#endif

    if (!upgrade_secondary) {
        bzero(&req, sizeof(req));
        req.hdr.srcSlot = 0;
        req.hdr.srcCpu = 0;
        req.hdr.srcApp = 
        req.hdr.srcPlane = MGMTPLANE;
        req.hdr.mid = CM_SET_HEARTBEAT_OFF;
        req.feature_en = 0;
        nfxsh_send(&req, sizeof(req), "cm", 0, 1, MGMTPLANE,
                   0, NULL, 0, NFXSH_SEND_AGILE);
        E_LOG(class_1, notice_s, eee_getApplicationId("nfxsh"), 0, 0, 0, 
             ("System will reboot due to system upgrade.\n"));
        if (sys_upgrade) {
            fprintf(sys_upgrade,"System will reboot due to system upgrade.\n");
            fflush(sys_upgrade);
        }
#ifndef BOBCAT
        sleep_accurately(3);
        /* Reboot FP and SP for cluster failover and wait for them
         * to come back to resume upgrade.
         */
        reboot_boards(NULL, NULL);
#else
        bzero(&ipm_req, sizeof(ipm_link_change_status_t));
        bzero(&ipm_rsp, sizeof(ipm_link_change_status_t));
        ipm_req.hdr.ipmh_mtype = IPM_MSG_LINK_DIS;
        ipm_req.hdr.ipmh_size = sizeof(ipm_link_change_status_t);
        for (i = 0; i < 4; i++) {
            strcpy(ipm_req.link_name, fp_ports[i]);
            if (nfxsh_send(&ipm_req, sizeof(ipm_link_change_status_t), "ipm",
                           NFX_NFP_TXRX1, NFX_SLOTTYPE_NFP, MGMTPLANE, 3,
                           &ipm_rsp, sizeof(ipm_link_change_status_t),
                           NFXSH_SEND_AGILE) 
                           < sizeof(ipm_link_change_status_t)) {
                sprintf(sys_log_str,"Timeout disabling FP port %s\n", ipm_req.link_name);
                my_print(sys_log_str);
            }
        }
/*
        execute_command("/usr/local/agile/bin/storage", 4, "control", "port",
                        "disable", "once", NULL);
*/
#endif
        execute_command("/usr/local/agile/bin/chassis", 2, 
                        "wd", "disable", NULL);
/*
        sleep_accurately(3);
*/
        shutdown_pm();
#ifndef BOBCAT
        sleep_accurately(90);
#endif
        shutdown_system();
        shutdown_inetd();
    }

    if ((upgrade_secondary || (rc = noisy_make_allfs_writable()) == 0)
        && (rc = upgrade_directories(mtree_file)) == 0
        && (rc = upgrade_files(files_list, truename_func)) == 0
        && (rc = update_devices_if_needed(dv, files_list, truename_func)) == 0
        && (rc = upgrade_proms_if_needed(dv, files_list,
                                         truename_func) == 0)) {
        if (upgrade_secondary) {
            sync();
#if 0
/* @@@ should be safer way to copy configuration files from a
 * live system.
 */
            shutdown_all();
#endif

            if (sys_upgrade) {
                fprintf(sys_upgrade,"Updating configuration files, Start time: %s\n",get_time());
                fflush(sys_upgrade);
            }
            my_print("Updating configuration files\n");

            do_copy_files("/", secondary_mount, sys_config_files);
            do_system("/usr/sbin/pwd_mkdb -d %s/etc %s/etc/master.passwd",
                    secondary_mount, secondary_mount);
            if (sys_upgrade) {
                fprintf(sys_upgrade,"Updating configuration files, End time: %s\n",get_time());
                fflush(sys_upgrade);
            }
        } else {
#ifndef BOBCAT
            /* Stop the hostidd before rebooting boards so they can't try
             * to download while SSC is going down.
             */
            strcpy(buf, "suspend");
            nfxsh_send(buf, strlen(buf), "hostid",
                       NFX_SSC_UNIX, SSC_SLOT, MGMTPLANE, _4sec, 0, 0,
                       NFXSH_SEND_AGILE);
            reboot_boards(files_list, truename_func);
#endif
			if (sys_upgrade) {
				fprintf(sys_upgrade, "System Upgrade completed at: %s\n",
					get_time());
				fflush(sys_upgrade);
			}
            reboot_cold();
        }

		my_print("Upgrade of the standby flash completed\n");
		if (sys_upgrade) {
			fprintf(sys_upgrade, "System Upgrade completed at: %s\n",
				get_time());
			fflush(sys_upgrade);
		}

    }

    return rc;
}


/*-----------------------------------------------------------------
 * Name :   needs_upgrade()
 *
 * Description: Stores true in the location pointed to by the argument
 * need_upgrade_ptr if the file needs to be upgraded.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
needs_upgrade(vector dv, char *src_file,
              char *dst_file, struct descriptor *descr, int *need_upgrade_ptr)
{
    int need_upgrade = 0;
    int rc = CMD_SUCCESS;

    sprintf(sys_log_str,"checking %s...", dst_file);
    my_print(sys_log_str);
    if (is_config(descr)) {
        my_print("user data");
    } else if (is_version(descr)) {
        my_print("version file");
        need_upgrade = 1;
    } else {
        struct stat src_st, dst_st;
        if (lstat(src_file, &src_st) == 0) {
            if (lstat(dst_file, &dst_st) < 0) {
                my_print("new file");
                need_upgrade = 1;
            } else {
                if (S_ISREG(src_st.st_mode) && S_ISREG(dst_st.st_mode)) {
					rc = do_system("cmp -s %s %s", src_file, dst_file);
					rc = rc >> 8;
					if (rc == 1) {
							need_upgrade = 1;
							rc = CMD_SUCCESS;
							my_print("needs upgrade");
					} else if (rc == 0) {
						my_print("up-to-date");
					} else {
						my_print("failed to compare\n");
					}
                } else if (S_ISLNK(src_st.st_mode)) {
                    my_print("symbolic link");
                } else {
                    my_print("special file");
                }
            }
        } else {
            rc = CMD_ERR_FAILED;
        }
    }
    my_print("\n");
    *need_upgrade_ptr = need_upgrade;
    if (rc == CMD_ERR_FAILED) {
        sprintf(sys_log_str,"Error while checking %s\n", dst_file);
        my_print(sys_log_str);
        E_LOG(class_1, err_s, eee_getApplicationId("nfxsh"), 0, 0, 0, 
             ("Error while checking %s during system upgrade or compare\n",
			  dst_file));
        if (sys_upgrade) {
            fprintf(sys_upgrade,
				"Error while checking %s during system upgrade or compare\n\n",
				dst_file);
            fflush(sys_upgrade);
        }
    }
    return rc;
}
                         


/*-----------------------------------------------------------------
 * Name :   make_files_to_upgrade_list()
 *
 * Description: Make the list of the files which need to be upgraded
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
make_files_to_upgrade_list(
    vector dv,
    vector files_to_upgrade,
    vector files)
{
    int rc = CMD_SUCCESS;
    int i;
    struct descriptor *descr = NULL;
    int stat = 0;
    chassisdMsgVersionReq_t req;
    chassisdMsgVersionResp_t resp;
    FILE *f = NULL; 
    char *s = NULL;
    size_t size;

    /* Get current PROM versions to see if upgrade is necessary
     * Note: will upgrade proms if failed to get versions to compare
     */
    bzero(&resp, sizeof(resp));
    req.hdr.mid = CHASSISD_GET_VERSION_REQ;
    stat = nfxsh_send(&req, sizeof(req),
                      "cm", 0, 0, 0,
                      _4sec, &resp, sizeof(resp), NFXSH_SEND_AGILE);

    for (i = 0; rc == CMD_SUCCESS && i < vector_max(files); ++i) {
        char *src_file = vector_lookup_index(files, i);
        char *dst_file = cur_truename_func(src_file);
        int need_upgrade;
        descr = get_file_descriptor(dv, upgrade_truename(src_file));
        if (is_prom(descr) || is_bigprom(descr)) {
            rc = needs_upgrade(dv, src_file, dst_file,  descr, &need_upgrade);
            if (need_upgrade == 1) {
                vector_push(files_to_upgrade, src_file);
                continue;
            }
            need_upgrade = 1;
            f = NULL;
#ifdef BOBCAT
            if (compare_descr_file(descr, "/usr/local/agile/Images/r9k.bin") ||
                compare_descr_file(descr,"/usr/local/agile/Images/r9kfimg.bin"))
#elif defined(COUGAR)
//we not gonna use this excellent stuff on cougar!
#else
            if (compare_descr_file(descr, "/usr/local/agile/Images/r7k.bin") ||
                compare_descr_file(descr,"/usr/local/agile/Images/r7kfimg.bin"))
#endif
            {
                /* Compare slot 2 PROM version and SSC PROM version 
                 * with r7k.version or r9k.version. Will upgrade all 
                 * if either needs it. 
                 */
#ifdef BOBCAT
                f = fopen("/usr/local/agile/Images/r9k.version", "r");
#else
                f = fopen("/usr/local/agile/Images/r7k.version", "r");
#endif
                if (f != NULL) {
                    s = fgetln(f, &size);
                    if (s != NULL && s[size - 1] == '\n') {
                        s[size - 1] = 0;
                        if ((strcmp(s, resp.prom_ver[NFX_SLOTTYPE_FC][0]) == 0)
                            && (strcmp(s, resp.prom_ver[NFX_SLOTTYPE_SSC]
                                                       [NFX_SSC_UNIX]) == 0))
                        {
                            need_upgrade = 0;
                        }
                    }
                }
            }
            else
#ifdef BOBCAT
            if (compare_descr_file(descr, 
                                   "/usr/local/agile/Images/sibyte_bc.bin") 
                || 
                compare_descr_file(descr,
                                   "/usr/local/agile/Images/sibfimg_bc.bin"))
#else
            if (compare_descr_file(descr, "/usr/local/agile/Images/sibyte.bin") 
                || 
                compare_descr_file(descr,"/usr/local/agile/Images/sibfimg.bin"))
#endif
            {
                /* Compare slot 1 PROM version with sibyte.version.
                 */
#ifdef BOBCAT
                f = fopen("/usr/local/agile/Images/sibyte_bc.version", "r");
#else
                f = fopen("/usr/local/agile/Images/sibyte.version", "r");
#endif
                if (f != NULL) {
                    s = fgetln(f, &size);
                    if (s != NULL && s[size - 1] == '\n') {
                        s[size - 1] = 0;
                        if (strcmp(s, resp.prom_ver[NFX_SLOTTYPE_NFP][0]) == 0)
                        {
                            need_upgrade = 0;
                        }
                    }
                }
            }
#ifndef BOBCAT
            else if (compare_descr_file(descr,"/usr/local/agile/Images/toshiba.bin")) {
                /* Compare slot 0 Toshiba PROM version with toshiba.version. 
                 */
                f = fopen("/usr/local/agile/Images/toshiba.version", "r");
                if (f != NULL) {
                    s = fgetln(f, &size);
                    if (s != NULL && s[size - 1] == '\n') {
                        s[size - 1] = 0;
                        if (strcmp(s, resp.prom_ver[NFX_SLOTTYPE_SSC]
                                                   [NFX_SSC_MGMT]) == 0) {
                            need_upgrade = 0;
                        }
                    }
                }
            }
#endif
            if (f != NULL) {
                fclose(f);
            }
        } else {
            rc = needs_upgrade(dv, src_file, dst_file,  descr, &need_upgrade);
        }
        if (need_upgrade)
            vector_push(files_to_upgrade, src_file);
    }
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   read_upgrade()
 *
 * Description: Read the descriptor in the upgrade directory
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static vector
read_upgrade_descriptor()
{
    char filename[MAXPATHLEN];
    sprintf(filename, "%s%s", patch_dir_name, descriptor_file);
    return read_descriptor(filename);
}


/*-----------------------------------------------------------------
 * Name :   get_file_inode()
 *
 * Description: Return the inode of the file filename or -1 if can not stat
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/28/02
 *
 *-----------------------------------------------------------------
 */
static void *
get_file_inode(void *filename)
{
    struct stat st;
    ino_t rv = -1;
    if (lstat(filename, &st) == 0) {
        rv = st.st_ino;
    }
    return (void *)rv;
}


/*-----------------------------------------------------------------
 * Name :   copy_local_truename()
 *
 * Description: Return the name of temporary copy of the file.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    09/13/02
 *
 *-----------------------------------------------------------------
 */
static char *
copy_local_truename(char *file)
{
    static char name[MAXPATHLEN];
    strcpy(name, local_dest);
    strcat(name, file + strlen(patch_dir_name));
    return name;
}


/*-----------------------------------------------------------------
 * Name :   copy_files_to_local()
 *
 * Description: Copy files to local disk and return new files locations.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    09/13/02
 *
 *-----------------------------------------------------------------
 */
static int
copy_files_to_local(vector files, vector *new_files)
{
    int rc = CMD_ERR_FAILED;
    char *tmp = zstrdup(MTYPE_TMP, local_dest);

    if (ensure_dir_exists(tmp, 0777) == 0) {
        int rc;

        rc = do_system("mount_mfs -s 100000 swap %s", local_dest);
        if (rc == 0) {
            /* Create directories in temporary copy */
            rc = do_system("/usr/sbin/mtree -qdUef "
                    "%s%s -p %s >/dev/null 2>/dev/null",
                    mount_dir, mtree_file_name, local_dest);
            if (rc == 0) {
                /* Copy mtree file to temporary location because will
                   need it later to make directories in the real tree */
                rc = do_system("/usr/bin/install %s%s %s%s",
                        mount_dir, mtree_file_name,
                        local_dest, mtree_file_name);
                if (rc == 0) {
                    if (upgrade_files(files, copy_local_truename) == 0) {
                        int i;
                        *new_files = vector_init(vector_max(files));
                        for (i = 0; i < vector_max(files); ++i) {
                            char *f = vector_lookup_index(files, i);
                            char *newf;
                            asprintf(&newf, "%s%s", local_dest,
                                     cur_truename_func(f));
                            vector_push(*new_files, newf);
                        }
                        rc = CMD_SUCCESS;
                    } else {
                        my_print("Please retry upgrade using a management"
                               "interface.\n");
                    }
                }
            } else {
                my_print("Can't update local directory tree\n");
            }
            if (rc != CMD_SUCCESS)
                do_system("/sbin/umount %s", local_dest);
        } else {
            my_print("Can't mount filesystem for local copy\n");
        }
    } else {
        sprintf(sys_log_str,"Can't create directory %s\n", local_dest);
        my_print(sys_log_str);
    }
    zfree(MTYPE_TMP, tmp);
    return convert_rc(rc);
}


/*-----------------------------------------------------------------
 * Name :   has_valid_ip_addr()
 *
 * Description: Return true if the patch location contains a valid
 *              ip address
 * interface.
 *
 * Created by:  Laurent Brard
 *
 * Date Created:07/09/03
 *
 *-----------------------------------------------------------------
 */
static int
has_valid_ip_addr(char *patch_location)
{
    char *column = strchr(patch_location, ':');
    struct in_addr host_addr;
    int rc;
    
    if (column == NULL)
        return FALSE;
    *column = 0;
    rc = inet_aton(patch_location, &host_addr);
    *column = ':';

    return rc;
}

/*-----------------------------------------------------------------
 * Name :   is_fp_addr()
 *
 * Description: Return true if the patch is accessed through fp
 * interface.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    11/01/02
 *
 *-----------------------------------------------------------------
 */
static int
is_fp_addr(char *patch_location)
{
    char *column = strchr(patch_location, ':');
    struct in_addr host_addr;
    in_addr_t our_addr;
    int rc;
    char iface[256];
    *column = 0;

    inet_aton(patch_location, &host_addr);
    rc = get_our_addr(host_addr.s_addr, iface, &our_addr);
    return !(rc == 0 && (!strcmp(iface, "sc1") || !strcmp(iface, "sc2")));
}

/*-----------------------------------------------------------------
 * Name :   need_local_copy()
 *
 * Description: Return true if need to copy files to local disk before
 * upgrading - if using fp interface to upgrade and not upgrading the standby
 * flash.
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    09/13/02
 *
 *-----------------------------------------------------------------
 */
static int
need_local_copy()
{
    return (!upgrade_secondary &&
            !is_ftp_upgrade(patch_location) &&
            is_fp_addr(patch_location));
}

/*-----------------------------------------------------------------
 * Name :   perform_upgrade()
 *
 * Description: upgrade a system from a complete distribution
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
perform_upgrade(void)
{
    vector files = NULL;
    vector files_no_dups = NULL;
    vector dv;
    int rc = CMD_ERR_FAILED;

    my_print("Reading the system descriptor...");
    dv = read_upgrade_descriptor();
    if (dv != NULL) {
        my_print("done\n");
        files = vector_init(200);
        my_print("Reading the upgrade directory...");
        rc = find_files(patch_dir_name, files);
        if (rc == CMD_SUCCESS) {
            vector files_to_upgrade;
            my_print("done\n");
            if (sys_upgrade) {
                fprintf(sys_upgrade,"Make upgrade file list, Start time: %s\n",get_time());
                fflush(sys_upgrade);
            }
            my_print("Making upgrade files list\n");
            //files_no_dups = vector_remove_duplicates(files, get_file_inode);
            //vector_free(files);
            files_to_upgrade = vector_init(200);
            rc = make_files_to_upgrade_list(dv, files_to_upgrade, files);
            if (rc == CMD_SUCCESS) {
                int make_local_copy = need_local_copy();
                if (sys_upgrade) {
                    fprintf(sys_upgrade,"Make upgrade file list, End time: %s\n",get_time());
                    fflush(sys_upgrade);
                }
                my_print("The following files will be upgraded:\n");
                print_string_vector(files_to_upgrade);
                if (make_local_copy) {
                    vector new_files;
                    my_print("Copying files to local disk\n");
                    rc = copy_files_to_local(files_to_upgrade, &new_files);
                    if (rc == CMD_SUCCESS) {
                        if (sys_upgrade) {
                            fprintf(sys_upgrade,"Files upgraded, End time: %s\n",get_time());
                            fflush(sys_upgrade);
                        }
                        do_system("/sbin/umount %s", mount_dir);
                        files_to_upgrade = new_files;
                    }
                }
                if (rc == CMD_SUCCESS) {
                    char mtree_file[256];
                    sprintf(mtree_file, "%s%s",
                            make_local_copy ? local_dest : mount_dir,
                            mtree_file_name);
                    rc = complete_upgrade(dv, files_to_upgrade,
							cur_truename_func, mtree_file);
                }
            } else {
                my_print("Failed to get the list of files to upgrade\n");
            }
            vector_free_all(files_no_dups);
        } else {
            my_print("failed\n");
        }
        vector_free(files);
        vector_free_all(dv);
    } else {
        my_print("failed\n");
    }
    return rc;
}

extern int __getopt_initialized;

/*-----------------------------------------------------------------
 * Name :   parse_args()
 *
 * Description: parse command line arguments
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    11/01/02
 *
 *-----------------------------------------------------------------
 */
static int
parse_args(int argc, char **argv)
{
    int i;

    upgrade_secondary = 0;
    force_upgrade = 0;

    if ((argc > 1) && (argc <= 3)) {
        for (i = 0; i < argc-1; i++) {
            if (!strcmp(argv[i], "-s"))
                upgrade_secondary = 1;
            else
            if (!strcmp(argv[i], "-f"))
                force_upgrade = 1;
            else {
                printf("? Invalid option\n");
                return CMD_ERR_FAILED;
            }
        }
    }
    else {
        if (argc != 1) {
            printf("? Invalid option\n");
            return CMD_ERR_FAILED;
        }
    }

    patch_location = argv[argc-1];
    if (!is_ftp_upgrade(patch_location)) {
    // if (!is_ftp_upgrade(patch_location) &&
    //     !has_valid_ip_addr(patch_location)) {
        my_print("Invalid upgrade location\n");
        return CMD_ERR_FAILED;
    }
    else {
        if (sys_upgrade) {
            fprintf(sys_upgrade,"Performing system upgrade from location %s\n",patch_location);
            fflush(sys_upgrade);
        }
    }
    return CMD_SUCCESS;
}

/*-----------------------------------------------------------------
 * Name : form_full_path()
 *
 * Description : Get the password and forms a full path for ftp
 *
 * Created by:
 *
 * Date Created: 03/16/06
 *
 * -----------------------------------------------------------------
 */
int
form_full_path(int argc, char **argv, char **full_path)
{
    char passwd[SEC_PWD_MAX], *start, *start_colon, *end_colon;
    char *patch_location = argv[argc-1];
    char strTar[8];
    /*
     * Check for the command incomplete.
     * if ftp is not specified then error msg will be displayed.
     */
    if (!is_ftp_upgrade(patch_location))
    {
        my_print("ftp URL is not specified\n");
        return CMD_ERR_INCOMPLETE;
    }

    /* Check if tar file is specified */
    bzero(strTar,8);
    strncpy(strTar,patch_location + strlen(patch_location)-6,6);
    if (strcmp(strTar, "tar.gz"))
    {
        my_print("tar file is not specified\n");  
        return CMD_ERR_FAILED;
    }

     /*
     * Check for the '@' in ftp.
     * If it is not specified then error msg will be displayed.
     */
    if ((start = strchr(patch_location, '@')) == NULL)
    {
        my_print("Unable to find hostname/ip address in ftp URL\n");
        return CMD_ERR_FAILED;
    }

    /*
     * Check to see whether the password is specified with the username.
     */
    start_colon = strchr(patch_location, ':');
    end_colon = strrchr(patch_location, ':');
    if (start_colon != end_colon)
    {
        *full_path = NULL;
        return CMD_SUCCESS;
    }
    
    /*
     * If the password is not specified with the user name, this function
     * gets the password from the user.
     */
    if (getPasswdFromUser(passwd, NULL, 0, sizeof(passwd), TRUE) != 0)
    {
        return CMD_ERR_FAILED;
    }

    *full_path = (char *)malloc(strlen(argv[argc-1]) + strlen(passwd) + 2);
    if(*full_path == NULL)
    {
        my_print("Couldn't allocate memory\n");
        return CMD_ERR_FAILED;
    }
    /*
     * Splits the 'ftp://user@ipaddr/path' into two parts.
     * Extracts the 'ftp://user' string.
     */
    memset(*full_path, 0, (strlen(argv[argc-1]) + strlen(passwd) + 2));
    strncat(*full_path, patch_location, start-patch_location);
    /*
     * Concatenates ':' and passwd with 'ftp://user'
     * After that the string will be 'ftp://user:passwd'
     */
    strcat(*full_path, ":");
    strcat(*full_path, passwd);
    /*
     * Appends the remaining string in ftp.
     * The remaining string will be '@ipaddr/path'.
     */
    strcat(*full_path, start);
    
    /*
     * Assigns the new string to argv[argc-1]
     */
    argv[argc-1] = *full_path;
    return CMD_SUCCESS;
}
    
/*-----------------------------------------------------------------
 * Name :        sendUpgradeEvent()
 *
 * Description:  Send a "NFX_EVENT_UPGRADE" event to support.sh.
 *
 * Created by:   Ed Kwan
 *
 * Date Created: 09/06/06
 *
 *-----------------------------------------------------------------
 */
static void
sendUpgradeEvent(void)
{
	do_system("/usr/local/agile/bin/support.sh -c0 -g NFX_EVENT_UPGRADE "
			 "-Called_from_nfxsh %s > /dev/null 2>&1", sys_upgrade_logfile);
}

/*-----------------------------------------------------------------
 * Name :   do_upgrade()
 *
 * Description: make system upgrade
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
int
do_upgrade(int argc, char **argv) 
{
    struct version current_version, upgrade_version;
    struct version org_upgrade_version;
    int rc = CMD_SUCCESS;
    int i;
    vector secondary_fstabs = NULL;

    become_root();
    if ((sys_upgrade = fopen(sys_upgrade_logfile,"w")) == NULL )
        printf("Error opening file %s.\n",sys_upgrade_logfile);

    if (sys_upgrade) {
        fprintf(sys_upgrade,"System Upgrade Command started at: %s\n",
		    get_time());
        fflush(sys_upgrade);
    }

	/*
	 * system upgrade uses /tmp space. verify that /tmp is not full.
	 * if /tmp is full, then fail upgrade, and log error.
	 */
	if (system("if [ `df -h /tmp | tail -1 | awk '{print $5}' | sed 's/%//'` -lt 99 ]; then exit 0; else exit 1; fi")) {
		fprintf(sys_upgrade, "/tmp is full, system upgrade failed\n");
		printf("/tmp is FULL, system upgrade failed!\n");
		unbecome_root();
		rc = CMD_ERR_FAILED;
		goto done;
	}

    rc = parse_args(argc, argv);
    if (rc != CMD_SUCCESS) {
		goto done;
	}
    
    if (upgrade_secondary) {
        get_device_names();
		secondary_fstabs = make_secondary_fstabs();
        my_print("Checking file system...\n");
        if (sys_upgrade) {
            fprintf(sys_upgrade,"filesystem check started at: %s\n",get_time());
            fflush(sys_upgrade);
        }
        for (i = 0; i < vector_max(secondary_fstabs); ++i) {
            struct fstab *fs = vector_lookup_index(secondary_fstabs, i);
            execute_command("/sbin/fsck", 2, "-y", fs->fs_spec, NULL);
        }
        my_print("Unmounting secondary disk...");
        //whoops, kiss that memory goodbye
		//secondary_fstabs = make_secondary_fstabs();
        u_mount_secondary(secondary_fstabs);
        my_print("Mounting secondary disk...");
        rc = convert_rc(mount_secondary(secondary_fstabs));
        sprintf(sys_log_str, "%s\n", rc == CMD_SUCCESS ? "done." : "failed.");
        my_print(sys_log_str);
        if (sys_upgrade) {
            fprintf(sys_upgrade, "Mounted secondary disk at: %s\n", get_time());
            fflush(sys_upgrade);
        }
        cur_truename_func = secondary_upgrade_truename;
    } else {
        cur_truename_func = upgrade_truename;
    }

    if (rc == CMD_SUCCESS) {
        rc = mount_patch(patch_location);
        if (rc == CMD_SUCCESS) {
            my_print("Mounted the upgrade directory\n");
            if (sys_upgrade) {
                fprintf(sys_upgrade,"Mounted upgrade directory at: %s\n",get_time());
                fflush(sys_upgrade);
            }
            if ((rc = get_upgrade_version(&upgrade_version)) == CMD_SUCCESS) {
                get_org_upgrade_version(&org_upgrade_version);
                if ((rc = get_local_version(&current_version)) == CMD_SUCCESS) {
                    if (current_version.platform != upgrade_version.platform) {
                        my_print("The upgrade distribution is not compatible with this system!\n");
                    } else { 
                        sprintf(sys_log_str,"Current system version: %d.%d.%d.%d "
                            "upgrade version: %d.%d.%d.%d\n",
                            current_version.major, current_version.minor,
                            current_version.maintenance, current_version.patch,
                            upgrade_version.major, upgrade_version.minor,
                            upgrade_version.maintenance, upgrade_version.patch);
                        my_print(sys_log_str);
                        if (!force_upgrade &&
                            (compare_versions(&current_version,
                                             &upgrade_version) >= 0)) {
                            my_print("The system is up-to-date\n");
                        } else {
                            /* Check for illegal upgrades. */
                            rc = check_versions_compatible(
                                     &current_version,
                                     &upgrade_version);
                            if (rc != CMD_SUCCESS) {
                                sprintf(sys_log_str,"Cannot upgrade from "
                                        "version %d.%d.%d.%d to version "
                                        "%d.%d.%d.%d\n",
                                        current_version.major,
                                        current_version.minor,
                                        current_version.maintenance,
                                        current_version.patch,
                                        upgrade_version.major,
                                        upgrade_version.minor,
                                        upgrade_version.maintenance,
                                        upgrade_version.patch);
                                my_print(sys_log_str);
                            } else if (force_upgrade ||
                                (compare_versions(&current_version,
                                                  &org_upgrade_version) >= 0)) {
                                rc = perform_upgrade();
                            } else {
                                sprintf(sys_log_str,"Start version %d.%d.%d.%d is newer "
                                       "than current, can not upgrade\n",
                                       org_upgrade_version.major,
                                       org_upgrade_version.minor,
                                       org_upgrade_version.maintenance,
                                       org_upgrade_version.patch);
                                my_print(sys_log_str);
                                rc = CMD_ERR_FAILED;
                            }
                        }
                    }
                }
            } else {
                my_print("failed to determine the upgrade version\n");
            }
            umount_patch();
        }
    }

    if (upgrade_secondary) {
        u_mount_secondary(secondary_fstabs);
        free_fstab_vector(secondary_fstabs);
    }

    if (fclose(sys_upgrade) != 0) {
        printf("Error closing file %s.\n", sys_upgrade_logfile);
	}
done:
    unbecome_root();
    sendUpgradeEvent();
    return rc;
}

/*-----------------------------------------------------------------
 * Name :   show_local_version()
 *
 * Description: Show the system version
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
show_local_version(void)
{
    struct version current_version;
    int rc = get_root_version(&current_version);
    if (rc != CMD_SUCCESS) {
        fprintf(stderr, "Can't determine current version\n");
        if (sys_upgrade) {
            fprintf(sys_upgrade, "Can't determine current version\n");
            fflush(sys_upgrade);
        }
    }
    else {
        print_version(&current_version);
    }
    return rc;
}

/*-----------------------------------------------------------------
 * Name :   show_secondary_version()
 *
 * Description: Show the version of the secondary flash
 *
 * Created by:  Danqing Jin
 *
 * Date Created:    07/05/06
 *
 *-----------------------------------------------------------------
 */
static int
show_secondary_version(void)
{
    struct version sec_version;
    int rc;
    vector secondary_fstabs = NULL;

    become_root();
    get_device_names();
    secondary_fstabs = make_secondary_fstabs();

    if ((rc = convert_rc(mount_secondary(secondary_fstabs))) == CMD_SUCCESS) {
        if (get_secondary_version(&sec_version) == CMD_SUCCESS) {
            print_version(&sec_version);
        }
        else {
            fprintf(stderr, "Failed to get a valid version\n");
        } 
    }
    else {
        fprintf(stderr, "Mount of the secondary flash failed\n");
    }
    u_mount_secondary(secondary_fstabs);
    free_fstab_vector(secondary_fstabs);
    unbecome_root();

    return rc;
}

/*-----------------------------------------------------------------
 * Name :   show_remote_version()
 *
 * Description: Show the version of the patch 
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
static int
show_remote_version(char *patch_path)
{
    struct version version;
    int rc;
	char version_file[MAXPATHLEN + 1];
    
    become_root();
    rc = mount_patch(patch_path);
    if (rc == CMD_SUCCESS) {
   	    snprintf(version_file, MAXPATHLEN+1, "%s/version", mount_dir);
        if ((rc = read_version(version_file, &version)) == CMD_SUCCESS) {
            print_version(&version);
        }
        umount_patch();
    }
    else {
        fprintf(stderr, "Can not mount the patch directory\n");
        if (sys_upgrade) {
             fprintf(sys_upgrade, "Can not mount the patch directory\n");
             fflush(sys_upgrade);
        }
    }
    unbecome_root();
    
    return rc;
}


/*-----------------------------------------------------------------
 * Name :   do_show_version()
 *
 * Description: show the local version or a patch version
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    05/14/02
 *
 *-----------------------------------------------------------------
 */
int
do_show_version(int argc, char **argv)
{
    int c;
    optind = 0;  // This seems to be the trick for getopt() to work

    if (argc == 0) {
        return show_local_version();
    } else if (argc == 1) {
        while ((c = getopt(argc, argv, "s")) != -1) {
            switch (c) {
            case 's':
                return show_secondary_version();
            default:
                fprintf(stderr, "Invalid option\n");
                return (CMD_ERR_FAILED);
    }
        }
        return show_remote_version(argv[0]);
    } else {
        return (CMD_ERR_FAILED);
    }
}


/*-----------------------------------------------------------------
 * Name :   do_prom_upgrade()
 *
 * Description: prom upgrade command 
 *
 * Created by:  Maxim Kozlovsky
 *
 * Date Created:    06/26/02
 *
 *-----------------------------------------------------------------
 */
int
do_prom_upgrade(int argc, char **argv)
{
    int rc = CMD_ERR_FAILED;
    if (argc == 2) {
        int slot = atoi(argv[0]);
        int cpu = atoi(argv[1]);
        if (valid_slot_cpu(slot, cpu)) {
            rc = upgrade_prom_slotcpu(slot, cpu, NULL);
        }
    }
    return rc;
}

/*++

Routine Description:
    This routine sleeps for an absolute time more accurately than sleep().

Arguments:    
    secs - time to sleep

Return value:
    NFX_OK or NFX_ERR

--*/
int
sleep_accurately(int secs)
{
    uint32 end_secs;
    struct timeval tv;

    if (gettimeofday(&tv, NULL) == 0) {
        end_secs = tv.tv_sec + secs;
    }
    else {
        return NFX_ERR;
    }
    while (tv.tv_sec < end_secs) {
        sleep(1);
        if (gettimeofday(&tv, NULL) != 0) {
            return NFX_ERR;
        }
    }
    return NFX_OK;
}

extern int __getopt_initialized;

/*-----------------------------------------------------------------
 * Name :   parse_compare_args()
 *
 * Description: parse command line arguments for System compare
 *
 * Created by:  Vikas Saini
 *
 * Date Created:    07/13/05
 *
 *-----------------------------------------------------------------
 */
static int
parse_compare_args(int argc, char **argv)
{
    int c;

    compare_secondary = 0;

    __getopt_initialized = 0;
    optind = 0;

    while ((c = getopt(argc, argv, "s")) != -1) {
        switch (c) {
        case 's':
            compare_secondary = 1;
            break;
        default:
            printf("Invalid option\n");
            return CMD_ERR_FAILED;
        }
    }

    if (optind != argc - 1) {
        printf("Upgrade location not specified\n");
        return CMD_ERR_FAILED;
    }

    patch_location = argv[optind];
    if (!is_ftp_upgrade(patch_location) &&
        !has_valid_ip_addr(patch_location)) {
        printf("Invalid upgrade location\n");
        return CMD_ERR_FAILED;
    }

    return CMD_SUCCESS;
}



/*-----------------------------------------------------------------
 * Name :   perform_compare()
 *
 * Description: compares a complete system software distribution
 *
 * Created by:  Vikas Saini
 *
 * Date Created:    07/13/05
 *
 *-----------------------------------------------------------------
 */
static int
perform_compare(void)
{
    vector files = NULL;
    vector files_no_dups = NULL;
    vector dv;
    int rc = CMD_ERR_FAILED;
    unsigned int diff_file_count;
    int i;
    
    printf("Reading the system descriptor...");
    fflush(stdout);
    dv = read_upgrade_descriptor();
    if (dv != NULL) {
        printf("done\n");
        files = vector_init(200);
        printf("Reading the External System Software directory...");
        fflush(stdout);
        rc = find_files(patch_dir_name, files);
        if (rc == CMD_SUCCESS) {
            vector files_to_upgrade;
            printf("done\n");
            printf("Making changed files list\n");
            files_no_dups = vector_remove_duplicates(files, get_file_inode);
            vector_free(files);
            files_to_upgrade = vector_init(200);
            rc = make_files_to_upgrade_list(dv, files_to_upgrade, files_no_dups);
            if (rc == CMD_SUCCESS) {
                diff_file_count = vector_count(files_to_upgrade);
                if (diff_file_count == 0) {
                     printf("\n\nfiles are same on source and target location:\n");
                }    
                else if (diff_file_count == 1) {
                     for (i = 0; rc == CMD_SUCCESS && i < vector_max(files_to_upgrade); ++i) {
                         char *src_file = vector_lookup_index(files_to_upgrade, i);
                         if (!(strcmp(src_file, "/version")) || !(strcmp(src_file, "/mnt/version")) || !(strcmp(src_file, "/mnt1/version"))) { 
                            printf("\n\nfiles are same on source and target location:\n");
                         }
                     }
                } 
                else {
                     printf("\n\nThe following files are different:\n");
                     print_string_vector(files_to_upgrade);
                }
            }
            else {
                printf("Failed to get the list of files that are different\n");
            }
            vector_free_all(files_no_dups);
        }
        else {
            printf("failed\n");
        }
        vector_free(files);
        vector_free_all(dv);
    }
    else {
        printf("failed\n");
    }
    return rc;
}
/*-----------------------------------------------------------------
 * Name :   do_compare()
 *
 * Description: compare system software
 *
 * Created by:  Vikas Saini
 *
 * Date Created:    07/13/05
 *
 *-----------------------------------------------------------------
 */
int
do_compare(int argc, char **argv)
{
    struct version current_version, upgrade_version;
    struct version org_upgrade_version;
    int rc = CMD_SUCCESS;
    int i;
    vector secondary_fstabs = NULL;

    rc = parse_compare_args(argc, argv);
    if (rc != CMD_SUCCESS)
        return rc;

    become_root();
    if (compare_secondary) {
		get_device_names();
        secondary_fstabs = make_secondary_fstabs();
        printf("Checking file system...\n");
        for (i = 0; i < vector_max(secondary_fstabs); ++i) {
            struct fstab *fs = vector_lookup_index(secondary_fstabs, i);
            execute_command("/sbin/fsck", 2, "-y", fs->fs_spec, NULL);
        }
        printf("Mounting secondary disk...");
        fflush(stdout);
        //lost in memory
        //secondary_fstabs = make_secondary_fstabs();
        u_mount_secondary(secondary_fstabs);
        rc = convert_rc(mount_secondary(secondary_fstabs));
        printf("%s\n", rc == CMD_SUCCESS ? "done." : "failed.");
        cur_truename_func = secondary_upgrade_truename;
    } else {
        cur_truename_func = upgrade_truename;
    }

    if (rc == CMD_SUCCESS) {
        rc = mount_patch(patch_location);
        if (rc == CMD_SUCCESS) {
            printf("Mounted the external system software directory\n");
            if ((rc = get_upgrade_version(&upgrade_version)) == CMD_SUCCESS) {
                get_org_upgrade_version(&org_upgrade_version);
                if ((rc = get_local_version(&current_version)) == CMD_SUCCESS) {
                    if (current_version.platform != upgrade_version.platform) {
                        printf("The external system software distribution is not compatible with this system!\n");
                    }
                    else {
                        printf("Current system version: %d.%d.%d.%d "
                            "compare version: %d.%d.%d.%d\n",
                            current_version.major, current_version.minor,
                            current_version.maintenance, current_version.patch,
                            upgrade_version.major, upgrade_version.minor,
                            upgrade_version.maintenance, upgrade_version.patch);
                        rc = perform_compare();
                    }
                }
            }
            else {
                printf("failed to determine the compare version and perform comparison\n");
            }
            umount_patch();
        }
    }

    if (compare_secondary) {
        u_mount_secondary(secondary_fstabs);
        free_fstab_vector(secondary_fstabs);
    }
    
    unbecome_root();
    return rc;
}



--MP_IFDMtwXLKPhRPHHeG_momek--
